blob: d810eccc15db3f260f5f22d2af1b4f5d5256f88b [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
2 * Copyright 2015-2016 ARM Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020017#include "spirv_cpp.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010018
19using namespace spv;
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020020using namespace spirv_cross;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010021using namespace std;
22
23void CompilerCPP::emit_buffer_block(const SPIRVariable &var)
24{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020025 add_resource_name(var.self);
26
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020027 auto &type = get<SPIRType>(var.basetype);
28 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020030 uint32_t descriptor_set = meta[var.self].decoration.set;
31 uint32_t binding = meta[var.self].decoration.binding;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010032
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020033 emit_block_struct(type);
34 auto buffer_name = to_name(type.self);
35
36 statement("internal::Resource<", buffer_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020037 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
38 resource_registrations.push_back(
39 join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
40 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010041}
42
43void CompilerCPP::emit_interface_block(const SPIRVariable &var)
44{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020045 add_resource_name(var.self);
46
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020047 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010048
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020049 const char *qual = var.storage == StorageClassInput ? "StageInput" : "StageOutput";
50 const char *lowerqual = var.storage == StorageClassInput ? "stage_input" : "stage_output";
51 auto instance_name = to_name(var.self);
52 uint32_t location = meta[var.self].decoration.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010053
Hans-Kristian Arntzen885c24f2016-08-26 13:43:21 +020054 string buffer_name;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020055 auto flags = meta[type.self].decoration.decoration_flags;
56 if (flags & (1ull << DecorationBlock))
Hans-Kristian Arntzen885c24f2016-08-26 13:43:21 +020057 {
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020058 emit_block_struct(type);
Hans-Kristian Arntzen885c24f2016-08-26 13:43:21 +020059 buffer_name = to_name(type.self);
60 }
61 else
62 buffer_name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010063
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020064 statement("internal::", qual, "<", buffer_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020065 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
66 resource_registrations.push_back(join("s.register_", lowerqual, "(", instance_name, "__", ", ", location, ");"));
67 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010068}
69
70void CompilerCPP::emit_shared(const SPIRVariable &var)
71{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020072 add_resource_name(var.self);
73
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020074 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020075 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020076 statement_no_indent("#define ", instance_name, " __res->", instance_name);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010077}
78
79void CompilerCPP::emit_uniform(const SPIRVariable &var)
80{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020081 add_resource_name(var.self);
82
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020083 auto &type = get<SPIRType>(var.basetype);
84 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010085
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020086 uint32_t descriptor_set = meta[var.self].decoration.set;
87 uint32_t binding = meta[var.self].decoration.binding;
88 uint32_t location = meta[var.self].decoration.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020090 if (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
91 type.basetype == SPIRType::AtomicCounter)
92 {
93 statement("internal::Resource<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
94 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
95 resource_registrations.push_back(
96 join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
97 }
98 else
99 {
100 statement("internal::UniformConstant<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name,
101 "__;");
102 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
103 resource_registrations.push_back(
104 join("s.register_uniform_constant(", instance_name, "__", ", ", location, ");"));
105 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100106
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200107 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100108}
109
110void CompilerCPP::emit_push_constant_block(const SPIRVariable &var)
111{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200112 add_resource_name(var.self);
113
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200114 auto &type = get<SPIRType>(var.basetype);
115 auto &flags = meta[var.self].decoration.decoration_flags;
116 if ((flags & (1ull << DecorationBinding)) || (flags & (1ull << DecorationDescriptorSet)))
117 throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
118 "Remap to location with reflection API first or disable these decorations.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100119
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200120 emit_block_struct(type);
121 auto buffer_name = to_name(type.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200122 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100123
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200124 statement("internal::PushConstant<", buffer_name, type_to_array_glsl(type), "> ", instance_name, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200125 statement_no_indent("#define ", instance_name, " __res->", instance_name, ".get()");
126 resource_registrations.push_back(join("s.register_push_constant(", instance_name, "__", ");"));
127 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100128}
129
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200130void CompilerCPP::emit_block_struct(SPIRType &type)
131{
132 // C++ can't do interface blocks, so we fake it by emitting a separate struct.
133 // However, these structs are not allowed to alias anything, so remove it before
134 // emitting the struct.
135 //
136 // The type we have here needs to be resolved to the non-pointer type so we can remove aliases.
137 auto &self = get<SPIRType>(type.self);
138 self.type_alias = 0;
139 emit_struct(self);
140}
141
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100142void CompilerCPP::emit_resources()
143{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200144 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
145 // when such variables are instantiated.
146 for (auto &id : ids)
147 {
148 if (id.get_type() == TypeType)
149 {
150 auto &type = id.get<SPIRType>();
151 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
152 (meta[type.self].decoration.decoration_flags &
153 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
154 {
155 emit_struct(type);
156 }
157 }
158 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100159
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200160 statement("struct Resources : ", resource_type);
161 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100162
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200163 // Output UBOs and SSBOs
164 for (auto &id : ids)
165 {
166 if (id.get_type() == TypeVariable)
167 {
168 auto &var = id.get<SPIRVariable>();
169 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100170
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +0200171 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200172 !is_hidden_variable(var) && (meta[type.self].decoration.decoration_flags &
173 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200174 {
175 emit_buffer_block(var);
176 }
177 }
178 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100179
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200180 // Output push constant blocks
181 for (auto &id : ids)
182 {
183 if (id.get_type() == TypeVariable)
184 {
185 auto &var = id.get<SPIRVariable>();
186 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200187 if (!is_hidden_variable(var) && var.storage != StorageClassFunction && type.pointer &&
188 type.storage == StorageClassPushConstant)
189 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200190 emit_push_constant_block(var);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200191 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200192 }
193 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100194
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200195 // Output in/out interfaces.
196 for (auto &id : ids)
197 {
198 if (id.get_type() == TypeVariable)
199 {
200 auto &var = id.get<SPIRVariable>();
201 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100202
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200203 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
204 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200205 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200206 {
207 emit_interface_block(var);
208 }
209 }
210 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100211
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200212 // Output Uniform Constants (values, samplers, images, etc).
213 for (auto &id : ids)
214 {
215 if (id.get_type() == TypeVariable)
216 {
217 auto &var = id.get<SPIRVariable>();
218 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100219
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200220 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200221 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
222 {
223 emit_uniform(var);
224 }
225 }
226 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100227
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200228 // Global variables.
229 bool emitted = false;
230 for (auto global : global_variables)
231 {
232 auto &var = get<SPIRVariable>(global);
233 if (var.storage == StorageClassWorkgroup)
234 {
235 emit_shared(var);
236 emitted = true;
237 }
238 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200240 if (emitted)
241 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100242
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200243 statement("inline void init(spirv_cross_shader& s)");
244 begin_scope();
245 statement(resource_type, "::init(s);");
246 for (auto &reg : resource_registrations)
247 statement(reg);
248 end_scope();
249 resource_registrations.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100250
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200251 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100252
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200253 statement("");
254 statement("Resources* __res;");
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200255 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200256 statement("ComputePrivateResources __priv_res;");
257 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100258
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200259 // Emit regular globals which are allocated per invocation.
260 emitted = false;
261 for (auto global : global_variables)
262 {
263 auto &var = get<SPIRVariable>(global);
264 if (var.storage == StorageClassPrivate)
265 {
266 if (var.storage == StorageClassWorkgroup)
267 emit_shared(var);
268 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200269 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200270 emitted = true;
271 }
272 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100273
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200274 if (emitted)
275 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100276}
277
278string CompilerCPP::compile()
279{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200280 // Do not deal with ES-isms like precision, older extensions and such.
281 options.es = false;
282 options.version = 450;
283 backend.float_literal_suffix = true;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200284 backend.double_literal_suffix = false;
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200285 backend.long_long_literal_suffix = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200286 backend.uint32_t_literal_suffix = true;
287 backend.basic_int_type = "int32_t";
288 backend.basic_uint_type = "uint32_t";
289 backend.swizzle_is_function = true;
290 backend.shared_is_implied = true;
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +0200291 backend.flexible_member_array_supported = false;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200292 backend.explicit_struct_type = true;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200293 backend.use_initializer_list = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100294
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200295 uint32_t pass_count = 0;
296 do
297 {
298 if (pass_count >= 3)
299 throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100300
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200301 resource_registrations.clear();
302 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100303
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200304 // Move constructor for this type is broken on GCC 4.9 ...
305 buffer = unique_ptr<ostringstream>(new ostringstream());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200307 emit_header();
308 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100309
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200310 emit_function(get<SPIRFunction>(entry_point), 0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200312 pass_count++;
313 } while (force_recompile);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200315 // Match opening scope of emit_header().
316 end_scope_decl();
317 // namespace
318 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200320 // Emit C entry points
321 emit_c_linkage();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200323 return buffer->str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100324}
325
326void CompilerCPP::emit_c_linkage()
327{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200328 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100329
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200330 statement("spirv_cross_shader_t *spirv_cross_construct(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200331 begin_scope();
332 statement("return new ", impl_type, "();");
333 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200335 statement("");
336 statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
337 begin_scope();
338 statement("delete static_cast<", impl_type, "*>(shader);");
339 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 statement("");
342 statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
343 begin_scope();
344 statement("static_cast<", impl_type, "*>(shader)->invoke();");
345 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100346
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200347 statement("");
348 statement("static const struct spirv_cross_interface vtable =");
349 begin_scope();
350 statement("spirv_cross_construct,");
351 statement("spirv_cross_destruct,");
352 statement("spirv_cross_invoke,");
353 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200355 statement("");
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200356 statement("const struct spirv_cross_interface *",
357 interface_name.empty() ? string("spirv_cross_get_interface") : interface_name, "(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200358 begin_scope();
359 statement("return &vtable;");
360 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100361}
362
363void CompilerCPP::emit_function_prototype(SPIRFunction &func, uint64_t)
364{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200365 local_variable_names = resource_names;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200366 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100367
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200368 auto &type = get<SPIRType>(func.return_type);
369 decl += "inline ";
370 decl += type_to_glsl(type);
371 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100372
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200373 if (func.self == entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200374 {
375 decl += "main";
376 processing_entry_point = true;
377 }
378 else
379 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100380
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200381 decl += "(";
382 for (auto &arg : func.arguments)
383 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200384 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100385
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200386 decl += argument_decl(arg);
387 if (&arg != &func.arguments.back())
388 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200390 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
391 auto *var = maybe_get<SPIRVariable>(arg.id);
392 if (var)
393 var->parameter = &arg;
394 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100395
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200396 decl += ")";
397 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100398}
399
400string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg)
401{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200402 auto &type = expression_type(arg.id);
403 bool constref = !type.pointer || arg.write_count == 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100404
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200405 auto &var = get<SPIRVariable>(arg.id);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200406
407 string base = type_to_glsl(type);
408 for (auto &array : type.array)
409 base = join("std::array<", base, ", ", array, ">");
410
411 return join(constref ? "const " : "", base, " &", to_name(var.self));
412}
413
414string CompilerCPP::variable_decl(const SPIRType &type, const string &name)
415{
416 string base = type_to_glsl(type);
417 bool runtime = false;
418 for (auto &array : type.array)
419 {
420 if (array)
421 base = join("std::array<", base, ", ", array, ">");
422 else
423 {
424 // Avoid using runtime arrays with std::array since this is undefined.
425 // Runtime arrays cannot be passed around as values, so this is fine.
426 runtime = true;
427 }
428 }
429 base += ' ';
430 return base + name + (runtime ? "[1]" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100431}
432
433void CompilerCPP::emit_header()
434{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200435 auto &execution = get_entry_point();
436
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200437 statement("// This C++ shader is autogenerated by spirv-cross.");
438 statement("#include \"spirv_cross/internal_interface.hpp\"");
439 statement("#include \"spirv_cross/external_interface.h\"");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200440 // Needed to properly implement GLSL-style arrays.
441 statement("#include <array>");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200442 statement("#include <stdint.h>");
443 statement("");
444 statement("using namespace spirv_cross;");
445 statement("using namespace glm;");
446 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100447
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200448 statement("namespace Impl");
449 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100450
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200451 switch (execution.model)
452 {
453 case ExecutionModelGeometry:
454 case ExecutionModelTessellationControl:
455 case ExecutionModelTessellationEvaluation:
456 case ExecutionModelGLCompute:
457 case ExecutionModelFragment:
458 case ExecutionModelVertex:
459 statement("struct Shader");
460 begin_scope();
461 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100462
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200463 default:
464 throw CompilerError("Unsupported execution model.");
465 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100466
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200467 switch (execution.model)
468 {
469 case ExecutionModelGeometry:
470 impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
471 resource_type = "GeometryResources";
472 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100473
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200474 case ExecutionModelVertex:
475 impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
476 resource_type = "VertexResources";
477 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200479 case ExecutionModelFragment:
480 impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
481 resource_type = "FragmentResources";
482 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100483
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200484 case ExecutionModelGLCompute:
485 impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution.workgroup_size.x, ", ",
486 execution.workgroup_size.y, ", ", execution.workgroup_size.z, ">");
487 resource_type = "ComputeResources";
488 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100489
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200490 case ExecutionModelTessellationControl:
491 impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
492 resource_type = "TessControlResources";
493 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100494
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200495 case ExecutionModelTessellationEvaluation:
496 impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
497 resource_type = "TessEvaluationResources";
498 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100499
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200500 default:
501 throw CompilerError("Unsupported execution model.");
502 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100503}