blob: 54cf78b51833645925fd76b1866d0ed009930fe0 [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 Arntzen4b8ed532016-05-05 09:33:18 +020054 auto flags = meta[type.self].decoration.decoration_flags;
55 if (flags & (1ull << DecorationBlock))
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020056 emit_block_struct(type);
57 auto buffer_name = to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010058
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +020059 statement("internal::", qual, "<", buffer_name, type_to_array_glsl(type), "> ", instance_name, "__;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020060 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
61 resource_registrations.push_back(join("s.register_", lowerqual, "(", instance_name, "__", ", ", location, ");"));
62 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010063}
64
65void CompilerCPP::emit_shared(const SPIRVariable &var)
66{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020067 add_resource_name(var.self);
68
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020069 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020070 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020071 statement_no_indent("#define ", instance_name, " __res->", instance_name);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010072}
73
74void CompilerCPP::emit_uniform(const SPIRVariable &var)
75{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020076 add_resource_name(var.self);
77
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020078 auto &type = get<SPIRType>(var.basetype);
79 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010080
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020081 uint32_t descriptor_set = meta[var.self].decoration.set;
82 uint32_t binding = meta[var.self].decoration.binding;
83 uint32_t location = meta[var.self].decoration.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010084
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020085 if (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
86 type.basetype == SPIRType::AtomicCounter)
87 {
88 statement("internal::Resource<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name, "__;");
89 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
90 resource_registrations.push_back(
91 join("s.register_resource(", instance_name, "__", ", ", descriptor_set, ", ", binding, ");"));
92 }
93 else
94 {
95 statement("internal::UniformConstant<", type_to_glsl(type), type_to_array_glsl(type), "> ", instance_name,
96 "__;");
97 statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
98 resource_registrations.push_back(
99 join("s.register_uniform_constant(", instance_name, "__", ", ", location, ");"));
100 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200102 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100103}
104
105void CompilerCPP::emit_push_constant_block(const SPIRVariable &var)
106{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200107 add_resource_name(var.self);
108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200109 auto &type = get<SPIRType>(var.basetype);
110 auto &flags = meta[var.self].decoration.decoration_flags;
111 if ((flags & (1ull << DecorationBinding)) || (flags & (1ull << DecorationDescriptorSet)))
112 throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
113 "Remap to location with reflection API first or disable these decorations.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100114
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200115 emit_block_struct(type);
116 auto buffer_name = to_name(type.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200117 auto instance_name = to_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100118
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200119 statement("internal::PushConstant<", buffer_name, type_to_array_glsl(type), "> ", instance_name, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200120 statement_no_indent("#define ", instance_name, " __res->", instance_name, ".get()");
121 resource_registrations.push_back(join("s.register_push_constant(", instance_name, "__", ");"));
122 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100123}
124
Hans-Kristian Arntzen2eb60372016-05-23 14:18:00 +0200125void CompilerCPP::emit_block_struct(SPIRType &type)
126{
127 // C++ can't do interface blocks, so we fake it by emitting a separate struct.
128 // However, these structs are not allowed to alias anything, so remove it before
129 // emitting the struct.
130 //
131 // The type we have here needs to be resolved to the non-pointer type so we can remove aliases.
132 auto &self = get<SPIRType>(type.self);
133 self.type_alias = 0;
134 emit_struct(self);
135}
136
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100137void CompilerCPP::emit_resources()
138{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200139 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
140 // when such variables are instantiated.
141 for (auto &id : ids)
142 {
143 if (id.get_type() == TypeType)
144 {
145 auto &type = id.get<SPIRType>();
146 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
147 (meta[type.self].decoration.decoration_flags &
148 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
149 {
150 emit_struct(type);
151 }
152 }
153 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100154
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200155 statement("struct Resources : ", resource_type);
156 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100157
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200158 // Output UBOs and SSBOs
159 for (auto &id : ids)
160 {
161 if (id.get_type() == TypeVariable)
162 {
163 auto &var = id.get<SPIRVariable>();
164 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100165
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +0200166 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200167 !is_hidden_variable(var) && (meta[type.self].decoration.decoration_flags &
168 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200169 {
170 emit_buffer_block(var);
171 }
172 }
173 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100174
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200175 // Output push constant blocks
176 for (auto &id : ids)
177 {
178 if (id.get_type() == TypeVariable)
179 {
180 auto &var = id.get<SPIRVariable>();
181 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200182 if (!is_hidden_variable(var) && var.storage != StorageClassFunction && type.pointer &&
183 type.storage == StorageClassPushConstant)
184 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200185 emit_push_constant_block(var);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200186 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200187 }
188 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100189
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200190 // Output in/out interfaces.
191 for (auto &id : ids)
192 {
193 if (id.get_type() == TypeVariable)
194 {
195 auto &var = id.get<SPIRVariable>();
196 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100197
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200198 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
199 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200200 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200201 {
202 emit_interface_block(var);
203 }
204 }
205 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200207 // Output Uniform Constants (values, samplers, images, etc).
208 for (auto &id : ids)
209 {
210 if (id.get_type() == TypeVariable)
211 {
212 auto &var = id.get<SPIRVariable>();
213 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100214
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200215 if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200216 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
217 {
218 emit_uniform(var);
219 }
220 }
221 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100222
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200223 // Global variables.
224 bool emitted = false;
225 for (auto global : global_variables)
226 {
227 auto &var = get<SPIRVariable>(global);
228 if (var.storage == StorageClassWorkgroup)
229 {
230 emit_shared(var);
231 emitted = true;
232 }
233 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100234
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200235 if (emitted)
236 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200238 statement("inline void init(spirv_cross_shader& s)");
239 begin_scope();
240 statement(resource_type, "::init(s);");
241 for (auto &reg : resource_registrations)
242 statement(reg);
243 end_scope();
244 resource_registrations.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100245
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200246 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100247
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200248 statement("");
249 statement("Resources* __res;");
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200250 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200251 statement("ComputePrivateResources __priv_res;");
252 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200254 // Emit regular globals which are allocated per invocation.
255 emitted = false;
256 for (auto global : global_variables)
257 {
258 auto &var = get<SPIRVariable>(global);
259 if (var.storage == StorageClassPrivate)
260 {
261 if (var.storage == StorageClassWorkgroup)
262 emit_shared(var);
263 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200264 statement(CompilerGLSL::variable_decl(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200265 emitted = true;
266 }
267 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100268
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200269 if (emitted)
270 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100271}
272
273string CompilerCPP::compile()
274{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200275 // Do not deal with ES-isms like precision, older extensions and such.
276 options.es = false;
277 options.version = 450;
278 backend.float_literal_suffix = true;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200279 backend.double_literal_suffix = false;
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200280 backend.long_long_literal_suffix = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200281 backend.uint32_t_literal_suffix = true;
282 backend.basic_int_type = "int32_t";
283 backend.basic_uint_type = "uint32_t";
284 backend.swizzle_is_function = true;
285 backend.shared_is_implied = true;
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +0200286 backend.flexible_member_array_supported = false;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200287 backend.explicit_struct_type = true;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200288 backend.use_initializer_list = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100289
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200290 uint32_t pass_count = 0;
291 do
292 {
293 if (pass_count >= 3)
294 throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100295
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200296 resource_registrations.clear();
297 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100298
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200299 // Move constructor for this type is broken on GCC 4.9 ...
300 buffer = unique_ptr<ostringstream>(new ostringstream());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100301
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200302 emit_header();
303 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100304
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200305 emit_function(get<SPIRFunction>(entry_point), 0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200307 pass_count++;
308 } while (force_recompile);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100309
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200310 // Match opening scope of emit_header().
311 end_scope_decl();
312 // namespace
313 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200315 // Emit C entry points
316 emit_c_linkage();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200318 return buffer->str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100319}
320
321void CompilerCPP::emit_c_linkage()
322{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200323 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100324
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200325 statement("spirv_cross_shader_t *spirv_cross_construct(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200326 begin_scope();
327 statement("return new ", impl_type, "();");
328 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100329
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200330 statement("");
331 statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
332 begin_scope();
333 statement("delete static_cast<", impl_type, "*>(shader);");
334 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200336 statement("");
337 statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
338 begin_scope();
339 statement("static_cast<", impl_type, "*>(shader)->invoke();");
340 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100341
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200342 statement("");
343 statement("static const struct spirv_cross_interface vtable =");
344 begin_scope();
345 statement("spirv_cross_construct,");
346 statement("spirv_cross_destruct,");
347 statement("spirv_cross_invoke,");
348 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100349
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200350 statement("");
Hans-Kristian Arntzenc172a352016-05-30 21:45:16 +0200351 statement("const struct spirv_cross_interface *",
352 interface_name.empty() ? string("spirv_cross_get_interface") : interface_name, "(void)");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200353 begin_scope();
354 statement("return &vtable;");
355 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100356}
357
358void CompilerCPP::emit_function_prototype(SPIRFunction &func, uint64_t)
359{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200360 local_variable_names = resource_names;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200361 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100362
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200363 auto &type = get<SPIRType>(func.return_type);
364 decl += "inline ";
365 decl += type_to_glsl(type);
366 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100367
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200368 if (func.self == entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200369 {
370 decl += "main";
371 processing_entry_point = true;
372 }
373 else
374 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100375
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200376 decl += "(";
377 for (auto &arg : func.arguments)
378 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200379 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100380
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200381 decl += argument_decl(arg);
382 if (&arg != &func.arguments.back())
383 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200385 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
386 auto *var = maybe_get<SPIRVariable>(arg.id);
387 if (var)
388 var->parameter = &arg;
389 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100390
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200391 decl += ")";
392 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100393}
394
395string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg)
396{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200397 auto &type = expression_type(arg.id);
398 bool constref = !type.pointer || arg.write_count == 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100399
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200400 auto &var = get<SPIRVariable>(arg.id);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200401
402 string base = type_to_glsl(type);
403 for (auto &array : type.array)
404 base = join("std::array<", base, ", ", array, ">");
405
406 return join(constref ? "const " : "", base, " &", to_name(var.self));
407}
408
409string CompilerCPP::variable_decl(const SPIRType &type, const string &name)
410{
411 string base = type_to_glsl(type);
412 bool runtime = false;
413 for (auto &array : type.array)
414 {
415 if (array)
416 base = join("std::array<", base, ", ", array, ">");
417 else
418 {
419 // Avoid using runtime arrays with std::array since this is undefined.
420 // Runtime arrays cannot be passed around as values, so this is fine.
421 runtime = true;
422 }
423 }
424 base += ' ';
425 return base + name + (runtime ? "[1]" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100426}
427
428void CompilerCPP::emit_header()
429{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200430 auto &execution = get_entry_point();
431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200432 statement("// This C++ shader is autogenerated by spirv-cross.");
433 statement("#include \"spirv_cross/internal_interface.hpp\"");
434 statement("#include \"spirv_cross/external_interface.h\"");
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +0200435 // Needed to properly implement GLSL-style arrays.
436 statement("#include <array>");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200437 statement("#include <stdint.h>");
438 statement("");
439 statement("using namespace spirv_cross;");
440 statement("using namespace glm;");
441 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100442
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200443 statement("namespace Impl");
444 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100445
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200446 switch (execution.model)
447 {
448 case ExecutionModelGeometry:
449 case ExecutionModelTessellationControl:
450 case ExecutionModelTessellationEvaluation:
451 case ExecutionModelGLCompute:
452 case ExecutionModelFragment:
453 case ExecutionModelVertex:
454 statement("struct Shader");
455 begin_scope();
456 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100457
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200458 default:
459 throw CompilerError("Unsupported execution model.");
460 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100461
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200462 switch (execution.model)
463 {
464 case ExecutionModelGeometry:
465 impl_type = "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
466 resource_type = "GeometryResources";
467 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100468
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200469 case ExecutionModelVertex:
470 impl_type = "VertexShader<Impl::Shader, Impl::Shader::Resources>";
471 resource_type = "VertexResources";
472 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100473
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200474 case ExecutionModelFragment:
475 impl_type = "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
476 resource_type = "FragmentResources";
477 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200479 case ExecutionModelGLCompute:
480 impl_type = join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution.workgroup_size.x, ", ",
481 execution.workgroup_size.y, ", ", execution.workgroup_size.z, ">");
482 resource_type = "ComputeResources";
483 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100484
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200485 case ExecutionModelTessellationControl:
486 impl_type = "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
487 resource_type = "TessControlResources";
488 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100489
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200490 case ExecutionModelTessellationEvaluation:
491 impl_type = "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
492 resource_type = "TessEvaluationResources";
493 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100494
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200495 default:
496 throw CompilerError("Unsupported execution model.");
497 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100498}