blob: 223a954131f4e0c64463c1e6634568da2e82f1f3 [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 Arntzen4d4e6d72016-09-20 10:55:09 +020090 string type_name = type_to_glsl(type);
91 remap_variable_type_name(type, instance_name, type_name);
92
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020093 if (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
94 type.basetype == SPIRType::AtomicCounter)
95 {
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +020096 statement("internal::Resource<", type_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020097 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
98 resource_registrations.push_back(
99 join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
100 }
101 else
102 {
Hans-Kristian Arntzen18129662016-09-21 08:20:16 +0200103 statement("internal::UniformConstant<", type_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200104 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
105 resource_registrations.push_back(
106 join("s.register_uniform_constant(", instance_name, "__", ", ", location, ");"));
107 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200109 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100110}
111
112void CompilerCPP::emit_push_constant_block(const SPIRVariable &var)
113{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200114 add_resource_name(var.self);
115
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200116 auto &type = get<SPIRType>(var.basetype);
117 auto &flags = meta[var.self].decoration.decoration_flags;
118 if ((flags & (1ull << DecorationBinding)) || (flags & (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100119 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
120 "Remap to location with reflection API first or disable these decorations.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100121
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200122 emit_block_struct(type);
123 auto buffer_name = to_name(type.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200124 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100125
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200126 statement("internal::PushConstant<", buffer_name, type_to_array_glsl(type), "> ", instance_name, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200127 statement_no_indent("#define ", instance_name, " __res->", instance_name, ".get()");
128 resource_registrations.push_back(join("s.register_push_constant(", instance_name, "__", ");"));
129 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100130}
131
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200132void CompilerCPP::emit_block_struct(SPIRType &type)
133{
134 // C++ can't do interface blocks, so we fake it by emitting a separate struct.
135 // However, these structs are not allowed to alias anything, so remove it before
136 // emitting the struct.
137 //
138 // The type we have here needs to be resolved to the non-pointer type so we can remove aliases.
139 auto &self = get<SPIRType>(type.self);
140 self.type_alias = 0;
141 emit_struct(self);
142}
143
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100144void CompilerCPP::emit_resources()
145{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200146 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
147 // when such variables are instantiated.
148 for (auto &id : ids)
149 {
150 if (id.get_type() == TypeType)
151 {
152 auto &type = id.get<SPIRType>();
153 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
154 (meta[type.self].decoration.decoration_flags &
155 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
156 {
157 emit_struct(type);
158 }
159 }
160 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100161
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200162 statement("struct Resources : ", resource_type);
163 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100164
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200165 // Output UBOs and SSBOs
166 for (auto &id : ids)
167 {
168 if (id.get_type() == TypeVariable)
169 {
170 auto &var = id.get<SPIRVariable>();
171 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100172
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +0200173 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200174 !is_hidden_variable(var) && (meta[type.self].decoration.decoration_flags &
175 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200176 {
177 emit_buffer_block(var);
178 }
179 }
180 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100181
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200182 // Output push constant blocks
183 for (auto &id : ids)
184 {
185 if (id.get_type() == TypeVariable)
186 {
187 auto &var = id.get<SPIRVariable>();
188 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200189 if (!is_hidden_variable(var) && var.storage != StorageClassFunction && type.pointer &&
190 type.storage == StorageClassPushConstant)
191 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200192 emit_push_constant_block(var);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200193 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200194 }
195 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100196
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200197 // Output in/out interfaces.
198 for (auto &id : ids)
199 {
200 if (id.get_type() == TypeVariable)
201 {
202 auto &var = id.get<SPIRVariable>();
203 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100204
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200205 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
206 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200207 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200208 {
209 emit_interface_block(var);
210 }
211 }
212 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100213
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200214 // Output Uniform Constants (values, samplers, images, etc).
215 for (auto &id : ids)
216 {
217 if (id.get_type() == TypeVariable)
218 {
219 auto &var = id.get<SPIRVariable>();
220 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100221
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200222 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200223 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
224 {
225 emit_uniform(var);
226 }
227 }
228 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100229
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200230 // Global variables.
231 bool emitted = false;
232 for (auto global : global_variables)
233 {
234 auto &var = get<SPIRVariable>(global);
235 if (var.storage == StorageClassWorkgroup)
236 {
237 emit_shared(var);
238 emitted = true;
239 }
240 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100241
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200242 if (emitted)
243 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100244
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200245 statement("inline void init(spirv_cross_shader& s)");
246 begin_scope();
247 statement(resource_type, "::init(s);");
248 for (auto &reg : resource_registrations)
249 statement(reg);
250 end_scope();
251 resource_registrations.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100252
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200253 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100254
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200255 statement("");
256 statement("Resources* __res;");
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200257 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200258 statement("ComputePrivateResources __priv_res;");
259 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200261 // Emit regular globals which are allocated per invocation.
262 emitted = false;
263 for (auto global : global_variables)
264 {
265 auto &var = get<SPIRVariable>(global);
266 if (var.storage == StorageClassPrivate)
267 {
268 if (var.storage == StorageClassWorkgroup)
269 emit_shared(var);
270 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200271 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200272 emitted = true;
273 }
274 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100275
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200276 if (emitted)
277 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100278}
279
280string CompilerCPP::compile()
281{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200282 // Do not deal with ES-isms like precision, older extensions and such.
283 options.es = false;
284 options.version = 450;
285 backend.float_literal_suffix = true;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200286 backend.double_literal_suffix = false;
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200287 backend.long_long_literal_suffix = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200288 backend.uint32_t_literal_suffix = true;
289 backend.basic_int_type = "int32_t";
290 backend.basic_uint_type = "uint32_t";
291 backend.swizzle_is_function = true;
292 backend.shared_is_implied = true;
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +0200293 backend.flexible_member_array_supported = false;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200294 backend.explicit_struct_type = true;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200295 backend.use_initializer_list = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200297 uint32_t pass_count = 0;
298 do
299 {
300 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100301 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200303 resource_registrations.clear();
304 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100305
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200306 // Move constructor for this type is broken on GCC 4.9 ...
307 buffer = unique_ptr<ostringstream>(new ostringstream());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100308
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200309 emit_header();
310 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100311
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200312 emit_function(get<SPIRFunction>(entry_point), 0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100313
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200314 pass_count++;
315 } while (force_recompile);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100316
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200317 // Match opening scope of emit_header().
318 end_scope_decl();
319 // namespace
320 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100321
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200322 // Emit C entry points
323 emit_c_linkage();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100324
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200325 return buffer->str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100326}
327
328void CompilerCPP::emit_c_linkage()
329{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200330 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100331
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200332 statement("spirv_cross_shader_t *spirv_cross_construct(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200333 begin_scope();
334 statement("return new ", impl_type, "();");
335 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200337 statement("");
338 statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
339 begin_scope();
340 statement("delete static_cast<", impl_type, "*>(shader);");
341 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100342
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200343 statement("");
344 statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
345 begin_scope();
346 statement("static_cast<", impl_type, "*>(shader)->invoke();");
347 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200349 statement("");
350 statement("static const struct spirv_cross_interface vtable =");
351 begin_scope();
352 statement("spirv_cross_construct,");
353 statement("spirv_cross_destruct,");
354 statement("spirv_cross_invoke,");
355 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100356
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200357 statement("");
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200358 statement("const struct spirv_cross_interface *",
359 interface_name.empty() ? string("spirv_cross_get_interface") : interface_name, "(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200360 begin_scope();
361 statement("return &vtable;");
362 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100363}
364
365void CompilerCPP::emit_function_prototype(SPIRFunction &func, uint64_t)
366{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200367 local_variable_names = resource_names;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200368 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100369
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200370 auto &type = get<SPIRType>(func.return_type);
371 decl += "inline ";
372 decl += type_to_glsl(type);
373 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100374
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200375 if (func.self == entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200376 {
377 decl += "main";
378 processing_entry_point = true;
379 }
380 else
381 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100382
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200383 decl += "(";
384 for (auto &arg : func.arguments)
385 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200386 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100387
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200388 decl += argument_decl(arg);
389 if (&arg != &func.arguments.back())
390 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100391
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200392 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
393 auto *var = maybe_get<SPIRVariable>(arg.id);
394 if (var)
395 var->parameter = &arg;
396 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100397
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200398 decl += ")";
399 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100400}
401
402string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg)
403{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200404 auto &type = expression_type(arg.id);
405 bool constref = !type.pointer || arg.write_count == 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100406
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200407 auto &var = get<SPIRVariable>(arg.id);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200408
409 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200410 string variable_name = to_name(var.self);
411 remap_variable_type_name(type, variable_name, base);
412
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200413 for (uint32_t i = 0; i < type.array.size(); i++)
414 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200415
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200416 return join(constref ? "const " : "", base, " &", variable_name);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200417}
418
419string CompilerCPP::variable_decl(const SPIRType &type, const string &name)
420{
421 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200422 remap_variable_type_name(type, name, base);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200423 bool runtime = false;
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200424
425 for (uint32_t i = 0; i < type.array.size(); i++)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200426 {
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200427 auto &array = type.array[i];
428 if (!array && type.array_size_literal[i])
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200429 {
430 // Avoid using runtime arrays with std::array since this is undefined.
431 // Runtime arrays cannot be passed around as values, so this is fine.
432 runtime = true;
433 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200434 else
435 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200436 }
437 base += ' ';
438 return base + name + (runtime ? "[1]" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100439}
440
441void CompilerCPP::emit_header()
442{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200443 auto &execution = get_entry_point();
444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200445 statement("// This C++ shader is autogenerated by spirv-cross.");
446 statement("#include \"spirv_cross/internal_interface.hpp\"");
447 statement("#include \"spirv_cross/external_interface.h\"");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200448 // Needed to properly implement GLSL-style arrays.
449 statement("#include <array>");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200450 statement("#include <stdint.h>");
451 statement("");
452 statement("using namespace spirv_cross;");
453 statement("using namespace glm;");
454 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100455
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200456 statement("namespace Impl");
457 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100458
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200459 switch (execution.model)
460 {
461 case ExecutionModelGeometry:
462 case ExecutionModelTessellationControl:
463 case ExecutionModelTessellationEvaluation:
464 case ExecutionModelGLCompute:
465 case ExecutionModelFragment:
466 case ExecutionModelVertex:
467 statement("struct Shader");
468 begin_scope();
469 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100470
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200471 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100472 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200473 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100474
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200475 switch (execution.model)
476 {
477 case ExecutionModelGeometry:
478 impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
479 resource_type = "GeometryResources";
480 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100481
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200482 case ExecutionModelVertex:
483 impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
484 resource_type = "VertexResources";
485 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100486
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200487 case ExecutionModelFragment:
488 impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
489 resource_type = "FragmentResources";
490 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100491
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200492 case ExecutionModelGLCompute:
493 impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution.workgroup_size.x, ", ",
494 execution.workgroup_size.y, ", ", execution.workgroup_size.z, ">");
495 resource_type = "ComputeResources";
496 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100497
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200498 case ExecutionModelTessellationControl:
499 impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
500 resource_type = "TessControlResources";
501 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200503 case ExecutionModelTessellationEvaluation:
504 impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
505 resource_type = "TessEvaluationResources";
506 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100507
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200508 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100509 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200510 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100511}