From 8366f8951984aa436938b1bb18a57067ff2260c1 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 28 Sep 2021 12:29:47 +0300 Subject: [PATCH] Store default-block uniform data in a memory block This is more cache-friendly than using individually allocated polymorphic objects. It also makes it easier to use push constants in Vulkan. --- source/core/pipelinestate.cpp | 23 +++---- source/core/pipelinestate.h | 6 +- source/core/program.cpp | 67 +++++++++++++++++++- source/core/program.h | 12 ++++ source/core/uniform.cpp | 113 ---------------------------------- source/core/uniform.h | 19 ------ source/core/uniformblock.cpp | 59 ++++-------------- source/core/uniformblock.h | 39 ++---------- source/render/programdata.cpp | 24 +++----- source/render/programdata.h | 2 +- 10 files changed, 113 insertions(+), 251 deletions(-) delete mode 100644 source/core/uniform.cpp diff --git a/source/core/pipelinestate.cpp b/source/core/pipelinestate.cpp index 1c65cda4..871336bb 100644 --- a/source/core/pipelinestate.cpp +++ b/source/core/pipelinestate.cpp @@ -123,17 +123,7 @@ void PipelineState::set_texture(unsigned binding, const Texture *tex, const Samp } } -void PipelineState::set_uniforms(const DefaultUniformBlock *block) -{ - set_uniform_block_(-1, block); -} - -void PipelineState::set_uniform_block(unsigned binding, const BufferBackedUniformBlock *block) -{ - set_uniform_block_(binding, block); -} - -void PipelineState::set_uniform_block_(int binding, const UniformBlock *block) +void PipelineState::set_uniform_block(int binding, const UniformBlock *block) { auto i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding); if(i==uniform_blocks.end() || i->binding!=binding) @@ -283,12 +273,15 @@ void PipelineState::apply(unsigned mask) const { if(u.binding>=0) { - const BufferBackedUniformBlock *block = static_cast(u.block); - glBindBufferRange(GL_UNIFORM_BUFFER, u.binding, block->get_buffer()->id, block->get_offset(), block->get_data_size()); + 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; } - else - static_cast(u.block)->apply(); + else if(shprog) + { + const char *data = static_cast(u.block->get_data_pointer()); + for(const Program::UniformCall &call: shprog->uniform_calls) + call.func(call.location, call.size, data+call.location*16); + } } u.changed = false; diff --git a/source/core/pipelinestate.h b/source/core/pipelinestate.h index b9fac143..9573f9fe 100644 --- a/source/core/pipelinestate.h +++ b/source/core/pipelinestate.h @@ -96,11 +96,7 @@ public: void set_face_cull(CullMode); void set_enabled_clip_planes(unsigned); void set_texture(unsigned, const Texture *, const Sampler *); - void set_uniforms(const DefaultUniformBlock *); - void set_uniform_block(unsigned, const BufferBackedUniformBlock *); -private: - void set_uniform_block_(int, const UniformBlock *); -public: + void set_uniform_block(int, const UniformBlock *); void set_depth_test(const DepthTest *); void set_stencil_test(const StencilTest *); void set_blend(const Blend *); diff --git a/source/core/program.cpp b/source/core/program.cpp index 919fceeb..35304554 100644 --- a/source/core/program.cpp +++ b/source/core/program.cpp @@ -23,6 +23,22 @@ using namespace std; +namespace { + +template +void uniform_wrapper(unsigned index, unsigned count, const void *data) +{ + func(index, count, static_cast(data)); +} + +template +void uniform_matrix_wrapper(unsigned index, unsigned count, const void *data) +{ + func(index, count, false, static_cast(data)); +} + +} + namespace Msp { namespace GL { @@ -349,10 +365,57 @@ void Program::query_uniforms() u.matrix_stride = get_type_size(get_matrix_column_type(u.type)); default_block.uniforms.push_back(&u); - if(is_image(u.type) && u.location>=0) - glGetUniformiv(id, u.location, &u.binding); + if(u.location>=0) + { + UniformCall::FuncPtr func = 0; + if(u.type==FLOAT) + func = &uniform_wrapper; + else if(u.type==FLOAT_VEC2) + func = &uniform_wrapper; + else if(u.type==FLOAT_VEC3) + func = &uniform_wrapper; + else if(u.type==FLOAT_VEC4) + func = &uniform_wrapper; + else if(u.type==INT) + func = &uniform_wrapper; + else if(u.type==INT_VEC2) + func = &uniform_wrapper; + else if(u.type==INT_VEC3) + func = &uniform_wrapper; + else if(u.type==INT_VEC4) + func = &uniform_wrapper; + else if(u.type==FLOAT_MAT2) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT3) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT4) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT2x3) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT3x2) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT2x4) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT4x2) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT3x4) + func = &uniform_matrix_wrapper; + else if(u.type==FLOAT_MAT4x3) + func = &uniform_matrix_wrapper; + else if(is_image(u.type)) + glGetUniformiv(id, u.location, &u.binding); + + if(func) + uniform_calls.push_back(UniformCall(u.location, u.array_size, func)); + } } + default_block.sort_uniforms(); + if(!default_block.uniforms.empty()) + { + const ReflectData::UniformInfo &uni = *default_block.uniforms.back(); + default_block.data_size = uni.location*16+uni.array_size*get_type_size(uni.type); + } default_block.update_layout_hash(); reflect_data.update_layout_hash(); } diff --git a/source/core/program.h b/source/core/program.h index 6301edbe..b384defe 100644 --- a/source/core/program.h +++ b/source/core/program.h @@ -63,10 +63,22 @@ private: std::map spec_values; }; + struct UniformCall + { + using FuncPtr = void (*)(unsigned, unsigned, const void *); + + unsigned location; + unsigned size; + FuncPtr func; + + UniformCall(unsigned l, unsigned s, FuncPtr f): location(l), size(s), func(f) { } + }; + unsigned id; unsigned stage_ids[MAX_STAGES]; bool linked; ReflectData reflect_data; + std::vector uniform_calls; std::string debug_name; public: diff --git a/source/core/uniform.cpp b/source/core/uniform.cpp deleted file mode 100644 index c18fc360..00000000 --- a/source/core/uniform.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include -#include "uniform.h" - -namespace Msp { -namespace GL { - -template<> -void UniformScalar::apply(int index, unsigned size, const int *value) -{ - glUniform1iv(index, size, value); -} - -template<> -void UniformScalar::apply(int index, unsigned size, const float *value) -{ - glUniform1fv(index, size, value); -} - - -template<> -void UniformVector::apply(int index, unsigned size, const int *value) -{ - glUniform2iv(index, size, value); -} - -template<> -void UniformVector::apply(int index, unsigned size, const float *value) -{ - glUniform2fv(index, size, value); -} - -template<> -void UniformVector::apply(int index, unsigned size, const int *value) -{ - glUniform3iv(index, size, value); -} - -template<> -void UniformVector::apply(int index, unsigned size, const float *value) -{ - glUniform3fv(index, size, value); -} - -template<> -void UniformVector::apply(int index, unsigned size, const int *value) -{ - glUniform4iv(index, size, value); -} - -template<> -void UniformVector::apply(int index, unsigned size, const float *value) -{ - glUniform4fv(index, size, value); -} - - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix2fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix3x2fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix4x2fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix2x3fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix3fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix4x3fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix2x4fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix3x4fv(index, size, false, value); -} - -template<> -void UniformMatrix::apply(int index, unsigned size, const float *value) -{ - glUniformMatrix4fv(index, size, false, value); -} - -} // namespace GL -} // namespace Msp diff --git a/source/core/uniform.h b/source/core/uniform.h index e12f6521..8cdcdfda 100644 --- a/source/core/uniform.h +++ b/source/core/uniform.h @@ -17,7 +17,6 @@ private: public: virtual ~Uniform() { } - virtual void apply(int) const = 0; virtual void store(const ReflectData::UniformInfo &, void *) const = 0; virtual Uniform *clone() const = 0; }; @@ -40,11 +39,6 @@ public: Type get() const { return value; } - virtual void apply(int index) const - { apply(index, 1, &value); } - - static void apply(int, unsigned, const T *); - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const { store(info, buffer, &value); } @@ -77,11 +71,6 @@ public: BaseType get(unsigned i) const { return value[i]; } - virtual void apply(int index) const - { apply(index, 1, value); } - - static void apply(int index, unsigned size, const T *value); - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const { store(info, buffer, value); } @@ -116,11 +105,6 @@ public: void set(const T *vp) { std::copy(vp, vp+rows*cols, value); } - virtual void apply(int index) const - { apply(index, 1, value); } - - static void apply(int index, unsigned size, const T *value); - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const { store(info, buffer, value); } @@ -174,9 +158,6 @@ public: void set(const BaseType *vp) { std::copy(vp, vp+elemsize*size_, values); } - virtual void apply(int index) const - { T::apply(index, size_, values); } - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const { for(unsigned i=0; i #include #include #include "buffer.h" @@ -10,64 +9,32 @@ #include "uniformblock.h" #include "vector.h" -using namespace std; - namespace Msp { namespace GL { -DefaultUniformBlock::DefaultUniformBlock() +UniformBlock::UniformBlock(const ReflectData::UniformBlockInfo &info): + data(info.data_size) { static Require _req(ARB_shader_objects); + if(info.bind_point>=0) + static Require _req2(ARB_uniform_buffer_object); } -void DefaultUniformBlock::attach(const ReflectData::UniformInfo &info, const Uniform &uni) -{ - if(info.block->bind_point>=0) - throw invalid_argument("DefaultUniformBlock::attach"); - - attach(info.location, uni); -} - -void DefaultUniformBlock::attach(int index, const Uniform &uni) -{ - if(index<0) - return; - - if(static_cast(index)>=uniforms.size()) - uniforms.resize(index+1, 0); - uniforms[index] = &uni; -} - -void DefaultUniformBlock::apply() const -{ - for(unsigned i=0; iapply(i); -} - - -BufferBackedUniformBlock::BufferBackedUniformBlock(unsigned s): - size(s), - data(size) -{ - static Require _req(ARB_shader_objects); - static Require _req2(ARB_uniform_buffer_object); - - if(!size) - throw invalid_argument("BufferBackedUniformBlock::BufferBackedUniformBlock"); -} - -unsigned BufferBackedUniformBlock::get_alignment() const +unsigned UniformBlock::get_alignment() const { return Limits::get_global().uniform_buffer_alignment; } -void BufferBackedUniformBlock::attach(const ReflectData::UniformInfo &info, const Uniform &uni) +void UniformBlock::store(const ReflectData::UniformInfo &info, const Uniform &uni) { if(info.block->bind_point<0) - throw invalid_argument("BufferBackedUniformBlock::attach"); - - uni.store(info, &data[info.offset]); + { + if(info.location<0) + return; + uni.store(info, &data[info.location*16]); + } + else + uni.store(info, &data[info.offset]); dirty = true; } diff --git a/source/core/uniformblock.h b/source/core/uniformblock.h index 08eaa9b8..9f2a0849 100644 --- a/source/core/uniformblock.h +++ b/source/core/uniformblock.h @@ -20,50 +20,21 @@ struct Color; Stores uniforms with a specific layout. Both named and default uniform blocks are supported. */ -class UniformBlock: public NonCopyable -{ -protected: - UniformBlock() { } -public: - virtual ~UniformBlock() { } - - virtual void attach(const ReflectData::UniformInfo &, const Uniform &) = 0; -}; - -/** Stores uniforms for the default uniform block. Uniforms are associated -with locations, as returned by Program::get_uniform_location. */ -class DefaultUniformBlock: public UniformBlock -{ -private: - std::vector uniforms; - -public: - DefaultUniformBlock(); - - virtual void attach(const ReflectData::UniformInfo &, const Uniform &); - void attach(int, const Uniform &); - void apply() const; -}; - -/** Stores uniforms for a buffer-backed uniform block. Uniform values are -stored in a memory block which can be uploaded into a buffer and bound for use -by a Program. */ -class BufferBackedUniformBlock: public UniformBlock, public Bufferable +class UniformBlock: public NonCopyable, public Bufferable { private: - unsigned size; std::vector data; public: - BufferBackedUniformBlock(unsigned); + UniformBlock(const ReflectData::UniformBlockInfo &); - virtual unsigned get_data_size() const { return size; } -private: + virtual unsigned get_data_size() const { return data.size(); } virtual const void *get_data_pointer() const { return &data[0]; } +private: virtual unsigned get_alignment() const; public: - void attach(const ReflectData::UniformInfo &, const Uniform &); + void store(const ReflectData::UniformInfo &, const Uniform &); }; } // namespace GL diff --git a/source/render/programdata.cpp b/source/render/programdata.cpp index 65934d38..377b5ace 100644 --- a/source/render/programdata.cpp +++ b/source/render/programdata.cpp @@ -564,6 +564,7 @@ void ProgramData::update_block_uniform_indices(SharedBlock &block, const Reflect if(block.used && !block.block) { + block.block = new UniformBlock(info); if(info.bind_point>=0) { if(!buffer) @@ -576,13 +577,9 @@ void ProgramData::update_block_uniform_indices(SharedBlock &block, const Reflect #endif } - BufferBackedUniformBlock *bb_block = new BufferBackedUniformBlock(info.data_size); - block.block = bb_block; - bb_block->use_buffer(buffer, last_buffer_block); - last_buffer_block = bb_block; + block.block->use_buffer(buffer, last_buffer_block); + last_buffer_block = block.block; } - else - block.block = new DefaultUniformBlock; } } @@ -594,13 +591,13 @@ void ProgramData::update_block(SharedBlock &block, const ReflectData::UniformBlo if(is_image(info.uniforms[i]->type)) ; // Temporarily ignore deprecated use of sampler uniforms in ProgramData else if(indices[i]!=0xFF) - block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value); + block.block->store(*info.uniforms[i], *uniforms[indices[i]].value); } } vector::const_iterator ProgramData::prepare_program(const Program &prog) const { - BufferBackedUniformBlock *old_last_block = last_buffer_block; + UniformBlock *old_last_block = last_buffer_block; auto prog_begin = get_program(prog); Mask force_dirty = (dirty==ALL_ONES ? ALL_ONES : 0U); @@ -688,14 +685,9 @@ void ProgramData::apply(const Program &prog, PipelineState &state) const for(auto i=prog_begin+1; (i!=programs.end() && i->prog_hash==prog_hash); ++i) if(i->block) { - if(i->bind_point<0) - state.set_uniforms(static_cast(i->block)); - else - { - const BufferBackedUniformBlock *block = static_cast(i->block); - block->refresh(); - state.set_uniform_block(i->bind_point, block); - } + state.set_uniform_block(i->bind_point, i->block); + if(i->bind_point>=0) + i->block->refresh(); } } diff --git a/source/render/programdata.h b/source/render/programdata.h index 380f352a..05e1bedc 100644 --- a/source/render/programdata.h +++ b/source/render/programdata.h @@ -157,7 +157,7 @@ private: unsigned generation; mutable std::vector blocks; mutable std::vector programs; - mutable BufferBackedUniformBlock *last_buffer_block; + mutable UniformBlock *last_buffer_block; mutable Buffer *buffer; mutable Mask dirty; std::string debug_name; -- 2.45.2