PyOpenCL:gl共享上下文创建失败(溢出错误)

时间:2016-07-10 16:39:40

标签: python opengl opencl pyopengl pyopencl

我想创建一个应用程序,它使用OpenCL来计算纹理中每个像素的颜色值,并使用OpenGL来显示该纹理。问题是,当我尝试使用GL共享属性创建上下文时,程序会冻结。使用函数get_gl_sharing_context_properties(),我得到一个列表[(8200, 65538), (8203, 18446744072971422270)]。列表中的最后一个数字太大,无法转换为64位int,我收到溢出错误。 我用来创建CL上下文的代码:

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)

代码永远不会达到print("Context creation done")。我使用QtPy4和QGLWidget来创建OpenGL上下文并显示纹理。

2 个答案:

答案 0 :(得分:0)

我自己遇到了类似的问题,这是我对它的解决方法。如果您根据get_gl_sharing_context_properties()模块下的PyOpenCL's source code on github准确查看tools正在执行的操作,您将找到以下特定于平台的代码:

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

现在,由于我在Windows上,我看了一下WGL代码(来自PyOpenGL)并发现WGL.wglGetCurrentDC()(当然get_gl_sharing_context_properties())返回错误处理值有时导致整数溢出。事实证明,DC(设备上下文)实际上假设 32位有符号整数。但是,在PyOpenGL包装函数中,它被错误地转换为 64位无符号整数。因此,每当负的DC句柄值传递到PyOpenGL时,它就会被转换为2^64 + annoying_negative_dc_number而不是!

解决方案:将其转换回来!以下是我现在要做的就是可靠地获得一个有效的gl互操作环境:

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)  

答案 1 :(得分:0)

pyopencl中存在一个错误导致上下文创建被错误处理。本质上,pyopencl为opencl属性获取元组列表,并在内部解析它们并将它们传递给CL上下文创建处理程序。元组要么作为指针或整数传递。当为某些属性传递指针时,假设将指针转换为整数值以传递给CL上下文创建处理程序,但它会错误地执行此操作。相反,它会抓取指针本身的地址。

有两种可能的修复方法。

从用户代码方面,您可以执行以下操作,手动传递已损坏属性(如GLX_DISPLAY_KHR)的整数值。或者你可以通过挑选从get_gl_sharing_context_properties()返回的元组并纠正它们来解决问题:

    glx_addr = ctypes.cast(OpenGL.GLX.glXGetCurrentDisplay(), ctypes.c_void_p).value #retrieve the glx ptr val as an int
    context = cl.Context(properties=
        [(cl.context_properties.GL_CONTEXT_KHR, OpenGL.platform.GetCurrentContext() )] +
        [(cl.context_properties.GLX_DISPLAY_KHR, glx_addr )] +
        [(cl.context_properties.PLATFORM, cl.get_platforms()[0])]
    )

或者在pyffncl的cffi_cl.py src代码中修复bug本身并重新编译:

def _parse_context_properties(properties):
    ...
    from ctypes import _Pointer, addressof
    from ctypes import cast # add this

    if isinstance(value, _Pointer):
        #val = addressof(value) # remove this
        val = cast(value, ctypes.c_void_p).value # add this
    else:
        val = int(value)
    ...

我稍微向开发人员传达了这个错误,所以希望很快就能解决。请参阅:https://lists.tiker.net/pipermail/pyopencl/2017-April/002285.html