我正在尝试将 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。这修复了段错误。
我不确定这是你的问题,但无论如何我都会尝试一下。
您尚未以可移植的方式同步对 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
正如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 系统来说,信息相当匮乏,需要从各种来源拼凑起来。