OpenCL/OpenGL互操作纹理段错误

3
我正在尝试使用OpenCL与OpenGL互操作,在GPU上计算路径跟踪算法,然后绘制GL纹理到四边形。在Intel CPU上按预期工作,但当我尝试在GTX 970上运行时,在解锁GL纹理时出现段错误。不知道这是原因还是运行内核的原因。我会让代码自己说明。顺便说一句,我正在使用OpenCL C ++包装器。
GL纹理创建
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glBindTexture(GL_TEXTURE_2D, 0); //Unbind texture

CL纹理分配

m_textureCL = cl::ImageGL(m_context,
        CL_MEM_READ_WRITE, 
        GL_TEXTURE_2D,
        0,
        texture,
        &errCode);

RunKernel function

//-----------------------------------------------------------------------------
//  Lock texture
//-----------------------------------------------------------------------------
std::vector<cl::Memory> glObjects; //Create vector of GL objects to lock
glObjects.push_back(m_textureCL); //Add created CL texture buffer
glFlush(); //Flush GL queue

errCode = m_cmdQueue.enqueueAcquireGLObjects(&glObjects, NULL, NULL);
if(errCode != CL_SUCCESS) {
    std::cerr << "Error locking texture" << errCode << std::endl;
    return errCode;
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//  Run queue
//-----------------------------------------------------------------------------
errCode = m_cmdQueue.enqueueNDRangeKernel(
        m_kernel,
        cl::NullRange,
        cl::NDRange(height*width),
        cl::NullRange,
        NULL,
        NULL);
if(errCode != CL_SUCCESS) {
    std::cerr << "Error running queue: " << errCode << std::endl;
    return errCode;
}
//---------------------------------------


//-----------------------------------------------------------------------------
//  Unlock
//-----------------------------------------------------------------------------
errCode = m_cmdQueue.enqueueReleaseGLObjects(&glObjects, NULL, NULL);
if(errCode != CL_SUCCESS) {
    std::cerr << "Error unlocking texture: " << errCode << std::endl;
    return errCode;
} <<------ Here's where segfault occurs, can't get past this point

内核函数定义。

__kernel void RadianceGPU (
    __write_only image2d_t texture,
    other_stuff...)

在内核中写入纹理

write_imagef(
        texture,
        (int2)(x, height-y-1),
        (float4)(
            clamp(framebuffer[id].x, 0.0f, 1.0f),
            clamp(framebuffer[id].y, 0.0f, 1.0f),
            clamp(framebuffer[id].z, 0.0f, 1.0f),
            1.0f) * 1.0f);

有趣的是,尽管纹理为UNSIGNED_BYTE,write_imagef()仍然有效。

编辑: 我最终弄清楚了问题的原因。在创建CL属性时设置了错误的显示器。我只是从GLFW中粘贴了窗口,这会在Nvidia驱动程序上引起问题。您需要使用glxGetCurrentDisplay或glfwGetX11Display。这样可以修复段错误。


你使用的是哪个版本的OpenCL? - Andreas
非常感谢!我和你一样,也遇到了完全相同的问题——将错误的显示参数传递给了CL上下文构造函数! - K. Raivio
2个回答

2
我不确定这是否是您的问题,但我会试着解决它。
您尚未以可移植的方式同步访问glObjects。来自OpenCL 1.1:
在调用clEnqueueAcquireGLObjects之前,应用程序必须确保访问mem_objects中指定的对象的任何挂起的GL操作已完成。可以通过在所有具有对这些对象的待处理引用的GL上下文上发出并等待完成glFinish命令来实现此目标,从而在可移植性上进行处理。实现可能提供更有效的同步方法;例如,在某些平台上,调用glFlush可能足够,或者同步可以在线程内部隐含,或者可能存在特定于供应商的扩展,使得能够在GL命令流中放置一个围栏,并在CL命令队列中等待该围栏完成。请注意,目前除glFinish之外的任何同步方法都无法在OpenGL实现之间进行可移植。
基本上,需要使用glFinish以实现可移植行为。
在上面引用的段落下面,还有更多可能感兴趣的信息。
同样地,在调用clEnqueueReleaseGLObjects之后,应用程序需要确保访问mem_objects中指定的对象的任何待处理的OpenCL操作在执行后续引用这些对象的GL命令之前已经完成。可以通过使用由clEnqueueReleaseGLObjects返回的事件对象调用clWaitForEvents或调用clFinish来实现可移植性。与上述情况类似,一些实现可能提供更有效的方法。
这里是引用文档的链接:https://www.khronos.org/registry/cl/specs/opencl-1.1.pdf#nameddest=section-9.8.6

谢谢你的回答,我一有机会就试试看。还有一件困扰我的事情是当我分配CL纹理时无法访问GL纹理。这种情况发生在我使用Nvidia opencl 1.2和OpenGL 4.5时,但是使用AMD的opencl 1.2在Intel CPU/GPU和OpenGL 3.3上却没有任何问题。 - Nixx
@Nixx 将其作为另一个问题发布,包括所有的代码。 - Andreas

0

正如OP在他们的编辑中已经解释的那样,问题是传入cl::Context构造函数的CL_GLX_DISPLAY_KHR属性的无效值:

cl_context_properties cps[] = {
    CL_GL_CONTEXT_KHR, (cl_context_properties) gl_context,
    CL_GLX_DISPLAY_KHR, (cl_context_properties) glXGetCurrentDisplay(), <-- make sure that you aren't passing SDL_Window*, for example
    CL_CONTEXT_PLATFORM, (cl_context_properties) (platforms[0])(),
    0
};

在此之后,属性与构造函数一样被使用。
cl::Context context{CL_DEVICE_TYPE_GPU, cps, nullptr, nullptr, &result};

这个问题的根本原因在于,虽然互联网上有大量关于如何创建OpenCL-OpenGL互操作上下文的资源,但几乎所有资源都只涵盖了在Windows系统上如何实现。对于X11系统来说,相关信息相当稀缺,需要从多个来源进行整合。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接