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