2 * Copyright 2015-2021 Arm Limited
3 * SPDX-License-Identifier: Apache-2.0 OR MIT
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>.
24 #include "spirv_cpp.hpp"
27 using namespace SPIRV_CROSS_NAMESPACE
;
30 void CompilerCPP::emit_buffer_block(const SPIRVariable
&var
)
32 add_resource_name(var
.self
);
34 auto &type
= get
<SPIRType
>(var
.basetype
);
35 auto instance_name
= to_name(var
.self
);
37 uint32_t descriptor_set
= ir
.meta
[var
.self
].decoration
.set
;
38 uint32_t binding
= ir
.meta
[var
.self
].decoration
.binding
;
40 emit_block_struct(type
);
41 auto buffer_name
= to_name(type
.self
);
43 statement("internal::Resource<", buffer_name
, type_to_array_glsl(type
, var
.self
), "> ", instance_name
, "__;");
44 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
, ");"));
50 void CompilerCPP::emit_interface_block(const SPIRVariable
&var
)
52 add_resource_name(var
.self
);
54 auto &type
= get
<SPIRType
>(var
.basetype
);
56 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
);
59 uint32_t location
= ir
.meta
[var
.self
].decoration
.location
;
62 auto flags
= ir
.meta
[type
.self
].decoration
.decoration_flags
;
63 if (flags
.get(DecorationBlock
))
65 emit_block_struct(type
);
66 buffer_name
= to_name(type
.self
);
69 buffer_name
= type_to_glsl(type
);
71 statement("internal::", qual
, "<", buffer_name
, type_to_array_glsl(type
, var
.self
), "> ", instance_name
, "__;");
72 statement_no_indent("#define ", instance_name
, " __res->", instance_name
, "__.get()");
73 resource_registrations
.push_back(join("s.register_", lowerqual
, "(", instance_name
, "__", ", ", location
, ");"));
77 void CompilerCPP::emit_shared(const SPIRVariable
&var
)
79 add_resource_name(var
.self
);
81 auto instance_name
= to_name(var
.self
);
82 statement(CompilerGLSL::variable_decl(var
), ";");
83 statement_no_indent("#define ", instance_name
, " __res->", instance_name
);
86 void CompilerCPP::emit_uniform(const SPIRVariable
&var
)
88 add_resource_name(var
.self
);
90 auto &type
= get
<SPIRType
>(var
.basetype
);
91 auto instance_name
= to_name(var
.self
);
93 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
;
97 string type_name
= type_to_glsl(type
);
98 remap_variable_type_name(type
, instance_name
, type_name
);
100 if (type
.basetype
== SPIRType::Image
|| type
.basetype
== SPIRType::SampledImage
||
101 type
.basetype
== SPIRType::AtomicCounter
)
103 statement("internal::Resource<", type_name
, type_to_array_glsl(type
, var
.self
), "> ", instance_name
, "__;");
104 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
, ");"));
110 statement("internal::UniformConstant<", type_name
, type_to_array_glsl(type
, var
.self
), "> ", instance_name
, "__;");
111 statement_no_indent("#define ", instance_name
, " __res->", instance_name
, "__.get()");
112 resource_registrations
.push_back(
113 join("s.register_uniform_constant(", instance_name
, "__", ", ", location
, ");"));
119 void CompilerCPP::emit_push_constant_block(const SPIRVariable
&var
)
121 add_resource_name(var
.self
);
123 auto &type
= get
<SPIRType
>(var
.basetype
);
124 auto &flags
= ir
.meta
[var
.self
].decoration
.decoration_flags
;
125 if (flags
.get(DecorationBinding
) || flags
.get(DecorationDescriptorSet
))
126 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.");
129 emit_block_struct(type
);
130 auto buffer_name
= to_name(type
.self
);
131 auto instance_name
= to_name(var
.self
);
133 statement("internal::PushConstant<", buffer_name
, type_to_array_glsl(type
, var
.self
), "> ", instance_name
, ";");
134 statement_no_indent("#define ", instance_name
, " __res->", instance_name
, ".get()");
135 resource_registrations
.push_back(join("s.register_push_constant(", instance_name
, "__", ");"));
139 void CompilerCPP::emit_block_struct(SPIRType
&type
)
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.
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
);
151 void CompilerCPP::emit_resources()
153 for (auto &id
: ir
.ids
)
155 if (id
.get_type() == TypeConstant
)
157 auto &c
= id
.get
<SPIRConstant
>();
159 bool needs_declaration
= c
.specialization
|| c
.is_used_as_lut
;
161 if (needs_declaration
)
163 if (!options
.vulkan_semantics
&& c
.specialization
)
165 c
.specialization_constant_macro_name
=
166 constant_value_macro_name(get_decoration(c
.self
, DecorationSpecId
));
171 else if (id
.get_type() == TypeConstantOp
)
173 emit_specialization_constant_op(id
.get
<SPIRConstantOp
>());
177 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
178 // when such variables are instantiated.
179 for (auto &id
: ir
.ids
)
181 if (id
.get_type() == TypeType
)
183 auto &type
= id
.get
<SPIRType
>();
184 if (type
.basetype
== SPIRType::Struct
&& type
.array
.empty() && !type
.pointer
&&
185 (!ir
.meta
[type
.self
].decoration
.decoration_flags
.get(DecorationBlock
) &&
186 !ir
.meta
[type
.self
].decoration
.decoration_flags
.get(DecorationBufferBlock
)))
193 statement("struct Resources : ", resource_type
);
196 // Output UBOs and SSBOs
197 for (auto &id
: ir
.ids
)
199 if (id
.get_type() == TypeVariable
)
201 auto &var
= id
.get
<SPIRVariable
>();
202 auto &type
= get
<SPIRType
>(var
.basetype
);
204 if (var
.storage
!= StorageClassFunction
&& type
.pointer
&& type
.storage
== StorageClassUniform
&&
205 !is_hidden_variable(var
) &&
206 (ir
.meta
[type
.self
].decoration
.decoration_flags
.get(DecorationBlock
) ||
207 ir
.meta
[type
.self
].decoration
.decoration_flags
.get(DecorationBufferBlock
)))
209 emit_buffer_block(var
);
214 // Output push constant blocks
215 for (auto &id
: ir
.ids
)
217 if (id
.get_type() == TypeVariable
)
219 auto &var
= id
.get
<SPIRVariable
>();
220 auto &type
= get
<SPIRType
>(var
.basetype
);
221 if (!is_hidden_variable(var
) && var
.storage
!= StorageClassFunction
&& type
.pointer
&&
222 type
.storage
== StorageClassPushConstant
)
224 emit_push_constant_block(var
);
229 // Output in/out interfaces.
230 for (auto &id
: ir
.ids
)
232 if (id
.get_type() == TypeVariable
)
234 auto &var
= id
.get
<SPIRVariable
>();
235 auto &type
= get
<SPIRType
>(var
.basetype
);
237 if (var
.storage
!= StorageClassFunction
&& !is_hidden_variable(var
) && type
.pointer
&&
238 (var
.storage
== StorageClassInput
|| var
.storage
== StorageClassOutput
) &&
239 interface_variable_exists_in_entry_point(var
.self
))
241 emit_interface_block(var
);
246 // Output Uniform Constants (values, samplers, images, etc).
247 for (auto &id
: ir
.ids
)
249 if (id
.get_type() == TypeVariable
)
251 auto &var
= id
.get
<SPIRVariable
>();
252 auto &type
= get
<SPIRType
>(var
.basetype
);
254 if (var
.storage
!= StorageClassFunction
&& !is_hidden_variable(var
) && type
.pointer
&&
255 (type
.storage
== StorageClassUniformConstant
|| type
.storage
== StorageClassAtomicCounter
))
263 bool emitted
= false;
264 for (auto global
: global_variables
)
266 auto &var
= get
<SPIRVariable
>(global
);
267 if (var
.storage
== StorageClassWorkgroup
)
277 statement("inline void init(spirv_cross_shader& s)");
279 statement(resource_type
, "::init(s);");
280 for (auto ®
: resource_registrations
)
283 resource_registrations
.clear();
288 statement("Resources* __res;");
289 if (get_entry_point().model
== ExecutionModelGLCompute
)
290 statement("ComputePrivateResources __priv_res;");
293 // Emit regular globals which are allocated per invocation.
295 for (auto global
: global_variables
)
297 auto &var
= get
<SPIRVariable
>(global
);
298 if (var
.storage
== StorageClassPrivate
)
300 if (var
.storage
== StorageClassWorkgroup
)
303 statement(CompilerGLSL::variable_decl(var
), ";");
312 string
CompilerCPP::compile()
314 ir
.fixup_reserved_names();
316 // Do not deal with ES-isms like precision, older extensions and such.
318 options
.version
= 450;
319 backend
.float_literal_suffix
= true;
320 backend
.double_literal_suffix
= false;
321 backend
.long_long_literal_suffix
= true;
322 backend
.uint32_t_literal_suffix
= true;
323 backend
.basic_int_type
= "int32_t";
324 backend
.basic_uint_type
= "uint32_t";
325 backend
.swizzle_is_function
= true;
326 backend
.shared_is_implied
= true;
327 backend
.unsized_array_supported
= false;
328 backend
.explicit_struct_type
= true;
329 backend
.use_initializer_list
= true;
332 reorder_type_alias();
333 build_function_control_flow_graphs_and_analyze();
334 update_active_builtins();
336 uint32_t pass_count
= 0;
339 resource_registrations
.clear();
342 // Move constructor for this type is broken on GCC 4.9 ...
348 emit_function(get
<SPIRFunction
>(ir
.default_entry_point
), Bitset());
351 } while (is_forcing_recompilation());
353 // Match opening scope of emit_header().
358 // Emit C entry points
361 // Entry point in CPP is always main() for the time being.
362 get_entry_point().name
= "main";
367 void CompilerCPP::emit_c_linkage()
371 statement("spirv_cross_shader_t *spirv_cross_construct(void)");
373 statement("return new ", impl_type
, "();");
377 statement("void spirv_cross_destruct(spirv_cross_shader_t *shader)");
379 statement("delete static_cast<", impl_type
, "*>(shader);");
383 statement("void spirv_cross_invoke(spirv_cross_shader_t *shader)");
385 statement("static_cast<", impl_type
, "*>(shader)->invoke();");
389 statement("static const struct spirv_cross_interface vtable =");
391 statement("spirv_cross_construct,");
392 statement("spirv_cross_destruct,");
393 statement("spirv_cross_invoke,");
397 statement("const struct spirv_cross_interface *",
398 interface_name
.empty() ? string("spirv_cross_get_interface") : interface_name
, "(void)");
400 statement("return &vtable;");
404 void CompilerCPP::emit_function_prototype(SPIRFunction
&func
, const Bitset
&)
406 if (func
.self
!= ir
.default_entry_point
)
407 add_function_overload(func
);
409 local_variable_names
= resource_names
;
412 auto &type
= get
<SPIRType
>(func
.return_type
);
414 decl
+= type_to_glsl(type
);
417 if (func
.self
== ir
.default_entry_point
)
420 processing_entry_point
= true;
423 decl
+= to_name(func
.self
);
426 for (auto &arg
: func
.arguments
)
428 add_local_variable_name(arg
.id
);
430 decl
+= argument_decl(arg
);
431 if (&arg
!= &func
.arguments
.back())
434 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
435 auto *var
= maybe_get
<SPIRVariable
>(arg
.id
);
437 var
->parameter
= &arg
;
444 string
CompilerCPP::argument_decl(const SPIRFunction::Parameter
&arg
)
446 auto &type
= expression_type(arg
.id
);
447 bool constref
= !type
.pointer
|| arg
.write_count
== 0;
449 auto &var
= get
<SPIRVariable
>(arg
.id
);
451 string base
= type_to_glsl(type
);
452 string variable_name
= to_name(var
.self
);
453 remap_variable_type_name(type
, variable_name
, base
);
455 for (uint32_t i
= 0; i
< type
.array
.size(); i
++)
456 base
= join("std::array<", base
, ", ", to_array_size(type
, i
), ">");
458 return join(constref
? "const " : "", base
, " &", variable_name
);
461 string
CompilerCPP::variable_decl(const SPIRType
&type
, const string
&name
, uint32_t /* id */)
463 string base
= type_to_glsl(type
);
464 remap_variable_type_name(type
, name
, base
);
465 bool runtime
= false;
467 for (uint32_t i
= 0; i
< type
.array
.size(); i
++)
469 auto &array
= type
.array
[i
];
470 if (!array
&& type
.array_size_literal
[i
])
472 // Avoid using runtime arrays with std::array since this is undefined.
473 // Runtime arrays cannot be passed around as values, so this is fine.
477 base
= join("std::array<", base
, ", ", to_array_size(type
, i
), ">");
480 return base
+ name
+ (runtime
? "[1]" : "");
483 void CompilerCPP::emit_header()
485 auto &execution
= get_entry_point();
487 statement("// This C++ shader is autogenerated by spirv-cross.");
488 statement("#include \"spirv_cross/internal_interface.hpp\"");
489 statement("#include \"spirv_cross/external_interface.h\"");
490 // Needed to properly implement GLSL-style arrays.
491 statement("#include <array>");
492 statement("#include <stdint.h>");
494 statement("using namespace spirv_cross;");
495 statement("using namespace glm;");
498 statement("namespace Impl");
501 switch (execution
.model
)
503 case ExecutionModelGeometry
:
504 case ExecutionModelTessellationControl
:
505 case ExecutionModelTessellationEvaluation
:
506 case ExecutionModelGLCompute
:
507 case ExecutionModelFragment
:
508 case ExecutionModelVertex
:
509 statement("struct Shader");
514 SPIRV_CROSS_THROW("Unsupported execution model.");
517 switch (execution
.model
)
519 case ExecutionModelGeometry
:
520 impl_type
= "GeometryShader<Impl::Shader, Impl::Shader::Resources>";
521 resource_type
= "GeometryResources";
524 case ExecutionModelVertex
:
525 impl_type
= "VertexShader<Impl::Shader, Impl::Shader::Resources>";
526 resource_type
= "VertexResources";
529 case ExecutionModelFragment
:
530 impl_type
= "FragmentShader<Impl::Shader, Impl::Shader::Resources>";
531 resource_type
= "FragmentResources";
534 case ExecutionModelGLCompute
:
535 impl_type
= join("ComputeShader<Impl::Shader, Impl::Shader::Resources, ", execution
.workgroup_size
.x
, ", ",
536 execution
.workgroup_size
.y
, ", ", execution
.workgroup_size
.z
, ">");
537 resource_type
= "ComputeResources";
540 case ExecutionModelTessellationControl
:
541 impl_type
= "TessControlShader<Impl::Shader, Impl::Shader::Resources>";
542 resource_type
= "TessControlResources";
545 case ExecutionModelTessellationEvaluation
:
546 impl_type
= "TessEvaluationShader<Impl::Shader, Impl::Shader::Resources>";
547 resource_type
= "TessEvaluationResources";
551 SPIRV_CROSS_THROW("Unsupported execution model.");