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