2
$\begingroup$

Every frame I dispatch a compute shader which write data in a storage buffer. The cpu needs to readback this data and use it. I would expect this to work :

// Dispatch compute shader
glDispatchCompute(x, y, z);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
void* data = glMapNamedBuffer(buffer, GL_READ_ONLY);

But it would introduce a sync point which I'd like to avoid. I'd like to hide the latency by reading the data written by the previous frame dispatch. If I was using textures I would have used PBOs, but I have not found a way to do this for storage buffers.

$\endgroup$
5
$\begingroup$

First, that's the wrong memory barrier. The barrier is for how you intend to use the memory, not how it was written to.

I'd like to hide the latency by reading the data written by the previous frame dispatch.

This is a general flaw in OpenGL: targeted synchronization of such memory operations is not possible.

In Vulkan, you can be extremely specific about both execution and visibility operations. When you start the dispatch, you can stick an event after it, which you can wait on using a specific execution and memory barrier.

In OpenGL, you only really have two tools: fence sync objects and a broad memory barrier that covers all prior commands which have executed. And sync objects don't actually ensure visibility. Yes, you can set a fence right after your dispatch, and spin on the CPU (doing actual work between checks of the fence). But even after the fence has completed, you can't guarantee visibility without firing off the barrier. And that barrier will affect all memory operations that were submitted before the barrier was called.

So if you had two dispatch operations, and call glMemoryBarrier after both of them, the barrier will wait on all of them, even if you only care about waiting for the first one.

The best you can really do is just delay the memory barrier call for as long as possible. But it's going to synchronize against all submitted commands when you call it.

You might also try... cheating. Use a persistent/coherent mapped buffer, and use a fence sync object on the CPU instead of calling the memory barrier. This is undefined behavior by the OpenGL specification, but on real systems, the fence sync should ensure execution of the operation, and the coherently-mapped buffer ought to ensure visibility.

But that doesn't mean it will. So don't expect miracles.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.