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