X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramdata.cpp;h=5f124a907fc8eebbb034d25cddb5ba475c67c022;hp=a0e0e8bc61376b814f28af1439f01329d8e7e61e;hb=bec07999d95b76f4b47cffcc564d0cd0afc0435e;hpb=72a13418cc19e750abf3f8d8a52aea5e1abe4983 diff --git a/source/programdata.cpp b/source/programdata.cpp index a0e0e8bc..5f124a90 100644 --- a/source/programdata.cpp +++ b/source/programdata.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include "buffer.h" #include "color.h" #include "error.h" @@ -24,28 +26,40 @@ ProgramData::ProgramData(const Program *p): // Blocks are intentionally left uncopied ProgramData::ProgramData(const ProgramData &other): - tied_program(0), - uniform_slots(other.uniform_slots), + tied_program(other.tied_program), uniforms(other.uniforms), last_block(0), buffer(0), dirty(0) { - for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - *i = (*i)->clone(); + for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + i->value = i->value->clone(); } -ProgramData &ProgramData::operator=(const ProgramData &other) +ProgramData::ProgramData(const ProgramData &other, const Program *p): + tied_program(p), + last_block(0), + buffer(0), + dirty(0) { - for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - delete *i; - uniforms.clear(); + if(tied_program) + { + for(vector::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i) + tied_program->get_uniform_info(i->name); + } + + uniforms = other.uniforms; + for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + i->value = i->value->clone(); +} +ProgramData &ProgramData::operator=(const ProgramData &other) +{ tied_program = other.tied_program; - uniform_slots = other.uniform_slots; - for(vector::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i) - uniforms.push_back((*i)->clone()); + uniforms = other.uniforms; + for(vector::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; @@ -60,10 +74,14 @@ ProgramData &ProgramData::operator=(const ProgramData &other) ProgramData::~ProgramData() { - for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - delete *i; + for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + delete i->value; for(BlockMap::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; + } delete buffer; } @@ -71,10 +89,11 @@ void ProgramData::uniform(const string &name, Uniform *uni) { try { - if(tied_program) - tied_program->get_uniform_info(name); - else if(name[name.size()-1]==']') - throw invalid_argument("ProgramData::uniform"); + if(!validate_name(name)) + { + delete uni; + return; + } } catch(...) { @@ -82,27 +101,88 @@ void ProgramData::uniform(const string &name, Uniform *uni) throw; } - SlotMap::iterator i = uniform_slots.find(name); - if(i!=uniform_slots.end()) + 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)); + + 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<second]; - /* 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 slot; - slot = uni; - - if(i->secondsecond; - else // Force a full update if the mask isn't wide enough - dirty = ALL_ONES; + if(tied_program) + tied_program->get_uniform_info(name); + else if(name[name.size()-1]==']') + throw invalid_argument("ProgramData::uniform"); + return true; } - else +#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()); + return false; + } +#endif +} + +void ProgramData::add_uniform(const string &name, Uniform *uni) +{ + if(uniforms.size()>=MASK_BITS) { - uniform_slots[name] = uniforms.size(); - uniforms.push_back(uni); - dirty = ALL_ONES; + 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; } void ProgramData::uniform(const string &name, const Uniform &u) @@ -112,12 +192,12 @@ void ProgramData::uniform(const string &name, const Uniform &u) void ProgramData::uniform(const string &name, int v) { - uniform(name, new Uniform1i(v)); + uniform(name, v); } void ProgramData::uniform(const string &name, float v) { - uniform(name, new Uniform1f(v)); + uniform(name, v); } void ProgramData::uniform(const string &name, int v0, int v1) @@ -134,12 +214,12 @@ void ProgramData::uniform(const string &name, float v0, float v1) void ProgramData::uniform2(const string &name, const int *v) { - uniform(name, new Uniform2i(v)); + uniform(name, v); } void ProgramData::uniform2(const string &name, const float *v) { - uniform(name, new Uniform2f(v)); + uniform(name, v); } void ProgramData::uniform(const string &name, int v0, int v1, int v2) @@ -161,12 +241,12 @@ void ProgramData::uniform(const string &name, const Vector3 &v) void ProgramData::uniform3(const string &name, const int *v) { - uniform(name, new Uniform3i(v)); + uniform(name, v); } void ProgramData::uniform3(const string &name, const float *v) { - uniform(name, new Uniform3f(v)); + uniform(name, v); } void ProgramData::uniform(const string &name, int v0, int v1, int v2, int v3) @@ -193,12 +273,12 @@ void ProgramData::uniform(const string &name, const Color &c) void ProgramData::uniform4(const string &name, const int *v) { - uniform(name, new Uniform4i(v)); + uniform(name, v); } void ProgramData::uniform4(const string &name, const float *v) { - uniform(name, new Uniform4f(v)); + uniform(name, v); } void ProgramData::uniform(const string &name, const LinAl::Matrix &m) @@ -208,7 +288,37 @@ void ProgramData::uniform(const string &name, const LinAl::Matrix & void ProgramData::uniform_matrix2(const string &name, const float *v) { - uniform(name, new UniformMatrix2x2f(v)); + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix3x2(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix3x2(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix4x2(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix4x2(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix2x3(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix2x3(const string &name, const float *v) +{ + uniform(name, v); } void ProgramData::uniform(const string &name, const LinAl::Matrix &m) @@ -218,7 +328,37 @@ void ProgramData::uniform(const string &name, const LinAl::Matrix & void ProgramData::uniform_matrix3(const string &name, const float *v) { - uniform(name, new UniformMatrix3x3f(v)); + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix4x3(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix4x3(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix2x4(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix2x4(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix3x4(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix3x4(const string &name, const float *v) +{ + uniform(name, v); } void ProgramData::uniform(const string &name, const Matrix &m) @@ -228,109 +368,176 @@ void ProgramData::uniform(const string &name, const Matrix &m) void ProgramData::uniform_matrix4(const string &name, const float *v) { - uniform(name, new UniformMatrix4x4f(v)); + uniform(name, v); } void ProgramData::uniform1_array(const string &name, unsigned n, const int *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::uniform1_array(const string &name, unsigned n, const float *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::uniform2_array(const string &name, unsigned n, const int *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::uniform2_array(const string &name, unsigned n, const float *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::uniform3_array(const string &name, unsigned n, const int *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::uniform3_array(const string &name, unsigned n, const float *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::uniform4_array(const string &name, unsigned n, const int *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::uniform4_array(const string &name, unsigned n, const float *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix2_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix3x2_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix4x2_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix2x3_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix3_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix4x3_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix2x4_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix3x4_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); } void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const float *v) { - uniform(name, new UniformArray(n, v)); + uniform_array(name, n, v); } void ProgramData::remove_uniform(const string &name) { - SlotMap::iterator i = uniform_slots.find(name); - if(i!=uniform_slots.end()) - { - vector::iterator j = uniforms.begin()+i->second; - delete *j; - uniforms.erase(j); - - for(SlotMap::iterator k=uniform_slots.begin(); k!=uniform_slots.end(); ++k) - if(k->second>i->second) - --k->second; + vector::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare); + if(i==uniforms.end() || i->name!=name) + return; - uniform_slots.erase(i); + delete i->value; + uniforms.erase(i); - dirty = ALL_ONES; - } + dirty = ALL_ONES; } vector ProgramData::get_uniform_names() const { vector names; - for(SlotMap::const_iterator i=uniform_slots.begin(); i!=uniform_slots.end(); ++i) - names.push_back(i->first); + names.reserve(uniforms.size()); + for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + names.push_back(i->name); return names; } const Uniform &ProgramData::get_uniform(const string &name) const { - return *uniforms[get_item(uniform_slots, name)]; + int i = find_uniform_index(name); + if(i<0) + throw key_error(name); + return *uniforms[i].value; } -unsigned ProgramData::compute_slot_mask(const Program::UniformBlockInfo &block) const +const Uniform *ProgramData::find_uniform(const string &name) const { - unsigned mask = 0; - for(vector::const_iterator i=block.uniforms.begin(); i!=block.uniforms.end(); ++i) - { - SlotMap::const_iterator j = uniform_slots.find((*i)->name); - /* TODO issue a warning (or even error?) either here or in update_block - if all uniforms for a buffer-backed block are not found */ - if(j!=uniform_slots.end() && j->secondsecond; - } + int i = find_uniform_index(name); + return (i>=0 ? uniforms[i].value : 0); +} + +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); } -void ProgramData::update_block(UniformBlock &block, const Program::UniformBlockInfo &info) const +void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program::UniformBlockInfo &info) const { - for(vector::const_iterator i=info.uniforms.begin(); i!=info.uniforms.end(); ++i) + UInt8 *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.type_flag = 0xFE; + } + indices = block.indices.dynamic.values; + } + + block.used = 0; + for(unsigned i=0; iname); - if(j!=uniform_slots.end()) - block.attach(**i, *uniforms[j->second]); + int j = find_uniform_index(info.uniforms[i]->name); + if(j>=0) + { + indices[i] = j; + if(static_cast(j)attach(*info.uniforms[i], *uniforms[indices[i]].value); } ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBlockInfo &info) const @@ -338,18 +545,32 @@ ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBl BlockMap::iterator i = blocks.find(info.layout_hash); if(i==blocks.end()) { - unsigned used = compute_slot_mask(info); - if(!used) + 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); +#else + throw incomplete_uniform_block(info.name); +#endif + } UniformBlock *block; if(info.bind_point>=0) { if(!buffer) - { buffer = new Buffer(UNIFORM_BUFFER); - buffer->set_usage(STREAM_DRAW); - } block = new UniformBlock(info.data_size); block->use_buffer(buffer, last_block); @@ -358,7 +579,8 @@ ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBl else block = new UniformBlock; - i = blocks.insert(BlockMap::value_type(info.layout_hash, SharedBlock(used, block))).first; + i = blocks.insert(BlockMap::value_type(info.layout_hash, SharedBlock(block))).first; + update_block_uniform_indices(i->second, info); } return &i->second; @@ -379,7 +601,7 @@ void ProgramData::apply() const { /* 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 - always cause this to happen. */ + cause this to happen if there's any dirty uniforms. */ if(affected) { for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) @@ -391,6 +613,7 @@ void ProgramData::apply() const const Program::UniformBlockMap &prog_blocks = prog->get_uniform_blocks(); + UniformBlock *old_last_block = last_block; if(pu.dirty==ALL_ONES) { /* The set of uniforms has changed since this program was last used. @@ -405,7 +628,7 @@ void ProgramData::apply() const if(shared) { if(shared->dirty==ALL_ONES) - shared->used = compute_slot_mask(i->second); + update_block_uniform_indices(*shared, i->second); pu.used |= shared->used; } @@ -421,7 +644,7 @@ void ProgramData::apply() const if(!j->shared || !j->shared->dirty) continue; - update_block(*j->block, i->second); + update_block(*j->shared, i->second); j->shared->dirty = 0; buffered_blocks_updated |= (j->bind_point>=0); } @@ -432,6 +655,22 @@ void ProgramData::apply() const to avoid state thrashing. */ if(buffered_blocks_updated && !ARB_direct_state_access) buffer->bind(); + + if(last_block!=old_last_block) + { + unsigned required_size = last_block->get_required_buffer_size(); + if(last_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->storage(required_size); + } + } } for(vector::iterator i=pu.blocks.begin(); i!=pu.blocks.end(); ++i) @@ -440,12 +679,33 @@ void ProgramData::apply() const } -ProgramData::SharedBlock::SharedBlock(unsigned u, UniformBlock *b): - used(u), - dirty(u), - block(b) +ProgramData::NamedUniform::NamedUniform(): + value(0) { } +void ProgramData::NamedUniform::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(UniformBlock *b): + used(0), + dirty(0), + block(b) +{ + indices.type_flag = 0xFD; +} + +const UInt8 *ProgramData::SharedBlock::get_uniform_indices() const +{ + return (indices.type_flag==0xFE ? indices.dynamic.values : indices.values); +} + ProgramData::ProgramBlock::ProgramBlock(): bind_point(-1), @@ -455,7 +715,7 @@ ProgramData::ProgramBlock::ProgramBlock(): ProgramData::ProgramBlock::ProgramBlock(int p, SharedBlock *b): bind_point(p), - block(b ? b->block : 0), + block((b && b->used) ? b->block : 0), shared(b) { }