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