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
This commit is contained in:
rdb 2025-01-20 20:57:51 +01:00
parent 271fa9d9c0
commit db692edfa9
6 changed files with 61 additions and 4 deletions

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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<BufferContext *> &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;

View File

@ -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
}

View File

@ -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;
};