diff --git a/modules/core/src/opengl.cpp b/modules/core/src/opengl.cpp index 45aa121a4a..83be34f147 100644 --- a/modules/core/src/opengl.cpp +++ b/modules/core/src/opengl.cpp @@ -42,6 +42,12 @@ #include "precomp.hpp" +#if defined (__APPLE__) || defined(MACOSX) + #define GL_SHARING_EXTENSION "cl_APPLE_gl_sharing" +#else + #define GL_SHARING_EXTENSION "cl_khr_gl_sharing" +#endif + #ifdef HAVE_OPENGL # include "gl_core_3_1.hpp" # ifdef HAVE_CUDA @@ -1635,94 +1641,148 @@ Context& initializeContextFromGL() #elif !defined(HAVE_OPENCL_OPENGL_SHARING) NO_OPENCL_SHARING_ERROR; #else - cl_uint numPlatforms; - cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); + cl_uint platformsCnt = 0; + cl_uint devCnt = 0; + cl_device_id* devices = nullptr; + cl_uint devUsed = 0; + cl_context context = nullptr; + + cl_int status = clGetPlatformIDs(0, NULL, &platformsCnt); if (status != CL_SUCCESS) CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: Can't get number of platforms: %d", status)); - if (numPlatforms == 0) + if (platformsCnt == 0) CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms"); - std::vector platforms(numPlatforms); - status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL); + std::vector platforms(platformsCnt); + status = clGetPlatformIDs(platformsCnt, &platforms[0], NULL); if (status != CL_SUCCESS) - CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: Can't get number of platforms: %d", status)); + CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: Can't get platforms: %d", status)); + // TODO Filter platforms by name from OPENCV_OPENCL_DEVICE + bool sharingSupported = false; - int found = -1; - cl_device_id device = NULL; - cl_context context = NULL; + for (unsigned int i = 0; (!sharingSupported && (i < platformsCnt)); ++i) { + status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, 0, NULL, &devCnt); + if (status != CL_SUCCESS) + CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: No devices available: %d", status)); - for (int i = 0; i < (int)numPlatforms; i++) - { - // query platform extension: presence of "cl_khr_gl_sharing" extension is required - { - AutoBuffer extensionStr; + try { + devices = new cl_device_id[devCnt]; - 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.data(), NULL); - } + status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, devCnt, devices, NULL); if (status != CL_SUCCESS) - CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: Can't get platform extension string: %d", status)); + CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: Can't get platform devices: %d", status)); - if (!strstr((const char*)extensionStr.data(), "cl_khr_gl_sharing")) - continue; + for (unsigned int j = 0; (!sharingSupported && (j < devCnt)); ++j) { + size_t extensionSize; + status = clGetDeviceInfo(devices[j], CL_DEVICE_EXTENSIONS, 0, NULL, &extensionSize ); + if (status != CL_SUCCESS) + CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: No devices available: %d", status)); + + if(extensionSize > 0) + { + char* extensions = nullptr; + + try { + extensions = new char[extensionSize]; + + status = clGetDeviceInfo(devices[j], CL_DEVICE_EXTENSIONS, extensionSize, extensions, &extensionSize); + if (status != CL_SUCCESS) + continue; + } catch(...) { + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Exception thrown during device extensions gathering"); + } + + std::string devString; + + if(extensions != nullptr) { + devString = extensions; + delete[] extensions; + } + else { + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Unexpected error during device extensions gathering"); + } + + size_t oldPos = 0; + size_t spacePos = devString.find(' ', oldPos); // extensions string is space delimited + while (spacePos != devString.npos) { + if (strcmp(GL_SHARING_EXTENSION, + devString.substr(oldPos, spacePos - oldPos).c_str()) + == 0) { + // Device supports context sharing with OpenGL + devUsed = i; + sharingSupported = true; + break; + } + do { + oldPos = spacePos + 1; + spacePos = devString.find(' ', oldPos); + } while (spacePos == oldPos); + } + } + } + } catch(...) { + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Exception thrown during device information gathering"); + if(devices != nullptr) { + delete[] devices; + } + continue; } - clGetGLContextInfoKHR_fn clGetGLContextInfoKHR = (clGetGLContextInfoKHR_fn) - clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetGLContextInfoKHR"); - if (!clGetGLContextInfoKHR) - continue; - - cl_context_properties properties[] = - { -#if 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(), + if (sharingSupported) { + // Define OS-specific context properties and create the OpenCL context +#if defined (__APPLE__) + CGLContextObj cglContext = CGLGetCurrentContext(); + CGLShareGroupObj cglShareGroup = CGLGetShareGroup(cglContext); + cl_context_properties props[] = + { + CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)cglShareGroup, + 0 + }; + context = clCreateContext(props, 0,0, NULL, NULL, &ciErrNum); #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(), + cl_context_properties props[] = + { + CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(), + CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(), + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + 0 + }; + context = clCreateContext(props, 1, &devices[devUsed], NULL, NULL, &status); +#elif defined(_WIN32) + cl_context_properties props[] = + { + CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(), + CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(), + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + 0 + }; + context = clCreateContext(props, 1, &devices[devUsed], NULL, NULL, &status); #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(), + cl_context_properties props[] = + { + CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(), + CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(), + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + 0 + }; + context = clCreateContext(props, 1, &devices[devUsed], NULL, NULL, &status); #endif - 0 - }; - - // query device - device = NULL; - status = clGetGLContextInfoKHR(properties, CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR, sizeof(cl_device_id), (void*)&device, NULL); - if (status != CL_SUCCESS) - continue; - - // create context - context = clCreateContext(properties, 1, &device, NULL, NULL, &status); - if (status != CL_SUCCESS) - { - clReleaseDevice(device); } + + if (status != CL_SUCCESS) + CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: Can't create context for OpenGL interop: %d", status)); else - { - found = i; break; - } } - if (found < 0) - CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for OpenGL interop"); - cl_platform_id platform = platforms[found]; + cl_platform_id platform = platforms[devUsed]; std::string platformName = PlatformInfo(&platform).name(); - OpenCLExecutionContext clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, device); - clReleaseDevice(device); + OpenCLExecutionContext clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, devices[devUsed]); + clReleaseDevice(devices[devUsed]); clReleaseContext(context); clExecCtx.bind(); return const_cast(clExecCtx.getContext());