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