Search code examples
pythonopenglopenclpyopenglpyopencl

PyOpenCL: gl sharing context creation failed (overflow error)


I want to create an application that uses OpenCL to caluculate the color value of every pixel in a texture and OpenGL to display that texture. The problem is that when I try to create a context with GL sharing properties the program freezes. Using the function get_gl_sharing_context_properties() I get a list [(8200, 65538), (8203, 18446744072971422270)]. The last number in the list is too big to convert to a 64 bit int and I get an overflow error. The code I use to create the CL context:

def cl_init():
    platform = cl.get_platforms()[1]
    device = platform.get_devices(cl.device_type.GPU)

    from pyopencl.tools import get_gl_sharing_context_properties

    print(cl.have_gl())
    print(get_gl_sharing_context_properties())
    print(sys.platform)
    context = cl.Context(properties=[
                (cl.context_properties.PLATFORM, platform)] +
                get_gl_sharing_context_properties())

    print("Context creation done")

    queue = cl.CommandQueue(context)

The code never reaches print("Context creation done"). I use QtPy4 and the QGLWidget to create the OpenGL context and display the texture.


Solution

  • Ok ran into a similar issue myself and here is my fix for it. If you look exactly at what get_gl_sharing_context_properties() is doing according to PyOpenCL's source code on github under the tools module, you will find the following platform-specific code:

    def get_gl_sharing_context_properties():
        ctx_props = cl.context_properties
    
        from OpenGL import platform as gl_platform
    
        props = []
    
        import sys
        if sys.platform in ["linux", "linux2"]:
            from OpenGL import GLX
            props.append(
                (ctx_props.GL_CONTEXT_KHR, gl_platform.GetCurrentContext()))
            props.append(
                    (ctx_props.GLX_DISPLAY_KHR,
                        GLX.glXGetCurrentDisplay()))
        elif sys.platform == "win32":
            from OpenGL import WGL
            props.append(
                (ctx_props.GL_CONTEXT_KHR, gl_platform.GetCurrentContext()))
            props.append(
                    (ctx_props.WGL_HDC_KHR,
                        WGL.wglGetCurrentDC()))
        elif sys.platform == "darwin":
            props.append(
                (ctx_props.CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE,
                    cl.get_apple_cgl_share_group()))
        else:
            raise NotImplementedError("platform '%s' not yet supported"
                    % sys.platform)
    
        return props
    

    Now, since I am on Windows, I took a look at the WGL code (which comes from PyOpenGL) and found that WGL.wglGetCurrentDC() (like get_gl_sharing_context_properties() of course) was returning incorrect handle values sometimes that caused the integer overflow. It turns out the DC (device context) is really supposed to be a 32 bit signed integer. However, in the PyOpenGL wrapper function, it is being converted wrongly to a 64 bit unsigned integer. As a result, whenever a negative DC handle value is passed into PyOpenGL, it is being converted to become 2^64 + annoying_negative_dc_number instead!

    The solution: convert it back! Here is what I now do to reliably get a working gl interop context:

    platform = cl.get_platforms()[0]
    ctx_props = cl.context_properties
    gl_props = get_gl_sharing_context_properties()
    device_context = gl_props[-1][-1]
    if device_context >= 2 ** 32:
        device_context -= (2 ** 64)
    fixed_gl_props = [gl_props[0], (gl_props[-1][0], device_context)]
    ctx = cl.Context(properties=[(ctx_props.PLATFORM, platform)] + fixed_gl_props)