Hi everyone!
I took on a nice project that uses Qt5.1 alpha and there are problems with OpenCL-GL interop. Let me not repeat myself, but simply link the Qt forum post I made there. All remakrs are welcome on both sides.
Solved! Go to Solution.
From http://developer.amd.com/download/AMD_APP_SDK_Release_Notes_Developer.pdf
Section 5.3
"
For OpenGL interoperability with OpenCL, there currently is a requirement on when the
OpenCL context is created and when texture/buffer shared allocations can be made. To use
shared resources, the OpenGL application must create an OpenGL context and then an
OpenCL context. All resources (GL buffers and textures) created after creation of the OpenCL
context can be shared between OpenGL and OpenCL. If resources are allocated before the
OpenCL context creation, they cannot be shared between OpenGL and OpenCL."
ie.for your minimalistic program, you need to move the code related to making your vbo (QOpenGLBuffer m_vbo; etc) until after you have made your cl context
i.e. after your for(auto& plat : my_cl_platforms) code block
The SimpleGL sample in the amd sdk creates the CL command queue before the vbo, so maybe that is required as well.
Will this help... It didn't for me. I also don't have access to an AMD graphics card.
May try GLIntercept with the ARB_debug_output, it might log something that tells you what is going on.
Also a pnf_notify on your CL context.
Note to AMD The info in Section 5.3 should also be in the AMD_Accelerated_Parallel_Processing_OpenCL_Programming_Guide under appendix G
I would have found this information a lot faster,
Hi!
I would really like to get on with this project, but I got no leads on why it doesn't work. Since my QPainter does not show on my canvas at all (trying to get all the same things working I had when using SFML and SFGUI), so I disabled it just for now. I got 2 complete set of OpenCL inits, both do the same thing (crash), and I have no idea what could cause the problem.
The things I would like to ask here:
IMHO it is possible that Qt is doing some threading under. OpenCL should be thread safe with exeption of clSetKernelArg() but OpenGL is not. I have Qt 4.8 app which use OpenCL and QGLWidget interoperability.
I have looked at it a little more. It seems that the app is really one threaded (at least I have not been able to identify any thread being launched by Qt itself, though it's not impossible). I definately know that I have no chance of getting a debug version of amdocl64.dll, but is there any chance that someone who has such a version can tell me what is at location 0x0000000000000118? This address is in the error is very much static, so I guess indeed it is something internal.
I am aware that the problem might be inside the code I wrote myself, but I have been debugging it for 5 days straight, and I can't find what's causing the problem. I would gladly upload a working test case with the base class using QWindow only which is most likely the future of Qt and many would appreciate it.
If someone who has access to debug versions of AMD dlls could check what resource is missing that causes a crash, I would very much appreciate that. I am using 5.1 beta which has installers here, plus VS2012 and Qt VS-addon 1.2.1.
If you place your binaries on some public share, I will have a look at it.
I have my 64-bit built binaries in the x64 dir on the root of this directory. They are meant to be launched from QInterop_test, as they are looking for shaders and kernels as ./Resources/my_shader.glsl etc. I wouldn't like to upload Qt binaries (pls refer to the prebuilt packages link in my previous post) they do link against icu 4.99 dlls, which I compressed in the root directory as icu.rar for convenience. Someone with VS2012, an installed 5.1 beta release of Qt, plus the Qt VS-addin found here can freely rebuild the app and debug inside VS.
I very much appreciate the help.
Hi Meteorhead,
cant access your link to the binary. It may be something from your side, or maybe my organisation blocking the content. Can you attach a zip file here. Also If you can elaborate on the steps to reproduce the issue, please do so
I have attached the entire Qt5_test solution, the same dir that I shared via the read-only Skydrive link. The precompiled exe of QInterop_test already holds the bug which selects the first interop capable GPU it finds (if not, then it falls back to the first interop capable CPU) and after displaying the first frame and trying to update, it segfaults inside clEnqueueAcquireGLObjects. If one wishes to debug, they need the aformentioned libs and the Qt Addin, all install fairly fast from the provided links.
To understand a little bit of code without reading through the link of the Qt forum post in my first message, the code is based upon a pure OpenGL example application (link in my Qt post). It basically shows a base class similar to QGLWidget, which specializes QWidget in a manner that it hides OpenGL context creation from the user and provides a few unimplemented functions that are called automatically by the event process loop and ensure that the unimplemneted initGL (or whatever the exact name is) function is run before the first paintGL function is called (both being triggered by the first expose or resize event the Widget gets).
The example application shows how to rewrite a class similar to QGLWidget, but not inheriting from QWidget (big overkill for most cases), but from QWindow which is a lot more lightweight and pretty much the future of writing GUI in terms of Qt. My InteropWindow base class is very similar to OpenGLWindow in the aforementioned link, but it provides both initializeGL and initializeCL functions which are run in the correct order (first OpenGL context is created, then OpenGL extension functions are initialized, then OpenGL resources are created (initializeGL), then OpenCL context is created on an interop device, then OpenCL resources are created (initializeCL) and all of this is ensured to run prior to the first attempt to draw the contents of the window. My inheriting class CubeRotator implements the mandatory functions and segfaults utterly when trying to update the scene.
To put it short: to reproduce the issue, run one of the prebuilt executable inside Qt5_test/x64 or to look at source code, look inside Qt5_test/QInterop_test directory, and to do step-by-step debug, install everything I mentioned, and do everthing in VS2012.
Hi!
I was hoping to get some response, but I guess nobody's got the time to debug user SW (which is understandable), however... I have spent roughly 1 week of my time (with a few other sideprojects) debugging into the issue, and I lost a small piece of my mind when I figured that it all works under linux.
I have attached the solution with the missing parts filled in for linux, and it all works (naturally, on the GPU). Effectively 3 smaller parts of the code differ:
// Resource handles
QPlatformNativeInterface* plat_int; // Platform native interface to obtain OS-spcific handles
#ifdef _WIN32
QPair<HDC,HGLRC> m_gl_device; // Windows-specific OpenGL device handles
#endif
#ifdef __linux__
QPair<Display*,GLXContext> m_gl_device; // Linux-specific OpenGL device handles
#endif
inside InteropWindow.hpp
#ifdef _WIN32
// Qt5 way
m_gl_device.first = GetDC(static_cast<HWND>(plat_int->nativeResourceForWindow(QByteArrayLiteral("handle"), this)));
m_gl_device.second = static_cast<HGLRC>(plat_int->nativeResourceForContext(QByteArrayLiteral("renderingContext"), m_gl_context));
// Native way
QPair<HDC,HGLRC> m_gl_device_native;
m_gl_device_native.first = wglGetCurrentDC();
m_gl_device_native.second = wglGetCurrentContext();
qDebug() << "InteropWindow: Window on screen " << this->screen()->name() << " has managed HDC = " << m_gl_device.first << " and HGLRC = " << m_gl_device.second;
qDebug() << "InteropWindow: Window on screen " << this->screen()->name() << " has native HDC = " << m_gl_device_native.first << " and HGLRC = " << m_gl_device_native.second;
#endif
#ifdef __linux__
/*
// Qt5 way
m_gl_device.first = *static_cast<Screen*>(plat_int->nativeResourceForWindow(QByteArrayLiteral("handle"), this));
m_gl_device.second = static_cast<GLXContext>(plat_int->nativeResourceForContext(QByteArrayLiteral("renderingContext"), m_gl_context));
*/
// Native way
QPair<Display*,GLXContext> m_gl_device_native;
m_gl_device_native.first = glXGetCurrentDisplay();
m_gl_device_native.second = glXGetCurrentContext();
m_gl_device = m_gl_device_native;
// qDebug() << "InteropWindow: Window on screen " << this->screen()->name() << " has managed Screen = " << m_gl_device.first.root << " and GLXContext = " << (void*)m_gl_device.second;
qDebug() << "InteropWindow: Window on screen " << this->screen()->name() << " has native Screen = " << m_gl_device_native.first << " and GLXContext = " << m_gl_device_native.second;
inside void InteropWindow::createCLcontext_helper()
cl_context_properties properties[] = {
CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(platform()),
#ifdef _WIN32
CL_GL_CONTEXT_KHR, reinterpret_cast<cl_context_properties>(m_gl_device.second),
CL_WGL_HDC_KHR, reinterpret_cast<cl_context_properties>(m_gl_device.first),
#endif
#ifdef __linux__
CL_GLX_DISPLAY_KHR, reinterpret_cast<intptr_t>(m_gl_device.first),
CL_GL_CONTEXT_KHR, reinterpret_cast<intptr_t>(m_gl_device.second),
#endif
0 };
inside bool InteropWindow::lookForDeviceType(cl_bitfield devtype).
I do not know the QPA literals to obtain the handles, so in under linux I only implemented the native way of obtaining the handles. On Windows, both QPA and the native way resolve to the same pointers.
I am on the verge of giving up, as I see really no reason why it doesn't work, moreover I have tried numerous things the could potentially solve a non-existing problem, but nothing works.
Sidenote: I used the official Qt5.1 beta prebuilt packages (linked against desktop OpenGL) found here.
In case someone would find the code too intimidating, I have created a minimalistic program that shows the problem. One main.cpp, Windows crashes, linux survives. Compile the program with whatever IDE or compiler you like.
#include <QGuiApplication>
#include <QtGui>
#include <CL/cl.hpp>
#ifdef __linux__
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <GL/glx.h>
#undef Bool
#endif
void myError(cl_int& err)
{
if(err != CL_SUCCESS)
{
qDebug() << "ERROR: " << err;
}
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
// Setup desired format
QSurfaceFormat my_surfaceformat;
my_surfaceformat.setRenderableType(QSurfaceFormat::RenderableType::OpenGL);
my_surfaceformat.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
my_surfaceformat.setSwapBehavior(QSurfaceFormat::SwapBehavior::DoubleBuffer);
my_surfaceformat.setMajorVersion(2);
my_surfaceformat.setMinorVersion(0);
my_surfaceformat.setRedBufferSize(8);
my_surfaceformat.setGreenBufferSize(8);
my_surfaceformat.setBlueBufferSize(8);
my_surfaceformat.setAlphaBufferSize(8);
my_surfaceformat.setDepthBufferSize(24);
my_surfaceformat.setStencilBufferSize(8);
my_surfaceformat.setStereo(false);
QOffscreenSurface my_offscreen_target;
my_offscreen_target.setFormat(my_surfaceformat);
my_offscreen_target.create();
QOpenGLContext my_gl_context(&app);
my_gl_context.setFormat(my_offscreen_target.format());
my_gl_context.create();
if(!my_gl_context.makeCurrent(&my_offscreen_target)) qWarning("Could not create OpenGL context");
QOpenGLBuffer m_vbo;
if(!m_vbo.create()) qWarning("Could not create VBO");
m_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
if(!m_vbo.bind()) qWarning("Could not bind VBO");
m_vbo.allocate(8*sizeof(QVector4D));
m_vbo.release();
cl_int CL_err = CL_SUCCESS;
std::vector<cl::Platform> my_cl_platforms;
cl::Platform::get(&my_cl_platforms);
cl::Context my_cl_context;
cl::Device my_cl_device;
cl::CommandQueue my_cl_commandqueue;
for(auto& plat : my_cl_platforms)
{
std::vector<cl::Device> devices;
plat.getDevices(CL_DEVICE_TYPE_GPU, &devices);
if(!devices.empty())
{
cl_context_properties properties[] = {
CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(plat()),
#ifdef _WIN32
CL_WGL_HDC_KHR, reinterpret_cast<cl_context_properties>(wglGetCurrentDC()),
CL_GL_CONTEXT_KHR, reinterpret_cast<cl_context_properties>(wglGetCurrentContext()),
#endif
#ifdef __linux__
CL_GLX_DISPLAY_KHR, reinterpret_cast<cl_context_properties>(glXGetCurrentDisplay()),
CL_GL_CONTEXT_KHR, reinterpret_cast<cl_context_properties>(glXGetCurrentContext()),
#endif
0 };
my_cl_device = devices.at(0);
my_cl_context = cl::Context(my_cl_device, properties, NULL, NULL, &CL_err);
myError(CL_err);
my_cl_commandqueue = cl::CommandQueue(my_cl_context, my_cl_device, 0, &CL_err);
myError(CL_err);
}
}
std::vector<cl::Memory> my_interop_buffs;
my_interop_buffs.push_back(cl::BufferGL(my_cl_context, CL_MEM_READ_WRITE, m_vbo.bufferId(), &CL_err));
myError(CL_err);
my_cl_commandqueue.enqueueAcquireGLObjects(&my_interop_buffs, NULL, NULL);
my_cl_commandqueue.enqueueReleaseGLObjects(&my_interop_buffs, NULL, NULL);
return app.exec();
}
Ultimately nothing should display, not even error messages.