]> git.tdb.fi Git - libs/gl.git/commitdiff
Refactor ProgramData to store blocks in vectors
authorMikko Rasa <tdb@tdb.fi>
Sat, 10 Apr 2021 18:42:58 +0000 (21:42 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sat, 10 Apr 2021 18:42:58 +0000 (21:42 +0300)
source/render/programdata.cpp
source/render/programdata.h

index 272489bb585f0d9536dd94653b0b8fb039b42fea..7323df905db7093fcbb5db5572b9b7f7faedb5ca 100644 (file)
@@ -62,8 +62,8 @@ ProgramData &ProgramData::operator=(const ProgramData &other)
        for(vector<TaggedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
                i->value = i->value->clone();
 
-       for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
-               delete i->second.block;
+       for(vector<SharedBlock>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+               delete i->block;
        programs.clear();
 
        last_block = 0;
@@ -77,11 +77,11 @@ ProgramData::~ProgramData()
 {
        for(vector<TaggedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
                delete i->value;
-       for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+       for(vector<SharedBlock>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
        {
-               if(i->second.indices.type_flag==0xFE)
-                       delete[] i->second.indices.dynamic.values;
-               delete i->second.block;
+               if(i->indices.type_flag==0xFE)
+                       delete[] i->indices.dynamic.values;
+               delete i->block;
        }
        delete buffer;
 }
@@ -496,6 +496,54 @@ int ProgramData::find_uniform_index(Tag tag) const
        return ((i!=uniforms.end() && i->tag==tag) ? i-uniforms.begin() : -1);
 }
 
+vector<ProgramData::ProgramBlock>::iterator ProgramData::get_program(const Program &prog) const
+{
+       Program::LayoutHash prog_hash = prog.get_uniform_layout_hash();
+       vector<ProgramBlock>::iterator i = lower_bound_member(programs, prog_hash, &ProgramBlock::prog_hash);
+       if(i!=programs.end() && i->prog_hash==prog_hash)
+               return i;
+
+       const vector<Program::UniformBlockInfo> &block_infos = prog.get_uniform_blocks();
+       unsigned index = i-programs.begin();
+       programs.insert(i, 1+block_infos.size(), ProgramBlock(prog_hash));
+
+       /* Block indices may change if new shared blocks need to be inserted.  Store
+       the hashes so they can be matched up later. */
+       vector<Program::LayoutHash> block_hashes;
+       block_hashes.reserve(programs.size());
+       for(vector<ProgramBlock>::iterator j=programs.begin(); j!=programs.end(); ++j)
+               block_hashes.push_back(j->block_index>=0 ? blocks[j->block_index].block_hash : 0);
+
+       for(unsigned j=0; j<block_infos.size(); ++j)
+       {
+               const Program::UniformBlockInfo &info = block_infos[j];
+               block_hashes[index+1+j] = info.layout_hash;
+               programs[index+1+j].bind_point = info.bind_point;
+
+               vector<SharedBlock>::iterator k = lower_bound_member(blocks, info.layout_hash, &SharedBlock::block_hash);
+               if(k==blocks.end() || k->block_hash!=info.layout_hash)
+               {
+                       k = blocks.insert(k, SharedBlock(info.layout_hash));
+                       update_block_uniform_indices(*k, info);
+               }
+       }
+
+       /* Reassign shared block indices from the stored hashes. */
+       for(unsigned j=0; j<programs.size(); ++j)
+       {
+               unsigned hash = block_hashes[j];
+               if(hash)
+               {
+                       vector<SharedBlock>::const_iterator k = lower_bound_member(blocks, hash, &SharedBlock::block_hash);
+                       programs[j].block_index = k-blocks.begin();
+               }
+               else
+                       programs[j].block_index = -1;
+       }
+
+       return programs.begin()+index;
+}
+
 void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program::UniformBlockInfo &info) const
 {
        UInt8 *indices = block.indices.values;
@@ -509,6 +557,8 @@ void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program
                indices = block.indices.dynamic.values;
        }
 
+       bool any_missing = false;
+
        block.used = 0;
        for(unsigned i=0; i<info.uniforms.size(); ++i)
        {
@@ -520,64 +570,45 @@ void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program
                                block.used |= 1<<j;
                }
                else
+               {
                        indices[i] = 0xFF;
+                       any_missing = true;
+               }
        }
 
-       block.dirty = block.used;
-}
-
-void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockInfo &info) const
-{
-       const UInt8 *indices = block.get_uniform_indices();
-       for(unsigned i=0; i<info.uniforms.size(); ++i)
-               if(indices[i]!=0xFF)
-                       block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value);
-}
-
-ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBlockInfo &info) const
-{
-       BlockMap::iterator i = blocks.find(info.layout_hash);
-       if(i==blocks.end())
+       if(block.used && any_missing && info.bind_point>=0)
        {
-               bool any_found = false;
-               bool all_found = true;
-               for(vector<const Program::UniformInfo *>::const_iterator j=info.uniforms.begin(); j!=info.uniforms.end(); ++j)
-               {
-                       if(find_uniform_index((*j)->name)>=0)
-                               any_found = true;
-                       else
-                               all_found = false;
-               }
-
-               if(!any_found)
-                       return 0;
-               else if(!all_found && info.bind_point>=0)
-               {
 #ifdef DEBUG
-                       IO::print(IO::cerr, "Warning: not all uniforms for block %s are present\n", info.name);
+               IO::print(IO::cerr, "Warning: not all uniforms for block %s are present\n", info.name);
 #else
-                       throw incomplete_uniform_block(info.name);
+               throw incomplete_uniform_block(info.name);
 #endif
-               }
+       }
+
+       block.dirty = block.used;
 
-               UniformBlock *block;
+       if(block.used && !block.block)
+       {
                if(info.bind_point>=0)
                {
                        if(!buffer)
                                buffer = new Buffer(UNIFORM_BUFFER);
 
-                       block = new UniformBlock(info.data_size);
-                       block->use_buffer(buffer, last_block);
-                       last_block = block;
+                       block.block = new UniformBlock(info.data_size);
+                       block.block->use_buffer(buffer, last_block);
+                       last_block = block.block;
                }
                else
-                       block = new UniformBlock;
-
-               i = blocks.insert(BlockMap::value_type(info.layout_hash, SharedBlock(block))).first;
-               update_block_uniform_indices(i->second, info);
+                       block.block = new UniformBlock;
        }
+}
 
-       return &i->second;
+void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockInfo &info) const
+{
+       const UInt8 *indices = block.get_uniform_indices();
+       for(unsigned i=0; i<info.uniforms.size(); ++i)
+               if(indices[i]!=0xFF)
+                       block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value);
 }
 
 void ProgramData::apply() const
@@ -586,64 +617,60 @@ void ProgramData::apply() const
        if(!prog)
                throw invalid_operation("ProgramData::apply");
 
-       Program::LayoutHash layout = prog->get_uniform_layout_hash();
-       ProgramUniforms &pu = programs[layout];
+       UniformBlock *old_last_block = last_block;
+       vector<ProgramBlock>::iterator prog_begin = get_program(*prog);
+       Program::LayoutHash prog_hash = prog->get_uniform_layout_hash();
 
        Mask force_dirty = (dirty==ALL_ONES ? ALL_ONES : 0U);
-       Mask affected = (dirty&pu.used) | force_dirty;
-       if(affected|pu.dirty)
+       Mask affected = (dirty&prog_begin->masks.used) | force_dirty;
+       if(affected|prog_begin->masks.dirty)
        {
-               /* If the global dirty flag affects this program, add it to per-program
-               dirty flags and clear the global flag.  A previously unseen program will
-               cause this to happen if there's any dirty uniforms. */
+               /* If the global dirty flag affects this program, add it to per-block and
+               per-program dirty flags and clear the global flag.  A previously unseen
+               program will cause this to happen if there's any dirty uniforms. */
                if(affected)
                {
-                       for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
-                               i->second.dirty |= (dirty&i->second.used) | force_dirty;
-                       for(ProgramMap::iterator i=programs.begin(); i!=programs.end(); ++i)
-                               i->second.dirty |= (dirty&i->second.used) | force_dirty;
+                       for(vector<SharedBlock>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+                               i->dirty |= (dirty&i->used) | force_dirty;
+                       for(vector<ProgramBlock>::iterator i=programs.begin(); i!=programs.end(); ++i)
+                               if(i->block_index<0)
+                                       i->masks.dirty |= (dirty&i->masks.used) | force_dirty;
                        dirty = 0;
                }
 
-               const vector<Program::UniformBlockInfo> &prog_blocks = prog->get_uniform_blocks();
+               const vector<Program::UniformBlockInfo> &block_infos = prog->get_uniform_blocks();
 
-               UniformBlock *old_last_block = last_block;
-               if(pu.dirty==ALL_ONES)
+               if(prog_begin->masks.dirty==ALL_ONES)
                {
                        /* The set of uniforms has changed since this program was last used.
-                       Regenerate the list of uniform blocks. */
-                       pu.blocks.clear();
-                       pu.blocks.reserve(prog_blocks.size());
-
-                       pu.used = 0;
-                       for(vector<Program::UniformBlockInfo>::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i)
+                       Refresh uniform indices within the program's blocks. */
+                       prog_begin->masks.used = 0;
+                       vector<ProgramBlock>::iterator j = prog_begin+1;
+                       for(vector<Program::UniformBlockInfo>::const_iterator i=block_infos.begin(); i!=block_infos.end(); ++i, ++j)
                        {
-                               SharedBlock *shared = get_shared_block(*i);
-                               if(shared)
-                               {
-                                       if(shared->dirty==ALL_ONES)
-                                               update_block_uniform_indices(*shared, *i);
-                                       pu.used |= shared->used;
-                               }
-
-                               pu.blocks.push_back(ProgramBlock(i->bind_point, shared));
+                               SharedBlock &shared = blocks[j->block_index];
+                               if(shared.dirty==ALL_ONES)
+                                       update_block_uniform_indices(shared, *i);
+                               prog_begin->masks.used |= shared.used;
+                               j->block = (shared.used ? shared.block : 0);
                        }
                }
 
                // Update the contents of all dirty blocks.
                bool buffered_blocks_updated = false;
-               vector<ProgramBlock>::iterator j = pu.blocks.begin();
-               for(vector<Program::UniformBlockInfo>::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i, ++j)
+               vector<ProgramBlock>::iterator j = prog_begin+1;
+               for(vector<Program::UniformBlockInfo>::const_iterator i=block_infos.begin(); i!=block_infos.end(); ++i, ++j)
                {
-                       if(!j->shared || !j->shared->dirty)
-                               continue;
-
-                       update_block(*j->shared, *i);
-                       j->shared->dirty = 0;
-                       buffered_blocks_updated |= (j->bind_point>=0);
+                       SharedBlock &shared = blocks[j->block_index];
+                       if(shared.dirty)
+                       {
+                               update_block(shared, *i);
+                               shared.dirty = 0;
+                               buffered_blocks_updated |= (j->bind_point>=0);
+                       }
                }
 
-               pu.dirty = 0;
+               prog_begin->masks.dirty = 0;
 
                /* If any blocks stored in the buffer were updated, bind the buffer here
                to avoid state thrashing. */
@@ -667,7 +694,7 @@ void ProgramData::apply() const
                }
        }
 
-       for(vector<ProgramBlock>::iterator i=pu.blocks.begin(); i!=pu.blocks.end(); ++i)
+       for(vector<ProgramBlock>::iterator i=prog_begin+1; (i!=programs.end() && i->prog_hash==prog_hash); ++i)
                if(i->block)
                        i->block->apply(i->bind_point);
 }
@@ -687,10 +714,11 @@ void ProgramData::TaggedUniform::replace_value(Uniform *v)
 }
 
 
-ProgramData::SharedBlock::SharedBlock(UniformBlock *b):
+ProgramData::SharedBlock::SharedBlock(Program::LayoutHash h):
+       block_hash(h),
        used(0),
        dirty(0),
-       block(b)
+       block(0)
 {
        indices.type_flag = 0xFD;
 }
@@ -701,23 +729,14 @@ const UInt8 *ProgramData::SharedBlock::get_uniform_indices() const
 }
 
 
-ProgramData::ProgramBlock::ProgramBlock():
+ProgramData::ProgramBlock::ProgramBlock(Program::LayoutHash h):
+       prog_hash(h),
        bind_point(-1),
-       block(0),
-       shared(0)
-{ }
-
-ProgramData::ProgramBlock::ProgramBlock(int p, SharedBlock *b):
-       bind_point(p),
-       block((b && b->used) ? b->block : 0),
-       shared(b)
-{ }
-
-
-ProgramData::ProgramUniforms::ProgramUniforms():
-       used(ALL_ONES),
-       dirty(ALL_ONES)
-{ }
+       block_index(-1)
+{
+       masks.used = ALL_ONES;
+       masks.dirty = ALL_ONES;
+}
 
 
 ProgramData::Loader::Loader(ProgramData &pd):
index 97f293430c1c718e06f594d84ddf0d2de1a84263..6f20d4d8317da1d393e5da555c0d4a3989498f67 100644 (file)
@@ -110,6 +110,7 @@ private:
 
        struct SharedBlock
        {
+               Program::LayoutHash block_hash;
                Mask used;
                Mask dirty;
                UniformBlock *block;
@@ -124,38 +125,34 @@ private:
                        } dynamic;
                } indices;
 
-               SharedBlock(UniformBlock *);
+               SharedBlock(Program::LayoutHash);
 
                const UInt8 *get_uniform_indices() const;
        };
 
        struct ProgramBlock
        {
+               Program::LayoutHash prog_hash;
                int bind_point;
-               UniformBlock *block;
-               SharedBlock *shared;
-
-               ProgramBlock();
-               ProgramBlock(int, SharedBlock *);
-       };
-
-       struct ProgramUniforms
-       {
-               std::vector<ProgramBlock> blocks;
-               Mask used;
-               Mask dirty;
+               int block_index;
+               union
+               {
+                       UniformBlock *block;
+                       struct
+                       {
+                               Mask used;
+                               Mask dirty;
+                       } masks;
+               };
 
-               ProgramUniforms();
+               ProgramBlock(Program::LayoutHash);
        };
 
-       typedef std::map<Program::LayoutHash, SharedBlock> BlockMap;
-       typedef std::map<Program::LayoutHash, ProgramUniforms> ProgramMap;
-
        // XXX All these mutables are a bit silly, but I'm out of better ideas
        const Program *tied_program;
        std::vector<TaggedUniform> uniforms;
-       mutable BlockMap blocks;
-       mutable ProgramMap programs;
+       mutable std::vector<SharedBlock> blocks;
+       mutable std::vector<ProgramBlock> programs;
        mutable UniformBlock *last_block;
        mutable Buffer *buffer;
        mutable Mask dirty;
@@ -237,9 +234,9 @@ public:
 
 private:
        int find_uniform_index(Tag) const;
+       std::vector<ProgramBlock>::iterator get_program(const Program &) const;
        void update_block_uniform_indices(SharedBlock &, const Program::UniformBlockInfo &) const;
        void update_block(SharedBlock &, const Program::UniformBlockInfo &) const;
-       SharedBlock *get_shared_block(const Program::UniformBlockInfo &) const;
 
 public:
        /** Applies uniform blocks for the currently bound program, creating them