blob: b7946bf337f1ffddf84415ca6e23c38585313e49 [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzen47044822021-01-14 16:07:49 +01002 * Copyright 2015-2021 Arm Limited
Jon Leechf2a65542021-05-08 01:47:48 -07003 * SPDX-License-Identifier: Apache-2.0 OR MIT
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010018/*
19 * At your option, you may choose to accept this material under either:
20 * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
21 * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010022 */
23
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020024#include "spirv_cpp.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010025
26using namespace spv;
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010027using namespace SPIRV_CROSS_NAMESPACE;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010028using namespace std;
29
30void CompilerCPP::emit_buffer_block(const SPIRVariable &var)
31{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020032 add_resource_name(var.self);
33
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020034 auto &type = get<SPIRType>(var.basetype);
35 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010036
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020037 uint32_t descriptor_set = ir.meta[var.self].decoration.set;
38 uint32_t binding = ir.meta[var.self].decoration.binding;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010039
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020040 emit_block_struct(type);
41 auto buffer_name = to_name(type.self);
42
43 statement("internal::Resource<", buffer_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020044 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
45 resource_registrations.push_back(
46 join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
47 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010048}
49
50void CompilerCPP::emit_interface_block(const SPIRVariable &var)
51{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020052 add_resource_name(var.self);
53
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020054 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010055
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020056 const char *qual = var.storage == StorageClassInput ? "StageInput" : "StageOutput";
57 const char *lowerqual = var.storage == StorageClassInput ? "stage_input" : "stage_output";
58 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020059 uint32_t location = ir.meta[var.self].decoration.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010060
Hans-Kristian Arntzen885c24f2016-08-26 13:43:21 +020061 string buffer_name;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020062 auto flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010063 if (flags.get(DecorationBlock))
Hans-Kristian Arntzen885c24f2016-08-26 13:43:21 +020064 {
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020065 emit_block_struct(type);
Hans-Kristian Arntzen885c24f2016-08-26 13:43:21 +020066 buffer_name = to_name(type.self);
67 }
68 else
69 buffer_name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010070
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020071 statement("internal::", qual, "<", buffer_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020072 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
73 resource_registrations.push_back(join("s.register_", lowerqual, "(", instance_name, "__", ", ", location, ");"));
74 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010075}
76
77void CompilerCPP::emit_shared(const SPIRVariable &var)
78{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020079 add_resource_name(var.self);
80
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020081 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020082 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020083 statement_no_indent("#define ", instance_name, " __res->", instance_name);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010084}
85
86void CompilerCPP::emit_uniform(const SPIRVariable &var)
87{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020088 add_resource_name(var.self);
89
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020090 auto &type = get<SPIRType>(var.basetype);
91 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010092
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020093 uint32_t descriptor_set = ir.meta[var.self].decoration.set;
94 uint32_t binding = ir.meta[var.self].decoration.binding;
95 uint32_t location = ir.meta[var.self].decoration.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010096
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +020097 string type_name = type_to_glsl(type);
98 remap_variable_type_name(type, instance_name, type_name);
99
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200100 if (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
101 type.basetype == SPIRType::AtomicCounter)
102 {
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200103 statement("internal::Resource<", 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_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
107 }
108 else
109 {
Hans-Kristian Arntzen18129662016-09-21 08:20:16 +0200110 statement("internal::UniformConstant<", type_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200111 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
112 resource_registrations.push_back(
113 join("s.register_uniform_constant(", instance_name, "__", ", ", location, ");"));
114 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100115
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200116 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100117}
118
119void CompilerCPP::emit_push_constant_block(const SPIRVariable &var)
120{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200121 add_resource_name(var.self);
122
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200123 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200124 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100125 if (flags.get(DecorationBinding) || flags.get(DecorationDescriptorSet))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100126 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
127 "Remap to location with reflection API first or disable these decorations.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100128
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200129 emit_block_struct(type);
130 auto buffer_name = to_name(type.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200131 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100132
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200133 statement("internal::PushConstant<", buffer_name, type_to_array_glsl(type), "> ", instance_name, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200134 statement_no_indent("#define ", instance_name, " __res->", instance_name, ".get()");
135 resource_registrations.push_back(join("s.register_push_constant(", instance_name, "__", ");"));
136 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100137}
138
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200139void CompilerCPP::emit_block_struct(SPIRType &type)
140{
141 // C++ can't do interface blocks, so we fake it by emitting a separate struct.
142 // However, these structs are not allowed to alias anything, so remove it before
143 // emitting the struct.
144 //
145 // The type we have here needs to be resolved to the non-pointer type so we can remove aliases.
146 auto &self = get<SPIRType>(type.self);
147 self.type_alias = 0;
148 emit_struct(self);
149}
150
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100151void CompilerCPP::emit_resources()
152{
Hans-Kristian Arntzen7cb04c72018-11-27 10:49:19 +0100153 for (auto &id : ir.ids)
154 {
155 if (id.get_type() == TypeConstant)
156 {
157 auto &c = id.get<SPIRConstant>();
158
159 bool needs_declaration = c.specialization || c.is_used_as_lut;
160
161 if (needs_declaration)
162 {
163 if (!options.vulkan_semantics && c.specialization)
164 {
165 c.specialization_constant_macro_name =
166 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
167 }
168 emit_constant(c);
169 }
170 }
171 else if (id.get_type() == TypeConstantOp)
172 {
173 emit_specialization_constant_op(id.get<SPIRConstantOp>());
174 }
175 }
176
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200177 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
178 // when such variables are instantiated.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200179 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200180 {
181 if (id.get_type() == TypeType)
182 {
183 auto &type = id.get<SPIRType>();
184 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200185 (!ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) &&
186 !ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200187 {
188 emit_struct(type);
189 }
190 }
191 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200193 statement("struct Resources : ", resource_type);
194 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100195
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200196 // Output UBOs and SSBOs
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200197 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200198 {
199 if (id.get_type() == TypeVariable)
200 {
201 auto &var = id.get<SPIRVariable>();
202 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100203
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +0200204 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +0100205 !is_hidden_variable(var) &&
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200206 (ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
207 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200208 {
209 emit_buffer_block(var);
210 }
211 }
212 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100213
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200214 // Output push constant blocks
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200215 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200216 {
217 if (id.get_type() == TypeVariable)
218 {
219 auto &var = id.get<SPIRVariable>();
220 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200221 if (!is_hidden_variable(var) && var.storage != StorageClassFunction && type.pointer &&
222 type.storage == StorageClassPushConstant)
223 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200224 emit_push_constant_block(var);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200225 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200226 }
227 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100228
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200229 // Output in/out interfaces.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200230 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200231 {
232 if (id.get_type() == TypeVariable)
233 {
234 auto &var = id.get<SPIRVariable>();
235 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100236
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200237 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
238 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200239 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200240 {
241 emit_interface_block(var);
242 }
243 }
244 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100245
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200246 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200247 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200248 {
249 if (id.get_type() == TypeVariable)
250 {
251 auto &var = id.get<SPIRVariable>();
252 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100253
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200254 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200255 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
256 {
257 emit_uniform(var);
258 }
259 }
260 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100261
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200262 // Global variables.
263 bool emitted = false;
264 for (auto global : global_variables)
265 {
266 auto &var = get<SPIRVariable>(global);
267 if (var.storage == StorageClassWorkgroup)
268 {
269 emit_shared(var);
270 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
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +0200277 declare_undefined_values();
278
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200279 statement("inline void init(spirv_cross_shader& s)");
280 begin_scope();
281 statement(resource_type, "::init(s);");
282 for (auto &reg : resource_registrations)
283 statement(reg);
284 end_scope();
285 resource_registrations.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100286
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200287 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200289 statement("");
290 statement("Resources* __res;");
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200291 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200292 statement("ComputePrivateResources __priv_res;");
293 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100294
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200295 // Emit regular globals which are allocated per invocation.
296 emitted = false;
297 for (auto global : global_variables)
298 {
299 auto &var = get<SPIRVariable>(global);
300 if (var.storage == StorageClassPrivate)
301 {
302 if (var.storage == StorageClassWorkgroup)
303 emit_shared(var);
304 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200305 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200306 emitted = true;
307 }
308 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100309
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200310 if (emitted)
311 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100312}
313
314string CompilerCPP::compile()
315{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200316 ir.fixup_reserved_names();
317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200318 // Do not deal with ES-isms like precision, older extensions and such.
319 options.es = false;
320 options.version = 450;
321 backend.float_literal_suffix = true;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200322 backend.double_literal_suffix = false;
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200323 backend.long_long_literal_suffix = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200324 backend.uint32_t_literal_suffix = true;
325 backend.basic_int_type = "int32_t";
326 backend.basic_uint_type = "uint32_t";
327 backend.swizzle_is_function = true;
328 backend.shared_is_implied = true;
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +0200329 backend.unsized_array_supported = false;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200330 backend.explicit_struct_type = true;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200331 backend.use_initializer_list = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100332
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200333 fixup_type_alias();
334 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200335 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100336 update_active_builtins();
337
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200338 uint32_t pass_count = 0;
339 do
340 {
341 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100342 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100343
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200344 resource_registrations.clear();
345 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100346
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200347 // Move constructor for this type is broken on GCC 4.9 ...
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200348 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100349
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200350 emit_header();
351 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100352
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200353 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200355 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200356 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100357
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200358 // Match opening scope of emit_header().
359 end_scope_decl();
360 // namespace
361 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100362
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200363 // Emit C entry points
364 emit_c_linkage();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100365
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100366 // Entry point in CPP is always main() for the time being.
367 get_entry_point().name = "main";
368
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200369 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100370}
371
372void CompilerCPP::emit_c_linkage()
373{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200374 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100375
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200376 statement("spirv_cross_shader_t *spirv_cross_construct(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200377 begin_scope();
378 statement("return new ", impl_type, "();");
379 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100380
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200381 statement("");
382 statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
383 begin_scope();
384 statement("delete static_cast<", impl_type, "*>(shader);");
385 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100386
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200387 statement("");
388 statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
389 begin_scope();
390 statement("static_cast<", impl_type, "*>(shader)->invoke();");
391 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100392
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200393 statement("");
394 statement("static const struct spirv_cross_interface vtable =");
395 begin_scope();
396 statement("spirv_cross_construct,");
397 statement("spirv_cross_destruct,");
398 statement("spirv_cross_invoke,");
399 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100400
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200401 statement("");
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200402 statement("const struct spirv_cross_interface *",
403 interface_name.empty() ? string("spirv_cross_get_interface") : interface_name, "(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200404 begin_scope();
405 statement("return &vtable;");
406 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100407}
408
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100409void CompilerCPP::emit_function_prototype(SPIRFunction &func, const Bitset &)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100410{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200411 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +0100412 add_function_overload(func);
413
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200414 local_variable_names = resource_names;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200415 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200417 auto &type = get<SPIRType>(func.return_type);
418 decl += "inline ";
419 decl += type_to_glsl(type);
420 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100421
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200422 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200423 {
424 decl += "main";
425 processing_entry_point = true;
426 }
427 else
428 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100429
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200430 decl += "(";
431 for (auto &arg : func.arguments)
432 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200433 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100434
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200435 decl += argument_decl(arg);
436 if (&arg != &func.arguments.back())
437 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100438
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200439 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
440 auto *var = maybe_get<SPIRVariable>(arg.id);
441 if (var)
442 var->parameter = &arg;
443 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200445 decl += ")";
446 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100447}
448
449string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg)
450{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200451 auto &type = expression_type(arg.id);
452 bool constref = !type.pointer || arg.write_count == 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100453
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200454 auto &var = get<SPIRVariable>(arg.id);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200455
456 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200457 string variable_name = to_name(var.self);
458 remap_variable_type_name(type, variable_name, base);
459
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200460 for (uint32_t i = 0; i < type.array.size(); i++)
461 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200462
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200463 return join(constref ? "const " : "", base, " &", variable_name);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200464}
465
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +0200466string CompilerCPP::variable_decl(const SPIRType &type, const string &name, uint32_t /* id */)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200467{
468 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200469 remap_variable_type_name(type, name, base);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200470 bool runtime = false;
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200471
472 for (uint32_t i = 0; i < type.array.size(); i++)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200473 {
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200474 auto &array = type.array[i];
475 if (!array && type.array_size_literal[i])
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200476 {
477 // Avoid using runtime arrays with std::array since this is undefined.
478 // Runtime arrays cannot be passed around as values, so this is fine.
479 runtime = true;
480 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200481 else
482 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200483 }
484 base += ' ';
485 return base + name + (runtime ? "[1]" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100486}
487
488void CompilerCPP::emit_header()
489{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200490 auto &execution = get_entry_point();
491
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200492 statement("// This C++ shader is autogenerated by spirv-cross.");
493 statement("#include \"spirv_cross/internal_interface.hpp\"");
494 statement("#include \"spirv_cross/external_interface.h\"");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200495 // Needed to properly implement GLSL-style arrays.
496 statement("#include <array>");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200497 statement("#include <stdint.h>");
498 statement("");
499 statement("using namespace spirv_cross;");
500 statement("using namespace glm;");
501 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200503 statement("namespace Impl");
504 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100505
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200506 switch (execution.model)
507 {
508 case ExecutionModelGeometry:
509 case ExecutionModelTessellationControl:
510 case ExecutionModelTessellationEvaluation:
511 case ExecutionModelGLCompute:
512 case ExecutionModelFragment:
513 case ExecutionModelVertex:
514 statement("struct Shader");
515 begin_scope();
516 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100517
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200518 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100519 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200520 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100521
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200522 switch (execution.model)
523 {
524 case ExecutionModelGeometry:
525 impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
526 resource_type = "GeometryResources";
527 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200529 case ExecutionModelVertex:
530 impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
531 resource_type = "VertexResources";
532 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200534 case ExecutionModelFragment:
535 impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
536 resource_type = "FragmentResources";
537 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100538
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200539 case ExecutionModelGLCompute:
540 impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution.workgroup_size.x, ", ",
541 execution.workgroup_size.y, ", ", execution.workgroup_size.z, ">");
542 resource_type = "ComputeResources";
543 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200545 case ExecutionModelTessellationControl:
546 impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
547 resource_type = "TessControlResources";
548 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100549
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200550 case ExecutionModelTessellationEvaluation:
551 impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
552 resource_type = "TessEvaluationResources";
553 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200555 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100556 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200557 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100558}