PyOpenCL:gl 共享上下文创建失败(溢出错误)
PyOpenCL: gl sharing context creation failed (overflow error)
我想创建一个应用程序,使用 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 上下文并显示纹理。
好的 运行 我自己也遇到过类似的问题,这是我的解决方法。如果你根据tools
模块下的PyOpenCL's source code on github具体看一下get_gl_sharing_context_properties()
是干什么的,你会发现下面的平台相关代码:
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)
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])]
)
或者在 cffi_cl.py pyopencl 的 src 代码中修复错误并重新编译:
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
我想创建一个应用程序,使用 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 上下文并显示纹理。
好的 运行 我自己也遇到过类似的问题,这是我的解决方法。如果你根据tools
模块下的PyOpenCL's source code on github具体看一下get_gl_sharing_context_properties()
是干什么的,你会发现下面的平台相关代码:
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)
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])]
)
或者在 cffi_cl.py pyopencl 的 src 代码中修复错误并重新编译:
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