From db692edfa9fc6f0bb808891d772d637dfbc89c1e Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 20 Jan 2025 20:57:51 +0100 Subject: [PATCH] glgsg: Issue memory barriers for SSBOs At the moment, it assumes that all SSBO accesses are writes, once shaderpipeline lands we can sort out readonly accesses based on the qualifiers in the shader --- panda/src/gles2gsg/gles2gsg.h | 2 ++ panda/src/glstuff/glBufferContext_src.h | 4 +++ .../glstuff/glGraphicsStateGuardian_src.cxx | 20 +++++++++-- .../src/glstuff/glGraphicsStateGuardian_src.h | 3 +- panda/src/glstuff/glShaderContext_src.cxx | 34 ++++++++++++++++++- panda/src/glstuff/glShaderContext_src.h | 2 ++ 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/panda/src/gles2gsg/gles2gsg.h b/panda/src/gles2gsg/gles2gsg.h index 967f341703..c43beded29 100644 --- a/panda/src/gles2gsg/gles2gsg.h +++ b/panda/src/gles2gsg/gles2gsg.h @@ -147,6 +147,7 @@ typedef char GLchar; #define GL_FRAMEBUFFER_BARRIER_BIT 0x400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x800 #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x1000 +#define GL_SHADER_STORAGE_BARRIER_BIT 0x2000 #define GL_HALF_FLOAT 0x140B #define GL_COLOR 0x1800 #define GL_DEPTH 0x1801 @@ -181,6 +182,7 @@ typedef char GLchar; #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 diff --git a/panda/src/glstuff/glBufferContext_src.h b/panda/src/glstuff/glBufferContext_src.h index b67a9d214e..dcc31c09ab 100644 --- a/panda/src/glstuff/glBufferContext_src.h +++ b/panda/src/glstuff/glBufferContext_src.h @@ -32,6 +32,10 @@ public: // This is the GL "name" of the data object. GLuint _index; + // This is set to glgsg->_shader_storage_barrier_counter if a write was + // performed, in which case a barrier is issued before the next use. + int _shader_storage_barrier_counter = -1; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 21383cc825..c8aa716366 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -6274,6 +6274,11 @@ issue_memory_barrier(GLbitfield barriers) { GLCAT.spam(false) << " framebuffer"; } + if (barriers & GL_SHADER_STORAGE_BARRIER_BIT) { + ++_shader_storage_barrier_counter; + GLCAT.spam(false) << " shader_storage"; + } + GLCAT.spam(false) << "\n"; report_my_gl_errors(); @@ -7367,6 +7372,9 @@ prepare_shader_buffer(ShaderBuffer *data) { _glBufferData(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), get_usage(data->get_usage_hint())); } + // Barrier not needed. + gbc->_shader_storage_barrier_counter = _shader_storage_barrier_counter - 1; + gbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); report_my_gl_errors(); @@ -7379,13 +7387,15 @@ prepare_shader_buffer(ShaderBuffer *data) { /** * Binds the given shader buffer to the given binding slot. */ -void CLP(GraphicsStateGuardian):: +CLP(BufferContext) *CLP(GraphicsStateGuardian):: apply_shader_buffer(GLuint base, ShaderBuffer *buffer) { + CLP(BufferContext) *gbc = nullptr; + GLuint index = 0; if (buffer != nullptr) { BufferContext *bc = buffer->prepare_now(get_prepared_objects(), this); if (bc != nullptr) { - CLP(BufferContext) *gbc = DCAST(CLP(BufferContext), bc); + gbc = DCAST(CLP(BufferContext), bc); index = gbc->_index; gbc->set_active(true); } @@ -7407,6 +7417,8 @@ apply_shader_buffer(GLuint base, ShaderBuffer *buffer) { report_my_gl_errors(); } + + return gbc; } /** @@ -7636,6 +7648,10 @@ dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) { PStatGPUTimer timer(this, _compute_dispatch_pcollector); nassertv(_supports_compute_shaders); nassertv(_current_shader_context != nullptr); + CLP(ShaderContext) *gsc; + DCAST_INTO_V(gsc, _current_shader_context); + gsc->issue_memory_barriers(); + _glDispatchCompute(num_groups_x, num_groups_y, num_groups_z); maybe_gl_finish(); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 1abbc1d2a4..759ddcff68 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -391,7 +391,7 @@ public: #ifndef OPENGLES virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data); - void apply_shader_buffer(GLuint base, ShaderBuffer *buffer); + CLP(BufferContext) *apply_shader_buffer(GLuint base, ShaderBuffer *buffer); virtual void release_shader_buffer(BufferContext *bc); virtual void release_shader_buffers(const pvector &contexts); #endif @@ -1167,6 +1167,7 @@ public: TextureSet _textures_needing_image_access_barrier; TextureSet _textures_needing_update_barrier; TextureSet _textures_needing_framebuffer_barrier; + int _shader_storage_barrier_counter = 0; #endif // RenderState::SlotMask _inv_state_mask; diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index f411bb9fcc..dde88cc554 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -2672,6 +2672,10 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { update_slider_table(table); } + // This ought to be moved elsewhere, but it's convenient to do this here for + // now since it's called before every Geom is drawn. + issue_memory_barriers(); + _glgsg->report_my_gl_errors(); return true; @@ -3039,7 +3043,35 @@ update_shader_buffer_bindings(ShaderContext *prev) { " (expected at least " << block._min_size << " bytes)\n"; } #endif - _glgsg->apply_shader_buffer(block._binding_index, buffer); + block._gbc = _glgsg->apply_shader_buffer(block._binding_index, buffer); + } +#endif +} + +/** + * Issues memory barriers for shader buffers, should be called before a draw. + */ +void CLP(ShaderContext):: +issue_memory_barriers() { +#ifndef OPENGLES + bool barrier_needed = false; + for (StorageBlock &block : _storage_blocks) { + if (block._gbc != nullptr && + block._gbc->_shader_storage_barrier_counter == _glgsg->_shader_storage_barrier_counter) { + barrier_needed = true; + break; + } + } + + if (barrier_needed) { + _glgsg->issue_memory_barrier(GL_SHADER_STORAGE_BARRIER_BIT); + } + + // We assume that all SSBOs will be written to, for now. + for (StorageBlock &block : _storage_blocks) { + if (block._gbc != nullptr) { + block._gbc->_shader_storage_barrier_counter = _glgsg->_shader_storage_barrier_counter; + } } #endif } diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index 5da63ed21a..f196c1b6ba 100644 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -58,6 +58,7 @@ public: void disable_shader_texture_bindings() override; void update_shader_texture_bindings(ShaderContext *prev) override; void update_shader_buffer_bindings(ShaderContext *prev) override; + void issue_memory_barriers(); bool uses_standard_vertex_arrays(void) override { return _uses_standard_vertex_arrays; @@ -96,6 +97,7 @@ private: #ifndef OPENGLES struct StorageBlock { CPT(InternalName) _name; + CLP(BufferContext) *_gbc = nullptr; GLuint _binding_index; GLuint _min_size; };