]> git.tdb.fi Git - libs/gl.git/blob - source/core/program.cpp
Use standard fixed-size integer types
[libs/gl.git] / source / core / program.cpp
1 #include <cstring>
2 #include <set>
3 #include <msp/core/algorithm.h>
4 #include <msp/core/hash.h>
5 #include <msp/core/maputils.h>
6 #include <msp/core/raii.h>
7 #include <msp/gl/extensions/arb_es2_compatibility.h>
8 #include <msp/gl/extensions/arb_fragment_shader.h>
9 #include <msp/gl/extensions/arb_gl_spirv.h>
10 #include <msp/gl/extensions/arb_geometry_shader4.h>
11 #include <msp/gl/extensions/arb_separate_shader_objects.h>
12 #include <msp/gl/extensions/arb_shader_objects.h>
13 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
14 #include <msp/gl/extensions/arb_vertex_shader.h>
15 #include <msp/gl/extensions/ext_gpu_shader4.h>
16 #include <msp/gl/extensions/khr_debug.h>
17 #include <msp/gl/extensions/nv_non_square_matrices.h>
18 #include <msp/io/print.h>
19 #include <msp/strings/format.h>
20 #include "buffer.h"
21 #include "error.h"
22 #include "misc.h"
23 #include "program.h"
24 #include "resources.h"
25 #include "shader.h"
26 #include "glsl/compiler.h"
27
28 using namespace std;
29
30 namespace Msp {
31 namespace GL {
32
33 Program::Program()
34 {
35         init();
36 }
37
38 Program::Program(const string &source)
39 {
40         init();
41
42         GlslModule mod;
43         mod.set_source(source);
44         add_stages(mod);
45
46         link();
47         module = 0;
48 }
49
50 Program::Program(const string &vert, const string &frag)
51 {
52         init();
53
54 #pragma GCC diagnostic push
55 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
56         attach_shader_owned(new VertexShader(vert));
57         attach_shader_owned(new FragmentShader(frag));
58 #pragma GCC diagnostic pop
59         link();
60 }
61
62 Program::Program(const Module &mod, const map<string, int> &spec_values)
63 {
64         init();
65         add_stages(mod, spec_values);
66         link();
67 }
68
69 void Program::init()
70 {
71         static Require _req(ARB_shader_objects);
72
73         id = glCreateProgram();
74         fill(stage_ids, stage_ids+MAX_STAGES, 0);
75         module = 0;
76         transient = 0;
77         linked = false;
78 }
79
80 Program::~Program()
81 {
82         for(unsigned i=0; i<MAX_STAGES; ++i)
83                 if(stage_ids[i])
84                         glDeleteShader(stage_ids[i]);
85         glDeleteProgram(id);
86 }
87
88 void Program::add_stages(const Module &mod, const map<string, int> &spec_values)
89 {
90         if(has_stages())
91                 throw invalid_operation("Program::add_stages");
92
93         switch(mod.get_format())
94         {
95         case Module::GLSL: return add_glsl_stages(static_cast<const GlslModule &>(mod), spec_values);
96         case Module::SPIR_V: return add_spirv_stages(static_cast<const SpirVModule &>(mod), spec_values);
97         default: throw invalid_argument("Program::add_stages");
98         }
99 }
100
101 bool Program::has_stages() const
102 {
103         for(unsigned i=0; i<MAX_STAGES; ++i)
104                 if(stage_ids[i])
105                         return true;
106         return false;
107 }
108
109 unsigned Program::add_stage(Stage type)
110 {
111         GLenum gl_type;
112         switch(type)
113         {
114         case VERTEX: { static Require _req(ARB_vertex_shader); gl_type = GL_VERTEX_SHADER; } break;
115         case GEOMETRY: { static Require _req(ARB_geometry_shader4); gl_type = GL_GEOMETRY_SHADER; } break;
116         case FRAGMENT: { static Require _req(ARB_fragment_shader); gl_type = GL_FRAGMENT_SHADER; } break;
117         default: throw invalid_argument("Program::add_stage");
118         }
119
120         if(stage_ids[type])
121                 throw invalid_operation("Program::add_stage");
122
123         unsigned stage_id = glCreateShader(gl_type);
124         stage_ids[type] = stage_id;
125         glAttachShader(id, stage_id);
126
127 #ifdef DEBUG
128         if(!debug_name.empty() && KHR_debug)
129                 set_stage_debug_name(stage_id, type);
130 #endif
131
132         return stage_id;
133 }
134
135 void Program::add_glsl_stages(const GlslModule &mod, const map<string, int> &spec_values)
136 {
137         module = &mod;
138
139         SL::Compiler compiler;
140         compiler.set_source(mod.get_prepared_source(), "<module>");
141         compiler.specialize(spec_values);
142         compiler.compile(SL::Compiler::PROGRAM);
143 #ifdef DEBUG
144         string diagnostics = compiler.get_diagnostics();
145         if(!diagnostics.empty())
146                 IO::print("Program diagnostics:\n%s\n", diagnostics);
147 #endif
148
149         vector<SL::Stage::Type> stages = compiler.get_stages();
150         for(SL::Stage::Type st: stages)
151         {
152                 unsigned stage_id = 0;
153                 switch(st)
154                 {
155                 case SL::Stage::VERTEX: stage_id = add_stage(VERTEX); break;
156                 case SL::Stage::GEOMETRY: stage_id = add_stage(GEOMETRY); break;
157                 case SL::Stage::FRAGMENT: stage_id = add_stage(FRAGMENT); break;
158                 default: throw invalid_operation("Program::add_glsl_stages");
159                 }
160
161                 string stage_src = compiler.get_stage_glsl(st);
162                 const char *src_ptr = stage_src.data();
163                 int src_len = stage_src.size();
164                 glShaderSource(stage_id, 1, &src_ptr, &src_len);
165
166                 if(st==SL::Stage::VERTEX)
167                 {
168                         for(const auto &kvp: compiler.get_vertex_attributes())
169                                 glBindAttribLocation(id, kvp.second, kvp.first.c_str());
170                 }
171
172                 if(st==SL::Stage::FRAGMENT && EXT_gpu_shader4)
173                 {
174                         for(const auto &kvp: compiler.get_fragment_outputs())
175                                 glBindFragDataLocation(id, kvp.second, kvp.first.c_str());
176                 }
177
178                 compile_glsl_stage(stage_id);
179         }
180
181         if(!transient)
182                 transient = new TransientData;
183         transient->textures = compiler.get_texture_bindings();
184         transient->blocks = compiler.get_uniform_block_bindings();
185 }
186
187 void Program::compile_glsl_stage(unsigned stage_id)
188 {
189         glCompileShader(stage_id);
190         bool compiled = get_shader_i(stage_id, GL_COMPILE_STATUS);
191
192         GLsizei info_log_len = get_shader_i(stage_id, GL_INFO_LOG_LENGTH);
193         string info_log(info_log_len+1, 0);
194         glGetShaderInfoLog(stage_id, info_log_len+1, &info_log_len, &info_log[0]);
195         info_log.erase(info_log_len);
196         if(module && module->get_format()==Module::GLSL)
197                 info_log = static_cast<const GlslModule *>(module)->get_source_map().translate_errors(info_log);
198
199         if(!compiled)
200                 throw compile_error(info_log);
201 #ifdef DEBUG
202         if(!info_log.empty())
203                 IO::print("Shader compile info log:\n%s", info_log);
204 #endif
205 }
206
207 void Program::add_spirv_stages(const SpirVModule &mod, const map<string, int> &spec_values)
208 {
209         static Require _req(ARB_gl_spirv);
210         static Require _req2(ARB_ES2_compatibility);
211
212         module = &mod;
213
214         unsigned n_stages = 0;
215         unsigned used_stage_ids[MAX_STAGES];
216         for(const SpirVModule::EntryPoint &e: mod.get_entry_points())
217         {
218                 unsigned stage_id = 0;
219                 switch(e.stage)
220                 {
221                 case SpirVModule::VERTEX: stage_id = add_stage(VERTEX); break;
222                 case SpirVModule::GEOMETRY: stage_id = add_stage(GEOMETRY); break;
223                 case SpirVModule::FRAGMENT: stage_id = add_stage(FRAGMENT); break;
224                 default: throw invalid_operation("Program::add_spirv_stages");
225                 }
226
227                 used_stage_ids[n_stages++] = stage_id;
228         }
229
230         const vector<uint32_t> &code = mod.get_code();
231         glShaderBinary(n_stages, used_stage_ids, GL_SHADER_BINARY_FORMAT_SPIR_V, &code[0], code.size()*4);
232
233         if(!spec_values.empty() && !transient)
234                 transient = new TransientData;
235
236         const vector<SpirVModule::Constant> &spec_consts = mod.get_spec_constants();
237         vector<unsigned> spec_id_array;
238         vector<unsigned> spec_value_array;
239         spec_id_array.reserve(spec_consts.size());
240         spec_value_array.reserve(spec_consts.size());
241         for(const SpirVModule::Constant &c: spec_consts)
242         {
243                 auto i = spec_values.find(c.name);
244                 if(i!=spec_values.end())
245                 {
246                         spec_id_array.push_back(c.constant_id);
247                         spec_value_array.push_back(i->second);
248                         transient->spec_values[c.constant_id] = i->second;
249                 }
250         }
251
252         auto j = mod.get_entry_points().begin();
253         for(unsigned i=0; i<MAX_STAGES; ++i)
254                 if(stage_ids[i])
255                         glSpecializeShader(stage_ids[i], j->name.c_str(), spec_id_array.size(), &spec_id_array[0], &spec_value_array[0]);
256 }
257
258 #pragma GCC diagnostic push
259 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
260 void Program::attach_shader(Shader &shader)
261 {
262         unsigned shader_id = shader.steal_id();
263         if(!shader_id)
264                 throw invalid_argument("Program::attach_shader");
265
266         int type;
267         glGetShaderiv(shader_id, GL_SHADER_TYPE, &type);
268         switch(type)
269         {
270         case GL_VERTEX_SHADER: stage_ids[VERTEX] = shader_id; break;
271         case GL_GEOMETRY_SHADER: stage_ids[GEOMETRY] = shader_id; break;
272         case GL_FRAGMENT_SHADER: stage_ids[FRAGMENT] = shader_id; break;
273         }
274
275         glAttachShader(id, shader_id);
276         compile_glsl_stage(shader_id);
277 }
278
279 void Program::attach_shader_owned(Shader *shader)
280 {
281         attach_shader(*shader);
282         delete shader;
283 }
284
285 void Program::detach_shader(Shader &)
286 {
287 }
288
289 const vector<Shader *> &Program::get_attached_shaders() const
290 {
291         static vector<Shader *> dummy;
292         return dummy;
293 }
294
295 void Program::bind_attribute(unsigned index, const string &name)
296 {
297         static Require _req(ARB_vertex_shader);
298         glBindAttribLocation(id, index, name.c_str());
299 }
300
301 void Program::bind_attribute(VertexAttribute attr, const string &name)
302 {
303         bind_attribute(get_attribute_semantic(attr), name);
304 }
305
306 void Program::bind_fragment_data(unsigned index, const string &name)
307 {
308         static Require _req(EXT_gpu_shader4);
309         glBindFragDataLocation(id, index, name.c_str());
310 }
311 #pragma GCC diagnostic pop
312
313 void Program::link()
314 {
315         if(!has_stages())
316                 throw invalid_operation("Program::link");
317
318         uniforms.clear();
319         uniform_blocks.clear();
320         attributes.clear();
321
322         glLinkProgram(id);
323         linked = get_program_i(id, GL_LINK_STATUS);
324
325         GLsizei info_log_len = get_program_i(id, GL_INFO_LOG_LENGTH);
326         string info_log(info_log_len+1, 0);
327         glGetProgramInfoLog(id, info_log_len+1, &info_log_len, &info_log[0]);
328         info_log.erase(info_log_len);
329         if(module && module->get_format()==Module::GLSL)
330                 info_log = static_cast<const GlslModule *>(module)->get_source_map().translate_errors(info_log);
331
332         if(!linked)
333                 throw compile_error(info_log);
334 #ifdef DEBUG
335         if(!info_log.empty())
336                 IO::print("Program link info log:\n%s", info_log);
337 #endif
338
339         if(module->get_format()==Module::GLSL)
340         {
341                 query_uniforms();
342                 query_attributes();
343                 if(transient)
344                 {
345                         for(unsigned i=0; i<uniform_blocks.size(); ++i)
346                         {
347                                 auto j = transient->blocks.find(uniform_blocks[i].name);
348                                 if(j!=transient->blocks.end())
349                                 {
350                                         glUniformBlockBinding(id, i, j->second);
351                                         uniform_blocks[i].bind_point = j->second;
352                                 }
353                         }
354
355                         if(!ARB_separate_shader_objects)
356                                 glUseProgram(id);
357                         for(const auto &kvp: transient->textures)
358                         {
359                                 int location = get_uniform_location(kvp.first);
360                                 if(location>=0)
361                                 {
362                                         if(ARB_separate_shader_objects)
363                                                 glProgramUniform1i(id, location, kvp.second);
364                                         else
365                                                 glUniform1i(location, kvp.second);
366                                 }
367                         }
368                 }
369         }
370         else if(module->get_format()==Module::SPIR_V)
371         {
372                 collect_uniforms();
373                 collect_attributes();
374         }
375
376         delete transient;
377         transient = 0;
378
379         for(const UniformInfo &u: uniforms)
380                 require_type(u.type);
381         for(const AttributeInfo &a: attributes)
382                 require_type(a.type);
383 }
384
385 void Program::query_uniforms()
386 {
387         unsigned count = get_program_i(id, GL_ACTIVE_UNIFORMS);
388         uniforms.reserve(count);
389         vector<string> uniform_names(count);
390         for(unsigned i=0; i<count; ++i)
391         {
392                 char name[128];
393                 int len = 0;
394                 int size;
395                 GLenum type;
396                 glGetActiveUniform(id, i, sizeof(name), &len, &size, &type, name);
397                 if(len && strncmp(name, "gl_", 3))
398                 {
399                         /* Some implementations report the first element of a uniform array,
400                         others report just the name of the array itself. */
401                         if(len>3 && !strcmp(name+len-3, "[0]"))
402                                 name[len-3] = 0;
403
404                         uniforms.push_back(UniformInfo());
405                         UniformInfo &info = uniforms.back();
406                         info.name = name;
407                         info.tag = name;
408                         info.array_size = size;
409                         info.type = from_gl_type(type);
410                         uniform_names[i] = name;
411                 }
412         }
413
414         sort_member(uniforms, &UniformInfo::tag);
415
416         if(ARB_uniform_buffer_object)
417         {
418                 vector<UniformInfo *> uniforms_by_index(count);
419                 for(unsigned i=0; i<count; ++i)
420                         if(!uniform_names[i].empty())
421                                 // The element is already known to be present
422                                 uniforms_by_index[i] = &*lower_bound_member(uniforms, Tag(uniform_names[i]), &UniformInfo::tag);
423                 query_uniform_blocks(uniforms_by_index);
424         }
425
426         uniform_blocks.push_back(UniformBlockInfo());
427         UniformBlockInfo &default_block = uniform_blocks.back();
428
429         for(UniformInfo &u: uniforms)
430                 if(!u.block)
431                 {
432                         u.location = glGetUniformLocation(id, u.name.c_str());
433                         u.block = &default_block;
434                         default_block.uniforms.push_back(&u);
435
436                         if(is_image(u.type) && u.location>=0)
437                                 glGetUniformiv(id, u.location, &u.binding);
438                 }
439
440         default_block.layout_hash = compute_layout_hash(default_block.uniforms);
441
442         update_layout_hash();
443 }
444
445 void Program::query_uniform_blocks(const vector<UniformInfo *> &uniforms_by_index)
446 {
447         unsigned count = get_program_i(id, GL_ACTIVE_UNIFORM_BLOCKS);
448         // Reserve an extra index for the default block
449         uniform_blocks.reserve(count+1);
450         for(unsigned i=0; i<count; ++i)
451         {
452                 char name[128];
453                 int len;
454                 glGetActiveUniformBlockName(id, i, sizeof(name), &len, name);
455                 uniform_blocks.push_back(UniformBlockInfo());
456                 UniformBlockInfo &info = uniform_blocks.back();
457                 info.name = name;
458
459                 int value;
460                 glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_DATA_SIZE, &value);
461                 info.data_size = value;
462
463                 glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_BINDING, &value);
464                 info.bind_point = value;
465
466                 glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &value);
467                 vector<int> indices(value);
468                 glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &indices[0]);
469                 for(int j: indices)
470                 {
471                         if(!uniforms_by_index[j])
472                                 throw logic_error("Program::link");
473                         info.uniforms.push_back(uniforms_by_index[j]);
474                         uniforms_by_index[j]->block = &info;
475                 }
476
477                 vector<unsigned> query_indices(indices.begin(), indices.end());
478                 vector<int> values(indices.size());
479                 glGetActiveUniformsiv(id, query_indices.size(), &query_indices[0], GL_UNIFORM_OFFSET, &values[0]);
480                 for(unsigned j=0; j<indices.size(); ++j)
481                         uniforms_by_index[indices[j]]->offset = values[j];
482
483                 query_indices.clear();
484                 for(int j: indices)
485                         if(uniforms_by_index[j]->array_size>1)
486                                 query_indices.push_back(j);
487                 if(!query_indices.empty())
488                 {
489                         glGetActiveUniformsiv(id, query_indices.size(), &query_indices[0], GL_UNIFORM_ARRAY_STRIDE, &values[0]);
490                         for(unsigned j=0; j<query_indices.size(); ++j)
491                                 uniforms_by_index[query_indices[j]]->array_stride = values[j];
492                 }
493
494                 query_indices.clear();
495                 for(int j: indices)
496                 {
497                         DataType t = uniforms_by_index[j]->type;
498                         if(is_matrix(t))
499                                 query_indices.push_back(j);
500                 }
501                 if(!query_indices.empty())
502                 {
503                         glGetActiveUniformsiv(id, query_indices.size(), &query_indices[0], GL_UNIFORM_MATRIX_STRIDE, &values[0]);
504                         for(unsigned j=0; j<query_indices.size(); ++j)
505                                 uniforms_by_index[query_indices[j]]->matrix_stride = values[j];
506                 }
507
508                 sort(info.uniforms, uniform_location_compare);
509                 info.layout_hash = compute_layout_hash(info.uniforms);
510         }
511 }
512
513 void Program::query_attributes()
514 {
515         unsigned count = get_program_i(id, GL_ACTIVE_ATTRIBUTES);
516         attributes.reserve(count);
517         for(unsigned i=0; i<count; ++i)
518         {
519                 char name[128];
520                 int len = 0;
521                 int size;
522                 GLenum type;
523                 glGetActiveAttrib(id, i, sizeof(name), &len, &size, &type, name);
524                 if(len && strncmp(name, "gl_", 3))
525                 {
526                         if(len>3 && !strcmp(name+len-3, "[0]"))
527                                 name[len-3] = 0;
528
529                         attributes.push_back(AttributeInfo());
530                         AttributeInfo &info = attributes.back();
531                         info.name = name;
532                         info.location = glGetAttribLocation(id, name);
533                         info.array_size = size;
534                         info.type = from_gl_type(type);
535                 }
536         }
537 }
538
539 void Program::collect_uniforms()
540 {
541         const SpirVModule &mod = static_cast<const SpirVModule &>(*module);
542
543         // Prepare the default block
544         uniform_blocks.push_back(UniformBlockInfo());
545         vector<vector<string> > block_uniform_names(1);
546
547         for(const SpirVModule::Variable &v: mod.get_variables())
548         {
549                 if(v.storage==SpirVModule::UNIFORM && v.struct_type)
550                 {
551                         uniform_blocks.push_back(UniformBlockInfo());
552                         UniformBlockInfo &info = uniform_blocks.back();
553                         info.name = v.struct_type->name;
554                         info.bind_point = v.binding;
555                         info.data_size = v.struct_type->size;
556
557                         string prefix;
558                         if(!v.name.empty())
559                                 prefix = v.struct_type->name+".";
560                         block_uniform_names.push_back(vector<string>());
561                         collect_block_uniforms(*v.struct_type, prefix, 0, block_uniform_names.back());
562                 }
563                 else if(v.storage==SpirVModule::UNIFORM_CONSTANT && v.location>=0)
564                 {
565                         block_uniform_names[0].push_back(v.name);
566                         uniforms.push_back(UniformInfo());
567                         UniformInfo &info = uniforms.back();
568                         info.name = v.name;
569                         info.tag = v.name;
570                         info.location = v.location;
571                         info.binding = v.binding;
572                         info.array_size = v.array_size;
573                         info.type = v.type;
574                 }
575         }
576
577         sort_member(uniforms, &UniformInfo::tag);
578
579         for(unsigned i=0; i<uniform_blocks.size(); ++i)
580         {
581                 UniformBlockInfo &block = uniform_blocks[i];
582                 for(const string &n: block_uniform_names[i])
583                 {
584                         // The element is already known to be present
585                         UniformInfo &uni = *lower_bound_member(uniforms, Tag(n), &UniformInfo::tag);
586                         block.uniforms.push_back(&uni);
587                         uni.block = &block;
588                 }
589                 sort(block.uniforms, uniform_location_compare);
590                 block.layout_hash = compute_layout_hash(block.uniforms);
591         }
592
593         update_layout_hash();
594 }
595
596 void Program::collect_block_uniforms(const SpirVModule::Structure &strct, const string &prefix, unsigned base_offset, vector<string> &uniform_names)
597 {
598         for(const SpirVModule::StructMember &m: strct.members)
599         {
600                 unsigned offset = base_offset+m.offset;
601                 if(m.struct_type)
602                 {
603                         unsigned array_size = m.array_size;
604                         if(m.array_size_spec)
605                         {
606                                 array_size = m.array_size_spec->i_value;
607                                 if(transient)
608                                 {
609                                         auto j = transient->spec_values.find(m.array_size_spec->constant_id);
610                                         if(j!=transient->spec_values.end())
611                                                 array_size = j->second;
612                                 }
613                         }
614
615                         if(array_size)
616                         {
617                                 for(unsigned j=0; j<array_size; ++j, offset+=m.array_stride)
618                                         collect_block_uniforms(*m.struct_type, format("%s%s[%d].", prefix, m.name, j), offset, uniform_names);
619                         }
620                         else
621                                 collect_block_uniforms(*m.struct_type, prefix+m.name+".", offset, uniform_names);
622                 }
623                 else
624                 {
625                         string name = prefix+m.name;
626                         uniform_names.push_back(name);
627                         uniforms.push_back(UniformInfo());
628                         UniformInfo &info = uniforms.back();
629                         info.name = name;
630                         info.tag = name;
631                         info.offset = offset;
632                         info.array_size = m.array_size;
633                         info.array_stride = m.array_stride;
634                         info.matrix_stride = m.matrix_stride;
635                         info.type = m.type;
636                 }
637         }
638 }
639
640 void Program::collect_attributes()
641 {
642         const SpirVModule &mod = static_cast<const SpirVModule &>(*module);
643
644         for(const SpirVModule::EntryPoint &e: mod.get_entry_points())
645                 if(e.stage==SpirVModule::VERTEX && e.name=="main")
646                 {
647                         for(const SpirVModule::Variable *v: e.globals)
648                                 if(v->storage==SpirVModule::INPUT)
649                                 {
650                                         attributes.push_back(AttributeInfo());
651                                         AttributeInfo &info = attributes.back();
652                                         info.name = v->name;
653                                         info.location = v->location;
654                                         info.array_size = v->array_size;
655                                         info.type = v->type;
656                                 }
657                 }
658 }
659
660 void Program::update_layout_hash()
661 {
662         string layout_descriptor;
663         for(const UniformBlockInfo &b: uniform_blocks)
664                 layout_descriptor += format("%d:%x\n", b.bind_point, b.layout_hash);
665         uniform_layout_hash = hash32(layout_descriptor);
666 }
667
668 Program::LayoutHash Program::compute_layout_hash(const vector<const UniformInfo *> &uniforms)
669 {
670         string layout_descriptor;
671         for(const UniformInfo *u: uniforms)
672                 layout_descriptor += format("%d:%s:%x:%d\n", u->location, u->name, u->type, u->array_size);
673         return hash32(layout_descriptor);
674 }
675
676 bool Program::uniform_location_compare(const UniformInfo *uni1, const UniformInfo *uni2)
677 {
678         return uni1->location<uni2->location;
679 }
680
681 string Program::get_info_log() const
682 {
683         GLsizei len = get_program_i(id, GL_INFO_LOG_LENGTH);
684         string log(len+1, 0);
685         glGetProgramInfoLog(id, len+1, &len, &log[0]);
686         log.erase(len);
687         return log;
688 }
689
690 const Program::UniformBlockInfo &Program::get_uniform_block_info(const string &name) const
691 {
692         auto i = find_member(uniform_blocks, name, &UniformBlockInfo::name);
693         if(i==uniform_blocks.end())
694                 throw key_error(name);
695         return *i;
696 }
697
698 const Program::UniformInfo &Program::get_uniform_info(const string &name) const
699 {
700         auto i = lower_bound_member(uniforms, Tag(name), &UniformInfo::tag);
701         if(i==uniforms.end() || i->name!=name)
702                 throw key_error(name);
703         return *i;
704 }
705
706 const Program::UniformInfo &Program::get_uniform_info(Tag tag) const
707 {
708         auto i = lower_bound_member(uniforms, tag, &UniformInfo::tag);
709         if(i==uniforms.end() || i->tag!=tag)
710                 throw key_error(tag);
711         return *i;
712 }
713
714 int Program::get_uniform_location(const string &name) const
715 {
716         if(name[name.size()-1]==']')
717                 throw invalid_argument("Program::get_uniform_location");
718
719         auto i = lower_bound_member(uniforms, Tag(name), &UniformInfo::tag);
720         return i!=uniforms.end() && i->name==name && i->block->bind_point<0 ? i->location : -1;
721 }
722
723 int Program::get_uniform_location(Tag tag) const
724 {
725         auto i = lower_bound_member(uniforms, tag, &UniformInfo::tag);
726         return i!=uniforms.end() && i->tag==tag && i->block->bind_point<0 ? i->location : -1;
727 }
728
729 int Program::get_uniform_binding(Tag tag) const
730 {
731         auto i = lower_bound_member(uniforms, tag, &UniformInfo::tag);
732         return i!=uniforms.end() && i->tag==tag ? i->binding : -1;
733 }
734
735 const Program::AttributeInfo &Program::get_attribute_info(const string &name) const
736 {
737         auto i = lower_bound_member(attributes, name, &AttributeInfo::name);
738         if(i==attributes.end() || i->name!=name)
739                 throw key_error(name);
740         return *i;
741 }
742
743 int Program::get_attribute_location(const string &name) const
744 {
745         if(name[name.size()-1]==']')
746                 throw invalid_argument("Program::get_attribute_location");
747
748         auto i = lower_bound_member(attributes, name, &AttributeInfo::name);
749         return i!=attributes.end() && i->name==name ? i->location : -1;
750 }
751
752 void Program::set_debug_name(const string &name)
753 {
754 #ifdef DEBUG
755         debug_name = name;
756         if(KHR_debug)
757         {
758                 glObjectLabel(GL_PROGRAM, id, name.size(), name.c_str());
759                 for(unsigned i=0; i<MAX_STAGES; ++i)
760                         if(stage_ids[i])
761                                 set_stage_debug_name(stage_ids[i], static_cast<Stage>(i));
762         }
763 #else
764         (void)name;
765 #endif
766 }
767
768 void Program::set_stage_debug_name(unsigned stage_id, Stage type)
769 {
770 #ifdef DEBUG
771         static const char *const suffixes[] = { " [VS]", " [GS]", " [FS]" };
772         string name = debug_name+suffixes[type];
773         glObjectLabel(GL_SHADER, stage_id, name.size(), name.c_str());
774 #else
775         (void)stage_id; (void)type;
776 #endif
777 }
778
779
780 Program::UniformInfo::UniformInfo():
781         block(0),
782         location(-1),
783         array_size(0),
784         array_stride(0),
785         matrix_stride(0),
786         type(VOID),
787         binding(-1)
788 { }
789
790
791 Program::UniformBlockInfo::UniformBlockInfo():
792         data_size(0),
793         bind_point(-1),
794         layout_hash(0)
795 { }
796
797
798 Program::AttributeInfo::AttributeInfo():
799         location(-1),
800         array_size(0),
801         type(VOID)
802 { }
803
804
805 Program::Loader::Loader(Program &p, Collection &c):
806         DataFile::CollectionObjectLoader<Program>(p, &c)
807 {
808         add("module",          &Loader::module);
809
810         // Deprecated
811         add("attribute",       &Loader::attribute);
812         add("fragment_shader", &Loader::fragment_shader);
813         add("geometry_shader", &Loader::geometry_shader);
814         add("vertex_shader",   &Loader::vertex_shader);
815 }
816
817 void Program::Loader::finish()
818 {
819         obj.link();
820 }
821
822 void Program::Loader::module(const string &n)
823 {
824         map<string, int> spec_values;
825         SpecializationLoader ldr(spec_values);
826         load_sub_with(ldr);
827         obj.add_stages(get_collection().get<Module>(n), spec_values);
828 }
829
830 #pragma GCC diagnostic push
831 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
832 void Program::Loader::attribute(unsigned i, const string &n)
833 {
834         obj.bind_attribute(i, n);
835 }
836
837 void Program::Loader::fragment_shader(const string &src)
838 {
839         obj.attach_shader_owned(new FragmentShader(src));
840 }
841
842 void Program::Loader::geometry_shader(const string &src)
843 {
844         obj.attach_shader_owned(new GeometryShader(src));
845 }
846
847 void Program::Loader::vertex_shader(const string &src)
848 {
849         obj.attach_shader_owned(new VertexShader(src));
850 }
851 #pragma GCC diagnostic pop
852
853
854 DataFile::Loader::ActionMap Program::SpecializationLoader::shared_actions;
855
856 Program::SpecializationLoader::SpecializationLoader(map<string, int> &sv):
857         spec_values(sv)
858 {
859         set_actions(shared_actions);
860 }
861
862 void Program::SpecializationLoader::init_actions()
863 {
864         add("specialize", &SpecializationLoader::specialize_bool);
865         add("specialize", &SpecializationLoader::specialize_int);
866 }
867
868 void Program::SpecializationLoader::specialize_bool(const string &name, bool value)
869 {
870         spec_values[name] = value;
871 }
872
873 void Program::SpecializationLoader::specialize_int(const string &name, int value)
874 {
875         spec_values[name] = value;
876 }
877
878 } // namespace GL
879 } // namespace Msp