C++ AMD Tahiti上的OpenCL/OpenGL隐式同步
在AMD Tahiti(AMD Radeon HD 7900系列)设备上,OpenCL和OpenGL的“隐式同步”有问题。该设备具有cl/gl扩展、cl_khr_gl_共享和cl_khr_gl_事件 当我运行这个程序时,它只是一个简单的vbo更新内核,并用简单的着色器将它画成一条白线,它会像疯了一样打嗝,每次更新都会暂停2-4帧。我可以确认我用来更新和绘制缓冲区的不是cl内核或gl着色器,因为如果我在获取和释放cl更新的gl对象之前和之后放置glFinish和commandQueue.finish(),一切都会正常工作 所以,我想我需要“启用”事件扩展C++ AMD Tahiti上的OpenCL/OpenGL隐式同步,c++,opengl,opencl,amd,C++,Opengl,Opencl,Amd,在AMD Tahiti(AMD Radeon HD 7900系列)设备上,OpenCL和OpenGL的“隐式同步”有问题。该设备具有cl/gl扩展、cl_khr_gl_共享和cl_khr_gl_事件 当我运行这个程序时,它只是一个简单的vbo更新内核,并用简单的着色器将它画成一条白线,它会像疯了一样打嗝,每次更新都会暂停2-4帧。我可以确认我用来更新和绘制缓冲区的不是cl内核或gl着色器,因为如果我在获取和释放cl更新的gl对象之前和之后放置glFinish和commandQueue.finis
#pragma OPENCL EXTENSION cl_khr_gl_event : enable
…在cl程序中,但这会引发错误。我假设这个扩展不是面向客户端的扩展,应该按照“预期”工作,这就是为什么我不能启用它
我注意到的第三个行为……如果我取出glFinish()和commandQueue.finish(),并在CodeXL调试中运行它,隐式同步就会工作。如中所示,在不更改代码库的情况下(如使用finish强制同步),CodeXL允许隐式同步。因此,隐式同步显然是有效的,但我无法通过VisualStudio定期运行应用程序并强制同步来实现它
很明显我遗漏了什么,但我真的看不出来。如果您有任何想法或解释,我将不胜感激,因为我希望保持隐式同步。我猜您没有使用GLsync-cl_事件同步器(
GL_ARB_cl_事件
和cl_khr_GL_事件
扩展),这就是为什么添加cl/glFinish和CodeXL的开销会有所帮助的原因
我猜您的代码如下所示:
A1. clEnqueueNDRangeKernel
A2. clEnqueueReleaseObjects
[here is where you inserted clFinish]
B1. glDraw*
B2. wgl/glXSwapBuffers
[here is where you inserted glFinish]
C1. clEnqueueAcquireObjects
[repeat from A1]
相反,你应该:
ClenqueureReleaseObjects
创建一个(输出)事件以传递给glCreateSyncFromCLeventARB
,然后使用glWaitSync
(而不是glClientWaitSync
——在这种情况下,它与clFinish
)相同clEnqueueAcquireObjects
获取(输入)事件,该事件将使用clCreateFromGLsync
创建,从glFenceSync
获取同步对象A1. `clEnqueueNDRangeKernel`
[Option 1.1:]
A2. `clEnqueueReleaseObjects`( ..., 0, NULL, &eve1)
[Option 1.2:]
A2. `clEnqueueReleaseObjects`( ..., 0, NULL, NULL)
A2'. `clEnqueueMarker`(&eve1)
A3. sync1 = glCreateSyncFromCLeventARB(eve1)
* clReleaseEvent(eve1)
A4. glWaitSync(sync1)
* glDeleteSync(sync1)
B1. glDraw*
B2. wgl/glXSwapBuffers
B3. sync2 = glFenceSync
B4. eve2 = clCreateFromGLSync(sync2)
* glDeleteSync(sync2)
[Option 2.1:]
C1. clEnqueueAcquireObjects(, ..., 1, &eve2, NULL)
* clReleaseEvent(eve2)
[Option 2.2:]
B5. clEnqueueWaitForEvents(1, &eve2)
* clReleaseEvent(eve2)
C1. clEnqueueAcquireObjects(, ..., 0, NULL, NULL)
[Repeat from A1]
(如果在将控制权移交给另一个API之前,您事先不确切知道最后一次排队是什么,则选项1.2/2.2更好)
作为补充说明,我假设您没有为OpenCL使用无序队列(在这种情况下,确实不需要这样做)-如果您使用了,当然,您还必须同步
clEnqueueAcquire
->clEnqueueNDRange
->clEnqueueRelease
我理解使用glSync和clEvent显式同步行为。然而,从OpenCL扩展(cl_khr_gl_事件)来看,它说“……该扩展修改了clEnqueueAcquireGLObjects和clEnqueueReleaseGLObjects的行为,以隐式地保证与绑定在同一线程中的OpenGL上下文同步……”这就是为什么我相信CodeXL可以按预期工作的原因。某些开关被翻转,但不会自动翻转。我想我想知道的是,既然支持隐式同步,为什么我必须创建显式同步?或者这是一个AMD错误?正确;如果存在这些扩展,则根据您引用的规范的部分,不需要clFinish/glFinish调用。然而,只有当你在同一个线程上工作时。是这样吗?我注意到的第三个行为……如果我取出glFinish()和commandQueue.finish(),并在CodeXL调试中运行它,隐式同步就会工作。你肯定吗?由于这是一个调试器,我倾向于相信它在锁步中运行,而不是像驱动程序通常那样排队3-4帧的命令(AMD称之为驱动程序中的翻转队列大小)。我相信每次在CodeXL中交换缓冲区时,glFinish(…)
命令都会有效地插入到命令流中(如果它与gDEBugger类似的话)。这肯定可以解释同步从何而来,但仍然不能解释为什么设备不允许从cl_khr_gl_事件扩展进行隐式同步。