I have found several unofficial sources for how to get OpenCL to play nice with OpenGL and Qt5, each with different levels of complexity:
- https://github.com/smistad/Qt-OpenGL-OpenCL-Interoperability
- https://github.com/petoknm/QtOpenCLGLInterop
- http://www.krazer.com/?p=109
Having these examples is nice, however they don't answer the following question: What exact steps are the minimum required to have a Qt5 widgets program display the result of a calculation made in OpenCL kernel and then transferred directly to attached OpenGL context initiated by Qt5?
Sub-questions include:
- What is the correct way to expose the OpenGL context in Qt5 to OpenCL?
- How do I initiate my Qt5 app in the first place to make sure that the OpenGL context is correctly set up for use with OpenCL?
- How should OpenCL be initiated to be compatible with the OpenGL context in Qt5?
- What quirks must I look out for to have this working across the platforms that Qt5 supports?
- Is there such a thing as an "official" way to do this, or is Digia working on one?
Note, I am primarily interested in using OpenGL as a widget as opposed to a window/full-screen.
I have used Qt5 and OpenCL together on mac, linux and windows with the following strategy:
- Create a QGLWidget and GL context (this example creates two GL context, one for Qt/visualization in the QGLwidget and one for OpenCL called mainGLContext, useful when doing multi-threading. These two context will be able to share data.)
QGLWidget* widget = new QGLWidget;
QGLContext* mainGLContext = new QGLContext(QGLFormat::defaultFormat(), widget);
mainGLContext->create();
- Create an OpenCL context using the OpenGL context. This is platform specific. For linux you use glx, for windows wgl, and mac cgl sharegroups. Below is the function I use to create the context properties for interoperability. The display variable is used on linux and windows and you can get it with glXGetCurrentDisplay() and 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;
}
Often you want to do multi-threading, having one thread do the Qt event handling, while doing some OpenCL processing in another thread. Remember to make the GL context "current" in each thread. Use the makeCurrent and moveToThread function on the QGLContext object for this. You can find details on how I have done this here: https://github.com/smistad/FAST/blob/master/source/FAST/Visualization/Window.cpp
I don't know of a Qt OpenCL wrapper to create the OpenCL context.
After working on this some more I felt compelled to add some more info. Erik Smistad's answer is correct and will remain accepted, however it is only one of several ways to do this.
Based on this article there are at least 3 ways we can have OpenGL vs. OpenCL interop:
- Sharing an OpenGL texture directly with OpenCL. PROS: Fastest route since everything is zero-copy. CONS: Severely limits available supported data formats.
- Sharing an OpenGL PBO with OpenCL and copy from this into a Texture. Second quickest, but will force the need for a memory copy.
- Mapping output buffer in OpenCL to host memory and uploading texture from there. Slowest when using OpenCL on GPU. Fastest when using OpenCL on CPU. Forces data to be copied to host memory and back. Most flexible with respect to available data formats.