Merge pull request #26281 from kallaballa:clgl_device_discovery

Rewrote OpenCL-OpenGL-interop device discovery routine without extensions and with Apple support
pull/24927/merge
Alexander Smorkalov 4 weeks ago committed by GitHub
commit e026a5ad8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 186
      modules/core/src/opengl.cpp

@ -42,6 +42,12 @@
#include "precomp.hpp" #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 #ifdef HAVE_OPENGL
# include "gl_core_3_1.hpp" # include "gl_core_3_1.hpp"
# ifdef HAVE_CUDA # ifdef HAVE_CUDA
@ -1635,94 +1641,148 @@ Context& initializeContextFromGL()
#elif !defined(HAVE_OPENCL_OPENGL_SHARING) #elif !defined(HAVE_OPENCL_OPENGL_SHARING)
NO_OPENCL_SHARING_ERROR; NO_OPENCL_SHARING_ERROR;
#else #else
cl_uint numPlatforms; cl_uint platformsCnt = 0;
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); 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) 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 number of platforms: %d", status));
if (numPlatforms == 0) if (platformsCnt == 0)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms"); CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms");
std::vector<cl_platform_id> platforms(numPlatforms); std::vector<cl_platform_id> platforms(platformsCnt);
status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL); status = clGetPlatformIDs(platformsCnt, &platforms[0], NULL);
if (status != CL_SUCCESS) 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 // TODO Filter platforms by name from OPENCV_OPENCL_DEVICE
bool sharingSupported = false;
int found = -1; for (unsigned int i = 0; (!sharingSupported && (i < platformsCnt)); ++i) {
cl_device_id device = NULL; status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, 0, NULL, &devCnt);
cl_context context = NULL; if (status != CL_SUCCESS)
CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: No devices available: %d", status));
for (int i = 0; i < (int)numPlatforms; i++) try {
{ devices = new cl_device_id[devCnt];
// query platform extension: presence of "cl_khr_gl_sharing" extension is required
{
AutoBuffer<char> extensionStr;
size_t extensionSize; status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, devCnt, devices, NULL);
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);
}
if (status != CL_SUCCESS) 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")) for (unsigned int j = 0; (!sharingSupported && (j < devCnt)); ++j) {
continue; size_t extensionSize;
} status = clGetDeviceInfo(devices[j], CL_DEVICE_EXTENSIONS, 0, NULL, &extensionSize );
if (status != CL_SUCCESS)
clGetGLContextInfoKHR_fn clGetGLContextInfoKHR = (clGetGLContextInfoKHR_fn) CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: No devices available: %d", status));
clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetGLContextInfoKHR");
if (!clGetGLContextInfoKHR) 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; continue;
}
cl_context_properties properties[] = if (sharingSupported) {
{ // Define OS-specific context properties and create the OpenCL context
#if defined(_WIN32) #if defined (__APPLE__)
CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], CGLContextObj cglContext = CGLGetCurrentContext();
CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(), CGLShareGroupObj cglShareGroup = CGLGetShareGroup(cglContext);
CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(), 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__) #elif defined(__ANDROID__)
CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], cl_context_properties props[] =
CL_GL_CONTEXT_KHR, (cl_context_properties)eglGetCurrentContext(), {
CL_EGL_DISPLAY_KHR, (cl_context_properties)eglGetCurrentDisplay(), 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__) #elif defined(__linux__)
CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], cl_context_properties props[] =
CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(), {
CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(), 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 #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) if (status != CL_SUCCESS)
{ CV_Error_(cv::Error::OpenCLInitError, ("OpenCL: Can't create context for OpenGL interop: %d", status));
clReleaseDevice(device);
}
else else
{
found = i;
break; 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(); std::string platformName = PlatformInfo(&platform).name();
OpenCLExecutionContext clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, device); OpenCLExecutionContext clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, devices[devUsed]);
clReleaseDevice(device); clReleaseDevice(devices[devUsed]);
clReleaseContext(context); clReleaseContext(context);
clExecCtx.bind(); clExecCtx.bind();
return const_cast<Context&>(clExecCtx.getContext()); return const_cast<Context&>(clExecCtx.getContext());

Loading…
Cancel
Save