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