OpenGL OpenCL sample

057cd52 first versions: cv::ogl::convertFromGLTexture2D & cv::ogl::convertToGLTexture2D
5656e94 added autogenerated stuff for cl_gl.h
765f1fd resolved CL functions in opengl.cpp
9f9fee3 implemented function cv::ogl::ocl::initializeContextFromGLTexture2D()
a792adb cv::ogl::ocl::initializeContextFromGLTexture2D() - added linux support (glx.h)
51c2869 added missing error message in function cv::ogl::ocl::initializeContextFromGLTexture2D()
513b887 fixed extension call in function cv::ogl::ocl::initializeContextFromGLTexture2D()
475a3e9 added CL-GL interop Windows sample (gpu/opengl_interop.cpp)
07af28f added building of CL-GL interop sample - Windows only
befe3a2 fixed whitespace errors & doxygen warnings (precommit_docs)
551251a changed function name to cv::ogl::ocl::initializeContextFromGL(), removed unused argument
4d5f009 changed CL_DEVICES_FOR_GL_CONTEXT_KHR to CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR
9fc3055 changed CL_DEVICES_FOR_GL_CONTEXT_KHR to CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KH
6d31cee Revert "changed CL_DEVICES_FOR_GL_CONTEXT_KHR to CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KH"
cc6a025 added texture format check in cv::ogl::convertFromGLTexture2D()
063a2c1 CL-GL sample: added Linux implementation (Xlib/GLX)
c392ae9 fixed trailing whitespace
85a80d0 fixed include files
ae23628 excluded samples/opengl from build case 2
9870ea5 added android EGL support
530b64c added doxygen documentation comments to CL-GL interop functions
This commit is contained in:
Alexey Ershov
2015-06-01 18:16:22 +03:00
committed by Alexander Alekhin
parent 04b2edcc8c
commit 3f68787051
6 changed files with 1003 additions and 2 deletions

View File

@@ -47,7 +47,9 @@
# ifdef HAVE_CUDA
# include <cuda_gl_interop.h>
# endif
#endif
#else // HAVE_OPENGL
# define NO_OPENGL_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenGL support")
#endif // HAVE_OPENGL
using namespace cv;
using namespace cv::cuda;
@@ -1572,3 +1574,264 @@ void cv::ogl::render(const ogl::Arrays& arr, InputArray indices, int mode, Scala
}
#endif
}
////////////////////////////////////////////////////////////////////////
// CL-GL Interoperability
#ifdef HAVE_OPENCL
# include "opencv2/core/opencl/runtime/opencl_gl.hpp"
#else // HAVE_OPENCL
# define NO_OPENCL_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenCL support")
#endif // HAVE_OPENCL
#if defined(HAVE_OPENGL)
# if defined(ANDROID)
# include <EGL/egl.h>
# elif defined(__linux__)
# include <GL/glx.h>
# endif
#endif // HAVE_OPENGL
namespace cv { namespace ogl {
namespace ocl {
Context& initializeContextFromGL()
{
#if !defined(HAVE_OPENGL)
NO_OPENGL_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
cl_uint numPlatforms;
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms");
if (numPlatforms == 0)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms");
std::vector<cl_platform_id> platforms(numPlatforms);
status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms");
// TODO Filter platforms by name from OPENCV_OPENCL_DEVICE
int found = -1;
cl_device_id device = NULL;
cl_context context = NULL;
for (int i = 0; i < (int)numPlatforms; i++)
{
// query platform extension: presence of "cl_khr_gl_sharing" extension is requred
{
AutoBuffer<char> extensionStr;
size_t extensionSize;
status = clGetPlatformInfo(platforms[i], CL_PLATFORM_EXTENSIONS, 0, NULL, &extensionSize);
if (status == CL_SUCCESS)
{
extensionStr.allocate(extensionSize+1);
status = clGetPlatformInfo(platforms[i], CL_PLATFORM_EXTENSIONS, extensionSize, (char*)extensionStr, NULL);
}
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get platform extension string");
if (!strstr((const char*)extensionStr, "cl_khr_gl_sharing"))
continue;
}
clGetGLContextInfoKHR_fn clGetGLContextInfoKHR = (clGetGLContextInfoKHR_fn)
clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetGLContextInfoKHR");
if (!clGetGLContextInfoKHR)
continue;
cl_context_properties properties[] =
{
#if defined(WIN32) || defined(_WIN32)
CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i],
CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(),
#elif defined(ANDROID)
CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i],
CL_GL_CONTEXT_KHR, (cl_context_properties)eglGetCurrentContext(),
CL_EGL_DISPLAY_KHR, (cl_context_properties)eglGetCurrentDisplay(),
#elif defined(__linux__)
CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i],
CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(),
CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(),
#endif
0
};
// query device
device = NULL;
size_t numDevices = 0;
{
size_t sizeDevices = 0;
status = clGetGLContextInfoKHR(properties, CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR, 0, NULL, &sizeDevices);
if (status == CL_SUCCESS)
{
numDevices = sizeDevices / sizeof(cl_device_id);
if (numDevices > 0)
{
numDevices = 1;
sizeDevices = numDevices * sizeof(cl_device_id);
status = clGetGLContextInfoKHR(properties, CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR, sizeDevices, (void*)&device, NULL);
}
}
if (status != CL_SUCCESS)
continue;
}
// create context
if (numDevices > 0)
{
context = clCreateContext(properties, 1, &device, NULL, NULL, &status);
if (status != CL_SUCCESS)
{
clReleaseDevice(device);
}
else
{
found = i;
break;
}
}
}
if (found < 0)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for OpenGL interop");
Context& ctx = Context::getDefault(false);
initializeContextFromHandle(ctx, platforms[found], context, device);
return ctx;
#endif
}
} // namespace cv::ogl::ocl
#if defined(HAVE_OPENGL) && defined(HAVE_OPENCL)
static void __OpenCLinitializeGL()
{
// temp stub
}
#endif // defined(HAVE_OPENGL) && defined(HAVE_OPENCL)
void convertToGLTexture2D(InputArray src, Texture2D& texture)
{
(void)src; (void)texture;
#if !defined(HAVE_OPENGL)
NO_OPENGL_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
// ... // check "interop available" flag first (i.e. sharegroup existence)
__OpenCLinitializeGL();
Size srcSize = src.size();
CV_Assert(srcSize.width == (int)texture.cols() && srcSize.height == (int)texture.rows());
using namespace cv::ocl;
Context& ctx = Context::getDefault();
cl_context context = (cl_context)ctx.ptr();
UMat u = src.getUMat();
// TODO Add support for roi
CV_Assert(u.offset == 0);
CV_Assert(u.isContinuous());
cl_int status = 0;
cl_mem clImage = clCreateFromGLTexture(context, CL_MEM_WRITE_ONLY, gl::TEXTURE_2D, 0, texture.texId(), &status);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromGLTexture failed");
cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ);
cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr();
status = clEnqueueAcquireGLObjects(q, 1, &clImage, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireGLObjects failed");
size_t offset = 0; // TODO
size_t dst_origin[3] = {0, 0, 0};
size_t region[3] = {u.cols, u.rows, 1};
status = clEnqueueCopyBufferToImage(q, clBuffer, clImage, offset, dst_origin, region, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyBufferToImage failed");
status = clEnqueueReleaseGLObjects(q, 1, &clImage, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseGLObjects failed");
status = clFinish(q); // TODO Use events
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed");
status = clReleaseMemObject(clImage); // TODO RAII
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMemObject failed");
#endif
}
void convertFromGLTexture2D(const Texture2D& texture, OutputArray dst)
{
(void)texture; (void)dst;
#if !defined(HAVE_OPENGL)
NO_OPENGL_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
// ... // check "interop available" flag first (i.e. sharegroup existence)
__OpenCLinitializeGL();
// check texture format
const int dtype = CV_8UC4;
CV_Assert(texture.format() == Texture2D::RGBA);
int textureType = dtype;
CV_Assert(textureType >= 0);
using namespace cv::ocl;
Context& ctx = Context::getDefault();
cl_context context = (cl_context)ctx.ptr();
// TODO Need to specify ACCESS_WRITE here somehow to prevent useless data copying!
dst.create(texture.size(), textureType);
UMat u = dst.getUMat();
// TODO Add support for roi
CV_Assert(u.offset == 0);
CV_Assert(u.isContinuous());
cl_int status = 0;
cl_mem clImage = clCreateFromGLTexture(context, CL_MEM_READ_ONLY, gl::TEXTURE_2D, 0, texture.texId(), &status);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromGLTexture failed");
cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ);
cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr();
status = clEnqueueAcquireGLObjects(q, 1, &clImage, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireGLObjects failed");
size_t offset = 0; // TODO
size_t src_origin[3] = {0, 0, 0};
size_t region[3] = {u.cols, u.rows, 1};
status = clEnqueueCopyImageToBuffer(q, clImage, clBuffer, src_origin, region, offset, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyImageToBuffer failed");
status = clEnqueueReleaseGLObjects(q, 1, &clImage, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseGLObjects failed");
status = clFinish(q); // TODO Use events
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed");
status = clReleaseMemObject(clImage); // TODO RAII
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMemObject failed");
#endif
}
}} // namespace cv::ogl