cv::ogl::mapGLBuffer调用报CL_INVALID_CONTEXT错误求助
问题描述
目标是利用OpenCV提供的OpenGL/OpenCL互操作能力,直接在GPU上完成图像快速畸变处理,规避GPU与CPU之间的图像数据传输开销。在Qt框架中基于已有的OpenGL缓冲区对象创建cv::ogl::Buffer实例,相关代码如下:
// m_pub is of type QOpenGLBuffer cv::ogl::Buffer b(512, 512, CV_8UC4, m_pub.bufferId());
执行后续映射代码时程序抛出异常:
cv::UMat m = cv::ogl::mapGLBuffer(b);
OpenCV初始返回的错误信息如下:
OpenCV(4.5.5) Error: Unknown error code -220 (OpenCL: clCreateFromGLBuffer failed) in cv::ogl::mapGLBuffer, file D:\OpenCV\opencv-4.5.5\modules\core\src\opengl.cpp, line 1886
在opengl.cpp源码中添加cv::ocl::getOpenCLErrorString(status);调用重新编译OpenCV后,确认具体错误码为CL_INVALID_CONTEXT。已完成cv::ocl::Context、cv::ocl::Device、cv::ocl::Platform相关配置排查,也尝试调用cv::ocl::attachContext完成上下文绑定,问题未解决。
解决方案
CL_INVALID_CONTEXT在GL/CL互操作场景下的核心原因是OpenCL上下文与当前线程绑定的OpenGL上下文不存在共享关系,cv::ocl::attachContext调用无效通常是传入的平台、设备句柄与OpenGL上下文实际绑定的硬件设备不匹配,按以下步骤排查修复:
- 校验上下文绑定时机:必须在Qt OpenGL上下文完成当前线程绑定(即
QOpenGLContext::makeCurrent()调用返回成功)之后,再调用任何OpenCV OpenGL/OpenCL互操作接口、创建cv::ogl::Buffer实例。禁止在全局初始化阶段、子线程未绑定GL上下文时提前初始化相关OpenCV资源,子线程做GPU处理时需手动完成GL上下文绑定,且处理过程中不得切换上下文。 - 手动创建与GL上下文匹配的OpenCL上下文,不要使用OpenCV自动探测的默认OpenCL上下文:
- 从当前激活的
QOpenGLContext中获取原生平台句柄,Windows平台取HGLRC、HDC句柄,Linux平台取GLX上下文句柄,macOS平台取CGL上下文句柄。 - 调用OpenCL扩展接口
clGetGLContextInfoKHR,查询当前GL上下文关联的OpenCL平台ID、设备ID,不要手动枚举设备选择,手动枚举极易出现集显/独显不匹配的问题。 - 传入查询到的平台、设备ID,配置
CL_GL_CONTEXT_KHR等GL共享属性创建OpenCL上下文,再调用cv::ocl::attachContext将该上下文绑定到OpenCV,后续再创建cv::ogl::Buffer、调用mapGLBuffer即可消除上下文不匹配错误。
- 从当前激活的
- 额外排查项:
- 确认OpenCV编译时开启了
WITH_OPENGL、WITH_OPENCL、WITH_OPENGL_INTEROP选项,显卡驱动支持cl_khr_gl_sharing扩展,可先通过cv::ocl::haveOpenCL()、cv::ocl::useOpenCL()确认OpenCL运行时正常加载。 - 双显卡设备需强制程序运行在和OpenGL上下文相同的GPU上,Qt默认创建GL上下文可能选中集成显卡,OpenCV自动探测OpenCL设备选中独立显卡时,两个上下文分属不同硬件,必然触发
CL_INVALID_CONTEXT错误。 - 调用
mapGLBuffer映射缓冲区后,在对应unmapGLBuffer调用完成前,不得执行任何切换GL上下文、触发GL缓冲区CPU回读的操作。
- 确认OpenCV编译时开启了
内容的提问来源于stack exchange,提问作者Sang

