让 OpenCL 在 Qt5 中与 OpenGL 良好配合的正确方法是什么?

What is the correct way to get OpenCL to play nice with OpenGL in Qt5?

我找到了几个关于如何让 OpenCL 与 OpenGL 和 Qt5 良好配合的非官方资源,每个资源都有不同的复杂程度:

有这些例子很好,但是它们没有回答以下问题:最少 需要 Qt5[=41] 的具体步骤是什么=] 小部件程序显示在 OpenCL 内核 中进行的计算结果,然后直接传输到由 Qt5 启动的附加 OpenGL 上下文 ?

子题包括:

  • 将 Qt5 中的 OpenGL 上下文公开给 OpenCL 的正确方法是什么?
  • 首先如何启动我的 Qt5 应用程序以确保正确设置 OpenGL 上下文以便与 OpenCL 一起使用?
  • OpenCL应该如何启动才能兼容Qt5中的OpenGL上下文?
  • 我必须注意哪些问题才能在 Qt5 支持的平台上运行?
  • 是否有 "official" 方法来做到这一点,或者 Digia 正在研究一种方法?

请注意,我主要对使用 OpenGL 作为小部件感兴趣,而不是 window/full-screen。

我在 mac、linux 和 windows 上同时使用了 Qt5 和 OpenCL,策略如下:

  1. Create a QGLWidget and GL context(这个例子创建了两个GL context,一个是QGLwidget中的Qt/visualization,一个是OpenCL的叫mainGLContext,在做多线程的时候很有用。这两个context就可以了共享数据。)
QGLWidget* widget = new QGLWidget;
QGLContext* mainGLContext = new QGLContext(QGLFormat::defaultFormat(), widget);
mainGLContext->create();
  1. 使用 OpenGL 上下文创建 OpenCL 上下文。这是特定于平台的。对于 linux,您使用 glx,对于 windows wgl,以及 mac cgl 共享组。下面是我用来创建互操作性上下文属性的函数。 display 变量用于 linux 和 windows,您可以使用 glXGetCurrentDisplay() 和 wglGetCurrentDC() 获取它。
cl_context_properties* createInteropContextProperties(
        const cl::Platform &platform,
        cl_context_properties OpenGLContext,
        cl_context_properties display) {
#if defined(__APPLE__) || defined(__MACOSX)
CGLSetCurrentContext((CGLContextObj)OpenGLContext);
CGLShareGroupObj shareGroup = CGLGetShareGroup((CGLContextObj)OpenGLContext);
if(shareGroup == NULL)
throw Exception("Not able to get sharegroup");
    cl_context_properties * cps = new cl_context_properties[3];
    cps[0] = CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE;
    cps[1] = (cl_context_properties)shareGroup;
    cps[2] = 0;

#else
#ifdef _WIN32
    // Windows
    cl_context_properties * cps = new cl_context_properties[7];
    cps[0] = CL_GL_CONTEXT_KHR;
    cps[1] = OpenGLContext;
    cps[2] = CL_WGL_HDC_KHR;
    cps[3] = display;
    cps[4] = CL_CONTEXT_PLATFORM;
    cps[5] = (cl_context_properties) (platform)();
    cps[6] = 0;
#else
    cl_context_properties * cps = new cl_context_properties[7];
    cps[0] = CL_GL_CONTEXT_KHR;
    cps[1] = OpenGLContext;
    cps[2] = CL_GLX_DISPLAY_KHR;
    cps[3] = display;
    cps[4] = CL_CONTEXT_PLATFORM;
    cps[5] = (cl_context_properties) (platform)();
    cps[6] = 0;
#endif
#endif
    return cps;
}
  1. 通常您希望进行多线程处理,让一个线程执行 Qt 事件处理,同时在另一个线程中执行一些 OpenCL 处理。请记住在每个线程中创建 GL 上下文 "current"。为此,在 QGLContext 对象上使用 makeCurrent 和 moveToThread 函数。您可以在此处找到有关我如何完成此操作的详细信息:https://github.com/smistad/FAST/blob/master/source/FAST/Visualization/Window.cpp

  2. 我不知道用于创建 OpenCL 上下文的 Qt OpenCL 包装器。

在完成更多工作后,我觉得有必要添加更多信息。 Erik Smistad 的回答是正确的,并将继续被接受,但这只是实现此目的的几种方法之一。

根据 this 文章,我们至少可以通过 3 种方式进行 OpenGL 与 OpenCL 互操作:

  1. 直接与 OpenCL 共享 OpenGL 纹理。优点:最快的路线,因为一切都是零拷贝。缺点:严重限制可用的受支持数据格式。
  2. 与 OpenCL 共享 OpenGL PBO 并将其复制到纹理中。第二快,但会强制需要内存复制。
  3. 将 OpenCL 中的输出缓冲区映射到主机内存并从那里上传纹理。在 GPU 上使用 OpenCL 时最慢。在 CPU 上使用 OpenCL 时最快。强制将数据复制到主机内存并返回。在可用数据格式方面最灵活。