我有以下管道:
现在,问题在于在阶段4和5之间同步数据.以下是我尝试过的同步解决方案.
glFlush - 并不真正起作用,因为它不能保证所有命令执行的完整性.
glFinish - 这个有效.但不推荐使用它,因为它最终确定了提交给驱动程序的所有命令.
ARB_sync 这里有人说它不推荐使用,因为它会严重影响性能.
glMemoryBarrier这个很有意思.但它根本行不通.
以下是代码示例:
glMemoryBarrier(GL_ALL_BARRIER_BITS);
Run Code Online (Sandbox Code Playgroud)
并尝试过:
glTextureBarrierNV()
Run Code Online (Sandbox Code Playgroud)
代码执行如下:
//rendered into the fbo...
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindImageTexture(imageUnit1, fboTex, 0, GL_FALSE, 0, GL_READ_ONLY,GL_RGBA8);
glBindImageTexture(imageUnit2, imageTex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8));
glDispatchCompute(16, 16, 1);
glFinish(); // <-- must sync here,otherwise cuda buffer doesn't receive all the data
//cuda maps the image to CUDA buffer here..
Run Code Online (Sandbox Code Playgroud)
此外,我尝试在启动计算之前从上下文中取消绑定FBO和取消绑定纹理,我甚至尝试使用glMemoryBarrier它们之间的集合启动一个计算,然后从第一次计算启动到CUDA获取目标图像.仍然没有同步.(嗯,这是有道理的,因为两个计算也彼此不同步)
在计算着色器阶段之后.它没有同步!只有当我更换glFinish或完全停止管道的任何其他操作时.比如glMapBuffer(),例如.
那么我应该使用glFinish(),还是我在这里遗漏了什么?为什么glMemoryBarrier()在CUDA接管控制之前不同步计算着色器工作?
UPDATE
我想稍微重构一下这个问题,因为原来的问题已经很久了.尽管如此,即使使用最新的CUDA和视频编解码器SDK(NVENC),问题仍然存在.所以,我不关心为什么glMemoryBarrier不同步.我想知道的是:
如果可以将OpenGL计算着色器执行完成与CUDA对该共享资源的使用同步,而不会拖延整个渲染管道,这在我的案例中是OpenGL图像.
如果答案是'是',那怎么样?
我知道这是一个老问题,但如果有任何可怜的灵魂偶然发现这个......
首先,原因glMemoryBarrier是行不通的:它需要OpenGL驱动程序在管道中插入一个屏障。CUDA 根本不关心 OpenGL 管道。
其次,除了 之外的唯一其他方法是与 结合glFinish使用:glFenceSyncglClientWaitSync
....
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindImageTexture(imageUnit1, fboTex, 0, GL_FALSE, 0, GL_READ_ONLY,GL_RGBA8);
glBindImageTexture(imageUnit2, imageTex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8));
glDispatchCompute(16, 16, 1);
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
... other work you might want to do that does not impact the buffer...
GLenum res = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, timeoutInNs);
if(res == GL_TIMEOUT_EXPIRED || res == GL_WAIT_FAILED) {
...handle timeouts and failures
}
cudaGraphicsMapResources(1, &gfxResource, stream);
...
Run Code Online (Sandbox Code Playgroud)
这将导致 CPU 阻塞,直到 GPU 完成栅栏之前的所有命令。这包括内存传输和计算操作。
不幸的是,没有办法告诉 CUDA 等待 OpenGL 内存屏障/栅栏。如果您确实需要额外的异步性,则必须切换到 DirectX 12,为此 CUDA 支持导入栅栏/信号量并等待以及通过cuImportExternalSemaphore、cuWaitExternalSemaphoresAsync和从 CUDA 流向它们发出信号cuSignalExternalSemaphoresAsync。