OpenCL/OpenGL 互操作性纹理段错误

问题描述 投票:0回答:2

我正在尝试将 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);

运行内核函数

//-----------------------------------------------------------------------------
//  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。这修复了段错误。

c++ linux opengl segmentation-fault opencl
2个回答
2
投票

我不确定这是你的问题,但无论如何我都会尝试一下。

您尚未以可移植的方式同步对 glObjects 的访问。从 OpenCL 1.1 开始:

在调用 clEnqueueAcquireGLObjects 之前,应用程序必须 确保任何访问对象的未决 GL 操作 mem_objects 中指定的已完成。这或许可以实现 通过发出并等待 glFinish 命令完成来实现可移植 在所有具有对这些对象的待处理引用的 GL 上下文上。 实现可以提供更有效的同步方法;为了 在某些平台上调用 glFlush 的示例可能就足够了,或者 同步可能是隐含在线程中的,也可能是 小贩 - 特定扩展,允许在 GL 命令流中放置栅栏并等待 CL 命令中该栅栏的完成 队列。请注意,除了 glFinish 之外,没有其他同步方法 此时可在 OpenGL 实现之间移植。

基本上,glFinish 是可移植行为所必需的。

在已引用的下面段落中,有更多可能感兴趣的信息:

同样,调用 clEnqueueReleaseGLObjects 后,应用程序 负责确保任何待处理的 OpenCL 操作 对 mem_objects 中指定的对象的访问已完成 在执行引用这些的后续 GL 命令之前 对象。这可以通过调用来便携地完成 clWaitForEvents 与 clEnqueueRelease GL 返回的事件对象 对象,或通过调用 clFinish。如上所述,一些实现 可能会提供更有效的方法。

这里是引用的文档的链接:https://www.khronos.org/registry/cl/specs/opencl-1.1.pdf#nameddest=section-9.8.6


0
投票

正如OP在他们的编辑中已经解释的那样,问题是

CL_GLX_DISPLAY_KHR
属性的值无效,该值被传递到
cl::Context
的构造函数中:

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 系统来说,信息相当匮乏,需要从各种来源拼凑起来。

© www.soinside.com 2019 - 2024. All rights reserved.