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