]> git.tdb.fi Git - libs/gl.git/blob - source/core/program.cpp
Move all OpenGL-specific code to a separate directory
[libs/gl.git] / source / core / program.cpp
1 #include <msp/core/algorithm.h>
2 #include "error.h"
3 #include "program.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9
10 Program::Program(const Module &mod, const map<string, int> &spec_values)
11 {
12         add_stages(mod, spec_values);
13 }
14
15 void Program::add_stages(const Module &mod, const map<string, int> &spec_values)
16 {
17         if(has_stages())
18                 throw invalid_operation("Program::add_stages");
19
20         TransientData transient;
21         switch(mod.get_format())
22         {
23         case Module::GLSL:
24                 add_glsl_stages(static_cast<const GlslModule &>(mod), spec_values, transient);
25                 break;
26         case Module::SPIR_V:
27                 add_spirv_stages(static_cast<const SpirVModule &>(mod), spec_values, transient);
28                 break;
29         default:
30                 throw invalid_argument("Program::add_stages");
31         }
32
33         reflect_data = ReflectData();
34
35         finalize(mod);
36
37         if(mod.get_format()==Module::GLSL)
38         {
39                 query_uniforms();
40                 query_attributes();
41                 apply_bindings(transient);
42         }
43         else if(mod.get_format()==Module::SPIR_V)
44         {
45                 collect_uniforms(static_cast<const SpirVModule &>(mod), transient.spec_values);
46                 collect_attributes(static_cast<const SpirVModule &>(mod));
47         }
48
49         for(const ReflectData::UniformInfo &u: reflect_data.uniforms)
50                 require_type(u.type);
51         for(const ReflectData::AttributeInfo &a: reflect_data.attributes)
52                 require_type(a.type);
53 }
54
55 void Program::collect_uniforms(const SpirVModule &mod, const map<unsigned, int> &spec_values)
56 {
57         // Prepare the default block
58         reflect_data.uniform_blocks.push_back(ReflectData::UniformBlockInfo());
59         vector<vector<string> > block_uniform_names(1);
60
61         for(const SpirVModule::Variable &v: mod.get_variables())
62         {
63                 if(v.storage==SpirVModule::UNIFORM && v.struct_type)
64                 {
65                         reflect_data.uniform_blocks.push_back(ReflectData::UniformBlockInfo());
66                         ReflectData::UniformBlockInfo &info = reflect_data.uniform_blocks.back();
67                         info.name = v.struct_type->name;
68                         info.bind_point = v.binding;
69                         info.data_size = v.struct_type->size;
70
71                         string prefix;
72                         if(!v.name.empty())
73                                 prefix = v.struct_type->name+".";
74                         block_uniform_names.push_back(vector<string>());
75                         collect_block_uniforms(*v.struct_type, prefix, 0, spec_values, block_uniform_names.back());
76                 }
77                 else if(v.storage==SpirVModule::UNIFORM_CONSTANT && v.location>=0)
78                 {
79                         block_uniform_names[0].push_back(v.name);
80                         reflect_data.uniforms.push_back(ReflectData::UniformInfo());
81                         ReflectData::UniformInfo &info = reflect_data.uniforms.back();
82                         info.name = v.name;
83                         info.tag = v.name;
84                         info.location = v.location;
85                         info.binding = v.binding;
86                         info.array_size = v.array_size;
87                         info.type = v.type;
88                 }
89         }
90
91         sort_member(reflect_data.uniforms, &ReflectData::UniformInfo::tag);
92
93         for(unsigned i=0; i<reflect_data.uniform_blocks.size(); ++i)
94         {
95                 ReflectData::UniformBlockInfo &block = reflect_data.uniform_blocks[i];
96                 for(const string &n: block_uniform_names[i])
97                 {
98                         // The element is already known to be present
99                         ReflectData::UniformInfo &uni = *lower_bound_member(reflect_data.uniforms, Tag(n), &ReflectData::UniformInfo::tag);
100                         block.uniforms.push_back(&uni);
101                         uni.block = &block;
102                 }
103                 block.sort_uniforms();
104                 block.update_layout_hash();
105         }
106
107         reflect_data.update_layout_hash();
108 }
109
110 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)
111 {
112         for(const SpirVModule::StructMember &m: strct.members)
113         {
114                 unsigned offset = base_offset+m.offset;
115                 if(m.struct_type)
116                 {
117                         unsigned array_size = m.array_size;
118                         if(m.array_size_spec)
119                         {
120                                 array_size = m.array_size_spec->i_value;
121                                 auto j = spec_values.find(m.array_size_spec->constant_id);
122                                 if(j!=spec_values.end())
123                                         array_size = j->second;
124                         }
125
126                         if(array_size)
127                         {
128                                 for(unsigned j=0; j<array_size; ++j, offset+=m.array_stride)
129                                         collect_block_uniforms(*m.struct_type, format("%s%s[%d].", prefix, m.name, j), offset, spec_values, uniform_names);
130                         }
131                         else
132                                 collect_block_uniforms(*m.struct_type, prefix+m.name+".", offset, spec_values, uniform_names);
133                 }
134                 else
135                 {
136                         string name = prefix+m.name;
137                         uniform_names.push_back(name);
138                         reflect_data.uniforms.push_back(ReflectData::UniformInfo());
139                         ReflectData::UniformInfo &info = reflect_data.uniforms.back();
140                         info.name = name;
141                         info.tag = name;
142                         info.offset = offset;
143                         info.array_size = m.array_size;
144                         info.array_stride = m.array_stride;
145                         info.matrix_stride = m.matrix_stride;
146                         info.type = m.type;
147                 }
148         }
149 }
150
151 void Program::collect_attributes(const SpirVModule &mod)
152 {
153         for(const SpirVModule::EntryPoint &e: mod.get_entry_points())
154                 if(e.stage==SpirVModule::VERTEX && e.name=="main")
155                 {
156                         for(const SpirVModule::Variable *v: e.globals)
157                                 if(v->storage==SpirVModule::INPUT)
158                                 {
159                                         reflect_data.attributes.push_back(ReflectData::AttributeInfo());
160                                         ReflectData::AttributeInfo &info = reflect_data.attributes.back();
161                                         info.name = v->name;
162                                         info.location = v->location;
163                                         info.array_size = v->array_size;
164                                         info.type = v->type;
165                                 }
166                 }
167 }
168
169 const ReflectData::UniformBlockInfo &Program::get_uniform_block_info(const string &name) const
170 {
171         auto i = find_member(reflect_data.uniform_blocks, name, &ReflectData::UniformBlockInfo::name);
172         if(i==reflect_data.uniform_blocks.end())
173                 throw key_error(name);
174         return *i;
175 }
176
177 const ReflectData::UniformInfo &Program::get_uniform_info(const string &name) const
178 {
179         auto i = lower_bound_member(reflect_data.uniforms, Tag(name), &ReflectData::UniformInfo::tag);
180         if(i==reflect_data.uniforms.end() || i->name!=name)
181                 throw key_error(name);
182         return *i;
183 }
184
185 const ReflectData::UniformInfo &Program::get_uniform_info(Tag tag) const
186 {
187         auto i = lower_bound_member(reflect_data.uniforms, tag, &ReflectData::UniformInfo::tag);
188         if(i==reflect_data.uniforms.end() || i->tag!=tag)
189                 throw key_error(tag);
190         return *i;
191 }
192
193 int Program::get_uniform_location(const string &name) const
194 {
195         if(name[name.size()-1]==']')
196                 throw invalid_argument("Program::get_uniform_location");
197
198         auto i = lower_bound_member(reflect_data.uniforms, Tag(name), &ReflectData::UniformInfo::tag);
199         return i!=reflect_data.uniforms.end() && i->name==name && i->block->bind_point<0 ? i->location : -1;
200 }
201
202 int Program::get_uniform_location(Tag tag) const
203 {
204         auto i = lower_bound_member(reflect_data.uniforms, tag, &ReflectData::UniformInfo::tag);
205         return i!=reflect_data.uniforms.end() && i->tag==tag && i->block->bind_point<0 ? i->location : -1;
206 }
207
208 int Program::get_uniform_binding(Tag tag) const
209 {
210         auto i = lower_bound_member(reflect_data.uniforms, tag, &ReflectData::UniformInfo::tag);
211         return i!=reflect_data.uniforms.end() && i->tag==tag ? i->binding : -1;
212 }
213
214 const ReflectData::AttributeInfo &Program::get_attribute_info(const string &name) const
215 {
216         auto i = lower_bound_member(reflect_data.attributes, name, &ReflectData::AttributeInfo::name);
217         if(i==reflect_data.attributes.end() || i->name!=name)
218                 throw key_error(name);
219         return *i;
220 }
221
222 int Program::get_attribute_location(const string &name) const
223 {
224         if(name[name.size()-1]==']')
225                 throw invalid_argument("Program::get_attribute_location");
226
227         auto i = lower_bound_member(reflect_data.attributes, name, &ReflectData::AttributeInfo::name);
228         return i!=reflect_data.attributes.end() && i->name==name ? i->location : -1;
229 }
230
231
232 Program::Loader::Loader(Program &p, Collection &c):
233         DataFile::CollectionObjectLoader<Program>(p, &c)
234 {
235         add("module", &Loader::module);
236 }
237
238 void Program::Loader::module(const string &n)
239 {
240         map<string, int> spec_values;
241         SpecializationLoader ldr(spec_values);
242         load_sub_with(ldr);
243         obj.add_stages(get_collection().get<Module>(n), spec_values);
244 }
245
246
247 DataFile::Loader::ActionMap Program::SpecializationLoader::shared_actions;
248
249 Program::SpecializationLoader::SpecializationLoader(map<string, int> &sv):
250         spec_values(sv)
251 {
252         set_actions(shared_actions);
253 }
254
255 void Program::SpecializationLoader::init_actions()
256 {
257         add("specialize", &SpecializationLoader::specialize_bool);
258         add("specialize", &SpecializationLoader::specialize_int);
259 }
260
261 void Program::SpecializationLoader::specialize_bool(const string &name, bool value)
262 {
263         spec_values[name] = value;
264 }
265
266 void Program::SpecializationLoader::specialize_int(const string &name, int value)
267 {
268         spec_values[name] = value;
269 }
270
271 } // namespace GL
272 } // namespace Msp