aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Weissflog <floooh@gmail.com>2025-04-12 15:04:07 +0200
committerAndre Weissflog <floooh@gmail.com>2025-04-12 15:04:07 +0200
commit2a32a7fa64e1cf140c74372d7ada00e56a9db3be (patch)
tree9b7f5bb8f1fb8d92cf24175d0a3050202b7ac66c
parentf0e24dce1b92413da70c454efbced27fd9989d71 (diff)
sokol_gfx.h gl: update memory barrier code for vertex- and index-buffer bindings
-rw-r--r--sokol_gfx.h71
1 files changed, 53 insertions, 18 deletions
diff --git a/sokol_gfx.h b/sokol_gfx.h
index 9ca922f4..6836c574 100644
--- a/sokol_gfx.h
+++ b/sokol_gfx.h
@@ -5742,13 +5742,20 @@ typedef _sg_dummy_attachments_t _sg_attachments_t;
#elif defined(_SOKOL_ANY_GL)
+typedef enum {
+ _SG_GL_GPUDIRTY_VERTEXBUFFER = (1<<0),
+ _SG_GL_GPUDIRTY_INDEXBUFFER = (1<<1),
+ _SG_GL_GPUDIRTY_STORAGEBUFFER = (1<<2),
+ _SG_GL_GPUDIRTY_BUFFER_ALL = _SG_GL_GPUDIRTY_VERTEXBUFFER | _SG_GL_GPUDIRTY_INDEXBUFFER | _SG_GL_GPUDIRTY_STORAGEBUFFER,
+} _sg_gl_gpudirty_t;
+
typedef struct _sg_buffer_s {
_sg_slot_t slot;
_sg_buffer_common_t cmn;
struct {
GLuint buf[SG_NUM_INFLIGHT_FRAMES];
bool injected; // if true, external buffers were injected with sg_buffer_desc.gl_buffers
- bool gpu_dirty; // true if modified by GPU shader but memory barrier hasn't been issued yet
+ uint8_t gpu_dirty_flags; // combination of _sg_gl_gpudirty_t flags
} gl;
} _sg_gl_buffer_t;
typedef _sg_gl_buffer_t _sg_buffer_t;
@@ -9986,26 +9993,53 @@ _SOKOL_PRIVATE void _sg_gl_handle_memory_barriers(const _sg_shader_t* shd, const
if (!_sg.features.compute) {
return;
}
- // NOTE: currently only storage buffers can be GPU-written, and storage
- // buffers cannot be bound as vertex- or index-buffers.
- bool needs_barrier = false;
+ GLbitfield gl_barrier_bits = 0;
+
+ // if vertex-, index- or storage-buffer bindings have been written
+ // by a compute shader before, a barrier must be issued
+ for (size_t i = 0; i < SG_MAX_VERTEXBUFFER_BINDSLOTS; i++) {
+ _sg_buffer_t* buf = bnd->vbs[i];
+ if (!buf) {
+ continue;
+ }
+ if (buf->gl.gpu_dirty_flags & _SG_GL_GPUDIRTY_VERTEXBUFFER) {
+ gl_barrier_bits |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
+ buf->gl.gpu_dirty_flags &= ~_SG_GL_GPUDIRTY_VERTEXBUFFER;
+ }
+ }
+ if (bnd->ib) {
+ _sg_buffer_t* buf = bnd->ib;
+ if (buf->gl.gpu_dirty_flags & _SG_GL_GPUDIRTY_INDEXBUFFER) {
+ gl_barrier_bits |= GL_ELEMENT_ARRAY_BARRIER_BIT;
+ buf->gl.gpu_dirty_flags &= ~_SG_GL_GPUDIRTY_INDEXBUFFER;
+ }
+ }
for (size_t i = 0; i < SG_MAX_STORAGEBUFFER_BINDSLOTS; i++) {
- if (shd->cmn.storage_buffers[i].stage == SG_SHADERSTAGE_NONE) {
+ _sg_buffer_t* buf = bnd->sbufs[i];
+ if (!buf) {
continue;
}
+ SOKOL_ASSERT(shd->cmn.storage_buffers[i].stage != SG_SHADERSTAGE_NONE);
+ if (buf->gl.gpu_dirty_flags & _SG_GL_GPUDIRTY_STORAGEBUFFER) {
+ gl_barrier_bits |= GL_SHADER_STORAGE_BARRIER_BIT;
+ buf->gl.gpu_dirty_flags &= ~_SG_GL_GPUDIRTY_STORAGEBUFFER;
+ }
+ }
+
+ // mark storage buffers as dirty which will be written by compute shaders
+ // (don't merge this into the above loop, this would mess up the dirty
+ // dirty flags if the same buffer is bound multiple times)
+ for (size_t i = 0; i < SG_MAX_STORAGEBUFFER_BINDSLOTS; i++) {
_sg_buffer_t* buf = bnd->sbufs[i];
- // if this buffer has pending GPU changes, issue a memory barrier
- if (buf->gl.gpu_dirty) {
- buf->gl.gpu_dirty = false;
- needs_barrier = true;
+ if (!buf) {
+ continue;
}
- // if this binding is going to be written by the GPU set the buffer to 'gpu_dirty'
if (!shd->cmn.storage_buffers[i].readonly) {
- buf->gl.gpu_dirty = true;
+ buf->gl.gpu_dirty_flags = _SG_GL_GPUDIRTY_BUFFER_ALL;
}
}
- if (needs_barrier) {
- glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
+ if (0 != gl_barrier_bits) {
+ glMemoryBarrier(gl_barrier_bits);
_sg_stats_add(gl.num_memory_barriers, 1);
}
}
@@ -10018,11 +10052,6 @@ _SOKOL_PRIVATE bool _sg_gl_apply_bindings(_sg_bindings_t* bnd) {
_SG_GL_CHECK_ERROR();
const _sg_shader_t* shd = bnd->pip->shader;
- // take care of storage buffer memory barriers
- #if defined(_SOKOL_GL_HAS_COMPUTE)
- _sg_gl_handle_memory_barriers(shd, bnd);
- #endif
-
// bind combined image-samplers
_SG_GL_CHECK_ERROR();
for (size_t img_smp_index = 0; img_smp_index < SG_MAX_IMAGE_SAMPLER_PAIRS; img_smp_index++) {
@@ -10122,6 +10151,12 @@ _SOKOL_PRIVATE bool _sg_gl_apply_bindings(_sg_bindings_t* bnd) {
}
}
_SG_GL_CHECK_ERROR();
+
+ // take care of storage buffer memory barriers (this needs to happen after the bindings are set)
+ #if defined(_SOKOL_GL_HAS_COMPUTE)
+ _sg_gl_handle_memory_barriers(shd, bnd);
+ #endif
+
return true;
}