blob: 8d934d2c579795bb8b306b6d44d825825a860088 [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 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 resource_registrations.clear();
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +0100342 reset(pass_count);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100343
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200344 // Move constructor for this type is broken on GCC 4.9 ...
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200345 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100346
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200347 emit_header();
348 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100349
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200350 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200352 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200353 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200355 // Match opening scope of emit_header().
356 end_scope_decl();
357 // namespace
358 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100359
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200360 // Emit C entry points
361 emit_c_linkage();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100362
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100363 // Entry point in CPP is always main() for the time being.
364 get_entry_point().name = "main";
365
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200366 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100367}
368
369void CompilerCPP::emit_c_linkage()
370{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200371 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100372
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200373 statement("spirv_cross_shader_t *spirv_cross_construct(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200374 begin_scope();
375 statement("return new ", impl_type, "();");
376 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100377
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200378 statement("");
379 statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
380 begin_scope();
381 statement("delete static_cast<", impl_type, "*>(shader);");
382 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100383
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200384 statement("");
385 statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
386 begin_scope();
387 statement("static_cast<", impl_type, "*>(shader)->invoke();");
388 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200390 statement("");
391 statement("static const struct spirv_cross_interface vtable =");
392 begin_scope();
393 statement("spirv_cross_construct,");
394 statement("spirv_cross_destruct,");
395 statement("spirv_cross_invoke,");
396 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100397
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200398 statement("");
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200399 statement("const struct spirv_cross_interface *",
400 interface_name.empty() ? string("spirv_cross_get_interface") : interface_name, "(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200401 begin_scope();
402 statement("return &vtable;");
403 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100404}
405
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100406void CompilerCPP::emit_function_prototype(SPIRFunction &func, const Bitset &)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100407{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200408 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +0100409 add_function_overload(func);
410
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200411 local_variable_names = resource_names;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200412 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100413
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200414 auto &type = get<SPIRType>(func.return_type);
415 decl += "inline ";
416 decl += type_to_glsl(type);
417 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100418
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200419 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200420 {
421 decl += "main";
422 processing_entry_point = true;
423 }
424 else
425 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100426
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200427 decl += "(";
428 for (auto &arg : func.arguments)
429 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200430 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200432 decl += argument_decl(arg);
433 if (&arg != &func.arguments.back())
434 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200436 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
437 auto *var = maybe_get<SPIRVariable>(arg.id);
438 if (var)
439 var->parameter = &arg;
440 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100441
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200442 decl += ")";
443 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100444}
445
446string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg)
447{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200448 auto &type = expression_type(arg.id);
449 bool constref = !type.pointer || arg.write_count == 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100450
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200451 auto &var = get<SPIRVariable>(arg.id);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200452
453 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200454 string variable_name = to_name(var.self);
455 remap_variable_type_name(type, variable_name, base);
456
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200457 for (uint32_t i = 0; i < type.array.size(); i++)
458 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200459
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200460 return join(constref ? "const " : "", base, " &", variable_name);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200461}
462
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +0200463string CompilerCPP::variable_decl(const SPIRType &type, const string &name, uint32_t /* id */)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200464{
465 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200466 remap_variable_type_name(type, name, base);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200467 bool runtime = false;
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200468
469 for (uint32_t i = 0; i < type.array.size(); i++)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200470 {
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200471 auto &array = type.array[i];
472 if (!array && type.array_size_literal[i])
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200473 {
474 // Avoid using runtime arrays with std::array since this is undefined.
475 // Runtime arrays cannot be passed around as values, so this is fine.
476 runtime = true;
477 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200478 else
479 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200480 }
481 base += ' ';
482 return base + name + (runtime ? "[1]" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100483}
484
485void CompilerCPP::emit_header()
486{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200487 auto &execution = get_entry_point();
488
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200489 statement("// This C++ shader is autogenerated by spirv-cross.");
490 statement("#include \"spirv_cross/internal_interface.hpp\"");
491 statement("#include \"spirv_cross/external_interface.h\"");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200492 // Needed to properly implement GLSL-style arrays.
493 statement("#include <array>");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200494 statement("#include <stdint.h>");
495 statement("");
496 statement("using namespace spirv_cross;");
497 statement("using namespace glm;");
498 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100499
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200500 statement("namespace Impl");
501 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200503 switch (execution.model)
504 {
505 case ExecutionModelGeometry:
506 case ExecutionModelTessellationControl:
507 case ExecutionModelTessellationEvaluation:
508 case ExecutionModelGLCompute:
509 case ExecutionModelFragment:
510 case ExecutionModelVertex:
511 statement("struct Shader");
512 begin_scope();
513 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100514
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200515 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100516 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200517 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100518
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200519 switch (execution.model)
520 {
521 case ExecutionModelGeometry:
522 impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
523 resource_type = "GeometryResources";
524 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100525
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200526 case ExecutionModelVertex:
527 impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
528 resource_type = "VertexResources";
529 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100530
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200531 case ExecutionModelFragment:
532 impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
533 resource_type = "FragmentResources";
534 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100535
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200536 case ExecutionModelGLCompute:
537 impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution.workgroup_size.x, ", ",
538 execution.workgroup_size.y, ", ", execution.workgroup_size.z, ">");
539 resource_type = "ComputeResources";
540 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200542 case ExecutionModelTessellationControl:
543 impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
544 resource_type = "TessControlResources";
545 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200547 case ExecutionModelTessellationEvaluation:
548 impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
549 resource_type = "TessEvaluationResources";
550 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100551
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200552 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100553 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200554 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100555}