X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Frender%2Fprogramdata.cpp;h=43bcbf3febea57702fb6be343818b01d9d472325;hp=401ed18949af2ff09ec7b826b5c36627854e4201;hb=38712d8ecc57d043a2419ffbaeeb57f7a6586f14;hpb=f2e54dc47d0ddba2b1ca582e8c8feb64ccfcb270 diff --git a/source/render/programdata.cpp b/source/render/programdata.cpp index 401ed189..43bcbf3f 100644 --- a/source/render/programdata.cpp +++ b/source/render/programdata.cpp @@ -1,14 +1,13 @@ -#include +#include #include -#include #include #include "buffer.h" #include "color.h" #include "error.h" #include "matrix.h" +#include "pipelinestate.h" #include "program.h" #include "programdata.h" -#include "uniform.h" #include "uniformblock.h" #include "vector.h" @@ -19,7 +18,8 @@ namespace GL { ProgramData::ProgramData(const Program *p): tied_program(p), - last_block(0), + generation(0), + last_buffer_block(0), buffer(0), dirty(0) { } @@ -28,29 +28,27 @@ ProgramData::ProgramData(const Program *p): ProgramData::ProgramData(const ProgramData &other): tied_program(other.tied_program), uniforms(other.uniforms), - last_block(0), + uniform_data(other.uniform_data), + generation(other.generation), + last_buffer_block(0), buffer(0), dirty(0) -{ - for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - i->value = i->value->clone(); -} +{ } ProgramData::ProgramData(const ProgramData &other, const Program *p): tied_program(p), - last_block(0), + last_buffer_block(0), buffer(0), dirty(0) { if(tied_program) { - for(vector::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i) - validate_name(i->name); + for(const TaggedUniform &u: other.uniforms) + validate_tag(u.tag); } uniforms = other.uniforms; - for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - i->value = i->value->clone(); + uniform_data = other.uniform_data; } ProgramData &ProgramData::operator=(const ProgramData &other) @@ -58,14 +56,14 @@ ProgramData &ProgramData::operator=(const ProgramData &other) tied_program = other.tied_program; uniforms = other.uniforms; - for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - i->value = i->value->clone(); + uniform_data = other.uniform_data; - for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) - delete i->second.block; + for(SharedBlock &b: blocks) + delete b.block; + blocks.clear(); programs.clear(); - last_block = 0; + last_buffer_block = 0; buffer = 0; dirty = 0; @@ -74,451 +72,420 @@ ProgramData &ProgramData::operator=(const ProgramData &other) ProgramData::~ProgramData() { - for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - delete i->value; - for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) + for(SharedBlock &b: blocks) { - if(i->second.indices.type_flag==0xFE) - delete[] i->second.indices.dynamic.values; - delete i->second.block; + if(b.indices.type_flag==0xFE) + delete[] b.indices.dynamic.values; + delete b.block; } delete buffer; } -void ProgramData::uniform(const string &name, 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_name(name)) - { - 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(name); - if(i<0) - return add_uniform(name, uni); - - uniforms[i].replace_value(uni); - dirty |= 1< -void ProgramData::uniform(const string &name, V value) -{ - if(!validate_name(name)) - return; - - int i = find_uniform_index(name); - if(i<0) - return add_uniform(name, new T(value)); - - if(T *uni = dynamic_cast(uniforms[i].value)) - uni->set(value); - else - uniforms[i].replace_value(new T(value)); + 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); - dirty |= 1< -void ProgramData::uniform_array(const string &name, unsigned n, V value) -{ - if(!validate_name(name)) - return; - - int i = find_uniform_index(name); - if(i<0) - return add_uniform(name, 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)); - - dirty |= 1<get_uniform_info(name); - else if(name[name.size()-1]==']') - throw invalid_argument("ProgramData::uniform"); + { + const ReflectData::UniformInfo &info = tied_program->get_uniform_info(tag); + if(is_image(info.type)) + throw invalid_operation("ProgramData::uniform"); + } return true; } #ifdef DEBUG catch(const exception &e) { - IO::print(IO::cerr, "Error while setting uniform %s: %s: %s\n", name, Debug::demangle(typeid(e).name()), e.what()); + IO::print(IO::cerr, "Error while setting uniform %s: %s: %s\n", tag, Debug::demangle(typeid(e).name()), e.what()); return false; } #endif } -void ProgramData::add_uniform(const string &name, Uniform *uni) +void ProgramData::mark_dirty(Mask bits) { - if(uniforms.size()>=MASK_BITS) - { - delete uni; - throw too_many_uniforms(name); - } - - vector::iterator j = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare); - - NamedUniform nu; - nu.name = name; - nu.value = uni; - uniforms.insert(j, nu); - - dirty = ALL_ONES; + if(!dirty) + ++generation; + dirty |= bits; } -void ProgramData::uniform(const string &name, const Uniform &u) +void ProgramData::uniform(Tag tag, int v) { - uniform(name, u.clone()); + uniform(tag, INT, 1, &v); } -void ProgramData::uniform(const string &name, int v) +void ProgramData::uniform(Tag tag, float v) { - uniform(name, v); + uniform(tag, FLOAT, 1, &v); } -void ProgramData::uniform(const string &name, float v) -{ - uniform(name, v); -} - -void ProgramData::uniform(const string &name, int v0, int v1) +void ProgramData::uniform(Tag tag, int v0, int v1) { int va[2] = { v0, v1 }; - uniform2(name, va); + uniform2(tag, va); } -void ProgramData::uniform(const string &name, float v0, float v1) +void ProgramData::uniform(Tag tag, float v0, float v1) { float va[2] = { v0, v1 }; - uniform2(name, va); + uniform2(tag, va); } -void ProgramData::uniform2(const string &name, const int *v) +void ProgramData::uniform2(Tag tag, const int *v) { - uniform(name, v); + uniform(tag, INT_VEC2, 1, v); } -void ProgramData::uniform2(const string &name, const float *v) +void ProgramData::uniform2(Tag tag, const float *v) { - uniform(name, v); + uniform(tag, FLOAT_VEC2, 1, v); } -void ProgramData::uniform(const string &name, int v0, int v1, int v2) +void ProgramData::uniform(Tag tag, int v0, int v1, int v2) { int va[3] = { v0, v1, v2 }; - uniform3(name, va); + uniform3(tag, va); } -void ProgramData::uniform(const string &name, float v0, float v1, float v2) +void ProgramData::uniform(Tag tag, float v0, float v1, float v2) { float va[3] = { v0, v1, v2 }; - uniform3(name, va); -} - -void ProgramData::uniform(const string &name, const Vector3 &v) -{ - uniform(name, v.x, v.y, v.z); + uniform3(tag, va); } -void ProgramData::uniform3(const string &name, const int *v) +void ProgramData::uniform3(Tag tag, const int *v) { - uniform(name, v); + uniform(tag, INT_VEC3, 1, v); } -void ProgramData::uniform3(const string &name, const float *v) +void ProgramData::uniform3(Tag tag, const float *v) { - uniform(name, v); + uniform(tag, FLOAT_VEC3, 1, v); } -void ProgramData::uniform(const string &name, int v0, int v1, int v2, int v3) +void ProgramData::uniform(Tag tag, int v0, int v1, int v2, int v3) { int va[4] = { v0, v1, v2, v3 }; - uniform4(name, va); + uniform4(tag, va); } -void ProgramData::uniform(const string &name, float v0, float v1, float v2, float v3) +void ProgramData::uniform(Tag tag, float v0, float v1, float v2, float v3) { float va[4] = { v0, v1, v2, v3 }; - uniform4(name, va); + uniform4(tag, va); } -void ProgramData::uniform(const string &name, const Vector4 &v) +void ProgramData::uniform(Tag tag, const Color &c) { - uniform(name, v.x, v.y, v.z, v.w); + uniform(tag, c.r, c.g, c.b, c.a); } -void ProgramData::uniform(const string &name, const Color &c) +void ProgramData::uniform4(Tag tag, const int *v) { - uniform(name, c.r, c.g, c.b, c.a); + uniform(tag, INT_VEC4, 1, v); } -void ProgramData::uniform4(const string &name, const int *v) +void ProgramData::uniform4(Tag tag, const float *v) { - uniform(name, v); + uniform(tag, FLOAT_VEC4, 1, v); } -void ProgramData::uniform4(const string &name, const float *v) +void ProgramData::uniform_matrix2(Tag tag, const float *v) { - uniform(name, v); + uniform(tag, FLOAT_MAT2, 1, v); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform_matrix3x2(Tag tag, const float *v) { - uniform_matrix2(name, &m(0, 0)); + uniform(tag, FLOAT_MAT3x2, 1, v); } -void ProgramData::uniform_matrix2(const string &name, const float *v) +void ProgramData::uniform_matrix4x2(Tag tag, const float *v) { - uniform(name, v); + uniform(tag, FLOAT_MAT4x2, 1, v); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform_matrix2x3(Tag tag, const float *v) { - uniform_matrix3x2(name, &m(0, 0)); + uniform(tag, FLOAT_MAT2x3, 1, v); } -void ProgramData::uniform_matrix3x2(const string &name, const float *v) +void ProgramData::uniform_matrix3(Tag tag, const float *v) { - uniform(name, v); + uniform(tag, FLOAT_MAT3, 1, v); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform_matrix4x3(Tag tag, const float *v) { - uniform_matrix4x2(name, &m(0, 0)); + uniform(tag, FLOAT_MAT4x3, 1, v); } -void ProgramData::uniform_matrix4x2(const string &name, const float *v) +void ProgramData::uniform_matrix2x4(Tag tag, const float *v) { - uniform(name, v); + uniform(tag, FLOAT_MAT2x4, 1, v); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform_matrix3x4(Tag tag, const float *v) { - uniform_matrix2x3(name, &m(0, 0)); + uniform(tag, FLOAT_MAT3x4, 1, v); } -void ProgramData::uniform_matrix2x3(const string &name, const float *v) +void ProgramData::uniform(Tag tag, const Matrix &m) { - uniform(name, v); + uniform_matrix4(tag, m.data()); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform_matrix4(Tag tag, const float *v) { - uniform_matrix3(name, &m(0, 0)); + uniform(tag, FLOAT_MAT4, 1, v); } -void ProgramData::uniform_matrix3(const string &name, const float *v) +void ProgramData::uniform_array(Tag tag, unsigned n, const int *v) { - uniform(name, v); + uniform(tag, INT, n, v); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform_array(Tag tag, unsigned n, const float *v) { - uniform_matrix4x3(name, &m(0, 0)); + uniform(tag, FLOAT, n, v); } -void ProgramData::uniform_matrix4x3(const string &name, const float *v) +void ProgramData::uniform1_array(Tag tag, unsigned n, const int *v) { - uniform(name, v); + uniform(tag, INT, n, v); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform1_array(Tag tag, unsigned n, const float *v) { - uniform_matrix2x4(name, &m(0, 0)); + uniform(tag, FLOAT, n, v); } -void ProgramData::uniform_matrix2x4(const string &name, const float *v) +void ProgramData::uniform2_array(Tag tag, unsigned n, const int *v) { - uniform(name, v); + uniform(tag, INT_VEC2, n, v); } -void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +void ProgramData::uniform2_array(Tag tag, unsigned n, const float *v) { - uniform_matrix3x4(name, &m(0, 0)); + uniform(tag, FLOAT_VEC2, n, v); } -void ProgramData::uniform_matrix3x4(const string &name, const float *v) +void ProgramData::uniform3_array(Tag tag, unsigned n, const int *v) { - uniform(name, v); + uniform(tag, INT_VEC3, n, v); } -void ProgramData::uniform(const string &name, const Matrix &m) +void ProgramData::uniform3_array(Tag tag, unsigned n, const float *v) { - uniform_matrix4(name, m.data()); + uniform(tag, FLOAT_VEC3, n, v); } -void ProgramData::uniform_matrix4(const string &name, const float *v) +void ProgramData::uniform4_array(Tag tag, unsigned n, const int *v) { - uniform(name, v); + uniform(tag, INT_VEC4, n, v); } -void ProgramData::uniform1_array(const string &name, unsigned n, const int *v) +void ProgramData::uniform4_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_VEC4, n, v); } -void ProgramData::uniform1_array(const string &name, unsigned n, const float *v) +void ProgramData::uniform_matrix2_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT2, n, v); } -void ProgramData::uniform2_array(const string &name, unsigned n, const int *v) +void ProgramData::uniform_matrix3x2_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT3x2, n, v); } -void ProgramData::uniform2_array(const string &name, unsigned n, const float *v) +void ProgramData::uniform_matrix4x2_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT4x2, n, v); } -void ProgramData::uniform3_array(const string &name, unsigned n, const int *v) +void ProgramData::uniform_matrix2x3_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT2x3, n, v); } -void ProgramData::uniform3_array(const string &name, unsigned n, const float *v) +void ProgramData::uniform_matrix3_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT3, n, v); } -void ProgramData::uniform4_array(const string &name, unsigned n, const int *v) +void ProgramData::uniform_matrix4x3_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT4x3, n, v); } -void ProgramData::uniform4_array(const string &name, unsigned n, const float *v) +void ProgramData::uniform_matrix2x4_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT2x4, n, v); } -void ProgramData::uniform_matrix2_array(const string &name, unsigned n, const float *v) +void ProgramData::uniform_matrix3x4_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT3x4, n, v); } -void ProgramData::uniform_matrix3x2_array(const string &name, unsigned n, const float *v) +void ProgramData::uniform_matrix4_array(Tag tag, unsigned n, const float *v) { - uniform_array(name, n, v); + uniform(tag, FLOAT_MAT4, n, v); } -void ProgramData::uniform_matrix4x2_array(const string &name, unsigned n, const float *v) +void ProgramData::remove_uniform(Tag tag) { - uniform_array(name, n, v); -} - -void ProgramData::uniform_matrix2x3_array(const string &name, unsigned n, const float *v) -{ - uniform_array(name, n, v); -} + auto i = lower_bound_member(uniforms, tag, &TaggedUniform::tag); + if(i==uniforms.end() || i->tag!=tag) + return; -void ProgramData::uniform_matrix3_array(const string &name, unsigned n, const float *v) -{ - uniform_array(name, n, v); -} + 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); -void ProgramData::uniform_matrix4x3_array(const string &name, unsigned n, const float *v) -{ - uniform_array(name, n, v); + mark_dirty(ALL_ONES); } -void ProgramData::uniform_matrix2x4_array(const string &name, unsigned n, const float *v) +vector ProgramData::get_uniform_tags() const { - uniform_array(name, n, v); + vector tags; + tags.reserve(uniforms.size()); + for(const TaggedUniform &u: uniforms) + tags.push_back(u.tag); + return tags; } -void ProgramData::uniform_matrix3x4_array(const string &name, unsigned n, const float *v) +void ProgramData::copy_uniform(const ProgramData &source, Tag tag) { - uniform_array(name, n, v); + int i = source.find_uniform_index(tag); + if(i<0) + throw key_error(tag); + const TaggedUniform &tu = source.uniforms[i]; + uniform(tag, tu.type, tu.array_size, source.uniform_data.data()+tu.data_offset); } -void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const float *v) +int ProgramData::find_uniform_index(Tag tag) const { - uniform_array(name, n, v); + auto i = lower_bound_member(uniforms, tag, &TaggedUniform::tag); + return ((i!=uniforms.end() && i->tag==tag) ? i-uniforms.begin() : -1); } -void ProgramData::remove_uniform(const string &name) +vector::iterator ProgramData::get_program(const Program &prog) const { - vector::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare); - if(i==uniforms.end() || i->name!=name) - return; - - delete i->value; - uniforms.erase(i); + ReflectData::LayoutHash prog_hash = prog.get_uniform_layout_hash(); + auto i = lower_bound_member(programs, prog_hash, &ProgramBlock::prog_hash); + if(i!=programs.end() && i->prog_hash==prog_hash) + return i; - dirty = ALL_ONES; -} + const vector &block_infos = prog.get_uniform_blocks(); + unsigned index = i-programs.begin(); + programs.insert(i, 1+block_infos.size(), ProgramBlock(prog_hash)); -vector ProgramData::get_uniform_names() const -{ - vector names; - names.reserve(uniforms.size()); - for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - names.push_back(i->name); - return names; -} + /* Block indices may change if new shared blocks need to be inserted. Store + the hashes so they can be matched up later. */ + vector block_hashes; + block_hashes.reserve(programs.size()); + for(const ProgramBlock &b: programs) + block_hashes.push_back(b.block_index>=0 ? blocks[b.block_index].block_hash : 0); -const Uniform &ProgramData::get_uniform(const string &name) const -{ - int i = find_uniform_index(name); - if(i<0) - throw key_error(name); - return *uniforms[i].value; -} + for(unsigned j=0; j=0 ? uniforms[i].value : 0); -} + auto 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); + } + } -bool ProgramData::uniform_name_compare(const NamedUniform &nu, const string &name) -{ - return nu.name::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare); - return ((i!=uniforms.end() && i->name==name) ? i-uniforms.begin() : -1); + return programs.begin()+index; } -void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program::UniformBlockInfo &info) const +void ProgramData::update_block_uniform_indices(SharedBlock &block, const ReflectData::UniformBlockInfo &info) const { - UInt8 *indices = block.indices.values; + uint8_t *indices = block.indices.values; if(info.uniforms.size()>16) { if(block.indices.type_flag==0xFD) { - block.indices.dynamic.values = new UInt8[info.uniforms.size()]; + block.indices.dynamic.values = new uint8_t[info.uniforms.size()]; block.indices.type_flag = 0xFE; } indices = block.indices.dynamic.values; } + bool any_missing = false; + block.used = 0; for(unsigned i=0; iname); + int j = find_uniform_index(info.uniforms[i]->tag); if(j>=0) { indices[i] = j; @@ -526,146 +493,132 @@ void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program block.used |= 1<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_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) + { + block.block = new UniformBlock(info); if(info.bind_point>=0) { if(!buffer) - buffer = new Buffer(UNIFORM_BUFFER); + { + buffer = new Buffer(); - block = new UniformBlock(info.data_size); - block->use_buffer(buffer, last_block); - last_block = block; - } - else - block = new UniformBlock; +#ifdef DEBUG + if(!debug_name.empty()) + buffer->set_debug_name(debug_name); +#endif + } - i = blocks.insert(BlockMap::value_type(info.layout_hash, SharedBlock(block))).first; - update_block_uniform_indices(i->second, info); + block.block->use_buffer(buffer, last_buffer_block); + last_buffer_block = block.block; + } } - - return &i->second; } -void ProgramData::apply() const +void ProgramData::update_block(SharedBlock &block, const ReflectData::UniformBlockInfo &info) const { - const Program *prog = Program::current(); - if(!prog) - throw invalid_operation("ProgramData::apply"); + const uint8_t *indices = block.get_uniform_indices(); + for(unsigned i=0; itype)) + ; // Temporarily ignore deprecated use of sampler uniforms in ProgramData + else if(indices[i]!=0xFF) + { + const TaggedUniform &tu = uniforms[indices[i]]; + block.block->store(*info.uniforms[i], tu.array_size, uniform_data.data()+tu.data_offset); + } + } +} - Program::LayoutHash layout = prog->get_uniform_layout_hash(); - ProgramUniforms &pu = programs[layout]; +vector::const_iterator ProgramData::prepare_program(const Program &prog) const +{ + UniformBlock *old_last_block = last_buffer_block; + auto prog_begin = get_program(prog); 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(SharedBlock &b: blocks) + b.dirty |= (dirty&b.used) | force_dirty; + for(ProgramBlock &b: programs) + if(b.block_index<0) + b.masks.dirty |= (dirty&b.masks.used) | force_dirty; dirty = 0; } - const vector &prog_blocks = prog->get_uniform_blocks(); + const vector &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::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i) + Refresh uniform indices within the program's blocks. */ + prog_begin->masks.used = 0; + auto j = prog_begin+1; + for(const ReflectData::UniformBlockInfo &b: block_infos) { - 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, b); + prog_begin->masks.used |= shared.used; + j->block = (shared.used ? shared.block : 0); + ++j; } } // Update the contents of all dirty blocks. bool buffered_blocks_updated = false; - std::vector::iterator j = pu.blocks.begin(); - for(vector::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i, ++j) + auto j = prog_begin+1; + for(const ReflectData::UniformBlockInfo &b: block_infos) { - 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, b); + shared.dirty = 0; + buffered_blocks_updated |= (j->bind_point>=0); + } + ++j; } - 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. */ - if(buffered_blocks_updated && !ARB_direct_state_access) - buffer->bind(); - - if(last_block!=old_last_block) + if(last_buffer_block!=old_last_block) { - unsigned required_size = last_block->get_required_buffer_size(); - if(last_block->get_required_buffer_size()>buffer->get_size()) + unsigned required_size = last_buffer_block->get_required_buffer_size(); + if(last_buffer_block->get_required_buffer_size()>buffer->get_size()) { if(buffer->get_size()>0) { delete buffer; - buffer = new Buffer(UNIFORM_BUFFER); - last_block->change_buffer(buffer); + buffer = new Buffer(); + last_buffer_block->change_buffer(buffer); + +#ifdef DEBUG + if(!debug_name.empty()) + buffer->set_debug_name(debug_name); +#endif } buffer->storage(required_size); @@ -673,57 +626,57 @@ void ProgramData::apply() const } } - for(vector::iterator i=pu.blocks.begin(); i!=pu.blocks.end(); ++i) - if(i->block) - i->block->apply(i->bind_point); + return prog_begin; } +void ProgramData::apply(const Program &prog, PipelineState &state) const +{ + auto prog_begin = prepare_program(prog); + ReflectData::LayoutHash prog_hash = prog_begin->prog_hash; + for(auto i=prog_begin+1; (i!=programs.end() && i->prog_hash==prog_hash); ++i) + if(i->block) + { + state.set_uniform_block(i->bind_point, i->block); + if(i->bind_point>=0) + i->block->refresh(); + } +} -ProgramData::NamedUniform::NamedUniform(): - value(0) -{ } - -void ProgramData::NamedUniform::replace_value(Uniform *v) +void ProgramData::set_debug_name(const string &name) { - /* 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; +#ifdef DEBUG + debug_name = name; + if(buffer) + buffer->set_debug_name(name); +#else + (void)name; +#endif } -ProgramData::SharedBlock::SharedBlock(UniformBlock *b): +ProgramData::SharedBlock::SharedBlock(ReflectData::LayoutHash h): + block_hash(h), used(0), dirty(0), - block(b) + block(0) { indices.type_flag = 0xFD; } -const UInt8 *ProgramData::SharedBlock::get_uniform_indices() const +const uint8_t *ProgramData::SharedBlock::get_uniform_indices() const { return (indices.type_flag==0xFE ? indices.dynamic.values : indices.values); } -ProgramData::ProgramBlock::ProgramBlock(): +ProgramData::ProgramBlock::ProgramBlock(ReflectData::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):