From: Mikko Rasa Date: Tue, 28 Sep 2021 22:49:20 +0000 (+0300) Subject: Eliminate the polymorphic Uniform class hierarchy X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=729a477b47e97aea41f3f0b5db551f02bf70d1ee;p=libs%2Fgl.git Eliminate the polymorphic Uniform class hierarchy Dynamically allocating a separate object for every uniform is not very cache friendly. ProgramData now stores uniform values in a single memory block instead. --- diff --git a/source/core/datatype.h b/source/core/datatype.h index a9115613..7188cb5a 100644 --- a/source/core/datatype.h +++ b/source/core/datatype.h @@ -141,6 +141,4 @@ void require_type(DataType); } // namespace GL } // namespace Msp -#include "datatype_backend.h" - #endif diff --git a/source/core/uniform.h b/source/core/uniform.h deleted file mode 100644 index 8cdcdfda..00000000 --- a/source/core/uniform.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef MSP_GL_UNIFORM_H_ -#define MSP_GL_UNIFORM_H_ - -#include -#include "reflectdata.h" - -namespace Msp { -namespace GL { - -class Uniform -{ -protected: - Uniform() { } -private: - Uniform(const Uniform &); - Uniform &operator=(const Uniform &); -public: - virtual ~Uniform() { } - - virtual void store(const ReflectData::UniformInfo &, void *) const = 0; - virtual Uniform *clone() const = 0; -}; - - -template -class UniformScalar: public Uniform -{ -public: - typedef T BaseType; - typedef T Type; - -private: - Type value; - -public: - UniformScalar(Type v): value(v) { } - - void set(Type v) { value = v; } - - Type get() const { return value; } - - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const - { store(info, buffer, &value); } - - static void store(const ReflectData::UniformInfo &, void *buffer, const T *value) - { *reinterpret_cast(buffer) = *value; } - - virtual UniformScalar *clone() const - { return new UniformScalar(value); } -}; - -typedef UniformScalar Uniform1i; -typedef UniformScalar Uniform1f; - - -template -class UniformVector: public Uniform -{ -public: - typedef T BaseType; - typedef T Type[vecsize]; - -private: - Type value; - -public: - UniformVector(const T *vp) { set(vp); } - - void set(const T *vp) - { std::copy(vp, vp+vecsize, value); } - - BaseType get(unsigned i) const { return value[i]; } - - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const - { store(info, buffer, value); } - - static void store(const ReflectData::UniformInfo &, void *buffer, const T *value) - { std::copy(value, value+vecsize, reinterpret_cast(buffer)); } - - virtual UniformVector *clone() const - { return new UniformVector(value); } -}; - -typedef UniformVector Uniform2i; -typedef UniformVector Uniform2f; -typedef UniformVector Uniform3i; -typedef UniformVector Uniform3f; -typedef UniformVector Uniform4i; -typedef UniformVector Uniform4f; - - -template -class UniformMatrix: public Uniform -{ -public: - typedef T BaseType; - typedef T Type[rows*cols]; - -private: - Type value; - -public: - UniformMatrix(const T *vp) { set(vp); } - - void set(const T *vp) - { std::copy(vp, vp+rows*cols, value); } - - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const - { store(info, buffer, value); } - - static void store(const ReflectData::UniformInfo &info, void *buffer, const T *value) - { - for(unsigned i=0; i::store(info, reinterpret_cast(buffer)+i*info.matrix_stride, value+i*rows); - } - - virtual UniformMatrix *clone() const - { return new UniformMatrix(value); } -}; - -// The naming of these types follows the OpenGL convention of columns x rows -typedef UniformMatrix UniformMatrix2x2f; -typedef UniformMatrix UniformMatrix3x2f; -typedef UniformMatrix UniformMatrix4x2f; -typedef UniformMatrix UniformMatrix2x3f; -typedef UniformMatrix UniformMatrix3x3f; -typedef UniformMatrix UniformMatrix4x3f; -typedef UniformMatrix UniformMatrix2x4f; -typedef UniformMatrix UniformMatrix3x4f; -typedef UniformMatrix UniformMatrix4x4f; - - -template -class UniformArray: public Uniform -{ -private: - typedef typename T::BaseType BaseType; - enum { elemsize = sizeof(typename T::Type)/sizeof(typename T::BaseType) }; - - unsigned size_; - BaseType *values; - -public: - UniformArray(unsigned n, const BaseType *vp): - size_(n), - values(new BaseType[elemsize*size_]) - { - set(vp); - } - - ~UniformArray() - { - delete[] values; - } - - unsigned size() const { return size_; } - - void set(const BaseType *vp) - { std::copy(vp, vp+elemsize*size_, values); } - - virtual void store(const ReflectData::UniformInfo &info, void *buffer) const - { - for(unsigned i=0; i(buffer)+i*info.array_stride, values+i*elemsize); - } - - virtual UniformArray *clone() const - { return new UniformArray(size_, values); } -}; - -} // namespace GL -} // namespace Msp - -#endif diff --git a/source/core/uniformblock.cpp b/source/core/uniformblock.cpp index f713bd2a..8f85b87f 100644 --- a/source/core/uniformblock.cpp +++ b/source/core/uniformblock.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "buffer.h" @@ -5,10 +6,11 @@ #include "deviceinfo.h" #include "error.h" #include "matrix.h" -#include "uniform.h" #include "uniformblock.h" #include "vector.h" +using namespace std; + namespace Msp { namespace GL { @@ -25,16 +27,64 @@ unsigned UniformBlock::get_alignment() const return Limits::get_global().uniform_buffer_alignment; } -void UniformBlock::store(const ReflectData::UniformInfo &info, const Uniform &uni) +void UniformBlock::store(const ReflectData::UniformInfo &info, unsigned array_size, const void *value) { + array_size = min(array_size, max(info.array_size, 1U)); + + char *store_ptr; + bool packed; if(info.block->bind_point<0) { if(info.location<0) return; - uni.store(info, &data[info.location*16]); + + store_ptr = data.data()+info.location*16; + packed = true; + } + else + { + store_ptr = data.data()+info.offset; + if(array_size!=1 && info.array_stride!=get_type_size(info.type)) + packed = false; + else if(is_matrix(info.type)) + packed = (info.matrix_stride==get_type_size(get_matrix_column_type(info.type))); + else + packed = true; + } + + const char *value_ptr = static_cast(value); + if(packed) + { + const char *data_end = value_ptr+array_size*get_type_size(info.type); + copy(value_ptr, data_end, store_ptr); + } + else if(is_matrix(info.type)) + { + unsigned col_size = get_type_size(get_matrix_column_type(info.type)); + unsigned cols = get_type_size(info.type)/col_size; + for(unsigned i=0; iuniform(tag, shdata.get_uniform(t)); + new_shdata->copy_uniform(shdata, tag); replaced = true; } diff --git a/source/render/programdata.cpp b/source/render/programdata.cpp index 377b5ace..31fc8fa2 100644 --- a/source/render/programdata.cpp +++ b/source/render/programdata.cpp @@ -10,7 +10,6 @@ #include "pipelinestate.h" #include "program.h" #include "programdata.h" -#include "uniform.h" #include "uniformblock.h" #include "vector.h" @@ -31,14 +30,12 @@ ProgramData::ProgramData(const Program *p): ProgramData::ProgramData(const ProgramData &other): tied_program(other.tied_program), uniforms(other.uniforms), + uniform_data(other.uniform_data), generation(other.generation), last_buffer_block(0), buffer(0), dirty(0) -{ - for(TaggedUniform &u: uniforms) - u.value = u.value->clone(); -} +{ } ProgramData::ProgramData(const ProgramData &other, const Program *p): tied_program(p), @@ -53,8 +50,7 @@ ProgramData::ProgramData(const ProgramData &other, const Program *p): } uniforms = other.uniforms; - for(TaggedUniform &u: uniforms) - u.value = u.value->clone(); + uniform_data = other.uniform_data; } ProgramData &ProgramData::operator=(const ProgramData &other) @@ -62,8 +58,7 @@ ProgramData &ProgramData::operator=(const ProgramData &other) tied_program = other.tied_program; uniforms = other.uniforms; - for(TaggedUniform &u: uniforms) - u.value = u.value->clone(); + uniform_data = other.uniform_data; for(SharedBlock &b: blocks) delete b.block; @@ -79,8 +74,6 @@ ProgramData &ProgramData::operator=(const ProgramData &other) ProgramData::~ProgramData() { - for(TaggedUniform &u: uniforms) - delete u.value; for(SharedBlock &b: blocks) { if(b.indices.type_flag==0xFE) @@ -90,65 +83,47 @@ ProgramData::~ProgramData() delete buffer; } -void ProgramData::uniform(Tag tag, Uniform *uni) +void ProgramData::uniform(Tag tag, DataType type, unsigned array_size, const void *value) { - try + if(!validate_tag(tag)) + return; + + auto i = lower_bound_member(uniforms, tag, &TaggedUniform::tag); + if(i==uniforms.end() || i->tag!=tag) { - if(!validate_tag(tag)) - { - delete uni; - return; - } + if(uniforms.size()>=MASK_BITS) + throw too_many_uniforms(tag.str()); + + TaggedUniform tu; + tu.tag = tag; + tu.type = type; + tu.array_size = array_size; + tu.data_offset = uniform_data.size(); + tu.data_size = array_size*get_type_size(type); + i = uniforms.insert(i, tu); + uniform_data.resize(tu.data_offset+tu.data_size); + + mark_dirty(ALL_ONES); } - catch(...) + else if(type!=i->type) + throw invalid_operation("ProgramData::uniform"); + else if(array_size>i->array_size) { - delete uni; - throw; + unsigned add_bytes = (array_size-i->array_size)*get_type_size(type); + uniform_data.insert(uniform_data.begin()+i->data_offset+i->data_size, add_bytes, 0); + for(TaggedUniform &u: uniforms) + if(u.data_offset>i->data_offset) + u.data_offset += add_bytes; + i->array_size = array_size; + i->data_size = array_size*get_type_size(type); } - int i = find_uniform_index(tag); - if(i<0) - return add_uniform(tag, uni); - - uniforms[i].replace_value(uni); - mark_dirty(1< -void ProgramData::uniform(Tag tag, V value) -{ - if(!validate_tag(tag)) - return; + const char *val_begin = static_cast(value); + const char *val_end = val_begin+array_size*get_type_size(type); + char *store_begin = uniform_data.data()+i->data_offset; + copy(val_begin, val_end, store_begin); - int i = find_uniform_index(tag); - if(i<0) - return add_uniform(tag, new T(value)); - - if(T *uni = dynamic_cast(uniforms[i].value)) - uni->set(value); - else - uniforms[i].replace_value(new T(value)); - - mark_dirty(1< -void ProgramData::uniform_array(Tag tag, unsigned n, V value) -{ - if(!validate_tag(tag)) - return; - - int i = find_uniform_index(tag); - if(i<0) - return add_uniform(tag, new UniformArray(n, value)); - - UniformArray *uni = dynamic_cast *>(uniforms[i].value); - if(uni && n==uni->size()) - uni->set(value); - else - uniforms[i].replace_value(new UniformArray(n, value)); - - mark_dirty(1<=MASK_BITS) - { - delete uni; - throw too_many_uniforms(tag.str()); - } - - auto j = lower_bound_member(uniforms, tag, &TaggedUniform::tag); - - TaggedUniform nu; - nu.tag = tag; - nu.value = uni; - uniforms.insert(j, nu); - - mark_dirty(ALL_ONES); -} - void ProgramData::mark_dirty(Mask bits) { if(!dirty) @@ -199,19 +156,14 @@ void ProgramData::mark_dirty(Mask bits) dirty |= bits; } -void ProgramData::uniform(Tag tag, const Uniform &u) -{ - uniform(tag, u.clone()); -} - void ProgramData::uniform(Tag tag, int v) { - uniform(tag, v); + uniform(tag, INT, 1, &v); } void ProgramData::uniform(Tag tag, float v) { - uniform(tag, v); + uniform(tag, FLOAT, 1, &v); } void ProgramData::uniform(Tag tag, int v0, int v1) @@ -228,12 +180,12 @@ void ProgramData::uniform(Tag tag, float v0, float v1) void ProgramData::uniform2(Tag tag, const int *v) { - uniform(tag, v); + uniform(tag, INT_VEC2, 1, v); } void ProgramData::uniform2(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_VEC2, 1, v); } void ProgramData::uniform(Tag tag, int v0, int v1, int v2) @@ -250,12 +202,12 @@ void ProgramData::uniform(Tag tag, float v0, float v1, float v2) void ProgramData::uniform3(Tag tag, const int *v) { - uniform(tag, v); + uniform(tag, INT_VEC3, 1, v); } void ProgramData::uniform3(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_VEC3, 1, v); } void ProgramData::uniform(Tag tag, int v0, int v1, int v2, int v3) @@ -277,52 +229,52 @@ void ProgramData::uniform(Tag tag, const Color &c) void ProgramData::uniform4(Tag tag, const int *v) { - uniform(tag, v); + uniform(tag, INT_VEC4, 1, v); } void ProgramData::uniform4(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_VEC4, 1, v); } void ProgramData::uniform_matrix2(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT2, 1, v); } void ProgramData::uniform_matrix3x2(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT3x2, 1, v); } void ProgramData::uniform_matrix4x2(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT4x2, 1, v); } void ProgramData::uniform_matrix2x3(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT2x3, 1, v); } void ProgramData::uniform_matrix3(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT3, 1, v); } void ProgramData::uniform_matrix4x3(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT4x3, 1, v); } void ProgramData::uniform_matrix2x4(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT2x4, 1, v); } void ProgramData::uniform_matrix3x4(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT3x4, 1, v); } void ProgramData::uniform(Tag tag, const Matrix &m) @@ -332,102 +284,102 @@ void ProgramData::uniform(Tag tag, const Matrix &m) void ProgramData::uniform_matrix4(Tag tag, const float *v) { - uniform(tag, v); + uniform(tag, FLOAT_MAT4, 1, v); } void ProgramData::uniform_array(Tag tag, unsigned n, const int *v) { - uniform_array(tag, n, v); + uniform(tag, INT, n, v); } void ProgramData::uniform_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT, n, v); } void ProgramData::uniform1_array(Tag tag, unsigned n, const int *v) { - uniform_array(tag, n, v); + uniform(tag, INT, n, v); } void ProgramData::uniform1_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT, n, v); } void ProgramData::uniform2_array(Tag tag, unsigned n, const int *v) { - uniform_array(tag, n, v); + uniform(tag, INT_VEC2, n, v); } void ProgramData::uniform2_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_VEC2, n, v); } void ProgramData::uniform3_array(Tag tag, unsigned n, const int *v) { - uniform_array(tag, n, v); + uniform(tag, INT_VEC3, n, v); } void ProgramData::uniform3_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_VEC3, n, v); } void ProgramData::uniform4_array(Tag tag, unsigned n, const int *v) { - uniform_array(tag, n, v); + uniform(tag, INT_VEC4, n, v); } void ProgramData::uniform4_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_VEC4, n, v); } void ProgramData::uniform_matrix2_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT2, n, v); } void ProgramData::uniform_matrix3x2_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT3x2, n, v); } void ProgramData::uniform_matrix4x2_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT4x2, n, v); } void ProgramData::uniform_matrix2x3_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT2x3, n, v); } void ProgramData::uniform_matrix3_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT3, n, v); } void ProgramData::uniform_matrix4x3_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT4x3, n, v); } void ProgramData::uniform_matrix2x4_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT2x4, n, v); } void ProgramData::uniform_matrix3x4_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT3x4, n, v); } void ProgramData::uniform_matrix4_array(Tag tag, unsigned n, const float *v) { - uniform_array(tag, n, v); + uniform(tag, FLOAT_MAT4, n, v); } void ProgramData::remove_uniform(Tag tag) @@ -436,7 +388,10 @@ void ProgramData::remove_uniform(Tag tag) if(i==uniforms.end() || i->tag!=tag) return; - delete i->value; + uniform_data.erase(uniform_data.begin()+i->data_offset, uniform_data.begin()+i->data_offset+i->data_size); + for(TaggedUniform &u: uniforms) + if(u.data_offset>i->data_offset) + u.data_offset -= i->data_size; uniforms.erase(i); mark_dirty(ALL_ONES); @@ -451,18 +406,13 @@ vector ProgramData::get_uniform_tags() const return tags; } -const Uniform &ProgramData::get_uniform(Tag tag) const +void ProgramData::copy_uniform(const ProgramData &source, Tag tag) { - int i = find_uniform_index(tag); + int i = source.find_uniform_index(tag); if(i<0) throw key_error(tag); - return *uniforms[i].value; -} - -const Uniform *ProgramData::find_uniform(Tag tag) const -{ - int i = find_uniform_index(tag); - return (i>=0 ? uniforms[i].value : 0); + const TaggedUniform &tu = source.uniforms[i]; + uniform(tag, tu.type, tu.array_size, source.uniform_data.data()+tu.data_offset); } int ProgramData::find_uniform_index(Tag tag) const @@ -591,7 +541,10 @@ 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->store(*info.uniforms[i], *uniforms[indices[i]].value); + { + const TaggedUniform &tu = uniforms[indices[i]]; + block.block->store(*info.uniforms[i], tu.array_size, uniform_data.data()+tu.data_offset); + } } } @@ -704,18 +657,12 @@ void ProgramData::set_debug_name(const string &name) ProgramData::TaggedUniform::TaggedUniform(): - value(0) + type(VOID), + array_size(0), + data_offset(0), + data_size(0) { } -void ProgramData::TaggedUniform::replace_value(Uniform *v) -{ - /* UniformBlock does not copy the uniforms, so existing default blocks - will be left with stale pointers. This is not a problem as long as no - one stores pointers to the blocks and expects them to stay valid. */ - delete value; - value = v; -} - ProgramData::SharedBlock::SharedBlock(ReflectData::LayoutHash h): block_hash(h), diff --git a/source/render/programdata.h b/source/render/programdata.h index 05e1bedc..474ca4e8 100644 --- a/source/render/programdata.h +++ b/source/render/programdata.h @@ -8,7 +8,6 @@ #include "matrix.h" #include "reflectdata.h" #include "tag.h" -#include "uniform.h" #include "vector.h" namespace Msp { @@ -104,11 +103,12 @@ private: struct TaggedUniform { Tag tag; - Uniform *value; + DataType type; + unsigned array_size; + unsigned data_offset; + unsigned data_size; TaggedUniform(); - - void replace_value(Uniform *); }; struct SharedBlock @@ -154,6 +154,7 @@ private: // XXX All these mutables are a bit silly, but I'm out of better ideas const Program *tied_program; std::vector uniforms; + std::vector uniform_data; unsigned generation; mutable std::vector blocks; mutable std::vector programs; @@ -170,16 +171,10 @@ public: ~ProgramData(); private: - void uniform(Tag, Uniform *); - template - void uniform(Tag, V); - template - void uniform_array(Tag, unsigned, V); + void uniform(Tag, DataType, unsigned, const void *); bool validate_tag(Tag) const; - void add_uniform(Tag, Uniform *); void mark_dirty(Mask); public: - void uniform(Tag, const Uniform &); void uniform(Tag, int); void uniform(Tag, float); void uniform(Tag, int, int); @@ -242,8 +237,7 @@ public: unsigned get_generation() const { return generation; } std::vector get_uniform_tags() const; - const Uniform &get_uniform(Tag) const; - const Uniform *find_uniform(Tag) const; + void copy_uniform(const ProgramData &, Tag); private: int find_uniform_index(Tag) const; @@ -260,19 +254,19 @@ public: template void ProgramData::uniform(Tag tag, const LinAl::Vector &v) -{ uniform >(tag, &v.x); } +{ uniform(tag, TypeTraits>::type, 1, &v.x); } template void ProgramData::uniform(Tag tag, const LinAl::Matrix &v) -{ uniform >(tag, &v(0, 0)); } +{ uniform(tag, TypeTraits>::type, 1, &v(0, 0)); } template void ProgramData::uniform_array(Tag tag, unsigned n, const LinAl::Vector *v) -{ uniform_array >(tag, n, &v[0].x); } +{ uniform(tag, TypeTraits>::type, n, &v[0].x); } template void ProgramData::uniform_array(Tag tag, unsigned n, const LinAl::Matrix *v) -{ uniform_array >(tag, n, &v[0](0, 0)); } +{ uniform(tag, TypeTraits>::type, n, &v[0](0, 0)); } } // namespace GL } // namespace Msp