我正在尝试将OpenCL与OpenGL互操作一起使用,以在GPU上计算路径跟踪算法,然后将GL纹理绘制为四边形。在英特尔 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::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 系统,信息非常稀缺,需要从各种来源拼凑在一起。