1 #include <msp/core/maputils.h>
2 #include <msp/debug/demangle.h>
3 #include <msp/gl/extensions/arb_direct_state_access.h>
4 #include <msp/io/print.h>
10 #include "programdata.h"
12 #include "uniformblock.h"
20 ProgramData::ProgramData(const Program *p):
27 // Blocks are intentionally left uncopied
28 ProgramData::ProgramData(const ProgramData &other):
29 tied_program(other.tied_program),
30 uniforms(other.uniforms),
35 for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
36 i->value = i->value->clone();
39 ProgramData::ProgramData(const ProgramData &other, const Program *p):
47 for(vector<NamedUniform>::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i)
48 tied_program->get_uniform_info(i->name);
51 uniforms = other.uniforms;
52 for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
53 i->value = i->value->clone();
56 ProgramData &ProgramData::operator=(const ProgramData &other)
58 tied_program = other.tied_program;
60 uniforms = other.uniforms;
61 for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
62 i->value = i->value->clone();
64 for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
65 delete i->second.block;
75 ProgramData::~ProgramData()
77 for(vector<NamedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
79 for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
81 if(i->second.indices.type_flag==0xFE)
82 delete i->second.indices.dynamic.values;
83 delete i->second.block;
88 void ProgramData::uniform(const string &name, Uniform *uni)
92 if(!validate_name(name))
104 int i = find_uniform_index(name);
106 return add_uniform(name, uni);
108 uniforms[i].replace_value(uni);
112 template<typename T, typename V>
113 void ProgramData::uniform(const string &name, V value)
115 if(!validate_name(name))
118 int i = find_uniform_index(name);
120 return add_uniform(name, new T(value));
122 if(T *uni = dynamic_cast<T *>(uniforms[i].value))
125 uniforms[i].replace_value(new T(value));
130 template<typename T, typename V>
131 void ProgramData::uniform_array(const string &name, unsigned n, V value)
133 if(!validate_name(name))
136 int i = find_uniform_index(name);
138 return add_uniform(name, new UniformArray<T>(n, value));
140 UniformArray<T> *uni = dynamic_cast<UniformArray<T> *>(uniforms[i].value);
141 if(uni && n==uni->size())
144 uniforms[i].replace_value(new UniformArray<T>(n, value));
149 bool ProgramData::validate_name(const string &name) const
156 tied_program->get_uniform_info(name);
157 else if(name[name.size()-1]==']')
158 throw invalid_argument("ProgramData::uniform");
162 catch(const exception &e)
164 IO::print(IO::cerr, "Error while setting uniform %s: %s: %s\n", name, Debug::demangle(typeid(e).name()), e.what());
170 void ProgramData::add_uniform(const string &name, Uniform *uni)
172 if(uniforms.size()>=MASK_BITS)
175 throw too_many_uniforms(name);
178 vector<NamedUniform>::iterator j = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
183 uniforms.insert(j, nu);
188 void ProgramData::uniform(const string &name, const Uniform &u)
190 uniform(name, u.clone());
193 void ProgramData::uniform(const string &name, int v)
195 uniform<Uniform1i>(name, v);
198 void ProgramData::uniform(const string &name, float v)
200 uniform<Uniform1f>(name, v);
203 void ProgramData::uniform(const string &name, int v0, int v1)
205 int va[2] = { v0, v1 };
209 void ProgramData::uniform(const string &name, float v0, float v1)
211 float va[2] = { v0, v1 };
215 void ProgramData::uniform2(const string &name, const int *v)
217 uniform<Uniform2i>(name, v);
220 void ProgramData::uniform2(const string &name, const float *v)
222 uniform<Uniform2f>(name, v);
225 void ProgramData::uniform(const string &name, int v0, int v1, int v2)
227 int va[3] = { v0, v1, v2 };
231 void ProgramData::uniform(const string &name, float v0, float v1, float v2)
233 float va[3] = { v0, v1, v2 };
237 void ProgramData::uniform(const string &name, const Vector3 &v)
239 uniform(name, v.x, v.y, v.z);
242 void ProgramData::uniform3(const string &name, const int *v)
244 uniform<Uniform3i>(name, v);
247 void ProgramData::uniform3(const string &name, const float *v)
249 uniform<Uniform3f>(name, v);
252 void ProgramData::uniform(const string &name, int v0, int v1, int v2, int v3)
254 int va[4] = { v0, v1, v2, v3 };
258 void ProgramData::uniform(const string &name, float v0, float v1, float v2, float v3)
260 float va[4] = { v0, v1, v2, v3 };
264 void ProgramData::uniform(const string &name, const Vector4 &v)
266 uniform(name, v.x, v.y, v.z, v.w);
269 void ProgramData::uniform(const string &name, const Color &c)
271 uniform(name, c.r, c.g, c.b, c.a);
274 void ProgramData::uniform4(const string &name, const int *v)
276 uniform<Uniform4i>(name, v);
279 void ProgramData::uniform4(const string &name, const float *v)
281 uniform<Uniform4f>(name, v);
284 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 2, 2> &m)
286 uniform_matrix2(name, &m(0, 0));
289 void ProgramData::uniform_matrix2(const string &name, const float *v)
291 uniform<UniformMatrix2x2f>(name, v);
294 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 2, 3> &m)
296 uniform_matrix3x2(name, &m(0, 0));
299 void ProgramData::uniform_matrix3x2(const string &name, const float *v)
301 uniform<UniformMatrix3x2f>(name, v);
304 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 2, 4> &m)
306 uniform_matrix4x2(name, &m(0, 0));
309 void ProgramData::uniform_matrix4x2(const string &name, const float *v)
311 uniform<UniformMatrix4x2f>(name, v);
314 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 3, 2> &m)
316 uniform_matrix2x3(name, &m(0, 0));
319 void ProgramData::uniform_matrix2x3(const string &name, const float *v)
321 uniform<UniformMatrix2x3f>(name, v);
324 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 3, 3> &m)
326 uniform_matrix3(name, &m(0, 0));
329 void ProgramData::uniform_matrix3(const string &name, const float *v)
331 uniform<UniformMatrix3x3f>(name, v);
334 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 3, 4> &m)
336 uniform_matrix4x3(name, &m(0, 0));
339 void ProgramData::uniform_matrix4x3(const string &name, const float *v)
341 uniform<UniformMatrix4x3f>(name, v);
344 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 4, 2> &m)
346 uniform_matrix2x4(name, &m(0, 0));
349 void ProgramData::uniform_matrix2x4(const string &name, const float *v)
351 uniform<UniformMatrix2x4f>(name, v);
354 void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 4, 3> &m)
356 uniform_matrix3x4(name, &m(0, 0));
359 void ProgramData::uniform_matrix3x4(const string &name, const float *v)
361 uniform<UniformMatrix3x4f>(name, v);
364 void ProgramData::uniform(const string &name, const Matrix &m)
366 uniform_matrix4(name, m.data());
369 void ProgramData::uniform_matrix4(const string &name, const float *v)
371 uniform<UniformMatrix4x4f>(name, v);
374 void ProgramData::uniform1_array(const string &name, unsigned n, const int *v)
376 uniform_array<Uniform1i>(name, n, v);
379 void ProgramData::uniform1_array(const string &name, unsigned n, const float *v)
381 uniform_array<Uniform1f>(name, n, v);
384 void ProgramData::uniform2_array(const string &name, unsigned n, const int *v)
386 uniform_array<Uniform2i>(name, n, v);
389 void ProgramData::uniform2_array(const string &name, unsigned n, const float *v)
391 uniform_array<Uniform2f>(name, n, v);
394 void ProgramData::uniform3_array(const string &name, unsigned n, const int *v)
396 uniform_array<Uniform3i>(name, n, v);
399 void ProgramData::uniform3_array(const string &name, unsigned n, const float *v)
401 uniform_array<Uniform3f>(name, n, v);
404 void ProgramData::uniform4_array(const string &name, unsigned n, const int *v)
406 uniform_array<Uniform4i>(name, n, v);
409 void ProgramData::uniform4_array(const string &name, unsigned n, const float *v)
411 uniform_array<Uniform4f>(name, n, v);
414 void ProgramData::uniform_matrix2_array(const string &name, unsigned n, const float *v)
416 uniform_array<UniformMatrix2x2f>(name, n, v);
419 void ProgramData::uniform_matrix3x2_array(const string &name, unsigned n, const float *v)
421 uniform_array<UniformMatrix3x2f>(name, n, v);
424 void ProgramData::uniform_matrix4x2_array(const string &name, unsigned n, const float *v)
426 uniform_array<UniformMatrix4x2f>(name, n, v);
429 void ProgramData::uniform_matrix2x3_array(const string &name, unsigned n, const float *v)
431 uniform_array<UniformMatrix2x3f>(name, n, v);
434 void ProgramData::uniform_matrix3_array(const string &name, unsigned n, const float *v)
436 uniform_array<UniformMatrix3x3f>(name, n, v);
439 void ProgramData::uniform_matrix4x3_array(const string &name, unsigned n, const float *v)
441 uniform_array<UniformMatrix4x3f>(name, n, v);
444 void ProgramData::uniform_matrix2x4_array(const string &name, unsigned n, const float *v)
446 uniform_array<UniformMatrix2x4f>(name, n, v);
449 void ProgramData::uniform_matrix3x4_array(const string &name, unsigned n, const float *v)
451 uniform_array<UniformMatrix3x4f>(name, n, v);
454 void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const float *v)
456 uniform_array<UniformMatrix4x4f>(name, n, v);
459 void ProgramData::remove_uniform(const string &name)
461 vector<NamedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
462 if(i==uniforms.end() || i->name!=name)
471 vector<string> ProgramData::get_uniform_names() const
473 vector<string> names;
474 names.reserve(uniforms.size());
475 for(vector<NamedUniform>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
476 names.push_back(i->name);
480 const Uniform &ProgramData::get_uniform(const string &name) const
482 int i = find_uniform_index(name);
484 throw key_error(name);
485 return *uniforms[i].value;
488 const Uniform *ProgramData::find_uniform(const string &name) const
490 int i = find_uniform_index(name);
491 return (i>=0 ? uniforms[i].value : 0);
494 bool ProgramData::uniform_name_compare(const NamedUniform &nu, const string &name)
499 int ProgramData::find_uniform_index(const string &name) const
501 vector<NamedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
502 return ((i!=uniforms.end() && i->name==name) ? i-uniforms.begin() : -1);
505 void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program::UniformBlockInfo &info) const
507 UInt8 *indices = block.indices.values;
508 if(info.uniforms.size()>16)
510 if(block.indices.type_flag==0xFD)
512 block.indices.dynamic.values = new UInt8[info.uniforms.size()];
513 block.indices.type_flag = 0xFE;
515 indices = block.indices.dynamic.values;
519 for(unsigned i=0; i<info.uniforms.size(); ++i)
521 int j = find_uniform_index(info.uniforms[i]->name);
525 if(static_cast<unsigned>(j)<MASK_BITS)
532 block.dirty = block.used;
535 void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockInfo &info) const
537 const UInt8 *indices = block.get_uniform_indices();
538 for(unsigned i=0; i<info.uniforms.size(); ++i)
540 block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value);
543 ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBlockInfo &info) const
545 BlockMap::iterator i = blocks.find(info.layout_hash);
548 bool any_found = false;
549 bool all_found = true;
550 for(vector<const Program::UniformInfo *>::const_iterator j=info.uniforms.begin(); j!=info.uniforms.end(); ++j)
552 if(find_uniform_index((*j)->name)>=0)
560 else if(!all_found && info.bind_point>=0)
563 IO::print(IO::cerr, "Warning: not all uniforms for block %s are present\n", info.name);
565 throw incomplete_uniform_block(info.name);
570 if(info.bind_point>=0)
573 buffer = new Buffer(UNIFORM_BUFFER);
575 block = new UniformBlock(info.data_size);
576 block->use_buffer(buffer, last_block);
580 block = new UniformBlock;
582 i = blocks.insert(BlockMap::value_type(info.layout_hash, SharedBlock(block))).first;
583 update_block_uniform_indices(i->second, info);
589 void ProgramData::apply() const
591 const Program *prog = Program::current();
593 throw invalid_operation("ProgramData::apply");
595 Program::LayoutHash layout = prog->get_uniform_layout_hash();
596 ProgramUniforms &pu = programs[layout];
598 Mask force_dirty = (dirty==ALL_ONES ? ALL_ONES : 0U);
599 Mask affected = (dirty&pu.used) | force_dirty;
600 if(affected|pu.dirty)
602 /* If the global dirty flag affects this program, add it to per-program
603 dirty flags and clear the global flag. A previously unseen program will
604 cause this to happen if there's any dirty uniforms. */
607 for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
608 i->second.dirty |= (dirty&i->second.used) | force_dirty;
609 for(ProgramMap::iterator i=programs.begin(); i!=programs.end(); ++i)
610 i->second.dirty |= (dirty&i->second.used) | force_dirty;
614 const Program::UniformBlockMap &prog_blocks = prog->get_uniform_blocks();
616 UniformBlock *old_last_block = last_block;
617 if(pu.dirty==ALL_ONES)
619 /* The set of uniforms has changed since this program was last used.
620 Regenerate the list of uniform blocks. */
622 pu.blocks.reserve(prog_blocks.size());
625 for(Program::UniformBlockMap::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i)
627 SharedBlock *shared = get_shared_block(i->second);
630 if(shared->dirty==ALL_ONES)
631 update_block_uniform_indices(*shared, i->second);
632 pu.used |= shared->used;
635 pu.blocks.push_back(ProgramBlock(i->second.bind_point, shared));
639 // Update the contents of all dirty blocks.
640 bool buffered_blocks_updated = false;
641 std::vector<ProgramBlock>::iterator j = pu.blocks.begin();
642 for(Program::UniformBlockMap::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i, ++j)
644 if(!j->shared || !j->shared->dirty)
647 update_block(*j->shared, i->second);
648 j->shared->dirty = 0;
649 buffered_blocks_updated |= (j->bind_point>=0);
654 /* If any blocks stored in the buffer were updated, bind the buffer here
655 to avoid state thrashing. */
656 if(buffered_blocks_updated && !ARB_direct_state_access)
659 if(last_block!=old_last_block)
661 unsigned required_size = last_block->get_required_buffer_size();
662 if(last_block->get_required_buffer_size()>buffer->get_size())
664 if(buffer->get_size()>0)
667 buffer = new Buffer(UNIFORM_BUFFER);
668 last_block->change_buffer(buffer);
671 buffer->storage(required_size);
676 for(vector<ProgramBlock>::iterator i=pu.blocks.begin(); i!=pu.blocks.end(); ++i)
678 i->block->apply(i->bind_point);
682 ProgramData::NamedUniform::NamedUniform():
686 void ProgramData::NamedUniform::replace_value(Uniform *v)
688 /* UniformBlock does not copy the uniforms, so existing default blocks
689 will be left with stale pointers. This is not a problem as long as no
690 one stores pointers to the blocks and expects them to stay valid. */
696 ProgramData::SharedBlock::SharedBlock(UniformBlock *b):
701 indices.type_flag = 0xFD;
704 const UInt8 *ProgramData::SharedBlock::get_uniform_indices() const
706 return (indices.type_flag==0xFE ? indices.dynamic.values : indices.values);
710 ProgramData::ProgramBlock::ProgramBlock():
716 ProgramData::ProgramBlock::ProgramBlock(int p, SharedBlock *b):
718 block((b && b->used) ? b->block : 0),
723 ProgramData::ProgramUniforms::ProgramUniforms():
729 ProgramData::Loader::Loader(ProgramData &pd):
730 DataFile::ObjectLoader<ProgramData>(pd)
732 add("uniform", &Loader::uniform1i);
733 add("uniform1i", &Loader::uniform1i);
734 add("uniform", &Loader::uniform1f);
735 add("uniform1f", &Loader::uniform1f);
736 add("uniform", &Loader::uniform2i);
737 add("uniform2i", &Loader::uniform2i);
738 add("uniform", &Loader::uniform2f);
739 add("uniform2f", &Loader::uniform2f);
740 add("uniform", &Loader::uniform3i);
741 add("uniform3i", &Loader::uniform3i);
742 add("uniform", &Loader::uniform3f);
743 add("uniform3f", &Loader::uniform3f);
744 add("uniform", &Loader::uniform4i);
745 add("uniform4i", &Loader::uniform4i);
746 add("uniform", &Loader::uniform4f);
747 add("uniform4f", &Loader::uniform4f);
748 add("uniform1i_array", &Loader::uniform1i_array);
749 add("uniform1f_array", &Loader::uniform1f_array);
750 add("uniform2f_array", &Loader::uniform2f_array);
751 add("uniform3f_array", &Loader::uniform3f_array);
752 add("uniform4f_array", &Loader::uniform4f_array);
753 add("uniform_array", &Loader::uniform_array);
756 void ProgramData::Loader::uniform1i(const string &n, int v)
761 void ProgramData::Loader::uniform1f(const string &n, float v)
766 void ProgramData::Loader::uniform2i(const string &n, int v0, int v1)
768 obj.uniform(n, v0, v1);
771 void ProgramData::Loader::uniform2f(const string &n, float v0, float v1)
773 obj.uniform(n, v0, v1);
776 void ProgramData::Loader::uniform3i(const string &n, int v0, int v1, int v2)
778 obj.uniform(n, v0, v1, v2);
781 void ProgramData::Loader::uniform3f(const string &n, float v0, float v1, float v2)
783 obj.uniform(n, v0, v1, v2);
786 void ProgramData::Loader::uniform4i(const string &n, int v0, int v1, int v2, int v3)
788 obj.uniform(n, v0, v1, v2, v3);
791 void ProgramData::Loader::uniform4f(const string &n, float v0, float v1, float v2, float v3)
793 obj.uniform(n, v0, v1, v2, v3);
796 void ProgramData::Loader::uniform_array_(const string &n, DataType t, unsigned e)
798 ArrayLoader ldr(t, e);
800 unsigned size = ldr.get_size();
802 throw logic_error("empty uniform array");
804 DataType type = ldr.get_data_type();
805 unsigned elem_size = ldr.get_element_size();
808 const int *data = reinterpret_cast<const int *>(ldr.get_data());
810 obj.uniform1_array(n, size, data);
811 else if(elem_size==2)
812 obj.uniform2_array(n, size, data);
813 else if(elem_size==3)
814 obj.uniform3_array(n, size, data);
815 else if(elem_size==4)
816 obj.uniform4_array(n, size, data);
818 throw logic_error("unsupported combination of array type and element size");
822 const float *data = reinterpret_cast<const float *>(ldr.get_data());
824 obj.uniform1_array(n, size, data);
825 else if(elem_size==2)
826 obj.uniform2_array(n, size, data);
827 else if(elem_size==3)
828 obj.uniform3_array(n, size, data);
829 else if(elem_size==4)
830 obj.uniform4_array(n, size, data);
832 throw logic_error("unsupported combination of array type and element size");
835 throw logic_error("unsupported array type");
838 void ProgramData::Loader::uniform1i_array(const string &n)
840 uniform_array_(n, INT, 1);
843 void ProgramData::Loader::uniform1f_array(const string &n)
845 uniform_array_(n, FLOAT, 1);
848 void ProgramData::Loader::uniform2i_array(const string &n)
850 uniform_array_(n, INT, 2);
853 void ProgramData::Loader::uniform2f_array(const string &n)
855 uniform_array_(n, FLOAT, 2);
858 void ProgramData::Loader::uniform3i_array(const string &n)
860 uniform_array_(n, INT, 3);
863 void ProgramData::Loader::uniform3f_array(const string &n)
865 uniform_array_(n, FLOAT, 3);
868 void ProgramData::Loader::uniform4i_array(const string &n)
870 uniform_array_(n, INT, 4);
873 void ProgramData::Loader::uniform4f_array(const string &n)
875 uniform_array_(n, FLOAT, 4);
878 void ProgramData::Loader::uniform_array(const string &n)
880 uniform_array_(n, static_cast<DataType>(0), 0);
884 ProgramData::ArrayLoader::ArrayLoader(DataType t, unsigned e):
888 add("uniform", &ArrayLoader::uniform1i);
889 add("uniform1i", &ArrayLoader::uniform1i);
890 add("uniform", &ArrayLoader::uniform1f);
891 add("uniform1f", &ArrayLoader::uniform1f);
892 add("uniform", &ArrayLoader::uniform2f);
893 add("uniform2f", &ArrayLoader::uniform2f);
894 add("uniform", &ArrayLoader::uniform3f);
895 add("uniform3f", &ArrayLoader::uniform3f);
896 add("uniform", &ArrayLoader::uniform4f);
897 add("uniform4f", &ArrayLoader::uniform4f);
900 void ProgramData::ArrayLoader::uniform(DataType t, unsigned e, const void *v)
902 if(element_size && (t!=type || e!=element_size))
903 throw logic_error("heterogeneous array contents");
911 const char *cv = reinterpret_cast<const char *>(v);
912 data.insert(data.end(), cv, cv+element_size*4);
915 void ProgramData::ArrayLoader::uniform1i(int v)
920 void ProgramData::ArrayLoader::uniform1f(float v)
922 uniform(FLOAT, 1, &v);
925 void ProgramData::ArrayLoader::uniform2i(int v0, int v1)
927 int va[2] = { v0, v1 };
931 void ProgramData::ArrayLoader::uniform2f(float v0, float v1)
933 float va[2] = { v0, v1 };
934 uniform(FLOAT, 2, va);
937 void ProgramData::ArrayLoader::uniform3i(int v0, int v1, int v2)
939 int va[3] = { v0, v1, v2 };
943 void ProgramData::ArrayLoader::uniform3f(float v0, float v1, float v2)
945 float va[3] = { v0, v1, v2 };
946 uniform(FLOAT, 3, va);
949 void ProgramData::ArrayLoader::uniform4i(int v0, int v1, int v2, int v3)
951 int va[4] = { v0, v1, v2, v3 };
955 void ProgramData::ArrayLoader::uniform4f(float v0, float v1, float v2, float v3)
957 float va[4] = { v0, v1, v2, v3 };
958 uniform(FLOAT, 4, va);