内存屏障无法通过CUDA在计算阶段和数据访问之间同步

Mic*_* IV 7 opengl cuda nvenc

我有以下管道:

  1. 渲染到自定义FBO的纹理附件.
  2. 将纹理附件绑定为图像.
  3. 运行计算着色器,使用imageLoad/Store从上面的图像中进行采样.
  4. 将结果写入SSBO或图像.
  5. 将SSBO(或图像)映射为CUDA CUgraphicsResource,并使用CUDA处理来自该缓冲区的数据.

现在,问题在于在阶段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不同步.我想知道的是:

  1. 如果可以将OpenGL计算着色器执行完成与CUDA对该共享资源的使用同步,而不会拖延整个渲染管道,这在我的案例中是OpenGL图像.

  2. 如果答案是'是',那怎么样?

IGa*_*ldI 2

我知道这是一个老问题,但如果有任何可怜的灵魂偶然发现这个......

首先,原因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 支持导入栅栏/信号量并等待以及通过cuImportExternalSemaphorecuWaitExternalSemaphoresAsync和从 CUDA 流向它们发出信号cuSignalExternalSemaphoresAsync