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