9using namespace SPIRV_CROSS_NAMESPACE;
17 fprintf(stderr,
"There was a compiler error: %s\n", msg.c_str());
22#define FLUTTER_CROSS_THROW(x) report_and_exit(x)
25 ir.fixup_reserved_names();
27 if (get_execution_model() != ExecutionModelFragment) {
33 options.version = 100;
34 options.vulkan_semantics =
false;
35 options.enable_420pack_extension =
false;
36 options.flatten_multidimensional_arrays =
true;
38 backend.allow_precision_qualifiers =
false;
39 backend.basic_int16_type =
"short";
40 backend.basic_int_type =
"int";
41 backend.basic_uint16_type =
"ushort";
42 backend.basic_uint_type =
"uint";
43 backend.double_literal_suffix =
false;
44 backend.float_literal_suffix =
false;
45 backend.long_long_literal_suffix =
false;
46 backend.needs_row_major_load_workaround =
true;
47 backend.nonuniform_qualifier =
"";
48 backend.support_precise_qualifier =
false;
49 backend.uint32_t_literal_suffix =
false;
50 backend.use_array_constructor =
true;
51 backend.workgroup_size_is_hidden =
true;
53 fixup_user_functions();
55 fixup_anonymous_struct_names();
58 build_function_control_flow_graphs_and_analyze();
59 fixup_image_load_store_access();
60 update_active_builtins();
61 analyze_image_and_sampler_usage();
62 analyze_interlocked_resource_usage();
64 uint32_t pass_count = 0;
74 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
77 }
while (is_forcing_recompilation());
79 statement(
"half4 main(float2 iFragCoord)");
81 statement(
" flutter_FragCoord = float4(iFragCoord, 0, 0);");
82 statement(
" FLT_main();");
83 statement(
" return " + output_name_ +
";");
89void CompilerSkSL::fixup_user_functions() {
90 const std::string prefix =
"FLT_flutter_local_";
91 ir.for_each_typed_id<SPIRFunction>([&](uint32_t,
const SPIRFunction& func) {
92 const auto& original_name = get_name(func.self);
94 if (original_name.rfind(prefix, 0) == 0) {
97 std::string new_name = prefix + original_name;
98 set_name(func.self, new_name);
101 ir.for_each_typed_id<SPIRFunctionPrototype>(
102 [&](uint32_t,
const SPIRFunctionPrototype& func) {
103 const auto& original_name = get_name(func.self);
105 if (original_name.rfind(prefix, 0) == 0) {
108 std::string new_name = prefix + original_name;
109 set_name(func.self, new_name);
113void CompilerSkSL::emit_header() {
114 statement(
"// This SkSL shader is autogenerated by spirv-cross.");
116 statement(
"float4 flutter_FragCoord;");
120void CompilerSkSL::emit_uniform(
const SPIRVariable& var) {
121 auto&
type = get<SPIRType>(var.basetype);
122 if (
type.basetype == SPIRType::UInt && is_legacy()) {
124 get_name(var.self) +
"'");
127 add_resource_name(var.self);
128 statement(variable_decl(var),
";");
132 if (
type.basetype == SPIRType::SampledImage) {
133 std::string
name = to_name(var.self);
134 statement(
"uniform half2 " +
name +
"_size;");
138bool CompilerSkSL::emit_constant_resources() {
139 bool emitted =
false;
141 for (
auto&
id : ir.ids) {
142 if (
id.get_type() == TypeConstant) {
143 auto& c =
id.get<SPIRConstant>();
144 bool needs_declaration = c.specialization || c.is_used_as_lut;
145 if (needs_declaration) {
146 if (!options.vulkan_semantics && c.specialization) {
147 c.specialization_constant_macro_name = constant_value_macro_name(
148 get_decoration(c.self, DecorationSpecId));
153 }
else if (
id.get_type() == TypeConstantOp) {
154 emit_specialization_constant_op(
id.get<SPIRConstantOp>());
162bool CompilerSkSL::emit_struct_resources() {
163 bool emitted =
false;
167 for (
auto&
id : ir.ids) {
168 if (
id.get_type() == TypeType) {
169 auto&
type =
id.get<SPIRType>();
170 if (
type.basetype == SPIRType::Struct &&
type.array.empty() &&
172 (!ir.meta[
type.self].decoration.decoration_flags.get(
174 !ir.meta[
type.self].decoration.decoration_flags.get(
175 DecorationBufferBlock))) {
185void CompilerSkSL::detect_unsupported_resources() {
186 for (
auto&
id : ir.ids) {
187 if (
id.get_type() == TypeVariable) {
188 auto& var =
id.get<SPIRVariable>();
189 auto&
type = get<SPIRType>(var.basetype);
192 if (var.storage != StorageClassFunction &&
type.pointer &&
193 type.storage == StorageClassUniform && !is_hidden_variable(var) &&
194 (ir.meta[
type.self].decoration.decoration_flags.get(
196 ir.meta[
type.self].decoration.decoration_flags.get(
197 DecorationBufferBlock))) {
199 get_name(var.self) +
"'");
203 if (!is_hidden_variable(var) && var.storage != StorageClassFunction &&
204 type.pointer &&
type.storage == StorageClassPushConstant) {
206 get_name(var.self) +
"'");
210 if (!is_hidden_variable(var) && var.storage != StorageClassFunction &&
211 type.pointer &&
type.storage == StorageClassInput) {
213 get_name(var.self) +
"'");
215 }
else if (
id.get_type() == TypeBlock) {
218 auto& block =
id.get<SPIRBlock>();
224 for (
auto instruction : block.ops) {
225 bool has_array_initializer =
false;
226 if (instruction.op == OpLine) {
229 file = get<SPIRString>(ir.spirv[instruction.offset]).str;
230 line = ir.spirv[instruction.offset + 1];
231 }
else if (instruction.op == OpStore) {
235 Variant& store_object_id = ir.ids[ir.spirv[instruction.offset + 1]];
236 if (store_object_id.get_type() == TypeConstant) {
237 auto& c = store_object_id.get<SPIRConstant>();
238 auto&
type = get<SPIRType>(c.constant_type);
239 has_array_initializer = !
type.array.empty();
241 }
else if (instruction.op == OpCompositeConstruct) {
245 auto result_type_id = ir.spirv[instruction.offset];
246 auto&
type = get<SPIRType>(result_type_id);
247 has_array_initializer = !
type.array.empty();
250 if (has_array_initializer) {
252 file +
":" + std::to_string(line));
259bool CompilerSkSL::emit_uniform_resources() {
260 bool emitted =
false;
263 std::vector<ID> regular_uniforms =
265 std::vector<ID> shader_uniforms =
267 if (regular_uniforms.size() > 0 || shader_uniforms.size() > 0) {
271 for (
const auto&
id : regular_uniforms) {
272 auto& var = get<SPIRVariable>(
id);
276 for (
const auto&
id : shader_uniforms) {
277 auto& var = get<SPIRVariable>(
id);
284bool CompilerSkSL::emit_output_resources() {
285 bool emitted =
false;
289 for (
auto&
id : ir.ids) {
290 if (
id.get_type() == TypeVariable) {
291 auto& var =
id.get<SPIRVariable>();
292 auto&
type = get<SPIRType>(var.basetype);
293 if (var.storage != StorageClassFunction && !is_hidden_variable(var) &&
295 (var.storage == StorageClassInput ||
296 var.storage == StorageClassOutput) &&
297 interface_variable_exists_in_entry_point(var.self)) {
298 emit_interface_block(var);
307bool CompilerSkSL::emit_global_variable_resources() {
308 bool emitted =
false;
310 for (
auto global : global_variables) {
311 auto& var = get<SPIRVariable>(global);
312 if (is_hidden_variable(var,
true)) {
315 if (var.storage != StorageClassOutput) {
316 if (!variable_is_lut(var)) {
317 add_resource_name(var.self);
318 std::string initializer;
319 if (options.force_zero_initialized_variables &&
320 var.storage == StorageClassPrivate && !var.initializer &&
321 !var.static_expression &&
322 type_can_zero_initialize(get_variable_data_type(var))) {
323 initializer = join(
" = ", to_zero_initialized_expression(
324 get_variable_data_type_id(var)));
326 statement(variable_decl(var), initializer,
";");
329 }
else if (var.initializer &&
330 maybe_get<SPIRConstant>(var.initializer) !=
nullptr) {
331 emit_output_variable_initializer(var);
338bool CompilerSkSL::emit_undefined_values() {
339 bool emitted =
false;
341 ir.for_each_typed_id<SPIRUndef>([&](uint32_t,
const SPIRUndef& undef) {
342 auto&
type = this->get<SPIRType>(undef.basetype);
344 if (
type.basetype == SPIRType::Void) {
348 std::string initializer;
349 if (options.force_zero_initialized_variables &&
350 type_can_zero_initialize(
type)) {
351 initializer = join(
" = ", to_zero_initialized_expression(undef.basetype));
354 statement(variable_decl(
type, to_name(undef.self), undef.self), initializer,
362void CompilerSkSL::emit_resources() {
363 detect_unsupported_resources();
365 if (emit_constant_resources()) {
369 if (emit_struct_resources()) {
373 if (emit_uniform_resources()) {
377 if (emit_output_resources()) {
381 if (emit_global_variable_resources()) {
385 if (emit_undefined_values()) {
390void CompilerSkSL::emit_interface_block(
const SPIRVariable& var) {
391 auto&
type = get<SPIRType>(var.basetype);
393 ir.meta[
type.self].decoration.decoration_flags.get(DecorationBlock);
396 to_name(var.self) +
"'");
401 add_resource_name(var.self);
402 statement(variable_decl(
type, to_name(var.self), var.self),
";");
403 if (output_name_.empty()) {
404 output_name_ = to_name(var.self);
405 }
else if (to_name(var.self) != output_name_) {
407 to_name(var.self) +
"'");
411void CompilerSkSL::emit_function_prototype(SPIRFunction& func,
412 const Bitset& return_flags) {
415 if (func.self != ir.default_entry_point) {
416 CompilerGLSL::emit_function_prototype(func, return_flags);
420 auto&
type = get<SPIRType>(func.return_type);
421 if (
type.basetype != SPIRType::Void) {
423 "Return type of the entrypoint function must be 'void'");
426 if (func.arguments.size() != 0) {
428 "The entry point function should not acept any parameters.");
431 processing_entry_point =
true;
436 statement(
"void FLT_main()");
439std::string CompilerSkSL::image_type_glsl(
const SPIRType&
type,
442 if (
type.basetype != SPIRType::SampledImage ||
type.image.dim != Dim2D) {
449std::string CompilerSkSL::builtin_to_glsl(BuiltIn builtin,
450 StorageClass storage) {
451 std::string gl_builtin = CompilerGLSL::builtin_to_glsl(builtin, storage);
453 case BuiltInFragCoord:
454 return "flutter_FragCoord";
463std::string CompilerSkSL::to_texture_op(
464 const Instruction&
i,
467 SmallVector<uint32_t>& inherited_expressions) {
468 auto op =
static_cast<Op>(
i.op);
469 if (op != OpImageSampleImplicitLod) {
473 return CompilerGLSL::to_texture_op(
i, sparse, forward, inherited_expressions);
476std::string CompilerSkSL::to_function_name(
477 const CompilerGLSL::TextureFunctionNameArguments&
args) {
478 std::string
name = to_expression(
args.base.img);
479 return name +
".eval";
482std::string CompilerSkSL::to_function_args(
const TextureFunctionArguments&
args,
484 std::string
name = to_expression(
args.base.img);
486 std::string glsl_args = CompilerGLSL::to_function_args(
args, p_forward);
492 "Only sampler and position arguments are supported in texture() "
499 std::string no_shader;
500 auto npos = glsl_args.find(
", ");
501 if (npos != std::string::npos) {
502 no_shader = glsl_args.substr(npos + 1);
505 if (no_shader.empty()) {
511 return name +
"_size * (" + no_shader +
")";
std::string compile() override
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
void Op(SkPathBuilder *one, SkPathBuilder *two, SkPathOp op)
void report_and_exit(const std::string &msg)
std::vector< spirv_cross::ID > SortUniforms(const spirv_cross::ParsedIR *ir, const spirv_cross::Compiler *compiler, std::optional< spirv_cross::SPIRType::BaseType > type_filter, bool include)
Sorts uniform declarations in an IR according to decoration order.
#define FLUTTER_CROSS_THROW(x)