Files
rocm-systems/opencl/api/opencl/amdocl/cl_gl.cpp
T
foreman d65b1ec47f P4 to Git Change 1275749 by wchau@wchau_WIN_OCL_HSA on 2016/06/02 13:38:16
SWDEV-89502 - [OCL] Support AMD DVR Core functionalities.  Add OCL support for DOPP for desktop and present texture (OCL RT changes)

Affected files ...

... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_gl.cpp#50 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_svm.cpp#17 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/khronos/headers/opencl1.2/CL/cl_ext.h#11 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/khronos/headers/opencl2.0/CL/cl_ext.h#25 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/khronos/headers/opencl2.1/CL/cl_ext.h#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpukernel.cpp#316 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpukernel.hpp#124 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuvirtual.cpp#403 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gslbe/src/rt/GSLDeviceGL.cpp#26 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/kernel.hpp#16 edit
2016-06-02 14:15:36 -04:00

2676 lines
92 KiB
C++

//
// Copyright 2010 Advanced Micro Devices, Inc. All rights reserved.
//
#ifdef _WIN32
#include <d3d10_1.h>
#include <d3d9.h>
#include <dxgi.h>
// This is necessary since there are common GL/D3D10 functions
#include "cl_d3d9_amd.hpp"
#include "cl_d3d10_amd.hpp"
#include "cl_d3d11_amd.hpp"
#endif //_WIN32
#include <GL/gl.h>
#include <GL/glext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include "cl_common.hpp"
#include "cl_gl_amd.hpp"
#include "device/device.hpp"
/* The pixel internal format for DOPP texture defined in gl_enum.h */
#define GL_BGR8_ATI 0x8083
#define GL_BGRA8_ATI 0x8088
#include <cstring>
#include <vector>
/*! \addtogroup API
* @{
*
* \addtogroup CL_GL_Interops
*
* This section discusses OpenCL functions that allow applications to
* use OpenGL buffer/texture/render-buffer objects as OpenCL memory
* objects. This allows efficient sharing of data between these OpenCL
* and OpenGL. The OpenCL API can be used to execute kernels that read
* and/or write memory objects that are also an OpenGL buffer object
* or a texture. An OpenCL image object can be created from an OpenGL
* texture or renderbuffer object. An OpenCL buffer object can be
* created from an OpenGL buffer object. An OpenCL memory object can
* be created from an OpenGL texture/buffer/render-buffer object or
* the default system provided framebuffer if any only if the OpenCL
* clContext has been created from a GL clContext. OpenGL contexts are
* created using platform specific APIs (EGL, CGL, WGL, GLX are some
* of the platform specific APIs that allow applications to create GL
* contexts). The appropriate platform API (such as EGL, CGL, WGL,
* GLX) will be extended to allow a CL clContext to be created from a
* GL clContext. Creating an OpenCL memory object from the default
* system provided framebuffer will also require an appropriate
* extension to the platform API. Refer to the appropriate platform
* API documentation to understand how to create a CL clContext from a
* GL clContext and creating a CL memory object from the default
* system provided framebuffer.
*
* @{
*
* \addtogroup clCreateFromGLBuffer
*
* @{
*/
/*! \brief Creates an OpenCL buffer object from an OpenGL buffer object.
*
* \param clContext is a valid OpenCL clContext created from an OpenGL clContext.
*
* \param clFlags is a bit-field that is used to specify usage information. Only
* CL_MEM_READ_ONLY, CL_MEM_WRITE_ONLY and CL_MEM_READ_WRITE can be used.
*
* \param glBufferName is a GL buffer object name. The GL buffer
* object must have a data store created though it does not need to
* be initialized. The size of the data store will be used to
* determine the size of the CL buffer object.
*
* \param pCpuMem is a pointer to the buffer data that may already be
* allocated by the application. The size of the buffer that pCpuMem points
* to must be >= \a size bytes. Passing in a pointer to an already allocated
* buffer on the host and using it as a buffer object allows applications to
* share data efficiently with kernels and the host.
*
* \param errcode_ret will return an appropriate error code. If errcode_ret
* is NULL, no error code is returned.
*
* \return valid non-zero OpenCL buffer object and errcode_ret is set
* to CL_SUCCESS if the buffer object is created successfully. It
* returns a NULL value with one of the following error values
* returned in \a errcode_ret:
* - CL_INVALID_CONTEXT if \a clContext is not a valid clContext.
* - CL_INVALID_VALUE if values specified in \a clFlags are not valid.
* - CL_INVALID_GL_OBJECT if glBufferName is not a GL buffer object or is a
* GL buffer object but does not have a data store created.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
* by the runtime.
*
* \version 1.0r29
*/
RUNTIME_ENTRY_RET(cl_mem, clCreateFromGLBuffer, (
cl_context context,
cl_mem_flags flags,
GLuint bufobj,
cl_int* errcode_ret))
{
cl_mem clMemObj = NULL;
if (!is_valid(context)) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("invalid parameter \"context\"");
return clMemObj;
}
if (!(((flags & CL_MEM_READ_ONLY) == CL_MEM_READ_ONLY)
|| ((flags & CL_MEM_WRITE_ONLY) == CL_MEM_WRITE_ONLY)
|| ((flags & CL_MEM_READ_WRITE) == CL_MEM_READ_WRITE))) {
*not_null(errcode_ret) = CL_INVALID_VALUE;
LogWarning("invalid parameter \"flags\"");
return clMemObj;
}
return(amd::clCreateFromGLBufferAMD(*as_amd(context), flags, bufobj, errcode_ret));
}
RUNTIME_EXIT
/*! \brief creates the following:
* - an OpenCL 2D image object from an OpenGL 2D texture object
* or a single face of an OpenGL cubemap texture object,
* - an OpenCL 2D image array object from an OpenGL 2D texture array object,
* - an OpenCL 1D image object from an OpenGL 1D texture object,
* - an OpenCL 1D image buffer object from an OpenGL texture buffer object,
* - an OpenCL 1D image array object from an OpenGL 1D texture array object,
* - an OpenCL 3D image object from an OpenGL 3D texture object.
*
* \param clContext is a valid OpenCL clContext created from an OpenGL clContext.
*
* \param clFlags is a bit-field that is used to specify usage information.
* Only CL_MEM_READ_ONLY, CL_MEM_WRITE_ONLY and CL_MEM_READ_WRITE values
* can be used.
*
* \param texture_target must be GL_TEXTURE_1D, GL_TEXTURE_1D_ARRAY,
* GL_TEXTURE_BUFFER, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D,
* GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
* GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
* GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z or GL_TEXTURE_RECTANGLE_ARB.
*
* \param miplevel is the mipmap level to be used. If \a texture_target
* is GL_TEXTURE_BUFFER, \a miplevel must be 0.
*
* \param texture is a GL 1D, 2D, 3D, 1D array, 2D array, cubemap,
* rectangle or buffer texture object.
* The texture object must be a complete texture as per
* OpenGL rules on texture completeness. The texture format and dimensions
* defined by OpenGL for the specified miplevel of the texture will be
* used to create the OpenCL image memory object. Only GL texture formats
* that map to appropriate image channel order and data type can be used
* to create the the OpenCL image memory object.
*
* \param errcode_ret will return an appropriate error code. If \a
* errcode_ret is NULL, no error code is returned.
*
* \return A valid non-zero OpenCL image object and \a errcode_ret is set to
* CL_SUCCESS if the image object is created successfully. It returns a NULL value
* with one of the following error values returned in \a errcode_ret:
* - CL_INVALID_CONTEXT if \a clContext is not a valid clContext or was not
* created from a GL clContext.
* - CL_INVALID_VALUE if values specified in \a clFlags are not valid.
* - CL_INVALID_MIP_LEVEL if \a miplevel is not a valid mip-level for \a texture.
* - CL_INVALID_GL_OBJECT if \a texture is not an appropriate GL 2D texture,
* cubemap or texture rectangle.
* - CL_INVALID_IMAGE_FORMAT_DESCRIPTOR if the OpenGL texture format does not
* map to an appropriate OpenCL image format.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
* by the runtime.
*
* \version 1.2r07
*/
RUNTIME_ENTRY_RET(cl_mem, clCreateFromGLTexture, (
cl_context context,
cl_mem_flags flags,
GLenum texture_target,
GLint miplevel,
GLuint texture,
cl_int* errcode_ret))
{
cl_mem clMemObj = NULL;
if (!is_valid(context)) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("invalid parameter \"context\"");
return clMemObj;
}
if (!(((flags & CL_MEM_READ_ONLY) == CL_MEM_READ_ONLY)
|| ((flags & CL_MEM_WRITE_ONLY) == CL_MEM_WRITE_ONLY)
|| ((flags & CL_MEM_READ_WRITE) == CL_MEM_READ_WRITE))) {
*not_null(errcode_ret) = CL_INVALID_VALUE;
LogWarning("invalid parameter \"flags\"");
return clMemObj;
}
const std::vector<amd::Device*>& devices = as_amd(context)->devices();
bool supportPass = false;
bool sizePass = false;
std::vector<amd::Device*>::const_iterator it;
for(it = devices.begin(); it != devices.end(); ++it) {
if ((*it)->info().imageSupport_) {
supportPass = true;
}
}
if (!supportPass) {
*not_null(errcode_ret) = CL_INVALID_OPERATION;
LogWarning("there are no devices in context to support images");
return static_cast<cl_mem>(0);
}
return amd::clCreateFromGLTextureAMD(*as_amd(context), flags,
texture_target, miplevel, texture, errcode_ret);
}
RUNTIME_EXIT
/*! @}
* \addtogroup clCreateFromGLTexture2D
* @{
*/
/*! \brief Create an OpenCL 2D image object from an OpenGL 2D texture object.
*
* \param clContext is a valid OpenCL clContext created from an OpenGL clContext.
*
* \param clFlags is a bit-field that is used to specify usage information.
* Only CL_MEM_READ_ONLY, CL_MEM_WRITE_ONLY and CL_MEM_READ_WRITE values
* can be used.
*
* \param target must be GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
* GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
* GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z or GL_TEXTURE_RECTANGLE_ARB.
*
* \param miplevel is the mipmap level to be used.
*
* \param texture is a GL 2D texture, cubemap or texture rectangle
* object name. The texture object must be a complete texture as per
* OpenGL rules on texture completeness. The \a texture format and
* dimensions specified using appropriate glTexImage2D call for \a
* miplevel will be used to create the 2D image object. Only GL
* texture formats that map to appropriate image channel order and
* data type can be used to create the 2D image object.
*
* \param errcode_ret will return an appropriate error code. If \a
* errcode_ret is NULL, no error code is returned.
*
* \return A valid non-zero OpenCL image object and \a errcode_ret is set to
* CL_SUCCESS if the image object is created successfully. It returns a NULL value
* with one of the following error values returned in \a errcode_ret:
* - CL_INVALID_CONTEXT if \a clContext is not a valid clContext or was not
* created from a GL clContext.
* - CL_INVALID_VALUE if values specified in \a clFlags are not valid.
* - CL_INVALID_MIP_LEVEL if \a miplevel is not a valid mip-level for \a texture.
* - CL_INVALID_GL_OBJECT if \a texture is not an appropriate GL 2D texture,
* cubemap or texture rectangle.
* - CL_INVALID_IMAGE_FORMAT_DESCRIPTOR if the OpenGL texture format does not
* map to an appropriate OpenCL image format.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
* by the runtime.
*
* \version 1.0r29
*/
RUNTIME_ENTRY_RET(cl_mem, clCreateFromGLTexture2D, (
cl_context context,
cl_mem_flags flags,
GLenum target,
GLint miplevel,
GLuint texture,
cl_int* errcode_ret))
{
cl_mem clMemObj = NULL;
if (!is_valid(context)) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("invalid parameter \"context\"");
return clMemObj;
}
if (!(((flags & CL_MEM_READ_ONLY) == CL_MEM_READ_ONLY)
|| ((flags & CL_MEM_WRITE_ONLY) == CL_MEM_WRITE_ONLY)
|| ((flags & CL_MEM_READ_WRITE) == CL_MEM_READ_WRITE))) {
*not_null(errcode_ret) = CL_INVALID_VALUE;
LogWarning("invalid parameter \"flags\"");
return clMemObj;
}
const std::vector<amd::Device*>& devices = as_amd(context)->devices();
bool supportPass = false;
bool sizePass = false;
std::vector<amd::Device*>::const_iterator it;
for(it = devices.begin(); it != devices.end(); ++it) {
if ((*it)->info().imageSupport_) {
supportPass = true;
}
}
if (!supportPass) {
*not_null(errcode_ret) = CL_INVALID_OPERATION;
LogWarning("there are no devices in context to support images");
return static_cast<cl_mem>(0);
}
return amd::clCreateFromGLTextureAMD(*as_amd(context), flags, target,
miplevel, texture, errcode_ret);
}
RUNTIME_EXIT
/*! @}
* \addtogroup clCreateFromGLTexture3D
* @{
*/
/*! \brief Create an OpenCL 3D image object from an OpenGL 3D texture object.
*
* \param clContext is a valid OpenCL clContext created from an OpenGL clContext.
*
* \param clFlags is a bit-field that is used to specify usage information.
* Only CL_MEM_READ_ONLY, CL_MEM_WRITE_ONLY and CL_MEM_READ_WRITE values
* can be used.
*
* \param target must be GL_TEXTURE_3D.
*
* \param miplevel is the mipmap level to be used.
*
* \param texture is a GL 3D texture object [name].
* The texture object must be a complete texture as per OpenGL rules on texture
* completeness. The \a texture format and dimensions specified using appropriate
* glTexImage3D call for \a miplevel will be used to create the 3D image object.
* Only GL texture formats that map to appropriate image channel order and
* data type can be used to create the 3D image object.
*
* \param errcode_ret will return an appropriate error code. If \a errcode_ret
* is NULL, no error code is returned.
*
* \return A valid non-zero OpenCL image object and \a errcode_ret is set to
* CL_SUCCESS if the image object is created successfully. It returns a NULL value
* with one of the following error values returned in \a errcode_ret:
* - CL_INVALID_CONTEXT if \a clContext is not a valid clContext or was not
* created from a GL clContext.
* - CL_INVALID_VALUE if values specified in \a clFlags are not valid.
* - CL_INVALID_MIP_LEVEL if \a miplevel is not a valid mip-level for \a texture.
* - CL_INVALID_GL_OBJECT if \a texture is not an GL 3D texture.
* - CL_INVALID_IMAGE_FORMAT_DESCRIPTOR if the OpenGL texture format does not
* map to an appropriate OpenCL image format.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
* by the runtime.
*
* \version 1.0r29
*/
RUNTIME_ENTRY_RET(cl_mem, clCreateFromGLTexture3D, (
cl_context context,
cl_mem_flags flags,
GLenum target,
GLint miplevel,
GLuint texture,
cl_int* errcode_ret))
{
cl_mem clMemObj = NULL;
if (!is_valid(context)) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("invalid parameter \"context\"");
return clMemObj;
}
if (!(((flags & CL_MEM_READ_ONLY) == CL_MEM_READ_ONLY)
|| ((flags & CL_MEM_WRITE_ONLY) == CL_MEM_WRITE_ONLY)
|| ((flags & CL_MEM_READ_WRITE) == CL_MEM_READ_WRITE))) {
*not_null(errcode_ret) = CL_INVALID_VALUE;
LogWarning("invalid parameter \"flags\"");
return clMemObj;
}
const std::vector<amd::Device*>& devices = as_amd(context)->devices();
bool supportPass = false;
bool sizePass = false;
std::vector<amd::Device*>::const_iterator it;
for(it = devices.begin(); it != devices.end(); ++it) {
if ((*it)->info().imageSupport_) {
supportPass = true;
}
}
if (!supportPass) {
*not_null(errcode_ret) = CL_INVALID_OPERATION;
LogWarning("there are no devices in context to support images");
return static_cast<cl_mem>(0);
}
return amd::clCreateFromGLTextureAMD(*as_amd(context), flags, target,
miplevel, texture, errcode_ret);
}
RUNTIME_EXIT
/*! @}
* \addtogroup clCreateFromGLRenderbuffer
* @{
*/
/*! \brief Create an OpenCL 2D image object from an OpenGL renderbuffer object.
*
* \param clContext is a valid OpenCL clContext created from an OpenGL clContext.
*
* \param clFlags is a bit-field that is used to specify usage information.
* Only CL_MEM_READ_ONLY, CL_MEM_WRITE_ONLY and CL_MEM_READ_WRITE values
* can be used.
*
* \param renderbuffer is a GL renderbuffer object name. The renderbuffer
* storage must be specified before the image object can be created. Only
* GL renderbuffer formats that map to appropriate image channel order and
* data type can be used to create the 2D image object.
*
* \param errcode_ret will return an appropriate error code. If \a errcode_ret
* is NULL, no error code is returned.
*
* \return A valid non-zero OpenCL image object and \a errcode_ret is set
* to CL_SUCCESS if the image object is created successfully. It returns a
* NULL value with one of the following error values returned in \a errcode_ret:
* - CL_INVALID_CONTEXT if \a clContext is not a valid clContext or was not
* created from a GL clContext.
* - CL_INVALID_VALUE if values specified in \a clFlags are not valid.
* - CL_INVALID_GL_OBJECT if \a renderbuffer is not an GL renderbuffer object.
* - CL_INVALID_IMAGE_FORMAT_DESCRIPTOR if the OpenGL renderbuffer format
* does not map to an appropriate OpenCL image format.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
* by the runtime.
*
* \version 1.0r29
*/
RUNTIME_ENTRY_RET(cl_mem, clCreateFromGLRenderbuffer, (
cl_context context,
cl_mem_flags flags,
GLuint renderbuffer,
cl_int* errcode_ret))
{
cl_mem clMemObj = NULL;
if (!is_valid(context)) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("invalid parameter \"context\"");
return clMemObj;
}
if (!(((flags & CL_MEM_READ_ONLY) == CL_MEM_READ_ONLY)
|| ((flags & CL_MEM_WRITE_ONLY) == CL_MEM_WRITE_ONLY)
|| ((flags & CL_MEM_READ_WRITE) == CL_MEM_READ_WRITE))) {
*not_null(errcode_ret) = CL_INVALID_VALUE;
LogWarning("invalid parameter \"flags\"");
return clMemObj;
}
return(amd::clCreateFromGLRenderbufferAMD(*as_amd(context), flags,
renderbuffer, errcode_ret));
}
RUNTIME_EXIT
/*! @}
* \addtogroup clGetGLObjectInfo
* @{
*/
/*! \brief Query GL object type from a CL memory object.
*
* \param memobj [is a valid cl_mem object created from a GL object].
*
* \param gl_object_type returns the type of GL object attached to memobj
* and can be CL_GL_OBJECT_BUFFER, CL_GL_OBJECT_TEXTURE2D,
* CL_GL_OBJECT_TEXTURE_RECTANGLE, CL_GL_OBJECT_TEXTURE3D, or
* CL_GL_OBJECT_RENDERBUFFER. If \a gl_object_type is NULL, it is ignored.
*
* \param gl_object_name returns the GL object name used to create memobj.
* If \a gl_object_name is NULL, it is ignored.
*
* \return One of the following values is returned:
* - CL_SUCCESS if the call was executed successfully.
* - CL_INVALID_MEM_OBJECT if \a memobj is not a valid OpenCL memory object.
* - CL_INVALID_GL_OBJECT if there is no GL object associated with \a memobj.
*
* \version 1.0r29
*/
RUNTIME_ENTRY(cl_int, clGetGLObjectInfo, (
cl_mem memobj,
cl_gl_object_type* gl_object_type,
GLuint* gl_object_name))
{
if (!is_valid(memobj)) {
LogWarning("\"memobj\" is not a valid cl_mem object");
return CL_INVALID_MEM_OBJECT;
}
amd::InteropObject* interop = as_amd(memobj)->getInteropObj();
if (NULL == interop) {
LogWarning("CL object \"memobj\" is not created from GL object");
return CL_INVALID_GL_OBJECT;
}
amd::GLObject* glObject = interop->asGLObject();
if (NULL == glObject) {
LogWarning("CL object \"memobj\" is not created from GL object");
return CL_INVALID_GL_OBJECT;
}
cl_int result;
cl_gl_object_type clGLType = glObject->getCLGLObjectType();
result = amd::clGetInfo(clGLType,
sizeof(cl_gl_object_type), gl_object_type, NULL);
GLuint glName = glObject->getGLName();
result |= amd::clGetInfo(glName, sizeof(GLuint), gl_object_name, NULL);
return result;
}
RUNTIME_EXIT
/*! @}
* \addtogroup clGetGLTextureInfo
* @{
*/
/*! \brief Query additional information about the GL texture object associated
* with \a memobj.
*
* \param memobj [is a valid cl_mem object created from a GL object].
*
* \param param_name specifies what additional information about the GL
* texture object associated with \a memobj to query:
* - CL_GL_TEXTURE_TARGET (GLenum) to query the \a target argument specified
* in clCreateGLTexture2D or clCreateGLTexture3D calls.
* - CL_GL_MIPMAP_LEVEL (GLint) to query the \a miplevel argument specified
* in clCreateGLTexture2D or clCreateGLTexture3D calls.
*
* \param param_value is a pointer to memory where the appropriate result
* being queried is returned. If \a param_value is NULL, it is ignored.
*
* \param param_value_size is used to specify the size in bytes of memory
* pointed to by \a param_value. This size must be >= size of return type as
* described for \a param_name argumnet (GLenum or GLint).
* \a param_value_size_ret returns the actual size in bytes of data copied to
* \a param_value. If \a param_value_size_ret is NULL, it is ignored
*
* \return One of the following values is returned:
* - CL_SUCCESS if the function is executed successfully.
* - CL_INVALID_MEM_OBJECT if \a memobj is not a valid OpenCL memory object.
* - CL_INVALID_GL_OBJECT if there is no GL texture object (2D or 3D texture)
* associated with \a memobj.
* - CL_INVALID_VALUE if \a param_name is not valid, or if size in bytes
* specified by \a param_value_size is < size of return type required by
* \a param_name and \a param_value is not NULL, or if \a param_value and
* \a param_value_size_ret are NULL.
*
* \version 1.0r29
*/
RUNTIME_ENTRY(cl_int, clGetGLTextureInfo, (
cl_mem memobj,
cl_gl_texture_info param_name,
size_t param_value_size,
void* param_value,
size_t* param_value_size_ret))
{
if (!is_valid(memobj)) {
LogWarning("\"memobj\" is not a valid cl_mem object");
return CL_INVALID_MEM_OBJECT;
}
amd::InteropObject* interop = as_amd(memobj)->getInteropObj();
if (NULL == interop) {
LogWarning("CL object \"memobj\" is not created from GL object");
return CL_INVALID_GL_OBJECT;
}
amd::GLObject* glObject = interop->asGLObject();
if ((NULL == glObject) || (NULL != glObject->asBufferGL())) {
LogWarning("CL object \"memobj\" is not created from GL texture");
return CL_INVALID_GL_OBJECT;
}
switch (param_name) {
case CL_GL_TEXTURE_TARGET: {
GLenum glTarget = glObject->getGLTarget();
if (glTarget == GL_TEXTURE_CUBE_MAP) {
glTarget = glObject->getCubemapFace();
}
return amd::clGetInfo(
glTarget, param_value_size, param_value, param_value_size_ret);
}
case CL_GL_MIPMAP_LEVEL: {
GLint mipLevel = glObject->getGLMipLevel();
return amd::clGetInfo(
mipLevel, param_value_size, param_value, param_value_size_ret);
}
case CL_GL_NUM_SAMPLES: {
GLsizei numSamples = glObject->getNumSamples();
return amd::clGetInfo(
numSamples,param_value_size, param_value, param_value_size_ret);
}
default:
LogWarning("Unknown param_name in clGetGLTextureInfoAMD");
break;
}
return CL_INVALID_VALUE;
}
RUNTIME_EXIT
/*! @}
* \addtogroup clEnqueueAcquireExtObjects
* @{
*/
/*! \brief Acquire OpenCL memory objects that have been created from external
* objects (OpenGL, D3D).
*
* \param command_queue is a valid command-queue.
*
* \param num_objects is the number of memory objects to be acquired
* in \a mem_objects.
*
* \param mem_objects is a pointer to a list of CL memory objects that refer
* to a GL object (buffer/texture/renderbuffer objects or the framebuffer).
*
* \param event_wait_list specify [is a pointer to] events that need to
* complete before this particular command can be executed.
* If \a event_wait_list is NULL, then this particular command does not wait
* on any event to complete. If \a event_wait_list is NULL,
* \a num_events_in_wait_list must be 0. If \a event_wait_list is not NULL,
* the list of events pointed to by \a event_wait_list must be valid and
* \a num_events_in_wait_list must be greater than 0. The events specified in
* \a event_wait_list act as synchronization points.
*
* \param num_events_in_wait_list specify the number of events in
* \a event_wait_list. It must be 0 if \a event_wait_list is NULL. It must be
* greater than 0 if \a event_wait_list is not NULL.
*
* \param event returns an event object that identifies this particular
* command and can be used to query or queue a wait for this particular
* command to complete. \a event can be NULL in which case it will not be
* possible for the application to query the status of this command or queue a
* wait for this command to complete.
*
* \return One of the following values is returned:
* - CL_SUCCESS if the function is executed successfully.
* - CL_SUCCESS if \a num_objects is 0 and \a mem_objects is NULL; the
* function does nothing.
* - CL_INVALID_VALUE if \a num_objects is zero and \a mem_objects is not a
* NULL value or if \a num_objects > 0 and \a mem_objects is NULL.
* - CL_INVALID_MEM_OBJECT if memory objects in \a mem_objects are not valid
* OpenCL memory objects.
* - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid command-queue.
* - CL_INVALID_CONTEXT if clContext associated with \a command_queue was not
* created from an OpenGL clContext.
* - CL_INVALID_GL_OBJECT if memory objects in \a mem_objects have not been
* created from a GL object(s).
* - CL_INVALID_EVENT_WAIT_LIST if \a event_wait_list is NULL and
* \a num_events_in_wait_list > 0, or \a event_wait_list is not NULL and
* \a num_events_in_wait_list is 0, or if event objects in \a event_wait_list
* are not valid events.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources
* required by the OpenCL implementation on the host.
*
* \version 1.0r29
*/
RUNTIME_ENTRY(cl_int, clEnqueueAcquireGLObjects, (
cl_command_queue command_queue,
cl_uint num_objects,
const cl_mem* mem_objects,
cl_uint num_events_in_wait_list,
const cl_event* event_wait_list,
cl_event* event))
{
return amd::clEnqueueAcquireExtObjectsAMD(
command_queue,
num_objects,
mem_objects,
num_events_in_wait_list,
event_wait_list,
event,
CL_COMMAND_ACQUIRE_GL_OBJECTS);
}
RUNTIME_EXIT
/*! @}
* \addtogroup clEnqueueReleaseGLObjects
* @{
*/
/*! \brief Release OpenCL memory objects that have been created from OpenGL
* objects.
*
* \param command_queue is a valid command-queue [which is associated with the
* OpenCL clContext releasing the OpenGL objects].
*
* \param num_objects is the number of memory objects to be released
* in \a mem_objects.
*
* \param mem_objects is a pointer to a list of CL memory objects that refer
* to a GL object (buffer/texture/renderbuffer objects or the framebuffer).
*
* \param event_wait_list specify [is a pointer to] events that need to
* complete before this particular command can be executed.
* If \a event_wait_list is NULL, then this particular command does not wait
* on any event to complete. If \a event_wait_list is NULL,
* \a num_events_in_wait_list must be 0. If \a event_wait_list is not NULL,
* the list of events pointed to by \a event_wait_list must be valid and
* \a num_events_in_wait_list must be greater than 0. The events specified in
* \a event_wait_list act as synchronization points.
*
* \param num_events_in_wait_list specify the number of events in
* \a event_wait_list. It must be 0 if \a event_wait_list is NULL. It must be
* greater than 0 if \a event_wait_list is not NULL.
*
* \param event returns an event object that identifies this particular
* command and can be used to query or queue a wait for this particular
* command to complete. \a event can be NULL in which case it will not be
* possible for the application to query the status of this command or queue a
* wait for this command to complete.
*
* \return One of the following values is returned:
* - CL_SUCCESS if the function is executed successfully.
* - CL_SUCCESS if \a num_objects is 0 and \a mem_objects is NULL; the
* function does nothing.
* - CL_INVALID_VALUE if \a num_objects is zero and \a mem_objects is not a
* NULL value or if \a num_objects > 0 and \a mem_objects is NULL.
* - CL_INVALID_MEM_OBJECT if memory objects in \a mem_objects are not valid
* OpenCL memory objects.
* - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid command-queue.
* - CL_INVALID_CONTEXT if clContext associated with \a command_queue was not
* created from an OpenGL clContext.
* - CL_INVALID_GL_OBJECT if memory objects in \a mem_objects have not been
* created from a GL object(s).
* - CL_INVALID_EVENT_WAIT_LIST if \a event_wait_list is NULL and
* \a num_events_in_wait_list > 0, or \a event_wait_list is not NULL and
* \a num_events_in_wait_list is 0, or if event objects in \a event_wait_list
* are not valid events.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources
* required by the OpenCL implementation on the host.
*
* \version 1.0r29
*/
RUNTIME_ENTRY(cl_int, clEnqueueReleaseGLObjects, (
cl_command_queue command_queue,
cl_uint num_objects,
const cl_mem* mem_objects,
cl_uint num_events_in_wait_list,
const cl_event* event_wait_list,
cl_event* event))
{
return amd::clEnqueueReleaseExtObjectsAMD(
command_queue,
num_objects,
mem_objects,
num_events_in_wait_list,
event_wait_list,
event,
CL_COMMAND_RELEASE_GL_OBJECTS);
}
RUNTIME_EXIT
/*! @}
* \addtogroup clCreateEventFromGLsyncKHR
* @{
*/
/*! \brief Creates an event object linked to an OpenGL sync object.
* Completion of such an event object is equivalent to waiting for completion
* of the fence command associated with the linked GL sync object.
*
* \param context is valid OpenCL context created from an OpenGL context
* or share group, using the cl_khr_gl_sharing extension.
*
* \param sync is the 'name' of a sync object in the GL share group associated
* with context.
*
* \param errcode_ret Returns an appropriate error code as described below.
* If errcode_ret is NULL, no error code is returned.
*
* \return a valid OpenCL event object and errcode_ret is set to CL_SUCCESS
* if the event object is created successfully.Otherwise, it returns a NULL
* value with one of the following error values returned in errcode_ret:
* - CL_INVALID_CONTEXT if context is not a valid context or was not created
* from a GL context.
* - CL_INVALID_GL_OBJECT if sync is not the name of a sync object in the
* GL share group associated with context.
*
* \version 1.1
*/
RUNTIME_ENTRY_RET(cl_event, clCreateEventFromGLsyncKHR, (
cl_context context,
cl_GLsync clGLsync,
cl_int* errcode_ret))
{
// create event of fence sync type
amd::ClGlEvent* clglEvent = new amd::ClGlEvent(*as_amd(context));
clglEvent->context().glenv()->glFlush_();
// initially set the status of fence as queued
clglEvent->setStatus(CL_SUBMITTED);
// store GLsync id of the fence in event in order to associate them together
clglEvent->setData(clGLsync);
amd::Event* evt = dynamic_cast<amd::Event*>(clglEvent);
evt->retain();
return as_cl(evt);
}
RUNTIME_EXIT
/*! @}
* \addtogroup clGetGLContextInfoKHR
* @{
*/
/*! \brief This f-n is defined in CL extension cl_khr_gl_sharing and serves
* the purpose of quering current device and all devices that support
* CL-GL interoperability.
*
* \param properties points to an <attribute list>, which is a array of
* ordered <attribute name, value> pairs terminated with zero. If an
* attribute is not specified in <properties>, then its default value
* (listed in table 4.attr) is used (it is said to be specified
* implicitly). If <properties> is NULL or empty (points to a list
* whose first value is zero), all attributes take on their default
* values.
*
* \param param_name may accept one of the following enumerated values:
* - CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR 0x2006
* - CL_DEVICES_FOR_GL_CONTEXT_KHR 0x2007.
*
* \param param_value_size is used to specify the size in bytes of memory
* pointed to by \a param_value. This size must be >= size of return type as
* described for \a param_name argumnet (GLenum or GLint).
* \a param_value_size_ret returns the actual size in bytes of data copied to
* \a param_value. If \a param_value_size_ret is NULL, it is ignored
*
* \param param_value is a pointer to memory where the appropriate result
* being queried is returned. If \a param_value is NULL, it is ignored.
*
* \param param_value_size is used to specify the size in bytes of memory
* pointed to by \a param_value. This size must be >= size of return type as
* described for \a param_name argumnet (GLenum or GLint).
* \a param_value_size_ret returns the actual size in bytes of data copied to
* \a param_value. If \a param_value_size_ret is NULL, it is ignored
*
* \return one of the following values is returned:
* - CL_SUCCESS if the function is executed successfully.
* - CL_SUCCESS if \a num_objects is 0 and \a mem_objects is NULL; the
* function does nothing.
* - CL_INVALID_VALUE if \a num_objects is zero and \a mem_objects is not a
* NULL value or if \a num_objects > 0 and \a mem_objects is NULL.
* - CL_INVALID_MEM_OBJECT if memory objects in \a mem_objects are not valid
* OpenCL memory objects.
* - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid command-queue.
* - CL_INVALID_CONTEXT if clContext associated with \a command_queue was not
* created from an OpenGL clContext.
* - CL_INVALID_GL_OBJECT if memory objects in \a mem_objects have not been
* created from a GL object(s).
* - CL_INVALID_EVENT_WAIT_LIST if \a event_wait_list is NULL and
* \a num_events_in_wait_list > 0, or \a event_wait_list is not NULL and
* \a num_events_in_wait_list is 0, or if event objects in \a event_wait_list
* are not valid events.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources
* required by the OpenCL implementation on the host.
* - CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR if
*
* \version 1.0r47
*/
RUNTIME_ENTRY(cl_int, clGetGLContextInfoKHR, (
const cl_context_properties *properties,
cl_gl_context_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret))
{
cl_int errcode;
cl_device_id* gpu_devices;
cl_device_id* cpu_devices;
cl_uint num_gpu_devices = 0;
cl_uint num_cpu_devices = 0;
amd::Context::Info info;
static const bool VALIDATE_ONLY = true;
errcode = amd::Context::checkProperties(properties, &info);
if (CL_SUCCESS != errcode) {
return errcode;
}
if (!(info.flags_ & amd::Context::GLDeviceKhr)) {
// No GL context is specified
return CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR;
}
// Get devices
errcode = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 0, NULL, &num_gpu_devices);
if (errcode != CL_SUCCESS && errcode != CL_DEVICE_NOT_FOUND) {
return CL_INVALID_VALUE;
}
errcode = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU, 0, NULL, &num_cpu_devices);
if (errcode != CL_SUCCESS && errcode != CL_DEVICE_NOT_FOUND) {
return CL_INVALID_VALUE;
}
if (!num_gpu_devices && !num_cpu_devices) {
return CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR;
}
switch(param_name) {
case CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR:
// Return the CL device currently associated with the specified OpenGL context.
if (num_gpu_devices) {
gpu_devices = (cl_device_id *) alloca(num_gpu_devices * sizeof(cl_device_id));
errcode = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU,
num_gpu_devices, gpu_devices, NULL);
if (errcode != CL_SUCCESS) {
return errcode;
}
for (cl_uint i = 0; i < num_gpu_devices; ++i) {
cl_device_id device = gpu_devices[i];
if (is_valid(device) &&
as_amd(device)->bindExternalDevice(info.flags_, info.hDev_, info.hCtx_, VALIDATE_ONLY)) {
return amd::clGetInfo(
device, param_value_size, param_value, param_value_size_ret);
}
}
*not_null(param_value_size_ret) = 0;
}
else {
cpu_devices = (cl_device_id *) alloca(num_cpu_devices * sizeof(cl_device_id));
errcode = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU,
num_cpu_devices, cpu_devices, NULL);
if (errcode != CL_SUCCESS) {
return errcode;
}
return amd::clGetInfo(
cpu_devices[0], param_value_size, param_value, param_value_size_ret);
}
break;
case CL_DEVICES_FOR_GL_CONTEXT_KHR:
{
//List of all CL devices that can be associated with the specified OpenGL context.
cl_uint total_devices = num_gpu_devices + num_cpu_devices;
size_t size = total_devices * sizeof(cl_device_id);
cl_device_id* devices = (cl_device_id *) alloca(size);
errcode = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_CPU,
total_devices, devices, NULL);
if (errcode != CL_SUCCESS) {
return errcode;
}
std::vector<amd::Device*> compatible_devices;
for (cl_uint i = 0; i < total_devices; ++i) {
cl_device_id device = devices[i];
if (is_valid(device) &&
as_amd(device)->bindExternalDevice(info.flags_, info.hDev_, info.hCtx_, VALIDATE_ONLY)) {
compatible_devices.push_back(as_amd(device));
}
}
size_t deviceCount = compatible_devices.size();
size_t deviceCountSize = deviceCount * sizeof(cl_device_id);
if (param_value != NULL && param_value_size < deviceCountSize) {
return CL_INVALID_VALUE;
}
*not_null(param_value_size_ret) = deviceCountSize;
if (param_value != NULL) {
cl_device_id* deviceList = (cl_device_id*) param_value;
std::vector<amd::Device*>::const_iterator it;
for (it = compatible_devices.begin(); it != compatible_devices.end(); ++it) {
*deviceList++ = as_cl(*it);
}
}
return CL_SUCCESS;
}
break;
default:
LogWarning("\"param_name\" is not valid");
return CL_INVALID_VALUE;
}
return CL_SUCCESS;
}
RUNTIME_EXIT
//
//
// namespace amd
//
//
namespace amd
{
typedef struct
{
GLenum glBinding;
GLenum glTarget;
} TargetBindings_t;
/*! @}
* \addtogroup CL-GL interop helper functions
* @{
*/
//! Function clearGLErrors() to clear all GL error bits, if any
void
clearGLErrors(const Context &amdContext)
{
GLenum glErr, glLastErr = GL_NO_ERROR;
while(1) {
glErr = amdContext.glenv()->glGetError_();
if (glErr == GL_NO_ERROR || glErr == glLastErr) {
break;
}
glLastErr = glErr;
LogWarning("GL error");
}
}
GLenum
checkForGLError(const Context &amdContext)
{
GLenum glRetErr = GL_NO_ERROR;
GLenum glErr;
while(GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_()))
{
glRetErr = glErr; // Just return the last GL error
LogWarning("Check GL error");
}
return glRetErr;
}
//! Function getCLFormatFromGL returns "true" if GL format
//! is compatible with CL format, "false" otherwise.
bool
getCLFormatFromGL(const Context& amdContext, GLint gliInternalFormat,
cl_image_format* pclImageFormat,
int* piBytesPerPixel,
cl_mem_flags flags)
{
bool bRetVal = false;
/*
Available values for "image_channel_order"
==========================================
CL_R
CL_A
CL_INTENSITY
CL_LUMINANCE
CL_RG
CL_RA
CL_RGB
CL_RGBA
CL_ARGB
CL_BGRA
Available values for "image_channel_data_type"
==============================================
CL_SNORM_INT8
CL_SNORM_INT16
CL_UNORM_INT8
CL_UNORM_INT16
CL_UNORM_SHORT_565
CL_UNORM_SHORT_555
CL_UNORM_INT_101010
CL_SIGNED_INT8
CL_SIGNED_INT16
CL_SIGNED_INT32
CL_UNSIGNED_INT8
CL_UNSIGNED_INT16
CL_UNSIGNED_INT32
CL_HALF_FLOAT
CL_FLOAT
*/
switch(gliInternalFormat)
{
case GL_BGR8_ATI:
case GL_BGRA8_ATI:
pclImageFormat->image_channel_order = CL_BGRA;
pclImageFormat->image_channel_data_type = CL_UNORM_INT8;//CL_UNSIGNED_INT8;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_ALPHA8:
pclImageFormat->image_channel_order = CL_A;
pclImageFormat->image_channel_data_type = CL_UNORM_INT8;//CL_UNSIGNED_INT8;
*piBytesPerPixel = 1;
bRetVal = true;
break;
case GL_R8:
case GL_R8UI:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_R8)? CL_UNORM_INT8:CL_UNSIGNED_INT8;
*piBytesPerPixel = 1;
bRetVal = true;
break;
case GL_R8I:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT8;
*piBytesPerPixel = 1;
bRetVal = true;
break;
case GL_RG8:
case GL_RG8UI:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_RG8)? CL_UNORM_INT8:CL_UNSIGNED_INT8;
*piBytesPerPixel = 2;
bRetVal = true;
break;
case GL_RG8I:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT8;
*piBytesPerPixel = 2;
bRetVal = true;
break;
case GL_RGB8:
case GL_RGB8UI:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_RGB8)? CL_UNORM_INT8:CL_UNSIGNED_INT8;
*piBytesPerPixel = 3;
bRetVal = true;
break;
case GL_RGB8I:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT8;
*piBytesPerPixel = 3;
bRetVal = true;
break;
case GL_RGBA:
case GL_RGBA8:
case GL_RGBA8UI:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_RGBA8UI)? CL_UNSIGNED_INT8:CL_UNORM_INT8;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_RGBA8I:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT8;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_R16:
case GL_R16UI:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_R16)? CL_UNORM_INT16:CL_UNSIGNED_INT16;
bRetVal = true;
*piBytesPerPixel = 2;
break;
case GL_R16I:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT16;
*piBytesPerPixel = 2;
bRetVal = true;
break;
case GL_R16F:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = CL_HALF_FLOAT;
*piBytesPerPixel = 2;
bRetVal = true;
break;
case GL_RG16:
case GL_RG16UI:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_RG16)? CL_UNORM_INT16:CL_UNSIGNED_INT16;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_RG16I:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT16;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_RG16F:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = CL_HALF_FLOAT;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_RGB16:
case GL_RGB16UI:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_RGB16)? CL_UNORM_INT16:CL_UNSIGNED_INT16;
*piBytesPerPixel = 6;
bRetVal = true;
break;
case GL_RGB16I:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT16;
*piBytesPerPixel = 6;
bRetVal = true;
break;
case GL_RGB16F:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = CL_HALF_FLOAT;
*piBytesPerPixel = 6;
bRetVal = true;
break;
case GL_RGBA16:
case GL_RGBA16UI:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = (gliInternalFormat == GL_RGBA16)? CL_UNORM_INT16:CL_UNSIGNED_INT16;
*piBytesPerPixel = 8;
bRetVal = true;
break;
case GL_RGBA16I:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT16;
*piBytesPerPixel = 8;
bRetVal = true;
break;
case GL_RGBA16F:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = CL_HALF_FLOAT;
*piBytesPerPixel = 8;
bRetVal = true;
break;
case GL_R32I:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT32;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_R32UI:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = CL_UNSIGNED_INT32;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_R32F:
pclImageFormat->image_channel_order = CL_R;
pclImageFormat->image_channel_data_type = CL_FLOAT;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_RG32I:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT32;
*piBytesPerPixel = 8;
bRetVal = true;
break;
case GL_RG32UI:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = CL_UNSIGNED_INT32;
*piBytesPerPixel = 8;
bRetVal = true;
break;
case GL_RG32F:
pclImageFormat->image_channel_order = CL_RG;
pclImageFormat->image_channel_data_type = CL_FLOAT;
*piBytesPerPixel = 8;
bRetVal = true;
break;
case GL_RGB32I:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT32;
*piBytesPerPixel = 12;
bRetVal = true;
break;
case GL_RGB32UI:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = CL_UNSIGNED_INT32;
*piBytesPerPixel = 12;
bRetVal = true;
break;
case GL_RGB32F:
pclImageFormat->image_channel_order = CL_RGB;
pclImageFormat->image_channel_data_type = CL_FLOAT;
*piBytesPerPixel = 12;
bRetVal = true;
break;
case GL_RGBA32I:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = CL_SIGNED_INT32;
*piBytesPerPixel = 16;
bRetVal = true;
break;
case GL_RGBA32UI:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = CL_UNSIGNED_INT32;
*piBytesPerPixel = 16;
bRetVal = true;
break;
case GL_RGBA32F:
pclImageFormat->image_channel_order = CL_RGBA;
pclImageFormat->image_channel_data_type = CL_FLOAT;
*piBytesPerPixel = 16;
bRetVal = true;
break;
case GL_DEPTH_COMPONENT32F:
pclImageFormat->image_channel_order = CL_DEPTH;
pclImageFormat->image_channel_data_type = CL_FLOAT;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_DEPTH_COMPONENT16:
pclImageFormat->image_channel_order = CL_DEPTH;
pclImageFormat->image_channel_data_type = CL_UNORM_INT16;
*piBytesPerPixel = 2;
bRetVal = true;
break;
case GL_DEPTH24_STENCIL8:
pclImageFormat->image_channel_order = CL_DEPTH_STENCIL;
pclImageFormat->image_channel_data_type = CL_UNORM_INT24;
*piBytesPerPixel = 4;
bRetVal = true;
break;
case GL_DEPTH32F_STENCIL8:
pclImageFormat->image_channel_order = CL_DEPTH_STENCIL;
pclImageFormat->image_channel_data_type = CL_FLOAT;
*piBytesPerPixel = 5;
bRetVal = true;
break;
default:
LogWarning("unsupported GL internal format");
break;
}
amd::Image::Format imageFormat(*pclImageFormat);
if (bRetVal && !imageFormat.isSupported(amdContext, 0, flags)) {
bRetVal = false;
}
return bRetVal;
}
void
BufferGL::initDeviceMemory()
{
deviceMemories_ = reinterpret_cast<DeviceMemory*>(
reinterpret_cast<char*>(this) + sizeof(BufferGL));
memset(deviceMemories_, 0,
context_().devices().size() * sizeof(DeviceMemory));
}
bool
BufferGL::mapExtObjectInCQThread()
{
assert(!context_().glenv()->isEGL());
GLFunctions::SetIntEnv ie(context_().glenv());
if (!ie.isValid()) {
return false;
}
GLenum glAccess = GL_READ_WRITE; // Default
if (getMemFlags() & CL_MEM_READ_ONLY) {
glAccess = GL_READ_ONLY;
}
else if (getMemFlags() & CL_MEM_WRITE_ONLY) {
glAccess = GL_WRITE_ONLY;
}
clearGLErrors(context_());
context_().glenv()->glBindBuffer_(GL_ARRAY_BUFFER, gluiName_);
void* pCpuMem = context_().glenv()->glMapBuffer_(GL_ARRAY_BUFFER, glAccess);
if (checkForGLError(context_()) != GL_NO_ERROR || !pCpuMem) {
LogError("cannot map GL buffer");
return false;
}
setHostMem(pCpuMem);
return true;
}
bool
BufferGL::unmapExtObjectInCQThread()
{
assert(!context_().glenv()->isEGL());
GLFunctions::SetIntEnv ie(context_().glenv());
if (!ie.isValid()) {
return false;
}
clearGLErrors(context_());
context_().glenv()->glBindBuffer_(GL_ARRAY_BUFFER, gluiName_);
if (GL_FALSE == context_().glenv()->glUnmapBuffer_(GL_ARRAY_BUFFER)) {
LogError("context_().glenv()->glUnmapBuffer_ returned GL_FALSE - buffer may be corrupted");
return false;
}
if (checkForGLError(context_()) != GL_NO_ERROR) {
LogWarning("Error unmapping GL buffer");
return false;
}
setHostMem(NULL);
return true;
}
static GLenum
clChannelDataTypeToGlType(cl_channel_type channel_type)
{
// Pick
// GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT,
// GL_UNSIGNED_INT, GL_FLOAT, GL_2_BYTES, GL_3_BYTES, GL_4_BYTES
// or GL_DOUBLE
switch (channel_type) {
case CL_SNORM_INT8: return GL_BYTE;
case CL_SNORM_INT16: return GL_SHORT;
case CL_UNORM_INT8: return GL_UNSIGNED_BYTE;
case CL_UNORM_INT16: return GL_UNSIGNED_SHORT;
case CL_SIGNED_INT8: return GL_BYTE;
case CL_SIGNED_INT16: return GL_SHORT;
case CL_SIGNED_INT32: return GL_INT;
case CL_UNSIGNED_INT8: return GL_UNSIGNED_BYTE;
case CL_UNSIGNED_INT16: return GL_UNSIGNED_SHORT;
case CL_UNSIGNED_INT32: return GL_UNSIGNED_INT;
case CL_FLOAT: return GL_FLOAT;
case CL_HALF_FLOAT:
case CL_UNORM_SHORT_565:
case CL_UNORM_SHORT_555:
case CL_UNORM_INT_101010:
default:
guarantee(false && "Unexpected CL type.");
return 0;
}
}
static GLenum
glInternalFormatToGlFormat(GLenum internalFormat)
{
switch (internalFormat) {
// Base internal formats
case GL_RGBA:
case GL_BGRA:
return internalFormat;
// Sized internal formats
case GL_RGBA8:
case GL_RGBA16:
case GL_RGBA16F:
case GL_RGBA32F:
return GL_RGBA;
case GL_RGBA8I:
case GL_RGBA8UI:
case GL_RGBA16I:
case GL_RGBA16UI:
case GL_RGBA32I:
case GL_RGBA32UI:
return GL_RGBA_INTEGER;
default:
guarantee(false && "Unexpected GL internal format.");
return 0;
}
}
void
ImageGL::initDeviceMemory()
{
deviceMemories_ = reinterpret_cast<DeviceMemory*>(
reinterpret_cast<char*>(this) + sizeof(ImageGL));
memset(deviceMemories_, 0,
context_().devices().size() * sizeof(DeviceMemory));
}
bool
ImageGL::mapExtObjectInCQThread()
{
assert(!context_().glenv()->isEGL());
GLFunctions::SetIntEnv ie(context_().glenv());
if (!ie.isValid()) {
return false;
}
GLenum glAccess = GL_READ_WRITE; // Default
if (getMemFlags() & CL_MEM_READ_ONLY) {
glAccess = GL_READ_ONLY;
}
else if (getMemFlags() & CL_MEM_WRITE_ONLY) {
glAccess = GL_WRITE_ONLY;
}
clearGLErrors(context_());
context_().glenv()->glBindTexture_(getGLTarget(), gluiName_);
size_t mem_size = getSize();
char* pCpuMem = new char[mem_size];
if (pCpuMem == NULL) {
LogError("Cannot alloc host memory for ImageGL");
return false;
}
context_().glenv()->glGetTexImage_(
getGLTarget(),
gliMipLevel_,
glInternalFormatToGlFormat(glInternalFormat_),
clChannelDataTypeToGlType(getImageFormat().image_channel_data_type),
pCpuMem);
if (checkForGLError(context_()) != GL_NO_ERROR) {
LogError("cannot map GL texture");
free(pCpuMem);
return false;
}
setHostMem(pCpuMem);
return true;
}
bool
ImageGL::unmapExtObjectInCQThread()
{
assert(!context_().glenv()->isEGL());
GLFunctions::SetIntEnv ie(context_().glenv());
if (!ie.isValid()) {
return false;
}
bool status = true;
clearGLErrors(context_());
context_().glenv()->glBindTexture_(getGLTarget(), gluiName_);
char* pCpuMem = (char *)getHostMem();
if (checkForGLError(context_()) != GL_NO_ERROR) {
LogError("Cannot map GL texture");
status = false;
goto cleanup;
}
context_().glenv()->glTexImage2D_(
getGLTarget(), // target
gliMipLevel_, // miplevel
glInternalFormat_, // internalFormat or bytes per pixel
gliWidth_, // width
gliHeight_, // height
0, // border
// format
glInternalFormatToGlFormat(glInternalFormat_),
// type
clChannelDataTypeToGlType(getImageFormat().image_channel_data_type),
pCpuMem); // data
if (checkForGLError(context_()) != GL_NO_ERROR) {
LogError("Cannot update GL texture");
status = false;
goto cleanup;
}
cleanup:
delete [] pCpuMem;
setHostMem(NULL);
return status;
}
//*******************************************************************
//
// Internal implementation of CL API functions
//
//*******************************************************************
//
// clCreateFromGLBufferAMD
//
cl_mem
clCreateFromGLBufferAMD(
Context& amdContext,
cl_mem_flags flags,
GLuint bufobj,
cl_int* errcode_ret)
{
BufferGL* pBufferGL = NULL;
GLenum glErr;
GLenum glTarget = GL_ARRAY_BUFFER;
GLint gliSize = 0;
GLint gliMapped = 0;
// Verify context init'ed for interop
if (!amdContext.glenv() || !amdContext.glenv()->isAssociated()) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("\"amdContext\" is not created from GL context or share list");
return (cl_mem) 0;
}
// Add this scope to bound the scoped lock
{
GLFunctions::SetIntEnv ie(amdContext.glenv());
if (!ie.isValid()) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("\"amdContext\" is not created from GL context or share list");
return as_cl<Memory>(0);
}
// Verify GL buffer object
clearGLErrors(amdContext);
if ((GL_FALSE == amdContext.glenv()->glIsBuffer_(bufobj))
|| (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_()))) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("\"bufobj\" is not a GL buffer object");
return (cl_mem) 0;
}
// It seems that CL spec is not concerned with GL_BUFFER_USAGE, so skip it
// Check if size is available - data store is created
amdContext.glenv()->glBindBuffer_(glTarget, bufobj);
clearGLErrors(amdContext);
amdContext.glenv()->glGetBufferParameteriv_(glTarget, GL_BUFFER_SIZE, &gliSize);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("cannot get the GL buffer size");
return (cl_mem) 0;
}
if (gliSize == 0) {
//@todo - check why sometime the size is zero
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("the GL buffer's data store is not created");
return (cl_mem) 0;
}
// Mapping will be done at acquire time (sync point)
} // Release scoped lock
// Now create BufferGL object
pBufferGL = new(amdContext) BufferGL(amdContext, flags, gliSize, 0, bufobj);
if (!pBufferGL) {
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
LogWarning("cannot create object of class BufferGL");
return (cl_mem) 0;
}
if (!pBufferGL->create()) {
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
pBufferGL->release();
return (cl_mem) 0;
}
*not_null(errcode_ret) = CL_SUCCESS;
// Create interop object
if (pBufferGL->getInteropObj() == NULL) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("cannot create object of class BufferGL");
return (cl_mem)0;
}
// Fixme: If more than one device is present in the context, we choose the first device.
// We should come up with a more elegant solution to handle this.
assert(amdContext.devices().size() == 1);
std::vector<amd::Device*>::const_iterator itr = amdContext.devices().begin();
amd::Device& dev = *(*itr);
if (dev.type() != CL_DEVICE_TYPE_CPU){
device::Memory* mem = pBufferGL->getDeviceMemory(dev);
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
pBufferGL->getSize());
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
}
mem->processGLResource(device::Memory::GLDecompressResource);
}
return as_cl<Memory>(pBufferGL);
}
cl_mem
clCreateFromGLTextureAMD(
Context& amdContext,
cl_mem_flags clFlags,
GLenum target,
GLint miplevel,
GLuint texture,
int* errcode_ret)
{
ImageGL* pImageGL = NULL;
GLenum glErr;
GLenum glTarget = 0;
GLenum glInternalFormat;
cl_image_format clImageFormat;
uint dim = 1;
cl_mem_object_type clType;
cl_gl_object_type clGLType;
GLsizei numSamples = 1;
// Verify context init'ed for interop
if (!amdContext.glenv() || !amdContext.glenv()->isAssociated()) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("\"amdContext\" is not created from GL context or share list");
return static_cast<cl_mem>(0);
}
GLint gliTexWidth = 1;
GLint gliTexHeight = 1;
GLint gliTexDepth = 1;
// Add this scope to bound the scoped lock
{
GLFunctions::SetIntEnv ie(amdContext.glenv());
if (!ie.isValid()) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("\"amdContext\" is not created from GL context or share list");
return as_cl<Memory>(0);
}
// Verify GL texture object
clearGLErrors(amdContext);
if ((GL_FALSE == amdContext.glenv()->glIsTexture_(texture))
|| (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_()))) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("\"texture\" is not a GL texture object");
return static_cast<cl_mem>(0);
}
bool image = true;
// Check target value validity
switch(target)
{
case GL_TEXTURE_BUFFER:
glTarget = GL_TEXTURE_BUFFER;
dim = 1;
clType = CL_MEM_OBJECT_IMAGE1D_BUFFER;
clGLType = CL_GL_OBJECT_TEXTURE_BUFFER;
image = false;
break;
case GL_TEXTURE_1D:
glTarget = GL_TEXTURE_1D;
dim = 1;
clType = CL_MEM_OBJECT_IMAGE1D;
clGLType = CL_GL_OBJECT_TEXTURE1D;
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
glTarget = GL_TEXTURE_CUBE_MAP;
dim = 2;
clType = CL_MEM_OBJECT_IMAGE2D;
clGLType = CL_GL_OBJECT_TEXTURE2D;
break;
case GL_TEXTURE_1D_ARRAY:
glTarget = GL_TEXTURE_1D_ARRAY;
dim = 2;
clType = CL_MEM_OBJECT_IMAGE1D_ARRAY;
clGLType = CL_GL_OBJECT_TEXTURE1D_ARRAY;
break;
case GL_TEXTURE_2D:
glTarget = GL_TEXTURE_2D;
dim = 2;
clType = CL_MEM_OBJECT_IMAGE2D;
clGLType = CL_GL_OBJECT_TEXTURE2D;
break;
case GL_TEXTURE_2D_MULTISAMPLE:
glTarget = GL_TEXTURE_2D_MULTISAMPLE;
dim = 2;
clType = CL_MEM_OBJECT_IMAGE2D;
clGLType = CL_GL_OBJECT_TEXTURE2D;
break;
case GL_TEXTURE_RECTANGLE_ARB:
glTarget = GL_TEXTURE_RECTANGLE_ARB;
dim = 2;
clType = CL_MEM_OBJECT_IMAGE2D;
clGLType = CL_GL_OBJECT_TEXTURE2D;
break;
case GL_TEXTURE_2D_ARRAY:
glTarget = GL_TEXTURE_2D_ARRAY;
dim = 3;
clType = CL_MEM_OBJECT_IMAGE2D_ARRAY;
clGLType = CL_GL_OBJECT_TEXTURE2D_ARRAY;
break;
case GL_TEXTURE_3D:
glTarget = GL_TEXTURE_3D;
dim = 3;
clType = CL_MEM_OBJECT_IMAGE3D;
clGLType = CL_GL_OBJECT_TEXTURE3D;
break;
default:
// wrong value
*not_null(errcode_ret) = CL_INVALID_VALUE;
LogWarning("invalid \"target\" value");
return static_cast<cl_mem>(0);
break;
}
amdContext.glenv()->glBindTexture_(glTarget, texture);
// Check if size is available - data store is created
if (image) {
// Check mipmap level for "texture" name
GLint gliTexBaseLevel;
GLint gliTexMaxLevel;
clearGLErrors(amdContext);
amdContext.glenv()->glGetTexParameteriv_(glTarget, GL_TEXTURE_BASE_LEVEL, &gliTexBaseLevel);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_MIP_LEVEL;
LogWarning("Cannot get base mipmap level of a GL \"texture\" object");
return static_cast<cl_mem>(0);
}
clearGLErrors(amdContext);
amdContext.glenv()->glGetTexParameteriv_(glTarget, GL_TEXTURE_MAX_LEVEL, &gliTexMaxLevel);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_MIP_LEVEL;
LogWarning("Cannot get max mipmap level of a GL \"texture\" object");
return static_cast<cl_mem>(0);
}
if ((gliTexBaseLevel > miplevel) || (miplevel > gliTexMaxLevel)) {
*not_null(errcode_ret) = CL_INVALID_MIP_LEVEL;
LogWarning("\"miplevel\" is not a valid mipmap level of the GL \"texture\" object");
return static_cast<cl_mem>(0);
}
// Get GL texture format and check if it's compatible with CL format
clearGLErrors(amdContext);
amdContext.glenv()->glGetTexLevelParameteriv_(target, miplevel, GL_TEXTURE_INTERNAL_FORMAT,
(GLint*) &glInternalFormat);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("Cannot get internal format of \"miplevel\" of GL \"texture\" object");
return static_cast<cl_mem>(0);
}
amdContext.glenv()->glGetTexLevelParameteriv_(target, miplevel, GL_TEXTURE_SAMPLES,
(GLint*) &numSamples);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("Cannot get numbers of samples of GL \"texture\" object");
return static_cast<cl_mem>(0);
}
if (numSamples > 1) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("MSAA \"texture\" object is not suppoerted for the device");
return static_cast<cl_mem>(0);
}
// Now get CL format from GL format and bytes per pixel
int iBytesPerPixel = 0;
if (!getCLFormatFromGL(amdContext, glInternalFormat, &clImageFormat, &iBytesPerPixel, clFlags)) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("\"texture\" format does not map to an appropriate CL image format");
return static_cast<cl_mem>(0);
}
switch (dim) {
case 3:
clearGLErrors(amdContext);
amdContext.glenv()->glGetTexLevelParameteriv_(target, miplevel, GL_TEXTURE_DEPTH, &gliTexDepth);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("Cannot get the depth of \"miplevel\" of GL \"texure\"");
return static_cast<cl_mem>(0);
}
// Fall trough to process other dimensions...
case 2:
clearGLErrors(amdContext);
amdContext.glenv()->glGetTexLevelParameteriv_(target, miplevel, GL_TEXTURE_HEIGHT, &gliTexHeight);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("Cannot get the height of \"miplevel\" of GL \"texure\"");
return static_cast<cl_mem>(0);
}
// Fall trough to process other dimensions...
case 1:
clearGLErrors(amdContext);
amdContext.glenv()->glGetTexLevelParameteriv_(target, miplevel, GL_TEXTURE_WIDTH, &gliTexWidth);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("Cannot get the width of \"miplevel\" of GL \"texure\"");
return static_cast<cl_mem>(0);
}
break;
default:
*not_null(errcode_ret) = CL_INVALID_VALUE;
LogWarning("invalid \"target\" value");
return static_cast<cl_mem>(0);
}
}
else {
GLint size;
// In case target is GL_TEXTURE_BUFFER
amdContext.glenv()->glBindBuffer_(glTarget, texture);
// Get GL texture format and check if it's compatible with CL format
clearGLErrors(amdContext);
amdContext.glenv()->glGetIntegerv_(GL_TEXTURE_BUFFER_FORMAT,
reinterpret_cast<GLint*>(&glInternalFormat));
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("Cannot get internal format of \"miplevel\" of GL \"texture\" object");
return static_cast<cl_mem>(0);
}
// Now get CL format from GL format and bytes per pixel
int iBytesPerPixel = 0;
if (!getCLFormatFromGL(amdContext, glInternalFormat, &clImageFormat, &iBytesPerPixel, clFlags)) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("\"texture\" format does not map to an appropriate CL image format");
return static_cast<cl_mem>(0);
}
clearGLErrors(amdContext);
amdContext.glenv()->glGetBufferParameteriv_(glTarget, GL_BUFFER_SIZE, &size);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("Cannot get internal format of \"miplevel\" of GL \"texture\" object");
return static_cast<cl_mem>(0);
}
gliTexWidth = size / iBytesPerPixel;
}
size_t imageSize = (clType == CL_MEM_OBJECT_IMAGE1D_ARRAY) ?
static_cast<size_t>(gliTexHeight) : static_cast<size_t>(gliTexDepth);
if (!amd::Image::validateDimensions(
amdContext.devices(), clType,
static_cast<size_t>(gliTexWidth), static_cast<size_t>(gliTexHeight),
static_cast<size_t>(gliTexDepth), imageSize)) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("The GL \"texture\" data store is not created or out of supported dimensions");
return static_cast<cl_mem>(0);
}
// PBO and mapping will be done at "acquire" time (sync point)
} // Release scoped lock
target = (glTarget == GL_TEXTURE_CUBE_MAP) ? target : 0;
pImageGL = new(amdContext)
ImageGL(amdContext, clType, clFlags, clImageFormat,
static_cast<size_t>(gliTexWidth), static_cast<size_t>(gliTexHeight),
static_cast<size_t>(gliTexDepth),
glTarget, texture, miplevel, glInternalFormat, clGLType,numSamples,
target);
if (!pImageGL) {
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
LogWarning("Cannot create class ImageGL - out of memory?");
return static_cast<cl_mem>(0);
}
if (!pImageGL->create()) {
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
pImageGL->release();
return static_cast<cl_mem>(0);
}
*not_null(errcode_ret) = CL_SUCCESS;
return as_cl<Memory>(pImageGL);
}
//
// clCreateFromGLRenderbufferDAMD
//
cl_mem
clCreateFromGLRenderbufferAMD(
Context& amdContext,
cl_mem_flags clFlags,
GLuint renderbuffer,
int* errcode_ret)
{
ImageGL* pImageGL = NULL;
GLenum glErr;
GLenum glTarget = GL_RENDERBUFFER;
GLenum glInternalFormat;
cl_image_format clImageFormat;
// Verify context init'ed for interop
if (!amdContext.glenv() || !amdContext.glenv()->isAssociated()) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("\"amdContext\" is not created from GL context or share list");
return (cl_mem) 0;
}
GLint gliRbWidth;
GLint gliRbHeight;
// Add this scope to bound the scoped lock
{
GLFunctions::SetIntEnv ie(amdContext.glenv());
if (!ie.isValid()) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
LogWarning("\"amdContext\" is not created from GL context or share list");
return as_cl<Memory>(0);
}
// Verify GL renderbuffer object
clearGLErrors(amdContext);
if ((GL_FALSE == amdContext.glenv()->glIsRenderbufferEXT_(renderbuffer))
|| (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_()))) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("\"renderbuffer\" is not a GL texture object");
return (cl_mem) 0;
}
amdContext.glenv()->glBindRenderbuffer_(glTarget, renderbuffer);
// Get GL RB format and check if it's compatible with CL format
clearGLErrors(amdContext);
amdContext.glenv()->glGetRenderbufferParameterivEXT_(glTarget, GL_RENDERBUFFER_INTERNAL_FORMAT,
(GLint*) &glInternalFormat);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("Cannot get internal format of GL \"renderbuffer\" object");
return (cl_mem) 0;
}
// Now get CL format from GL format and bytes per pixel
int iBytesPerPixel = 0;
if (!getCLFormatFromGL(amdContext, glInternalFormat, &clImageFormat, &iBytesPerPixel, clFlags)) {
*not_null(errcode_ret) = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
LogWarning("\"renderbuffer\" format does not map to an appropriate CL image format");
return (cl_mem) 0;
}
// Check if size is available - data store is created
clearGLErrors(amdContext);
amdContext.glenv()->glGetRenderbufferParameterivEXT_(glTarget, GL_RENDERBUFFER_WIDTH,
&gliRbWidth);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("Cannot get the width of GL \"renderbuffer\"");
return (cl_mem) 0;
}
if (gliRbWidth == 0) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("The GL \"renderbuffer\" data store is not created");
return (cl_mem) 0;
}
clearGLErrors(amdContext);
amdContext.glenv()->glGetRenderbufferParameterivEXT_(glTarget, GL_RENDERBUFFER_HEIGHT,
&gliRbHeight);
if (GL_NO_ERROR != (glErr = amdContext.glenv()->glGetError_())) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("Cannot get the height of GL \"renderbuffer\"");
return (cl_mem) 0;
}
if (gliRbHeight == 0) {
*not_null(errcode_ret) = CL_INVALID_GL_OBJECT;
LogWarning("The GL \"renderbuffer\" data store is not created");
return (cl_mem) 0;
}
// PBO and mapping will be done at "acquire" time (sync point)
} // Release scoped lock
pImageGL = new(amdContext)
ImageGL(amdContext, CL_MEM_OBJECT_IMAGE2D, clFlags, clImageFormat,
(size_t) gliRbWidth, (size_t) gliRbHeight, 1,
glTarget, renderbuffer, 0, glInternalFormat, CL_GL_OBJECT_RENDERBUFFER, 0);
if (!pImageGL) {
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
LogWarning("Cannot create class ImageGL from renderbuffer - out of memory?");
return (cl_mem) 0;
}
if (!pImageGL->create()) {
*not_null(errcode_ret) = CL_MEM_OBJECT_ALLOCATION_FAILURE;
pImageGL->release();
return (cl_mem) 0;
}
*not_null(errcode_ret) = CL_SUCCESS;
return as_cl<Memory>(pImageGL);
}
//
// clEnqueueAcquireExtObjectsAMD
//
static cl_int
clSetInteropObjects(cl_uint num_objects,
const cl_mem* mem_objects,
std::vector<amd::Memory*>& interopObjects)
{
if ((num_objects == 0 && mem_objects != NULL)
|| (num_objects != 0 && mem_objects == NULL)) {
return CL_INVALID_VALUE;
}
while (num_objects-- > 0) {
cl_mem obj = *mem_objects++;
if (!is_valid(obj)) {
return CL_INVALID_MEM_OBJECT;
}
amd::Memory* mem = as_amd(obj);
if (mem->getInteropObj() == NULL) {
return CL_INVALID_GL_OBJECT;
}
interopObjects.push_back(mem);
}
return CL_SUCCESS;
}
cl_int
clEnqueueAcquireExtObjectsAMD(cl_command_queue command_queue,
cl_uint num_objects, const cl_mem* mem_objects,
cl_uint num_events_in_wait_list, const cl_event* event_wait_list,
cl_event* event, cl_command_type cmd_type)
{
if (!is_valid(command_queue)) {
return CL_INVALID_COMMAND_QUEUE;
}
amd::HostQueue* queue = as_amd(command_queue)->asHostQueue();
if (NULL == queue) {
return CL_INVALID_COMMAND_QUEUE;
}
amd::HostQueue& hostQueue = *queue;
if (cmd_type == CL_COMMAND_ACQUIRE_GL_OBJECTS) {
// Verify context init'ed for interop
if (!hostQueue.context().glenv() || !hostQueue.context().glenv()->isAssociated()) {
LogWarning("\"amdContext\" is not created from GL context or share list");
return CL_INVALID_CONTEXT;
}
}
std::vector<amd::Memory*> memObjects;
cl_int err = clSetInteropObjects(num_objects, mem_objects, memObjects);
if (err != CL_SUCCESS){
return err;
}
amd::Command::EventWaitList eventWaitList;
err = amd::clSetEventWaitList(eventWaitList,
hostQueue.context(), num_events_in_wait_list, event_wait_list);
if (err != CL_SUCCESS){
return err;
}
#ifdef _WIN32
if ((hostQueue.context().info().flags_ & amd::Context::InteropUserSync) == 0)
{
//! Make sure D3D10 queues are flushed and all commands are finished
//! before CL side would access interop objects
if (cmd_type == CL_COMMAND_ACQUIRE_D3D10_OBJECTS_KHR) {
SyncD3D10Objects(memObjects);
}
//! Make sure D3D11 queues are flushed and all commands are finished
//! before CL side would access interop objects
if (cmd_type == CL_COMMAND_ACQUIRE_D3D11_OBJECTS_KHR) {
SyncD3D11Objects(memObjects);
}
//! Make sure D3D9 queues are flushed and all commands are finished
//! before CL side would access interop objects
if (cmd_type == CL_COMMAND_ACQUIRE_DX9_MEDIA_SURFACES_KHR) {
SyncD3D9Objects(memObjects);
}
}
#endif //_WIN32
//! Now create command and enqueue
amd::AcquireExtObjectsCommand* command = new amd::AcquireExtObjectsCommand(
hostQueue, eventWaitList, num_objects, memObjects, cmd_type);
if (command == NULL) {
return CL_OUT_OF_HOST_MEMORY;
}
// Make sure we have memory for the command execution
if (!command->validateMemory()) {
delete command;
return CL_MEM_OBJECT_ALLOCATION_FAILURE;
}
command->enqueue();
*not_null(event) = as_cl(&command->event());
if (event == NULL) {
command->release();
}
return CL_SUCCESS;
}
//
// clEnqueueReleaseExtObjectsAMD
//
cl_int
clEnqueueReleaseExtObjectsAMD(cl_command_queue command_queue,
cl_uint num_objects, const cl_mem* mem_objects,
cl_uint num_events_in_wait_list, const cl_event* event_wait_list,
cl_event* event, cl_command_type cmd_type)
{
if (!is_valid(command_queue)) {
return CL_INVALID_COMMAND_QUEUE;
}
amd::HostQueue* queue = as_amd(command_queue)->asHostQueue();
if (NULL == queue) {
return CL_INVALID_COMMAND_QUEUE;
}
amd::HostQueue& hostQueue = *queue;
std::vector<amd::Memory*> memObjects;
cl_int err = clSetInteropObjects(num_objects, mem_objects, memObjects);
if (err != CL_SUCCESS){
return err;
}
amd::Command::EventWaitList eventWaitList;
err = amd::clSetEventWaitList(eventWaitList,
hostQueue.context(), num_events_in_wait_list, event_wait_list);
if (err != CL_SUCCESS){
return err;
}
//! Now create command and enqueue
amd::ReleaseExtObjectsCommand* command = new amd::ReleaseExtObjectsCommand(
hostQueue, eventWaitList, num_objects, memObjects, cmd_type);
if (command == NULL) {
return CL_OUT_OF_HOST_MEMORY;
}
// Make sure we have memory for the command execution
if (!command->validateMemory()) {
delete command;
return CL_MEM_OBJECT_ALLOCATION_FAILURE;
}
command->enqueue();
#ifdef _WIN32
if ((hostQueue.context().info().flags_ & amd::Context::InteropUserSync) == 0)
{
//! Make sure CL command queue is flushed and all commands are finished
//! before D3D10 side would access interop resources
if (cmd_type == CL_COMMAND_RELEASE_DX9_MEDIA_SURFACES_KHR ||
cmd_type == CL_COMMAND_RELEASE_D3D10_OBJECTS_KHR ||
cmd_type == CL_COMMAND_RELEASE_D3D11_OBJECTS_KHR) {
command->awaitCompletion();
}
}
#endif //_WIN32
*not_null(event) = as_cl(&command->event());
if (event == NULL) {
command->release();
}
return CL_SUCCESS;
}
// Placed here as opposed to command.cpp, as glext.h and cl_gl_amd.hpp will have
// to be included because of the GL calls
bool ClGlEvent::waitForFence()
{
GLenum ret;
// get fence id associated with fence event
GLsync gs = reinterpret_cast<GLsync> (command().data());
if (!gs) return false;
// Try to use DC and GLRC of current thread, if it doesn't exist
// create a new GL context on this thread, which is shared with the original context
#ifdef _WIN32
HDC tempDC_ = wglGetCurrentDC();
HGLRC tempGLRC_ = wglGetCurrentContext();
// Set DC and GLRC
if (tempDC_ && tempGLRC_) {
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT, static_cast<GLuint64>(-1));
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
}
else
{
tempDC_ = context().glenv()->getDC();
tempGLRC_ = context().glenv()->getIntGLRC();
if (!context().glenv()->init(reinterpret_cast<intptr_t>(tempDC_), reinterpret_cast<intptr_t>(tempGLRC_))) return false;
// Make the newly created GL context current to this thread
context().glenv()->setIntEnv();
// If fence has not yet executed, wait till it finishes
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT, static_cast<GLuint64>(-1));
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
// Since we're done making GL calls, restore whatever context was previously current to this thread
context().glenv()->restoreEnv();
}
#else // Lnx
Display* tempDpy_ = context().glenv()->glXGetCurrentDisplay_();
GLXDrawable tempDrawable_ = context().glenv()->glXGetCurrentDrawable_();
GLXContext tempCtx_ = context().glenv()->glXGetCurrentContext_();
// Set internal Display and GLXContext
if (tempDpy_ && tempCtx_) {
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT, static_cast<GLuint64>(-1));
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
}
else {
if (!context().glenv()->init(reinterpret_cast<intptr_t>(context().glenv()->getIntDpy()),
reinterpret_cast<intptr_t>(context().glenv()->getIntCtx()))) return false;
// Make the newly created GL context current to this thread
context().glenv()->setIntEnv();
// If fence has not yet executed, wait till it finishes
ret = context().glenv()->glClientWaitSync_(gs, GL_SYNC_FLUSH_COMMANDS_BIT, static_cast<GLuint64>(-1));
if (!(ret == GL_ALREADY_SIGNALED || ret == GL_CONDITION_SATISFIED)) return false;
// Since we're done making GL calls, restore whatever context was previously current to this thread
context().glenv()->restoreEnv();
}
#endif
// If we reach this point, fence should have completed
setStatus(CL_COMPLETE);
return true;
}
//
// GLFunctions implementation
//
#ifdef _WIN32
#define CONVERT_CHAR_GLUBYTE
#else //!_WIN32
#define CONVERT_CHAR_GLUBYTE (GLubyte*)
#endif //!_WIN32
#define GLPREFIX(rtype, fcn, dclargs) \
if (!(fcn##_ = (PFN_##fcn) GETPROCADDRESS( \
libHandle_, #fcn))) { \
if (!(fcn##_ = (PFN_##fcn) GetProcAddress_( \
reinterpret_cast<FCN_STR_TYPE>(#fcn)))) ++missed_; \
}
GLFunctions::SetIntEnv::SetIntEnv(GLFunctions* env)
: env_(env)
{
env_->getLock().lock();
// Set environment (DC and GLRC)
isValid_ = env_->setIntEnv();
}
GLFunctions::SetIntEnv::~SetIntEnv()
{
// Restore environment (CL DC and CL GLRC)
env_->restoreEnv();
env_->getLock().unlock();
}
GLFunctions::GLFunctions(HMODULE h, bool isEGL) :
libHandle_(h),
missed_(0),
eglDisplay_(EGL_NO_DISPLAY),
eglOriginalContext_(EGL_NO_CONTEXT),
eglInternalContext_(EGL_NO_CONTEXT),
eglTempContext_(EGL_NO_CONTEXT),
isEGL_(isEGL),
#ifdef _WIN32
hOrigGLRC_(0),
hDC_(0),
hIntGLRC_(0)
#else //!_WIN32
Dpy_(0),
Drawable_(0),
origCtx_(0),
intDpy_(0),
intDrawable_(0),
intCtx_(0),
XOpenDisplay_(NULL),
XCloseDisplay_(NULL),
glXGetCurrentDrawable_(NULL),
glXGetCurrentDisplay_(NULL),
glXGetCurrentContext_(NULL),
glXChooseVisual_(NULL),
glXCreateContext_(NULL),
glXDestroyContext_(NULL),
glXMakeCurrent_(NULL)
#endif //!_WIN32
{
#define VERIFY_POINTER(p) if (NULL == p) {missed_++;}
if (isEGL_)
{
GetProcAddress_ = (PFN_xxxGetProcAddress) GETPROCADDRESS(h, "eglGetProcAddress");
}
else {
GetProcAddress_ = (PFN_xxxGetProcAddress) GETPROCADDRESS(h, API_GETPROCADDR);
}
#ifndef _WIN32
// Initialize pointers to X11/GLX functions
// We can not link with these functions on compile time since we need to support
// console mode. In console mode X server and X server components may be absent.
// Hence linking with X11 or libGL will fail module image loading in console mode.-tzachi cohen
if (!isEGL_) {
glXGetCurrentDrawable_ = (PFNglXGetCurrentDrawable)GETPROCADDRESS(h,"glXGetCurrentDrawable");
VERIFY_POINTER(glXGetCurrentDrawable_)
glXGetCurrentDisplay_ = (PFNglXGetCurrentDisplay)GETPROCADDRESS(h,"glXGetCurrentDisplay");
VERIFY_POINTER(glXGetCurrentDisplay_)
glXGetCurrentContext_ = (PFNglXGetCurrentContext) GETPROCADDRESS(h,"glXGetCurrentContext");
VERIFY_POINTER(glXGetCurrentContext_)
glXChooseVisual_ = (PFNglXChooseVisual)GETPROCADDRESS(h,"glXChooseVisual");
VERIFY_POINTER(glXChooseVisual_)
glXCreateContext_ = (PFNglXCreateContext)GETPROCADDRESS(h,"glXCreateContext");
VERIFY_POINTER(glXCreateContext_)
glXDestroyContext_ = (PFNglXDestroyContext) GETPROCADDRESS(h,"glXDestroyContext");
VERIFY_POINTER(glXDestroyContext_)
glXMakeCurrent_ = (PFNglXMakeCurrent) GETPROCADDRESS(h,"glXMakeCurrent");
VERIFY_POINTER(glXMakeCurrent_)
HMODULE hXModule = (HMODULE) Os::loadLibrary("libX11.so.6");
if (NULL != hXModule) {
XOpenDisplay_ = (PFNXOpenDisplay)GETPROCADDRESS(hXModule,"XOpenDisplay");
VERIFY_POINTER(XOpenDisplay_)
XCloseDisplay_= (PFNXCloseDisplay)GETPROCADDRESS(hXModule,"XCloseDisplay");
VERIFY_POINTER(XCloseDisplay_)
}
else {
missed_ += 2;
}
}
// Initialize pointers to GL functions
#include "gl_functions.hpp"
#else
if (!isEGL_) {
wglCreateContext_ = (PFN_wglCreateContext)GETPROCADDRESS(h,"wglCreateContext");
VERIFY_POINTER(wglCreateContext_)
wglGetCurrentContext_ = (PFN_wglGetCurrentContext)GETPROCADDRESS(h,"wglGetCurrentContext");
VERIFY_POINTER(wglGetCurrentContext_)
wglGetCurrentDC_ = (PFN_wglGetCurrentDC)GETPROCADDRESS(h,"wglGetCurrentDC");
VERIFY_POINTER(wglGetCurrentDC_)
wglDeleteContext_ = (PFN_wglDeleteContext)GETPROCADDRESS(h,"wglDeleteContext");
VERIFY_POINTER(wglDeleteContext_)
wglMakeCurrent_ = (PFN_wglMakeCurrent)GETPROCADDRESS(h,"wglMakeCurrent");
VERIFY_POINTER(wglMakeCurrent_)
wglShareLists_ = (PFN_wglShareLists)GETPROCADDRESS(h,"wglShareLists");
VERIFY_POINTER(wglShareLists_)
}
#endif
}
GLFunctions::~GLFunctions()
{
#ifdef _WIN32
if (hIntGLRC_) {
if (!wglDeleteContext_(hIntGLRC_)) {
DWORD dwErr = GetLastError();
LogWarning("Cannot delete GLRC");
}
}
#else //!_WIN32
if (intDpy_) {
if (intCtx_) {
glXDestroyContext_(intDpy_, intCtx_);
intCtx_ = NULL;
}
XCloseDisplay_(intDpy_);
intDpy_ = NULL;
}
#endif //!_WIN32
}
bool
GLFunctions::init(intptr_t hdc, intptr_t hglrc)
{
if (isEGL_) {
eglDisplay_ = (EGLDisplay)hdc;
eglOriginalContext_ = (EGLContext)hglrc;
return true;
}
#ifdef _WIN32
DWORD err;
if (missed_) {
return false;
}
if (!hdc) {
hDC_ = wglGetCurrentDC_();
}
else
{
hDC_ = (HDC) hdc;
}
hOrigGLRC_ = (HGLRC) hglrc;
if (!(hIntGLRC_ = wglCreateContext_(hDC_))) {
err = GetLastError();
return false;
}
if (!wglShareLists_(hOrigGLRC_, hIntGLRC_)) {
err = GetLastError();
return false;
}
bool makeCurrentNull = false;
if (wglGetCurrentContext_() == NULL) {
wglMakeCurrent_(hDC_, hIntGLRC_);
makeCurrentNull = true;
}
// Initialize pointers to GL functions
#include "gl_functions.hpp"
if (makeCurrentNull) {
wglMakeCurrent_(NULL, NULL);
}
if (missed_ == 0) {
return true;
}
#else //!_WIN32
if (!missed_) {
if (!hdc) {
Dpy_ = glXGetCurrentDisplay_();
}
else {
Dpy_ = (Display*) hdc;
}
Drawable_ = glXGetCurrentDrawable_();
origCtx_ = (GLXContext) hglrc;
int attribList[] = {
GLX_RGBA,
None};
if (!(intDpy_ = XOpenDisplay_(DisplayString(Dpy_)))) {
#if defined(ATI_ARCH_X86)
asm("int $3");
#endif
}
intDrawable_ = DefaultRootWindow(intDpy_);
XVisualInfo* vis;
int defaultScreen = DefaultScreen(intDpy_);
if (!(vis = glXChooseVisual_(intDpy_, defaultScreen , attribList))) {
return false;
}
if (!(intCtx_ = glXCreateContext_(intDpy_, vis, origCtx_, true))) {
return false;
}
return true;
}
#endif //!_WIN32
return false;
}
bool
GLFunctions::setIntEnv()
{
if (isEGL_) {
return true;
}
#ifdef _WIN32
// Save current DC and GLRC
tempDC_ = wglGetCurrentDC_();
tempGLRC_ = wglGetCurrentContext_();
// Set internal DC and GLRC
if (tempDC_ != getDC() || tempGLRC_ != getIntGLRC()) {
if (!wglMakeCurrent_(getDC(), getIntGLRC())) {
DWORD err = GetLastError();
LogWarning("cannot set internal GL environment");
return false;
}
}
#else //!_WIN32
tempDpy_ = glXGetCurrentDisplay_();
tempDrawable_ = glXGetCurrentDrawable_();
tempCtx_ = glXGetCurrentContext_();
// Set internal Display and GLXContext
if (tempDpy_ != getDpy() || tempCtx_ != getIntCtx()) {
if (!glXMakeCurrent_(
getIntDpy(), getIntDrawable(), getIntCtx())) {
LogWarning("cannot set internal GL environment");
return false;
}
}
#endif //!_WIN32
return true;
}
bool
GLFunctions::restoreEnv()
{
if (isEGL_) {
// eglMakeCurrent( );
return true;
}
#ifdef _WIN32
// Restore original DC and GLRC
if (!wglMakeCurrent_(tempDC_, tempGLRC_)) {
DWORD err = GetLastError();
LogWarning("cannot restore original GL environment");
return false;
}
#else //!_WIN32
// Restore Display and GLXContext
if (tempDpy_) {
if (!glXMakeCurrent_(tempDpy_, tempDrawable_, tempCtx_)) {
LogWarning("cannot restore original GL environment");
return false;
}
}
else {
// Just release internal context
if (!glXMakeCurrent_(getIntDpy(), None, NULL)) {
LogWarning("cannot reelase internal GL environment");
return false;
}
}
#endif //!_WIN32
return true;
}
} //namespace amd