blob: 25966b32ad7b961fc987a7d540ce9f812e2eee12 [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +01002 * Copyright 2015-2019 Arm Limited
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003 *
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 Arntzen9b92e682019-03-29 10:29:44 +010020using namespace SPIRV_CROSS_NAMESPACE;
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 Arntzen5bcf02f2018-10-05 11:30:57 +020030 uint32_t descriptor_set = ir.meta[var.self].decoration.set;
31 uint32_t binding = ir.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);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020052 uint32_t location = ir.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 Arntzen5bcf02f2018-10-05 11:30:57 +020055 auto flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010056 if (flags.get(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 Arntzen5bcf02f2018-10-05 11:30:57 +020086 uint32_t descriptor_set = ir.meta[var.self].decoration.set;
87 uint32_t binding = ir.meta[var.self].decoration.binding;
88 uint32_t location = ir.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);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200117 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100118 if (flags.get(DecorationBinding) || flags.get(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 Arntzen7cb04c72018-11-27 10:49:19 +0100146 for (auto &id : ir.ids)
147 {
148 if (id.get_type() == TypeConstant)
149 {
150 auto &c = id.get<SPIRConstant>();
151
152 bool needs_declaration = c.specialization || c.is_used_as_lut;
153
154 if (needs_declaration)
155 {
156 if (!options.vulkan_semantics && c.specialization)
157 {
158 c.specialization_constant_macro_name =
159 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
160 }
161 emit_constant(c);
162 }
163 }
164 else if (id.get_type() == TypeConstantOp)
165 {
166 emit_specialization_constant_op(id.get<SPIRConstantOp>());
167 }
168 }
169
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200170 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
171 // when such variables are instantiated.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200172 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200173 {
174 if (id.get_type() == TypeType)
175 {
176 auto &type = id.get<SPIRType>();
177 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200178 (!ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) &&
179 !ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200180 {
181 emit_struct(type);
182 }
183 }
184 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100185
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200186 statement("struct Resources : ", resource_type);
187 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100188
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200189 // Output UBOs and SSBOs
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200190 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200191 {
192 if (id.get_type() == TypeVariable)
193 {
194 auto &var = id.get<SPIRVariable>();
195 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100196
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +0200197 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +0100198 !is_hidden_variable(var) &&
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200199 (ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
200 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200201 {
202 emit_buffer_block(var);
203 }
204 }
205 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200207 // Output push constant blocks
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200208 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200209 {
210 if (id.get_type() == TypeVariable)
211 {
212 auto &var = id.get<SPIRVariable>();
213 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200214 if (!is_hidden_variable(var) && var.storage != StorageClassFunction && type.pointer &&
215 type.storage == StorageClassPushConstant)
216 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200217 emit_push_constant_block(var);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200218 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200219 }
220 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200222 // Output in/out interfaces.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200223 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200224 {
225 if (id.get_type() == TypeVariable)
226 {
227 auto &var = id.get<SPIRVariable>();
228 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100229
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200230 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
231 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200232 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200233 {
234 emit_interface_block(var);
235 }
236 }
237 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100238
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200239 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200240 for (auto &id : ir.ids)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200241 {
242 if (id.get_type() == TypeVariable)
243 {
244 auto &var = id.get<SPIRVariable>();
245 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100246
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200247 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200248 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
249 {
250 emit_uniform(var);
251 }
252 }
253 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100254
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200255 // Global variables.
256 bool emitted = false;
257 for (auto global : global_variables)
258 {
259 auto &var = get<SPIRVariable>(global);
260 if (var.storage == StorageClassWorkgroup)
261 {
262 emit_shared(var);
263 emitted = true;
264 }
265 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100266
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200267 if (emitted)
268 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100269
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +0200270 declare_undefined_values();
271
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200272 statement("inline void init(spirv_cross_shader& s)");
273 begin_scope();
274 statement(resource_type, "::init(s);");
275 for (auto &reg : resource_registrations)
276 statement(reg);
277 end_scope();
278 resource_registrations.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100279
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200280 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100281
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200282 statement("");
283 statement("Resources* __res;");
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200284 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200285 statement("ComputePrivateResources __priv_res;");
286 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100287
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200288 // Emit regular globals which are allocated per invocation.
289 emitted = false;
290 for (auto global : global_variables)
291 {
292 auto &var = get<SPIRVariable>(global);
293 if (var.storage == StorageClassPrivate)
294 {
295 if (var.storage == StorageClassWorkgroup)
296 emit_shared(var);
297 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200298 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200299 emitted = true;
300 }
301 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200303 if (emitted)
304 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100305}
306
307string CompilerCPP::compile()
308{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200309 // Do not deal with ES-isms like precision, older extensions and such.
310 options.es = false;
311 options.version = 450;
312 backend.float_literal_suffix = true;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200313 backend.double_literal_suffix = false;
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200314 backend.long_long_literal_suffix = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200315 backend.uint32_t_literal_suffix = true;
316 backend.basic_int_type = "int32_t";
317 backend.basic_uint_type = "uint32_t";
318 backend.swizzle_is_function = true;
319 backend.shared_is_implied = true;
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +0200320 backend.unsized_array_supported = false;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200321 backend.explicit_struct_type = true;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200322 backend.use_initializer_list = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100323
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200324 fixup_type_alias();
325 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200326 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100327 update_active_builtins();
328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200329 uint32_t pass_count = 0;
330 do
331 {
332 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100333 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200335 resource_registrations.clear();
336 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100337
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200338 // Move constructor for this type is broken on GCC 4.9 ...
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200339 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 emit_header();
342 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100343
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200344 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100345
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200346 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200347 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200349 // Match opening scope of emit_header().
350 end_scope_decl();
351 // namespace
352 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100353
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200354 // Emit C entry points
355 emit_c_linkage();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100356
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100357 // Entry point in CPP is always main() for the time being.
358 get_entry_point().name = "main";
359
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200360 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100361}
362
363void CompilerCPP::emit_c_linkage()
364{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200365 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100366
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200367 statement("spirv_cross_shader_t *spirv_cross_construct(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200368 begin_scope();
369 statement("return new ", impl_type, "();");
370 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100371
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200372 statement("");
373 statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
374 begin_scope();
375 statement("delete static_cast<", impl_type, "*>(shader);");
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_invoke(spirv_cross_shader_t *shader)");
380 begin_scope();
381 statement("static_cast<", impl_type, "*>(shader)->invoke();");
382 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100383
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200384 statement("");
385 statement("static const struct spirv_cross_interface vtable =");
386 begin_scope();
387 statement("spirv_cross_construct,");
388 statement("spirv_cross_destruct,");
389 statement("spirv_cross_invoke,");
390 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100391
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200392 statement("");
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200393 statement("const struct spirv_cross_interface *",
394 interface_name.empty() ? string("spirv_cross_get_interface") : interface_name, "(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200395 begin_scope();
396 statement("return &vtable;");
397 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100398}
399
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100400void CompilerCPP::emit_function_prototype(SPIRFunction &func, const Bitset &)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100401{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200402 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +0100403 add_function_overload(func);
404
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200405 local_variable_names = resource_names;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200406 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100407
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200408 auto &type = get<SPIRType>(func.return_type);
409 decl += "inline ";
410 decl += type_to_glsl(type);
411 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100412
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200413 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200414 {
415 decl += "main";
416 processing_entry_point = true;
417 }
418 else
419 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100420
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200421 decl += "(";
422 for (auto &arg : func.arguments)
423 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200424 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100425
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200426 decl += argument_decl(arg);
427 if (&arg != &func.arguments.back())
428 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100429
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200430 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
431 auto *var = maybe_get<SPIRVariable>(arg.id);
432 if (var)
433 var->parameter = &arg;
434 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200436 decl += ")";
437 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100438}
439
440string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg)
441{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200442 auto &type = expression_type(arg.id);
443 bool constref = !type.pointer || arg.write_count == 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200445 auto &var = get<SPIRVariable>(arg.id);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200446
447 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200448 string variable_name = to_name(var.self);
449 remap_variable_type_name(type, variable_name, base);
450
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200451 for (uint32_t i = 0; i < type.array.size(); i++)
452 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200453
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200454 return join(constref ? "const " : "", base, " &", variable_name);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200455}
456
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +0200457string CompilerCPP::variable_decl(const SPIRType &type, const string &name, uint32_t /* id */)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200458{
459 string base = type_to_glsl(type);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +0200460 remap_variable_type_name(type, name, base);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200461 bool runtime = false;
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200462
463 for (uint32_t i = 0; i < type.array.size(); i++)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200464 {
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200465 auto &array = type.array[i];
466 if (!array && type.array_size_literal[i])
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200467 {
468 // Avoid using runtime arrays with std::array since this is undefined.
469 // Runtime arrays cannot be passed around as values, so this is fine.
470 runtime = true;
471 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200472 else
473 base = join("std::array<", base, ", ", to_array_size(type, i), ">");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200474 }
475 base += ' ';
476 return base + name + (runtime ? "[1]" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100477}
478
479void CompilerCPP::emit_header()
480{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200481 auto &execution = get_entry_point();
482
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200483 statement("// This C++ shader is autogenerated by spirv-cross.");
484 statement("#include \"spirv_cross/internal_interface.hpp\"");
485 statement("#include \"spirv_cross/external_interface.h\"");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200486 // Needed to properly implement GLSL-style arrays.
487 statement("#include <array>");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200488 statement("#include <stdint.h>");
489 statement("");
490 statement("using namespace spirv_cross;");
491 statement("using namespace glm;");
492 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100493
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200494 statement("namespace Impl");
495 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100496
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200497 switch (execution.model)
498 {
499 case ExecutionModelGeometry:
500 case ExecutionModelTessellationControl:
501 case ExecutionModelTessellationEvaluation:
502 case ExecutionModelGLCompute:
503 case ExecutionModelFragment:
504 case ExecutionModelVertex:
505 statement("struct Shader");
506 begin_scope();
507 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100508
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200509 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100510 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200511 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100512
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200513 switch (execution.model)
514 {
515 case ExecutionModelGeometry:
516 impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
517 resource_type = "GeometryResources";
518 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100519
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200520 case ExecutionModelVertex:
521 impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
522 resource_type = "VertexResources";
523 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100524
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200525 case ExecutionModelFragment:
526 impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
527 resource_type = "FragmentResources";
528 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100529
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200530 case ExecutionModelGLCompute:
531 impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution.workgroup_size.x, ", ",
532 execution.workgroup_size.y, ", ", execution.workgroup_size.z, ">");
533 resource_type = "ComputeResources";
534 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100535
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200536 case ExecutionModelTessellationControl:
537 impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
538 resource_type = "TessControlResources";
539 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100540
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200541 case ExecutionModelTessellationEvaluation:
542 impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
543 resource_type = "TessEvaluationResources";
544 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100545
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200546 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100547 SPIRV_CROSS_THROW("Unsupported execution model.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200548 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100549}