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

<blockquote>
  <p>I'd like to hide the latency by reading the data written by the previous frame dispatch.</p>
</blockquote>

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

<p>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.</p>

<p>In OpenGL, you only really have two tools: fence sync objects and a broad memory barrier that covers <em>all</em> 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 <em>all memory operations</em> that were submitted before the barrier was called.</p>

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

<p>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.</p>

<p>You might also try... cheating. Use a persistent/coherent mapped buffer, and use a fence sync object on the CPU <em>instead of</em> 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.</p>

<p>But that doesn't mean it <em>will</em>. So don't expect miracles.</p>

CC BY-SA 4.0
2019-07-21T03:33:02.410Z
2019-07-21T03:33:02.410Z
Nicol Bolas
<p>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 :</p>

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

<p>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.</p>

<opengl>
Async readback storage buffer
Aulaulz
# Async readback storage buffer

(Asked by: username_0 on 2019-07-21)

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.

**Tags:** opengl


---

## 1 answers

### Answer by username_1 on 2019-07-21. Score: 5 | Accepted answer

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.


---

