+#include <msp/core/algorithm.h>
#include <msp/core/maputils.h>
#include <msp/debug/demangle.h>
#include <msp/gl/extensions/arb_direct_state_access.h>
#include "color.h"
#include "error.h"
#include "matrix.h"
+#include "pipelinestate.h"
#include "program.h"
#include "programdata.h"
#include "uniform.h"
ProgramData::ProgramData(const Program *p):
tied_program(p),
- last_block(0),
+ generation(0),
+ last_buffer_block(0),
buffer(0),
dirty(0)
{ }
ProgramData::ProgramData(const ProgramData &other):
tied_program(other.tied_program),
uniforms(other.uniforms),
- last_block(0),
+ generation(other.generation),
+ last_buffer_block(0),
buffer(0),
dirty(0)
{
- for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+ for(vector<TaggedUniform>::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<NamedUniform>::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i)
- validate_name(i->name);
+ for(vector<TaggedUniform>::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i)
+ validate_tag(i->tag);
}
uniforms = other.uniforms;
- for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+ for(vector<TaggedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
i->value = i->value->clone();
}
tied_program = other.tied_program;
uniforms = other.uniforms;
- for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+ 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;
+ last_buffer_block = 0;
buffer = 0;
dirty = 0;
ProgramData::~ProgramData()
{
- for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+ 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;
}
-void ProgramData::uniform(const string &name, Uniform *uni)
+void ProgramData::uniform(Tag tag, Uniform *uni)
{
try
{
- if(!validate_name(name))
+ if(!validate_tag(tag))
{
delete uni;
return;
throw;
}
- int i = find_uniform_index(name);
+ int i = find_uniform_index(tag);
if(i<0)
- return add_uniform(name, uni);
+ return add_uniform(tag, uni);
uniforms[i].replace_value(uni);
- dirty |= 1<<i;
+ mark_dirty(1<<i);
}
template<typename T, typename V>
-void ProgramData::uniform(const string &name, V value)
+void ProgramData::uniform(Tag tag, V value)
{
- if(!validate_name(name))
+ if(!validate_tag(tag))
return;
- int i = find_uniform_index(name);
+ int i = find_uniform_index(tag);
if(i<0)
- return add_uniform(name, new T(value));
+ return add_uniform(tag, new T(value));
if(T *uni = dynamic_cast<T *>(uniforms[i].value))
uni->set(value);
else
uniforms[i].replace_value(new T(value));
- dirty |= 1<<i;
+ mark_dirty(1<<i);
}
template<typename T, typename V>
-void ProgramData::uniform_array(const string &name, unsigned n, V value)
+void ProgramData::uniform_array(Tag tag, unsigned n, V value)
{
- if(!validate_name(name))
+ if(!validate_tag(tag))
return;
- int i = find_uniform_index(name);
+ int i = find_uniform_index(tag);
if(i<0)
- return add_uniform(name, new UniformArray<T>(n, value));
+ return add_uniform(tag, new UniformArray<T>(n, value));
UniformArray<T> *uni = dynamic_cast<UniformArray<T> *>(uniforms[i].value);
if(uni && n==uni->size())
else
uniforms[i].replace_value(new UniformArray<T>(n, value));
- dirty |= 1<<i;
+ mark_dirty(1<<i);
}
-bool ProgramData::validate_name(const string &name) const
+bool ProgramData::validate_tag(Tag tag) const
{
#ifdef DEBUG
try
#endif
{
if(tied_program)
- tied_program->get_uniform_info(name);
- else if(name[name.size()-1]==']')
- throw invalid_argument("ProgramData::uniform");
+ {
+ const Program::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::add_uniform(Tag tag, Uniform *uni)
{
if(uniforms.size()>=MASK_BITS)
{
delete uni;
- throw too_many_uniforms(name);
+ throw too_many_uniforms(tag.str());
}
- vector<NamedUniform>::iterator j = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
+ vector<TaggedUniform>::iterator j = lower_bound_member(uniforms, tag, &TaggedUniform::tag);
- NamedUniform nu;
- nu.name = name;
+ TaggedUniform nu;
+ nu.tag = tag;
nu.value = uni;
uniforms.insert(j, nu);
- dirty = ALL_ONES;
+ mark_dirty(ALL_ONES);
+}
+
+void ProgramData::mark_dirty(Mask bits)
+{
+ if(!dirty)
+ ++generation;
+ dirty |= bits;
}
-void ProgramData::uniform(const string &name, const Uniform &u)
+void ProgramData::uniform(Tag tag, const Uniform &u)
{
- uniform(name, u.clone());
+ uniform(tag, u.clone());
}
-void ProgramData::uniform(const string &name, int v)
+void ProgramData::uniform(Tag tag, int v)
{
- uniform<Uniform1i>(name, v);
+ uniform<Uniform1i>(tag, v);
}
-void ProgramData::uniform(const string &name, float v)
+void ProgramData::uniform(Tag tag, float v)
{
- uniform<Uniform1f>(name, v);
+ uniform<Uniform1f>(tag, 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<Uniform2i>(name, v);
+ uniform<Uniform2i>(tag, v);
}
-void ProgramData::uniform2(const string &name, const float *v)
+void ProgramData::uniform2(Tag tag, const float *v)
{
- uniform<Uniform2f>(name, v);
+ uniform<Uniform2f>(tag, 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<Uniform3i>(name, v);
+ uniform<Uniform3i>(tag, v);
}
-void ProgramData::uniform3(const string &name, const float *v)
+void ProgramData::uniform3(Tag tag, const float *v)
{
- uniform<Uniform3f>(name, v);
+ uniform<Uniform3f>(tag, 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);
-}
-
-void ProgramData::uniform(const string &name, const Vector4 &v)
-{
- uniform(name, v.x, v.y, v.z, v.w);
-}
-
-void ProgramData::uniform(const string &name, const Color &c)
-{
- uniform(name, c.r, c.g, c.b, c.a);
-}
-
-void ProgramData::uniform4(const string &name, const int *v)
-{
- uniform<Uniform4i>(name, v);
-}
-
-void ProgramData::uniform4(const string &name, const float *v)
-{
- uniform<Uniform4f>(name, v);
-}
-
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 2, 2> &m)
-{
- uniform_matrix2(name, &m(0, 0));
-}
-
-void ProgramData::uniform_matrix2(const string &name, const float *v)
-{
- uniform<UniformMatrix2x2f>(name, v);
-}
-
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 2, 3> &m)
-{
- uniform_matrix3x2(name, &m(0, 0));
+ uniform4(tag, va);
}
-void ProgramData::uniform_matrix3x2(const string &name, const float *v)
+void ProgramData::uniform(Tag tag, const Color &c)
{
- uniform<UniformMatrix3x2f>(name, v);
+ uniform(tag, c.r, c.g, c.b, c.a);
}
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 2, 4> &m)
+void ProgramData::uniform4(Tag tag, const int *v)
{
- uniform_matrix4x2(name, &m(0, 0));
+ uniform<Uniform4i>(tag, v);
}
-void ProgramData::uniform_matrix4x2(const string &name, const float *v)
+void ProgramData::uniform4(Tag tag, const float *v)
{
- uniform<UniformMatrix4x2f>(name, v);
+ uniform<Uniform4f>(tag, v);
}
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 3, 2> &m)
+void ProgramData::uniform_matrix2(Tag tag, const float *v)
{
- uniform_matrix2x3(name, &m(0, 0));
+ uniform<UniformMatrix2x2f>(tag, v);
}
-void ProgramData::uniform_matrix2x3(const string &name, const float *v)
+void ProgramData::uniform_matrix3x2(Tag tag, const float *v)
{
- uniform<UniformMatrix2x3f>(name, v);
+ uniform<UniformMatrix3x2f>(tag, v);
}
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 3, 3> &m)
+void ProgramData::uniform_matrix4x2(Tag tag, const float *v)
{
- uniform_matrix3(name, &m(0, 0));
+ uniform<UniformMatrix4x2f>(tag, v);
}
-void ProgramData::uniform_matrix3(const string &name, const float *v)
+void ProgramData::uniform_matrix2x3(Tag tag, const float *v)
{
- uniform<UniformMatrix3x3f>(name, v);
+ uniform<UniformMatrix2x3f>(tag, v);
}
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 3, 4> &m)
+void ProgramData::uniform_matrix3(Tag tag, const float *v)
{
- uniform_matrix4x3(name, &m(0, 0));
+ uniform<UniformMatrix3x3f>(tag, v);
}
-void ProgramData::uniform_matrix4x3(const string &name, const float *v)
+void ProgramData::uniform_matrix4x3(Tag tag, const float *v)
{
- uniform<UniformMatrix4x3f>(name, v);
+ uniform<UniformMatrix4x3f>(tag, v);
}
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 4, 2> &m)
+void ProgramData::uniform_matrix2x4(Tag tag, const float *v)
{
- uniform_matrix2x4(name, &m(0, 0));
+ uniform<UniformMatrix2x4f>(tag, v);
}
-void ProgramData::uniform_matrix2x4(const string &name, const float *v)
+void ProgramData::uniform_matrix3x4(Tag tag, const float *v)
{
- uniform<UniformMatrix2x4f>(name, v);
+ uniform<UniformMatrix3x4f>(tag, v);
}
-void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 4, 3> &m)
+void ProgramData::uniform(Tag tag, const Matrix &m)
{
- uniform_matrix3x4(name, &m(0, 0));
+ uniform_matrix4(tag, m.data());
}
-void ProgramData::uniform_matrix3x4(const string &name, const float *v)
+void ProgramData::uniform_matrix4(Tag tag, const float *v)
{
- uniform<UniformMatrix3x4f>(name, v);
+ uniform<UniformMatrix4x4f>(tag, v);
}
-void ProgramData::uniform(const string &name, const Matrix &m)
+void ProgramData::uniform_array(Tag tag, unsigned n, const int *v)
{
- uniform_matrix4(name, m.data());
+ uniform_array<Uniform1i>(tag, n, v);
}
-void ProgramData::uniform_matrix4(const string &name, const float *v)
+void ProgramData::uniform_array(Tag tag, unsigned n, const float *v)
{
- uniform<UniformMatrix4x4f>(name, v);
+ uniform_array<Uniform1f>(tag, n, v);
}
-void ProgramData::uniform1_array(const string &name, unsigned n, const int *v)
+void ProgramData::uniform1_array(Tag tag, unsigned n, const int *v)
{
- uniform_array<Uniform1i>(name, n, v);
+ uniform_array<Uniform1i>(tag, n, v);
}
-void ProgramData::uniform1_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform1_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<Uniform1f>(name, n, v);
+ uniform_array<Uniform1f>(tag, n, v);
}
-void ProgramData::uniform2_array(const string &name, unsigned n, const int *v)
+void ProgramData::uniform2_array(Tag tag, unsigned n, const int *v)
{
- uniform_array<Uniform2i>(name, n, v);
+ uniform_array<Uniform2i>(tag, n, v);
}
-void ProgramData::uniform2_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform2_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<Uniform2f>(name, n, v);
+ uniform_array<Uniform2f>(tag, n, v);
}
-void ProgramData::uniform3_array(const string &name, unsigned n, const int *v)
+void ProgramData::uniform3_array(Tag tag, unsigned n, const int *v)
{
- uniform_array<Uniform3i>(name, n, v);
+ uniform_array<Uniform3i>(tag, n, v);
}
-void ProgramData::uniform3_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform3_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<Uniform3f>(name, n, v);
+ uniform_array<Uniform3f>(tag, n, v);
}
-void ProgramData::uniform4_array(const string &name, unsigned n, const int *v)
+void ProgramData::uniform4_array(Tag tag, unsigned n, const int *v)
{
- uniform_array<Uniform4i>(name, n, v);
+ uniform_array<Uniform4i>(tag, n, v);
}
-void ProgramData::uniform4_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform4_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<Uniform4f>(name, n, v);
+ uniform_array<Uniform4f>(tag, n, v);
}
-void ProgramData::uniform_matrix2_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix2_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix2x2f>(name, n, v);
+ uniform_array<UniformMatrix2x2f>(tag, n, v);
}
-void ProgramData::uniform_matrix3x2_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix3x2_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix3x2f>(name, n, v);
+ uniform_array<UniformMatrix3x2f>(tag, n, v);
}
-void ProgramData::uniform_matrix4x2_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix4x2_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix4x2f>(name, n, v);
+ uniform_array<UniformMatrix4x2f>(tag, n, v);
}
-void ProgramData::uniform_matrix2x3_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix2x3_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix2x3f>(name, n, v);
+ uniform_array<UniformMatrix2x3f>(tag, n, v);
}
-void ProgramData::uniform_matrix3_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix3_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix3x3f>(name, n, v);
+ uniform_array<UniformMatrix3x3f>(tag, n, v);
}
-void ProgramData::uniform_matrix4x3_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix4x3_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix4x3f>(name, n, v);
+ uniform_array<UniformMatrix4x3f>(tag, n, v);
}
-void ProgramData::uniform_matrix2x4_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix2x4_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix2x4f>(name, n, v);
+ uniform_array<UniformMatrix2x4f>(tag, n, v);
}
-void ProgramData::uniform_matrix3x4_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix3x4_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix3x4f>(name, n, v);
+ uniform_array<UniformMatrix3x4f>(tag, n, v);
}
-void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const float *v)
+void ProgramData::uniform_matrix4_array(Tag tag, unsigned n, const float *v)
{
- uniform_array<UniformMatrix4x4f>(name, n, v);
+ uniform_array<UniformMatrix4x4f>(tag, n, v);
}
-void ProgramData::remove_uniform(const string &name)
+void ProgramData::remove_uniform(Tag tag)
{
- vector<NamedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
- if(i==uniforms.end() || i->name!=name)
+ vector<TaggedUniform>::const_iterator i = lower_bound_member(uniforms, tag, &TaggedUniform::tag);
+ if(i==uniforms.end() || i->tag!=tag)
return;
delete i->value;
uniforms.erase(i);
- dirty = ALL_ONES;
+ mark_dirty(ALL_ONES);
}
-vector<string> ProgramData::get_uniform_names() const
+vector<Tag> ProgramData::get_uniform_tags() const
{
- vector<string> names;
- names.reserve(uniforms.size());
- for(vector<NamedUniform>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
- names.push_back(i->name);
- return names;
+ vector<Tag> tags;
+ tags.reserve(uniforms.size());
+ for(vector<TaggedUniform>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+ tags.push_back(i->tag);
+ return tags;
}
-const Uniform &ProgramData::get_uniform(const string &name) const
+const Uniform &ProgramData::get_uniform(Tag tag) const
{
- int i = find_uniform_index(name);
+ int i = find_uniform_index(tag);
if(i<0)
- throw key_error(name);
+ throw key_error(tag);
return *uniforms[i].value;
}
-const Uniform *ProgramData::find_uniform(const string &name) const
+const Uniform *ProgramData::find_uniform(Tag tag) const
{
- int i = find_uniform_index(name);
+ int i = find_uniform_index(tag);
return (i>=0 ? uniforms[i].value : 0);
}
-bool ProgramData::uniform_name_compare(const NamedUniform &nu, const string &name)
+int ProgramData::find_uniform_index(Tag tag) const
{
- return nu.name<name;
+ vector<TaggedUniform>::const_iterator i = lower_bound_member(uniforms, tag, &TaggedUniform::tag);
+ return ((i!=uniforms.end() && i->tag==tag) ? i-uniforms.begin() : -1);
}
-int ProgramData::find_uniform_index(const string &name) const
+vector<ProgramData::ProgramBlock>::iterator ProgramData::get_program(const Program &prog) const
{
- vector<NamedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
- return ((i!=uniforms.end() && i->name==name) ? i-uniforms.begin() : -1);
+ 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
indices = block.indices.dynamic.values;
}
+ bool any_missing = false;
+
block.used = 0;
for(unsigned i=0; i<info.uniforms.size(); ++i)
{
- int j = find_uniform_index(info.uniforms[i]->name);
+ int j = find_uniform_index(info.uniforms[i]->tag);
if(j>=0)
{
indices[i] = j;
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
- }
+ }
- UniformBlock *block;
+ block.dirty = block.used;
+
+ if(block.used && !block.block)
+ {
if(info.bind_point>=0)
{
if(!buffer)
- buffer = new Buffer(UNIFORM_BUFFER);
+ {
+ buffer = new Buffer();
+
+#ifdef DEBUG
+ if(!debug_name.empty())
+ buffer->set_debug_name(debug_name);
+#endif
+ }
- block = new UniformBlock(info.data_size);
- block->use_buffer(buffer, last_block);
- last_block = block;
+ BufferBackedUniformBlock *bb_block = new BufferBackedUniformBlock(info.data_size);
+ block.block = bb_block;
+ bb_block->use_buffer(buffer, last_buffer_block);
+ last_buffer_block = bb_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 DefaultUniformBlock;
}
-
- return &i->second;
}
-void ProgramData::apply() const
+void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockInfo &info) const
{
- const Program *prog = Program::current();
- if(!prog)
- throw invalid_operation("ProgramData::apply");
+ const UInt8 *indices = block.get_uniform_indices();
+ for(unsigned i=0; i<info.uniforms.size(); ++i)
+ {
+ if(is_image(info.uniforms[i]->type))
+ ; // Temporarily ignore deprecated use of sampler uniforms in ProgramData
+ else if(indices[i]!=0xFF)
+ block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value);
+ }
+}
- Program::LayoutHash layout = prog->get_uniform_layout_hash();
- ProgramUniforms &pu = programs[layout];
+vector<ProgramData::ProgramBlock>::const_iterator ProgramData::prepare_program(const Program &prog) const
+{
+ BufferBackedUniformBlock *old_last_block = last_buffer_block;
+ vector<ProgramBlock>::iterator 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(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;
- std::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;
-
- /* 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();
+ prog_begin->masks.dirty = 0;
- 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);
}
}
- for(vector<ProgramBlock>::iterator i=pu.blocks.begin(); i!=pu.blocks.end(); ++i)
+ return prog_begin;
+}
+
+void ProgramData::apply(const Program &prog, PipelineState &state) const
+{
+ vector<ProgramBlock>::const_iterator prog_begin = prepare_program(prog);
+ Program::LayoutHash prog_hash = prog_begin->prog_hash;
+ for(vector<ProgramBlock>::const_iterator i=prog_begin+1; (i!=programs.end() && i->prog_hash==prog_hash); ++i)
if(i->block)
- i->block->apply(i->bind_point);
+ {
+ if(i->bind_point<0)
+ state.set_uniforms(static_cast<const DefaultUniformBlock *>(i->block));
+ else
+ {
+ const BufferBackedUniformBlock *block = static_cast<const BufferBackedUniformBlock *>(i->block);
+ block->refresh();
+ state.set_uniform_block(i->bind_point, block);
+ }
+ }
+}
+
+void ProgramData::set_debug_name(const string &name)
+{
+#ifdef DEBUG
+ debug_name = name;
+ if(buffer)
+ buffer->set_debug_name(name);
+#else
+ (void)name;
+#endif
}
-ProgramData::NamedUniform::NamedUniform():
+ProgramData::TaggedUniform::TaggedUniform():
value(0)
{ }
-void ProgramData::NamedUniform::replace_value(Uniform *v)
+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
}
-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;
}
}
-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):