From a6d84d93ce8c0adde41679a6c6852335e19ada17 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 18 Nov 2021 12:09:57 +0200 Subject: [PATCH] Refactor low-level state management The global context state is now held in Device. The changes mask in PipelineState was also moved to the backend class, because pipeline state is applied very differently in Vulkan. --- source/backends/opengl/buffer_backend.cpp | 7 +- source/backends/opengl/buffer_backend.h | 2 - source/backends/opengl/device_backend.cpp | 3 + source/backends/opengl/device_backend.h | 20 ++++ .../backends/opengl/pipelinestate_backend.cpp | 92 +++++++++---------- .../backends/opengl/pipelinestate_backend.h | 15 ++- source/backends/opengl/texture_backend.cpp | 7 +- source/backends/opengl/texture_backend.h | 2 - source/core/pipelinestate.h | 1 - 9 files changed, 83 insertions(+), 66 deletions(-) diff --git a/source/backends/opengl/buffer_backend.cpp b/source/backends/opengl/buffer_backend.cpp index e0f5525a..13944a86 100644 --- a/source/backends/opengl/buffer_backend.cpp +++ b/source/backends/opengl/buffer_backend.cpp @@ -6,14 +6,13 @@ #include #include "buffer.h" #include "buffer_backend.h" +#include "device.h" using namespace std; namespace Msp { namespace GL { -OpenGLBuffer *OpenGLBuffer::scratch_binding = 0; - OpenGLBuffer::OpenGLBuffer() { static Require _req(ARB_vertex_buffer_object); @@ -32,7 +31,7 @@ OpenGLBuffer::OpenGLBuffer(OpenGLBuffer &&other): OpenGLBuffer::~OpenGLBuffer() { - if(this==scratch_binding) + if(this==Device::get_current().get_state().scratch_buffer) unbind_scratch(); if(id) glDeleteBuffers(1, &id); @@ -115,6 +114,7 @@ void OpenGLBuffer::set_debug_name(const string &name) void OpenGLBuffer::bind_scratch() { + const OpenGLBuffer *&scratch_binding = Device::get_current().get_state().scratch_buffer; if(scratch_binding!=this) { glBindBuffer(GL_ARRAY_BUFFER, id); @@ -124,6 +124,7 @@ void OpenGLBuffer::bind_scratch() void OpenGLBuffer::unbind_scratch() { + const OpenGLBuffer *&scratch_binding = Device::get_current().get_state().scratch_buffer; if(scratch_binding) { glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/source/backends/opengl/buffer_backend.h b/source/backends/opengl/buffer_backend.h index 6595ec2a..3d76c01a 100644 --- a/source/backends/opengl/buffer_backend.h +++ b/source/backends/opengl/buffer_backend.h @@ -15,8 +15,6 @@ class OpenGLBuffer: public NonCopyable protected: unsigned id = 0; - static OpenGLBuffer *scratch_binding; - OpenGLBuffer(); OpenGLBuffer(OpenGLBuffer &&); ~OpenGLBuffer(); diff --git a/source/backends/opengl/device_backend.cpp b/source/backends/opengl/device_backend.cpp index 35c0ca5c..7819c98f 100644 --- a/source/backends/opengl/device_backend.cpp +++ b/source/backends/opengl/device_backend.cpp @@ -87,6 +87,9 @@ void OpenGLDevice::fill_info() feat.ext_texture_array = EXT_texture_array; feat.uniform_binding_range = lim.max_uniform_bindings; feat.texture_binding_range = lim.max_texture_bindings; + + state.bound_tex_targets.resize(lim.max_texture_bindings); + state.bound_uniform_blocks.resize(lim.max_uniform_bindings); } } // namespace GL diff --git a/source/backends/opengl/device_backend.h b/source/backends/opengl/device_backend.h index dfa16653..491f1b31 100644 --- a/source/backends/opengl/device_backend.h +++ b/source/backends/opengl/device_backend.h @@ -1,16 +1,33 @@ #ifndef MSP_GL_DEVICE_BACKEND_H_ #define MSP_GL_DEVICE_BACKEND_H_ +#include #include #include namespace Msp { namespace GL { +class OpenGLBuffer; +class OpenGLPipelineState; +class OpenGLTexture; + +struct OpenGLDeviceState +{ + const OpenGLPipelineState *last_pipeline = 0; + std::vector bound_tex_targets; + std::vector bound_uniform_blocks; + unsigned restart_index = 0; + unsigned n_clip_distances = 0; + const OpenGLBuffer *scratch_buffer = 0; + const OpenGLTexture *scratch_texture = 0; +}; + class OpenGLDevice: public NonCopyable { protected: Graphics::GLContext context; + OpenGLDeviceState state; OpenGLDevice(Graphics::Window &, const Graphics::GLOptions &); @@ -19,6 +36,9 @@ protected: void fill_info(); Graphics::GLContext &get_context() { return context; } + +public: + OpenGLDeviceState &get_state() { return state; } }; using DeviceBackend = OpenGLDevice; diff --git a/source/backends/opengl/pipelinestate_backend.cpp b/source/backends/opengl/pipelinestate_backend.cpp index 19ee0f58..9616b18b 100644 --- a/source/backends/opengl/pipelinestate_backend.cpp +++ b/source/backends/opengl/pipelinestate_backend.cpp @@ -26,37 +26,34 @@ using namespace std; namespace Msp { namespace GL { -const OpenGLPipelineState *OpenGLPipelineState::last_applied = 0; -vector OpenGLPipelineState::bound_tex_targets; -vector OpenGLPipelineState::bound_uniform_blocks; -unsigned OpenGLPipelineState::restart_index = 0; -unsigned OpenGLPipelineState::n_clip_distances = 0; - -OpenGLPipelineState::OpenGLPipelineState() -{ - if(bound_tex_targets.empty()) - bound_tex_targets.resize(Device::get_current().get_info().limits.max_texture_bindings); - if(bound_uniform_blocks.empty()) - bound_uniform_blocks.resize(Device::get_current().get_info().limits.max_uniform_bindings); -} - OpenGLPipelineState::~OpenGLPipelineState() { - if(this==last_applied) - last_applied = 0; + if(applied_to) + applied_to->get_state().last_pipeline = 0; } void OpenGLPipelineState::apply() const { - if(!last_applied) - OpenGLTexture::unbind_scratch(); + const PipelineState &self = *static_cast(this); + Device &device = Device::get_current(); + unsigned mask = changes; - apply(this==last_applied ? static_cast(this)->changes : ~0U); -} + if(applied_to && applied_to!=&device) + { + applied_to->get_state().last_pipeline = 0; + mask = ~0U; + } -void OpenGLPipelineState::apply(unsigned mask) const -{ - const PipelineState &self = *static_cast(this); + OpenGLDeviceState &dev_state = device.get_state(); + if(!dev_state.last_pipeline) + OpenGLTexture::unbind_scratch(); + + if(this!=dev_state.last_pipeline) + { + if(dev_state.last_pipeline) + dev_state.last_pipeline->applied_to = 0; + mask = ~0U; + } if(mask&PipelineState::FRAMEBUFFER) { @@ -93,16 +90,16 @@ void OpenGLPipelineState::apply(unsigned mask) const glUseProgram(self.shprog ? self.shprog->id : 0); unsigned ncd = (self.shprog ? self.shprog->get_n_clip_distances() : 0); - if(ncd!=n_clip_distances) + if(ncd!=dev_state.n_clip_distances) { - for(unsigned i=0; (i=0) { glBindBufferRange(GL_UNIFORM_BUFFER, u.binding, u.block->get_buffer()->id, u.block->get_offset(), u.block->get_data_size()); - bound_uniform_blocks[u.binding] = 1; + dev_state.bound_uniform_blocks[u.binding] = 1; } else if(u.binding==ReflectData::DEFAULT_BLOCK && self.shprog) { @@ -142,12 +139,12 @@ void OpenGLPipelineState::apply(unsigned mask) const else { glActiveTexture(GL_TEXTURE0+t.binding); - if(bound_tex_targets[t.binding] && static_cast(t.texture->target)!=bound_tex_targets[t.binding]) - glBindTexture(bound_tex_targets[t.binding], 0); + if(dev_state.bound_tex_targets[t.binding] && static_cast(t.texture->target)!=dev_state.bound_tex_targets[t.binding]) + glBindTexture(dev_state.bound_tex_targets[t.binding], 0); glBindTexture(t.texture->target, t.texture->id); } - bound_tex_targets[t.binding] = t.texture->target; + dev_state.bound_tex_targets[t.binding] = t.texture->target; glBindSampler(t.binding, t.sampler->id); t.sampler->refresh(); @@ -167,12 +164,12 @@ void OpenGLPipelineState::apply(unsigned mask) const vertex_setup->refresh(); unsigned ri = (vertex_setup->get_index_type()==UNSIGNED_INT ? 0xFFFFFFFF : 0xFFFF); - if(ri!=restart_index) + if(ri!=dev_state.restart_index) { - if(!restart_index) + if(!dev_state.restart_index) glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(ri); - restart_index = ri; + dev_state.restart_index = ri; } } } @@ -236,39 +233,41 @@ void OpenGLPipelineState::apply(unsigned mask) const } } - last_applied = this; - self.changes &= ~mask; + applied_to = &device; + dev_state.last_pipeline = this; + changes = 0; } void OpenGLPipelineState::clear() { - if(last_applied) + OpenGLDeviceState &dev_state = Device::get_current().get_state(); + if(dev_state.last_pipeline) { glUseProgram(0); glBindVertexArray(0); - for(unsigned i=0; iapplied_to = 0; + dev_state.last_pipeline = 0; } } diff --git a/source/backends/opengl/pipelinestate_backend.h b/source/backends/opengl/pipelinestate_backend.h index 566b819c..a8f2d306 100644 --- a/source/backends/opengl/pipelinestate_backend.h +++ b/source/backends/opengl/pipelinestate_backend.h @@ -7,25 +7,22 @@ namespace Msp { namespace GL { +class Device; + class OpenGLPipelineState: public NonCopyable { friend class OpenGLCommands; protected: - static const OpenGLPipelineState *last_applied; - static std::vector bound_tex_targets; - static std::vector bound_uniform_blocks; - static unsigned restart_index; - static unsigned n_clip_distances; + mutable Device *applied_to = 0; + mutable unsigned changes = 0; - OpenGLPipelineState(); + OpenGLPipelineState() = default; OpenGLPipelineState(OpenGLPipelineState &&) { } ~OpenGLPipelineState(); void apply() const; -private: - void apply(unsigned) const; -protected: + static void clear(); }; diff --git a/source/backends/opengl/texture_backend.cpp b/source/backends/opengl/texture_backend.cpp index ebfeb025..818defdd 100644 --- a/source/backends/opengl/texture_backend.cpp +++ b/source/backends/opengl/texture_backend.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "device.h" #include "gl.h" #include "error.h" #include "texture.h" @@ -12,8 +13,6 @@ using namespace std; namespace Msp { namespace GL { -OpenGLTexture *OpenGLTexture::scratch_binding = 0; - OpenGLTexture::OpenGLTexture(unsigned t): target(t) { @@ -35,7 +34,7 @@ OpenGLTexture::OpenGLTexture(OpenGLTexture &&other): OpenGLTexture::~OpenGLTexture() { - if(this==scratch_binding) + if(this==Device::get_current().get_state().scratch_texture) unbind_scratch(); if(id) glDeleteTextures(1, &id); @@ -119,6 +118,7 @@ void OpenGLTexture::set_debug_name(const string &name) void OpenGLTexture::bind_scratch() { + const OpenGLTexture *&scratch_binding = Device::get_current().get_state().scratch_texture; if(!scratch_binding) glActiveTexture(GL_TEXTURE0); if(scratch_binding!=this) @@ -132,6 +132,7 @@ void OpenGLTexture::bind_scratch() void OpenGLTexture::unbind_scratch() { + const OpenGLTexture *&scratch_binding = Device::get_current().get_state().scratch_texture; if(scratch_binding) { glBindTexture(scratch_binding->target, 0); diff --git a/source/backends/opengl/texture_backend.h b/source/backends/opengl/texture_backend.h index ecb3056f..623bd813 100644 --- a/source/backends/opengl/texture_backend.h +++ b/source/backends/opengl/texture_backend.h @@ -16,8 +16,6 @@ protected: unsigned target; std::string debug_name; - static OpenGLTexture *scratch_binding; - OpenGLTexture(unsigned); OpenGLTexture(OpenGLTexture &&); ~OpenGLTexture(); diff --git a/source/core/pipelinestate.h b/source/core/pipelinestate.h index 0973bfb5..5e593309 100644 --- a/source/core/pipelinestate.h +++ b/source/core/pipelinestate.h @@ -79,7 +79,6 @@ private: const DepthTest *depth_test = 0; const StencilTest *stencil_test = 0; const Blend *blend = 0; - mutable unsigned changes = 0; template void set(T &, T, unsigned); -- 2.43.0