]> git.tdb.fi Git - libs/gl.git/blob - source/render/programdata.cpp
Use Tag to identify uniforms in Program and ProgramData
[libs/gl.git] / source / render / programdata.cpp
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>
5 #include "buffer.h"
6 #include "color.h"
7 #include "error.h"
8 #include "matrix.h"
9 #include "program.h"
10 #include "programdata.h"
11 #include "uniform.h"
12 #include "uniformblock.h"
13 #include "vector.h"
14
15 using namespace std;
16
17 namespace Msp {
18 namespace GL {
19
20 ProgramData::ProgramData(const Program *p):
21         tied_program(p),
22         last_block(0),
23         buffer(0),
24         dirty(0)
25 { }
26
27 // Blocks are intentionally left uncopied
28 ProgramData::ProgramData(const ProgramData &other):
29         tied_program(other.tied_program),
30         uniforms(other.uniforms),
31         last_block(0),
32         buffer(0),
33         dirty(0)
34 {
35         for(vector<TaggedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
36                 i->value = i->value->clone();
37 }
38
39 ProgramData::ProgramData(const ProgramData &other, const Program *p):
40         tied_program(p),
41         last_block(0),
42         buffer(0),
43         dirty(0)
44 {
45         if(tied_program)
46         {
47                 for(vector<TaggedUniform>::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i)
48                         validate_tag(i->tag);
49         }
50
51         uniforms = other.uniforms;
52         for(vector<TaggedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
53                 i->value = i->value->clone();
54 }
55
56 ProgramData &ProgramData::operator=(const ProgramData &other)
57 {
58         tied_program = other.tied_program;
59
60         uniforms = other.uniforms;
61         for(vector<TaggedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
62                 i->value = i->value->clone();
63
64         for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
65                 delete i->second.block;
66         programs.clear();
67
68         last_block = 0;
69         buffer = 0;
70         dirty = 0;
71
72         return *this;
73 }
74
75 ProgramData::~ProgramData()
76 {
77         for(vector<TaggedUniform>::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
78                 delete i->value;
79         for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
80         {
81                 if(i->second.indices.type_flag==0xFE)
82                         delete[] i->second.indices.dynamic.values;
83                 delete i->second.block;
84         }
85         delete buffer;
86 }
87
88 void ProgramData::uniform(Tag tag, Uniform *uni)
89 {
90         try
91         {
92                 if(!validate_tag(tag))
93                 {
94                         delete uni;
95                         return;
96                 }
97         }
98         catch(...)
99         {
100                 delete uni;
101                 throw;
102         }
103
104         int i = find_uniform_index(tag);
105         if(i<0)
106                 return add_uniform(tag, uni);
107
108         uniforms[i].replace_value(uni);
109         dirty |= 1<<i;
110 }
111
112 template<typename T, typename V>
113 void ProgramData::uniform(Tag tag, V value)
114 {
115         if(!validate_tag(tag))
116                 return;
117
118         int i = find_uniform_index(tag);
119         if(i<0)
120                 return add_uniform(tag, new T(value));
121
122         if(T *uni = dynamic_cast<T *>(uniforms[i].value))
123                 uni->set(value);
124         else
125                 uniforms[i].replace_value(new T(value));
126
127         dirty |= 1<<i;
128 }
129
130 template<typename T, typename V>
131 void ProgramData::uniform_array(Tag tag, unsigned n, V value)
132 {
133         if(!validate_tag(tag))
134                 return;
135
136         int i = find_uniform_index(tag);
137         if(i<0)
138                 return add_uniform(tag, new UniformArray<T>(n, value));
139
140         UniformArray<T> *uni = dynamic_cast<UniformArray<T> *>(uniforms[i].value);
141         if(uni && n==uni->size())
142                 uni->set(value);
143         else
144                 uniforms[i].replace_value(new UniformArray<T>(n, value));
145
146         dirty |= 1<<i;
147 }
148
149 bool ProgramData::validate_tag(Tag tag) const
150 {
151 #ifdef DEBUG
152         try
153 #endif
154         {
155                 if(tied_program)
156                         tied_program->get_uniform_info(tag);
157                 return true;
158         }
159 #ifdef DEBUG
160         catch(const exception &e)
161         {
162                 IO::print(IO::cerr, "Error while setting uniform %s: %s: %s\n", tag, Debug::demangle(typeid(e).name()), e.what());
163                 return false;
164         }
165 #endif
166 }
167
168 void ProgramData::add_uniform(Tag tag, Uniform *uni)
169 {
170         if(uniforms.size()>=MASK_BITS)
171         {
172                 delete uni;
173                 throw too_many_uniforms(tag.str());
174         }
175
176         vector<TaggedUniform>::iterator j = lower_bound(uniforms.begin(), uniforms.end(), tag, uniform_tag_compare);
177
178         TaggedUniform nu;
179         nu.tag = tag;
180         nu.value = uni;
181         uniforms.insert(j, nu);
182
183         dirty = ALL_ONES;
184 }
185
186 void ProgramData::uniform(Tag tag, const Uniform &u)
187 {
188         uniform(tag, u.clone());
189 }
190
191 void ProgramData::uniform(Tag tag, int v)
192 {
193         uniform<Uniform1i>(tag, v);
194 }
195
196 void ProgramData::uniform(Tag tag, float v)
197 {
198         uniform<Uniform1f>(tag, v);
199 }
200
201 void ProgramData::uniform(Tag tag, int v0, int v1)
202 {
203         int va[2] = { v0, v1 };
204         uniform2(tag, va);
205 }
206
207 void ProgramData::uniform(Tag tag, float v0, float v1)
208 {
209         float va[2] = { v0, v1 };
210         uniform2(tag, va);
211 }
212
213 void ProgramData::uniform2(Tag tag, const int *v)
214 {
215         uniform<Uniform2i>(tag, v);
216 }
217
218 void ProgramData::uniform2(Tag tag, const float *v)
219 {
220         uniform<Uniform2f>(tag, v);
221 }
222
223 void ProgramData::uniform(Tag tag, int v0, int v1, int v2)
224 {
225         int va[3] = { v0, v1, v2 };
226         uniform3(tag, va);
227 }
228
229 void ProgramData::uniform(Tag tag, float v0, float v1, float v2)
230 {
231         float va[3] = { v0, v1, v2 };
232         uniform3(tag, va);
233 }
234
235 void ProgramData::uniform(Tag tag, const Vector3 &v)
236 {
237         uniform(tag, v.x, v.y, v.z);
238 }
239
240 void ProgramData::uniform3(Tag tag, const int *v)
241 {
242         uniform<Uniform3i>(tag, v);
243 }
244
245 void ProgramData::uniform3(Tag tag, const float *v)
246 {
247         uniform<Uniform3f>(tag, v);
248 }
249
250 void ProgramData::uniform(Tag tag, int v0, int v1, int v2, int v3)
251 {
252         int va[4] = { v0, v1, v2, v3 };
253         uniform4(tag, va);
254 }
255
256 void ProgramData::uniform(Tag tag, float v0, float v1, float v2, float v3)
257 {
258         float va[4] = { v0, v1, v2, v3 };
259         uniform4(tag, va);
260 }
261
262 void ProgramData::uniform(Tag tag, const Vector4 &v)
263 {
264         uniform(tag, v.x, v.y, v.z, v.w);
265 }
266
267 void ProgramData::uniform(Tag tag, const Color &c)
268 {
269         uniform(tag, c.r, c.g, c.b, c.a);
270 }
271
272 void ProgramData::uniform4(Tag tag, const int *v)
273 {
274         uniform<Uniform4i>(tag, v);
275 }
276
277 void ProgramData::uniform4(Tag tag, const float *v)
278 {
279         uniform<Uniform4f>(tag, v);
280 }
281
282 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 2, 2> &m)
283 {
284         uniform_matrix2(tag, &m(0, 0));
285 }
286
287 void ProgramData::uniform_matrix2(Tag tag, const float *v)
288 {
289         uniform<UniformMatrix2x2f>(tag, v);
290 }
291
292 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 2, 3> &m)
293 {
294         uniform_matrix3x2(tag, &m(0, 0));
295 }
296
297 void ProgramData::uniform_matrix3x2(Tag tag, const float *v)
298 {
299         uniform<UniformMatrix3x2f>(tag, v);
300 }
301
302 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 2, 4> &m)
303 {
304         uniform_matrix4x2(tag, &m(0, 0));
305 }
306
307 void ProgramData::uniform_matrix4x2(Tag tag, const float *v)
308 {
309         uniform<UniformMatrix4x2f>(tag, v);
310 }
311
312 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 3, 2> &m)
313 {
314         uniform_matrix2x3(tag, &m(0, 0));
315 }
316
317 void ProgramData::uniform_matrix2x3(Tag tag, const float *v)
318 {
319         uniform<UniformMatrix2x3f>(tag, v);
320 }
321
322 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 3, 3> &m)
323 {
324         uniform_matrix3(tag, &m(0, 0));
325 }
326
327 void ProgramData::uniform_matrix3(Tag tag, const float *v)
328 {
329         uniform<UniformMatrix3x3f>(tag, v);
330 }
331
332 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 3, 4> &m)
333 {
334         uniform_matrix4x3(tag, &m(0, 0));
335 }
336
337 void ProgramData::uniform_matrix4x3(Tag tag, const float *v)
338 {
339         uniform<UniformMatrix4x3f>(tag, v);
340 }
341
342 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 4, 2> &m)
343 {
344         uniform_matrix2x4(tag, &m(0, 0));
345 }
346
347 void ProgramData::uniform_matrix2x4(Tag tag, const float *v)
348 {
349         uniform<UniformMatrix2x4f>(tag, v);
350 }
351
352 void ProgramData::uniform(Tag tag, const LinAl::Matrix<float, 4, 3> &m)
353 {
354         uniform_matrix3x4(tag, &m(0, 0));
355 }
356
357 void ProgramData::uniform_matrix3x4(Tag tag, const float *v)
358 {
359         uniform<UniformMatrix3x4f>(tag, v);
360 }
361
362 void ProgramData::uniform(Tag tag, const Matrix &m)
363 {
364         uniform_matrix4(tag, m.data());
365 }
366
367 void ProgramData::uniform_matrix4(Tag tag, const float *v)
368 {
369         uniform<UniformMatrix4x4f>(tag, v);
370 }
371
372 void ProgramData::uniform1_array(Tag tag, unsigned n, const int *v)
373 {
374         uniform_array<Uniform1i>(tag, n, v);
375 }
376
377 void ProgramData::uniform1_array(Tag tag, unsigned n, const float *v)
378 {
379         uniform_array<Uniform1f>(tag, n, v);
380 }
381
382 void ProgramData::uniform2_array(Tag tag, unsigned n, const int *v)
383 {
384         uniform_array<Uniform2i>(tag, n, v);
385 }
386
387 void ProgramData::uniform2_array(Tag tag, unsigned n, const float *v)
388 {
389         uniform_array<Uniform2f>(tag, n, v);
390 }
391
392 void ProgramData::uniform3_array(Tag tag, unsigned n, const int *v)
393 {
394         uniform_array<Uniform3i>(tag, n, v);
395 }
396
397 void ProgramData::uniform3_array(Tag tag, unsigned n, const float *v)
398 {
399         uniform_array<Uniform3f>(tag, n, v);
400 }
401
402 void ProgramData::uniform4_array(Tag tag, unsigned n, const int *v)
403 {
404         uniform_array<Uniform4i>(tag, n, v);
405 }
406
407 void ProgramData::uniform4_array(Tag tag, unsigned n, const float *v)
408 {
409         uniform_array<Uniform4f>(tag, n, v);
410 }
411
412 void ProgramData::uniform_matrix2_array(Tag tag, unsigned n, const float *v)
413 {
414         uniform_array<UniformMatrix2x2f>(tag, n, v);
415 }
416
417 void ProgramData::uniform_matrix3x2_array(Tag tag, unsigned n, const float *v)
418 {
419         uniform_array<UniformMatrix3x2f>(tag, n, v);
420 }
421
422 void ProgramData::uniform_matrix4x2_array(Tag tag, unsigned n, const float *v)
423 {
424         uniform_array<UniformMatrix4x2f>(tag, n, v);
425 }
426
427 void ProgramData::uniform_matrix2x3_array(Tag tag, unsigned n, const float *v)
428 {
429         uniform_array<UniformMatrix2x3f>(tag, n, v);
430 }
431
432 void ProgramData::uniform_matrix3_array(Tag tag, unsigned n, const float *v)
433 {
434         uniform_array<UniformMatrix3x3f>(tag, n, v);
435 }
436
437 void ProgramData::uniform_matrix4x3_array(Tag tag, unsigned n, const float *v)
438 {
439         uniform_array<UniformMatrix4x3f>(tag, n, v);
440 }
441
442 void ProgramData::uniform_matrix2x4_array(Tag tag, unsigned n, const float *v)
443 {
444         uniform_array<UniformMatrix2x4f>(tag, n, v);
445 }
446
447 void ProgramData::uniform_matrix3x4_array(Tag tag, unsigned n, const float *v)
448 {
449         uniform_array<UniformMatrix3x4f>(tag, n, v);
450 }
451
452 void ProgramData::uniform_matrix4_array(Tag tag, unsigned n, const float *v)
453 {
454         uniform_array<UniformMatrix4x4f>(tag, n, v);
455 }
456
457 void ProgramData::remove_uniform(Tag tag)
458 {
459         vector<TaggedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), tag, uniform_tag_compare);
460         if(i==uniforms.end() || i->tag!=tag)
461                 return;
462
463         delete i->value;
464         uniforms.erase(i);
465
466         dirty = ALL_ONES;
467 }
468
469 vector<Tag> ProgramData::get_uniform_tags() const
470 {
471         vector<Tag> tags;
472         tags.reserve(uniforms.size());
473         for(vector<TaggedUniform>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
474                 tags.push_back(i->tag);
475         return tags;
476 }
477
478 const Uniform &ProgramData::get_uniform(Tag tag) const
479 {
480         int i = find_uniform_index(tag);
481         if(i<0)
482                 throw key_error(tag);
483         return *uniforms[i].value;
484 }
485
486 const Uniform *ProgramData::find_uniform(Tag tag) const
487 {
488         int i = find_uniform_index(tag);
489         return (i>=0 ? uniforms[i].value : 0);
490 }
491
492 bool ProgramData::uniform_tag_compare(const TaggedUniform &tu, Tag tag)
493 {
494         return tu.tag<tag;
495 }
496
497 int ProgramData::find_uniform_index(Tag tag) const
498 {
499         vector<TaggedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), tag, uniform_tag_compare);
500         return ((i!=uniforms.end() && i->tag==tag) ? i-uniforms.begin() : -1);
501 }
502
503 void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program::UniformBlockInfo &info) const
504 {
505         UInt8 *indices = block.indices.values;
506         if(info.uniforms.size()>16)
507         {
508                 if(block.indices.type_flag==0xFD)
509                 {
510                         block.indices.dynamic.values = new UInt8[info.uniforms.size()];
511                         block.indices.type_flag = 0xFE;
512                 }
513                 indices = block.indices.dynamic.values;
514         }
515
516         block.used = 0;
517         for(unsigned i=0; i<info.uniforms.size(); ++i)
518         {
519                 int j = find_uniform_index(info.uniforms[i]->tag);
520                 if(j>=0)
521                 {
522                         indices[i] = j;
523                         if(static_cast<unsigned>(j)<MASK_BITS)
524                                 block.used |= 1<<j;
525                 }
526                 else
527                         indices[i] = 0xFF;
528         }
529
530         block.dirty = block.used;
531 }
532
533 void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockInfo &info) const
534 {
535         const UInt8 *indices = block.get_uniform_indices();
536         for(unsigned i=0; i<info.uniforms.size(); ++i)
537                 if(indices[i]!=0xFF)
538                         block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value);
539 }
540
541 ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBlockInfo &info) const
542 {
543         BlockMap::iterator i = blocks.find(info.layout_hash);
544         if(i==blocks.end())
545         {
546                 bool any_found = false;
547                 bool all_found = true;
548                 for(vector<const Program::UniformInfo *>::const_iterator j=info.uniforms.begin(); j!=info.uniforms.end(); ++j)
549                 {
550                         if(find_uniform_index((*j)->name)>=0)
551                                 any_found = true;
552                         else
553                                 all_found = false;
554                 }
555
556                 if(!any_found)
557                         return 0;
558                 else if(!all_found && info.bind_point>=0)
559                 {
560 #ifdef DEBUG
561                         IO::print(IO::cerr, "Warning: not all uniforms for block %s are present\n", info.name);
562 #else
563                         throw incomplete_uniform_block(info.name);
564 #endif
565                 }
566
567                 UniformBlock *block;
568                 if(info.bind_point>=0)
569                 {
570                         if(!buffer)
571                                 buffer = new Buffer(UNIFORM_BUFFER);
572
573                         block = new UniformBlock(info.data_size);
574                         block->use_buffer(buffer, last_block);
575                         last_block = block;
576                 }
577                 else
578                         block = new UniformBlock;
579
580                 i = blocks.insert(BlockMap::value_type(info.layout_hash, SharedBlock(block))).first;
581                 update_block_uniform_indices(i->second, info);
582         }
583
584         return &i->second;
585 }
586
587 void ProgramData::apply() const
588 {
589         const Program *prog = Program::current();
590         if(!prog)
591                 throw invalid_operation("ProgramData::apply");
592
593         Program::LayoutHash layout = prog->get_uniform_layout_hash();
594         ProgramUniforms &pu = programs[layout];
595
596         Mask force_dirty = (dirty==ALL_ONES ? ALL_ONES : 0U);
597         Mask affected = (dirty&pu.used) | force_dirty;
598         if(affected|pu.dirty)
599         {
600                 /* If the global dirty flag affects this program, add it to per-program
601                 dirty flags and clear the global flag.  A previously unseen program will
602                 cause this to happen if there's any dirty uniforms. */
603                 if(affected)
604                 {
605                         for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
606                                 i->second.dirty |= (dirty&i->second.used) | force_dirty;
607                         for(ProgramMap::iterator i=programs.begin(); i!=programs.end(); ++i)
608                                 i->second.dirty |= (dirty&i->second.used) | force_dirty;
609                         dirty = 0;
610                 }
611
612                 const vector<Program::UniformBlockInfo> &prog_blocks = prog->get_uniform_blocks();
613
614                 UniformBlock *old_last_block = last_block;
615                 if(pu.dirty==ALL_ONES)
616                 {
617                         /* The set of uniforms has changed since this program was last used.
618                         Regenerate the list of uniform blocks. */
619                         pu.blocks.clear();
620                         pu.blocks.reserve(prog_blocks.size());
621
622                         pu.used = 0;
623                         for(vector<Program::UniformBlockInfo>::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i)
624                         {
625                                 SharedBlock *shared = get_shared_block(*i);
626                                 if(shared)
627                                 {
628                                         if(shared->dirty==ALL_ONES)
629                                                 update_block_uniform_indices(*shared, *i);
630                                         pu.used |= shared->used;
631                                 }
632
633                                 pu.blocks.push_back(ProgramBlock(i->bind_point, shared));
634                         }
635                 }
636
637                 // Update the contents of all dirty blocks.
638                 bool buffered_blocks_updated = false;
639                 std::vector<ProgramBlock>::iterator j = pu.blocks.begin();
640                 for(vector<Program::UniformBlockInfo>::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i, ++j)
641                 {
642                         if(!j->shared || !j->shared->dirty)
643                                 continue;
644
645                         update_block(*j->shared, *i);
646                         j->shared->dirty = 0;
647                         buffered_blocks_updated |= (j->bind_point>=0);
648                 }
649
650                 pu.dirty = 0;
651
652                 /* If any blocks stored in the buffer were updated, bind the buffer here
653                 to avoid state thrashing. */
654                 if(buffered_blocks_updated && !ARB_direct_state_access)
655                         buffer->bind();
656
657                 if(last_block!=old_last_block)
658                 {
659                         unsigned required_size = last_block->get_required_buffer_size();
660                         if(last_block->get_required_buffer_size()>buffer->get_size())
661                         {
662                                 if(buffer->get_size()>0)
663                                 {
664                                         delete buffer;
665                                         buffer = new Buffer(UNIFORM_BUFFER);
666                                         last_block->change_buffer(buffer);
667                                 }
668
669                                 buffer->storage(required_size);
670                         }
671                 }
672         }
673
674         for(vector<ProgramBlock>::iterator i=pu.blocks.begin(); i!=pu.blocks.end(); ++i)
675                 if(i->block)
676                         i->block->apply(i->bind_point);
677 }
678
679
680 ProgramData::TaggedUniform::TaggedUniform():
681         value(0)
682 { }
683
684 void ProgramData::TaggedUniform::replace_value(Uniform *v)
685 {
686         /* UniformBlock does not copy the uniforms, so existing default blocks
687         will be left with stale pointers.  This is not a problem as long as no
688         one stores pointers to the blocks and expects them to stay valid. */
689         delete value;
690         value = v;
691 }
692
693
694 ProgramData::SharedBlock::SharedBlock(UniformBlock *b):
695         used(0),
696         dirty(0),
697         block(b)
698 {
699         indices.type_flag = 0xFD;
700 }
701
702 const UInt8 *ProgramData::SharedBlock::get_uniform_indices() const
703 {
704         return (indices.type_flag==0xFE ? indices.dynamic.values : indices.values);
705 }
706
707
708 ProgramData::ProgramBlock::ProgramBlock():
709         bind_point(-1),
710         block(0),
711         shared(0)
712 { }
713
714 ProgramData::ProgramBlock::ProgramBlock(int p, SharedBlock *b):
715         bind_point(p),
716         block((b && b->used) ? b->block : 0),
717         shared(b)
718 { }
719
720
721 ProgramData::ProgramUniforms::ProgramUniforms():
722         used(ALL_ONES),
723         dirty(ALL_ONES)
724 { }
725
726
727 ProgramData::Loader::Loader(ProgramData &pd):
728         DataFile::ObjectLoader<ProgramData>(pd)
729 {
730         add("uniform", &Loader::uniform1i);
731         add("uniform1i", &Loader::uniform1i);
732         add("uniform", &Loader::uniform1f);
733         add("uniform1f", &Loader::uniform1f);
734         add("uniform", &Loader::uniform2i);
735         add("uniform2i", &Loader::uniform2i);
736         add("uniform", &Loader::uniform2f);
737         add("uniform2f", &Loader::uniform2f);
738         add("uniform", &Loader::uniform3i);
739         add("uniform3i", &Loader::uniform3i);
740         add("uniform", &Loader::uniform3f);
741         add("uniform3f", &Loader::uniform3f);
742         add("uniform", &Loader::uniform4i);
743         add("uniform4i", &Loader::uniform4i);
744         add("uniform", &Loader::uniform4f);
745         add("uniform4f", &Loader::uniform4f);
746         add("uniform1i_array", &Loader::uniform1i_array);
747         add("uniform1f_array", &Loader::uniform1f_array);
748         add("uniform2f_array", &Loader::uniform2f_array);
749         add("uniform3f_array", &Loader::uniform3f_array);
750         add("uniform4f_array", &Loader::uniform4f_array);
751         add("uniform_array", &Loader::uniform_array);
752 }
753
754 void ProgramData::Loader::uniform1i(const string &n, int v)
755 {
756         obj.uniform(n, v);
757 }
758
759 void ProgramData::Loader::uniform1f(const string &n, float v)
760 {
761         obj.uniform(n, v);
762 }
763
764 void ProgramData::Loader::uniform2i(const string &n, int v0, int v1)
765 {
766         obj.uniform(n, v0, v1);
767 }
768
769 void ProgramData::Loader::uniform2f(const string &n, float v0, float v1)
770 {
771         obj.uniform(n, v0, v1);
772 }
773
774 void ProgramData::Loader::uniform3i(const string &n, int v0, int v1, int v2)
775 {
776         obj.uniform(n, v0, v1, v2);
777 }
778
779 void ProgramData::Loader::uniform3f(const string &n, float v0, float v1, float v2)
780 {
781         obj.uniform(n, v0, v1, v2);
782 }
783
784 void ProgramData::Loader::uniform4i(const string &n, int v0, int v1, int v2, int v3)
785 {
786         obj.uniform(n, v0, v1, v2, v3);
787 }
788
789 void ProgramData::Loader::uniform4f(const string &n, float v0, float v1, float v2, float v3)
790 {
791         obj.uniform(n, v0, v1, v2, v3);
792 }
793
794 void ProgramData::Loader::uniform_array_(const string &n, DataType t, unsigned e)
795 {
796         ArrayLoader ldr(t, e);
797         load_sub_with(ldr);
798         unsigned size = ldr.get_size();
799         if(!size)
800                 throw logic_error("empty uniform array");
801
802         DataType type = ldr.get_data_type();
803         unsigned elem_size = ldr.get_element_size();
804         if(type==INT)
805         {
806                 const int *data = reinterpret_cast<const int *>(ldr.get_data());
807                 if(elem_size==1)
808                         obj.uniform1_array(n, size, data);
809                 else if(elem_size==2)
810                         obj.uniform2_array(n, size, data);
811                 else if(elem_size==3)
812                         obj.uniform3_array(n, size, data);
813                 else if(elem_size==4)
814                         obj.uniform4_array(n, size, data);
815                 else
816                         throw logic_error("unsupported combination of array type and element size");
817         }
818         else if(type==FLOAT)
819         {
820                 const float *data = reinterpret_cast<const float *>(ldr.get_data());
821                 if(elem_size==1)
822                         obj.uniform1_array(n, size, data);
823                 else if(elem_size==2)
824                         obj.uniform2_array(n, size, data);
825                 else if(elem_size==3)
826                         obj.uniform3_array(n, size, data);
827                 else if(elem_size==4)
828                         obj.uniform4_array(n, size, data);
829                 else
830                         throw logic_error("unsupported combination of array type and element size");
831         }
832         else
833                 throw logic_error("unsupported array type");
834 }
835
836 void ProgramData::Loader::uniform1i_array(const string &n)
837 {
838         uniform_array_(n, INT, 1);
839 }
840
841 void ProgramData::Loader::uniform1f_array(const string &n)
842 {
843         uniform_array_(n, FLOAT, 1);
844 }
845
846 void ProgramData::Loader::uniform2i_array(const string &n)
847 {
848         uniform_array_(n, INT, 2);
849 }
850
851 void ProgramData::Loader::uniform2f_array(const string &n)
852 {
853         uniform_array_(n, FLOAT, 2);
854 }
855
856 void ProgramData::Loader::uniform3i_array(const string &n)
857 {
858         uniform_array_(n, INT, 3);
859 }
860
861 void ProgramData::Loader::uniform3f_array(const string &n)
862 {
863         uniform_array_(n, FLOAT, 3);
864 }
865
866 void ProgramData::Loader::uniform4i_array(const string &n)
867 {
868         uniform_array_(n, INT, 4);
869 }
870
871 void ProgramData::Loader::uniform4f_array(const string &n)
872 {
873         uniform_array_(n, FLOAT, 4);
874 }
875
876 void ProgramData::Loader::uniform_array(const string &n)
877 {
878         uniform_array_(n, static_cast<DataType>(0), 0);
879 }
880
881
882 ProgramData::ArrayLoader::ArrayLoader(DataType t, unsigned e):
883         type(t),
884         element_size(e)
885 {
886         add("uniform", &ArrayLoader::uniform1i);
887         add("uniform1i", &ArrayLoader::uniform1i);
888         add("uniform", &ArrayLoader::uniform1f);
889         add("uniform1f", &ArrayLoader::uniform1f);
890         add("uniform", &ArrayLoader::uniform2f);
891         add("uniform2f", &ArrayLoader::uniform2f);
892         add("uniform", &ArrayLoader::uniform3f);
893         add("uniform3f", &ArrayLoader::uniform3f);
894         add("uniform", &ArrayLoader::uniform4f);
895         add("uniform4f", &ArrayLoader::uniform4f);
896 }
897
898 void ProgramData::ArrayLoader::uniform(DataType t, unsigned e, const void *v)
899 {
900         if(element_size && (t!=type || e!=element_size))
901                 throw logic_error("heterogeneous array contents");
902
903         if(!element_size)
904         {
905                 type = t;
906                 element_size = e;
907         }
908
909         const char *cv = reinterpret_cast<const char *>(v);
910         data.insert(data.end(), cv, cv+element_size*4);
911 }
912
913 void ProgramData::ArrayLoader::uniform1i(int v)
914 {
915         uniform(INT, 1, &v);
916 }
917
918 void ProgramData::ArrayLoader::uniform1f(float v)
919 {
920         uniform(FLOAT, 1, &v);
921 }
922
923 void ProgramData::ArrayLoader::uniform2i(int v0, int v1)
924 {
925         int va[2] = { v0, v1 };
926         uniform(INT, 2, va);
927 }
928
929 void ProgramData::ArrayLoader::uniform2f(float v0, float v1)
930 {
931         float va[2] = { v0, v1 };
932         uniform(FLOAT, 2, va);
933 }
934
935 void ProgramData::ArrayLoader::uniform3i(int v0, int v1, int v2)
936 {
937         int va[3] = { v0, v1, v2 };
938         uniform(INT, 3, va);
939 }
940
941 void ProgramData::ArrayLoader::uniform3f(float v0, float v1, float v2)
942 {
943         float va[3] = { v0, v1, v2 };
944         uniform(FLOAT, 3, va);
945 }
946
947 void ProgramData::ArrayLoader::uniform4i(int v0, int v1, int v2, int v3)
948 {
949         int va[4] = { v0, v1, v2, v3 };
950         uniform(INT, 4, va);
951 }
952
953 void ProgramData::ArrayLoader::uniform4f(float v0, float v1, float v2, float v3)
954 {
955         float va[4] = { v0, v1, v2, v3 };
956         uniform(FLOAT, 4, va);
957 }
958
959 } // namespace GL
960 } // namespace Msp