Flutter Impeller
compiler.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <cstdint>
8 #include <filesystem>
9 #include <memory>
10 #include <optional>
11 #include <sstream>
12 #include <string>
13 #include <utility>
14 
15 #include "flutter/fml/paths.h"
25 #include "third_party/skia/include/core/SkString.h"
26 #include "third_party/skia/include/effects/SkRuntimeEffect.h"
27 
28 namespace impeller {
29 namespace compiler {
30 
31 namespace {
32 constexpr const char* kEGLImageExternalExtension = "GL_OES_EGL_image_external";
33 constexpr const char* kEGLImageExternalExtension300 =
34  "GL_OES_EGL_image_external_essl3";
35 constexpr int kVerboseErrorLineThreshold = 6;
36 } // namespace
37 
38 // This value should be <= 7372. UBOs can be larger on some devices but a
39 // performance cost will be paid.
40 // https://docs.qualcomm.com/bundle/publicresource/topics/80-78185-2/best_practices.html?product=1601111740035277#buffer-best-practices
41 static const uint32_t kMaxUniformBufferSize = 6208;
42 
43 static uint32_t ParseMSLVersion(const std::string& msl_version) {
44  std::stringstream sstream(msl_version);
45  std::string version_part;
46  uint32_t major = 1;
47  uint32_t minor = 2;
48  uint32_t patch = 0;
49  if (std::getline(sstream, version_part, '.')) {
50  major = std::stoi(version_part);
51  if (std::getline(sstream, version_part, '.')) {
52  minor = std::stoi(version_part);
53  if (std::getline(sstream, version_part, '.')) {
54  patch = std::stoi(version_part);
55  }
56  }
57  }
58  if (major < 1 || (major == 1 && minor < 2)) {
59  std::cerr << "--metal-version version must be at least 1.2. Have "
60  << msl_version << std::endl;
61  }
62  return spirv_cross::CompilerMSL::Options::make_msl_version(major, minor,
63  patch);
64 }
65 
67  const spirv_cross::ParsedIR& ir,
68  const SourceOptions& source_options,
69  std::optional<uint32_t> msl_version_override = {}) {
70  auto sl_compiler = std::make_shared<spirv_cross::CompilerMSL>(ir);
71  spirv_cross::CompilerMSL::Options sl_options;
72  sl_options.platform =
74  sl_options.msl_version = msl_version_override.value_or(
75  ParseMSLVersion(source_options.metal_version));
76  sl_options.ios_use_simdgroup_functions =
77  sl_options.is_ios() &&
78  sl_options.msl_version >=
79  spirv_cross::CompilerMSL::Options::make_msl_version(2, 4, 0);
80  sl_options.use_framebuffer_fetch_subpasses = true;
81  sl_compiler->set_msl_options(sl_options);
82 
83  // Sort the float and sampler uniforms according to their declared/decorated
84  // order. For user authored fragment shaders, the API for setting uniform
85  // values uses the index of the uniform in the declared order. By default, the
86  // metal backend of spirv-cross will order uniforms according to usage. To fix
87  // this, we use the sorted order and the add_msl_resource_binding API to force
88  // the ordering to match the declared order. Note that while this code runs
89  // for all compiled shaders, it will only affect vertex and fragment shaders
90  // due to the specified stage.
91  auto floats =
92  SortUniforms(&ir, sl_compiler.get(), spirv_cross::SPIRType::Float);
93  auto images =
94  SortUniforms(&ir, sl_compiler.get(), spirv_cross::SPIRType::SampledImage);
95 
96  spv::ExecutionModel execution_model =
97  spv::ExecutionModel::ExecutionModelFragment;
98  if (source_options.type == SourceType::kVertexShader) {
99  execution_model = spv::ExecutionModel::ExecutionModelVertex;
100  }
101 
102  uint32_t buffer_offset = 0;
103  uint32_t sampler_offset = 0;
104  for (auto& float_id : floats) {
105  sl_compiler->add_msl_resource_binding(
106  {.stage = execution_model,
107  .basetype = spirv_cross::SPIRType::BaseType::Float,
108  .desc_set = sl_compiler->get_decoration(float_id,
109  spv::DecorationDescriptorSet),
110  .binding =
111  sl_compiler->get_decoration(float_id, spv::DecorationBinding),
112  .count = 1u,
113  .msl_buffer = buffer_offset});
114  buffer_offset++;
115  }
116  for (auto& image_id : images) {
117  sl_compiler->add_msl_resource_binding({
118  .stage = execution_model,
119  .basetype = spirv_cross::SPIRType::BaseType::SampledImage,
120  .desc_set =
121  sl_compiler->get_decoration(image_id, spv::DecorationDescriptorSet),
122  .binding =
123  sl_compiler->get_decoration(image_id, spv::DecorationBinding),
124  .count = 1u,
125  // A sampled image is both an image and a sampler, so both
126  // offsets need to be set or depending on the partiular shader
127  // the bindings may be incorrect.
128  .msl_texture = sampler_offset,
129  .msl_sampler = sampler_offset,
130  });
131  sampler_offset++;
132  }
133 
134  return CompilerBackend(sl_compiler);
135 }
136 
138  const spirv_cross::ParsedIR& ir,
139  const SourceOptions& source_options) {
140  auto gl_compiler = std::make_shared<spirv_cross::CompilerGLSL>(ir);
141  spirv_cross::CompilerGLSL::Options sl_options;
142  sl_options.force_zero_initialized_variables = true;
143  sl_options.vertex.fixup_clipspace = true;
144  sl_options.vulkan_semantics = true;
145  gl_compiler->set_common_options(sl_options);
146  return CompilerBackend(gl_compiler);
147 }
148 
149 static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR& ir,
150  const SourceOptions& source_options) {
151  auto gl_compiler = std::make_shared<spirv_cross::CompilerGLSL>(ir);
152 
153  // Walk the variables and insert the external image extension if any of them
154  // begins with the external texture prefix. Unfortunately, we can't walk
155  // `gl_compiler->get_shader_resources().separate_samplers` until the compiler
156  // is further along.
157  //
158  // Unfortunately, we can't just let the shader author add this extension and
159  // use `samplerExternalOES` directly because compiling to spirv requires the
160  // source language profile to be at least 310 ES, but this extension is
161  // incompatible with ES 310+.
162  for (auto& id : ir.ids_for_constant_or_variable) {
163  if (StringStartsWith(ir.get_name(id), kExternalTexturePrefix)) {
164  if (source_options.gles_language_version >= 300) {
165  gl_compiler->require_extension(kEGLImageExternalExtension300);
166  } else {
167  gl_compiler->require_extension(kEGLImageExternalExtension);
168  }
169  break;
170  }
171  }
172 
173  spirv_cross::CompilerGLSL::Options sl_options;
174  sl_options.force_zero_initialized_variables = true;
175  sl_options.vertex.fixup_clipspace = true;
176  if (source_options.target_platform == TargetPlatform::kOpenGLES ||
179  sl_options.version = source_options.gles_language_version > 0
180  ? source_options.gles_language_version
181  : 100;
182  sl_options.es = true;
183  if (source_options.target_platform == TargetPlatform::kRuntimeStageGLES3) {
184  sl_options.version = 300;
185  }
186  if (source_options.require_framebuffer_fetch &&
187  source_options.type == SourceType::kFragmentShader) {
188  gl_compiler->remap_ext_framebuffer_fetch(0, 0, true);
189  }
190  gl_compiler->set_variable_type_remap_callback(
191  [&](const spirv_cross::SPIRType& type, const std::string& var_name,
192  std::string& name_of_type) {
193  if (StringStartsWith(var_name, kExternalTexturePrefix)) {
194  name_of_type = "samplerExternalOES";
195  }
196  });
197  } else {
198  sl_options.version = source_options.gles_language_version > 0
199  ? source_options.gles_language_version
200  : 120;
201  sl_options.es = false;
202  }
203  gl_compiler->set_common_options(sl_options);
204  return CompilerBackend(gl_compiler);
205 }
206 
207 static CompilerBackend CreateSkSLCompiler(const spirv_cross::ParsedIR& ir,
208  const SourceOptions& source_options) {
209  auto sksl_compiler = std::make_shared<CompilerSkSL>(ir);
210  return CompilerBackend(sksl_compiler);
211 }
212 
214  switch (platform) {
216  FML_UNREACHABLE();
222  return false;
228  return true;
229  }
230  FML_UNREACHABLE();
231 }
232 
233 static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir,
234  const SourceOptions& source_options) {
235  CompilerBackend compiler;
236  switch (source_options.target_platform) {
240  compiler = CreateMSLCompiler(ir, source_options);
241  break;
244  compiler = CreateVulkanCompiler(ir, source_options);
245  break;
250  compiler = CreateGLSLCompiler(ir, source_options);
251  break;
253  compiler = CreateSkSLCompiler(ir, source_options);
254  break;
256  FML_UNREACHABLE();
257  }
258  if (!compiler) {
259  return {};
260  }
261  auto* backend = compiler.GetCompiler();
262  if (!EntryPointMustBeNamedMain(source_options.target_platform) &&
263  source_options.source_language == SourceLanguage::kGLSL) {
264  backend->rename_entry_point("main", source_options.entry_point_name,
265  ToExecutionModel(source_options.type));
266  }
267  return compiler;
268 }
269 
270 namespace {
271 uint32_t CalculateUBOSize(const spirv_cross::Compiler* compiler) {
272  spirv_cross::ShaderResources resources = compiler->get_shader_resources();
273  uint32_t result = 0;
274  for (const spirv_cross::Resource& ubo : resources.uniform_buffers) {
275  const spirv_cross::SPIRType& ubo_type =
276  compiler->get_type(ubo.base_type_id);
277  uint32_t size = compiler->get_declared_struct_size(ubo_type);
278  result += size;
279  }
280  return result;
281 }
282 
283 } // namespace
284 
285 Compiler::Compiler(const std::shared_ptr<const fml::Mapping>& source_mapping,
286  const SourceOptions& source_options,
287  Reflector::Options reflector_options)
288  : options_(source_options) {
289  if (!source_mapping || source_mapping->GetMapping() == nullptr) {
290  COMPILER_ERROR(error_stream_)
291  << "Could not read shader source or shader source was empty.";
292  return;
293  }
294 
295  if (source_options.target_platform == TargetPlatform::kUnknown) {
296  COMPILER_ERROR(error_stream_) << "Target platform not specified.";
297  return;
298  }
299 
300  SPIRVCompilerOptions spirv_options;
301 
302  // Make sure reflection is as effective as possible. The generated shaders
303  // will be processed later by backend specific compilers.
304  spirv_options.generate_debug_info = true;
305 
306  switch (options_.source_language) {
308  // Expects GLSL 4.60 (Core Profile).
309  // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
310  spirv_options.source_langauge =
311  shaderc_source_language::shaderc_source_language_glsl;
313  shaderc_profile::shaderc_profile_core, //
314  460, //
315  };
316  break;
318  spirv_options.source_langauge =
319  shaderc_source_language::shaderc_source_language_hlsl;
320  break;
322  COMPILER_ERROR(error_stream_) << "Source language invalid.";
323  return;
324  }
325 
326  switch (source_options.target_platform) {
329  SPIRVCompilerTargetEnv target;
330 
331  if (source_options.use_half_textures) {
332  target.env = shaderc_target_env::shaderc_target_env_opengl;
333  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
334  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
335  } else {
336  target.env = shaderc_target_env::shaderc_target_env_vulkan;
337  target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
338  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
339  }
340 
341  spirv_options.target = target;
342  } break;
347  SPIRVCompilerTargetEnv target;
348 
349  target.env = shaderc_target_env::shaderc_target_env_vulkan;
350  target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
351  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
352 
353  if (source_options.target_platform ==
355  spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
356  spirv_options.relaxed_vulkan_rules = true;
357  }
358  spirv_options.target = target;
359  } break;
363  SPIRVCompilerTargetEnv target;
364 
365  target.env = shaderc_target_env::shaderc_target_env_opengl;
366  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
367  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
368 
369  spirv_options.target = target;
370  spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
371  if (source_options.target_platform == TargetPlatform::kRuntimeStageGLES ||
372  source_options.target_platform ==
374  spirv_options.macro_definitions.push_back("IMPELLER_TARGET_OPENGLES");
375  }
376  } break;
377  case TargetPlatform::kSkSL: {
378  SPIRVCompilerTargetEnv target;
379 
380  target.env = shaderc_target_env::shaderc_target_env_opengl;
381  target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
382  target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
383 
384  // When any optimization level above 'zero' is enabled, the phi merges at
385  // loop continue blocks are rendered using syntax that is supported in
386  // GLSL, but not in SkSL.
387  // https://bugs.chromium.org/p/skia/issues/detail?id=13518.
388  spirv_options.optimization_level =
389  shaderc_optimization_level::shaderc_optimization_level_zero;
390  spirv_options.target = target;
391  spirv_options.macro_definitions.push_back("SKIA_GRAPHICS_BACKEND");
392  } break;
394  COMPILER_ERROR(error_stream_) << "Target platform invalid.";
395  return;
396  }
397 
398  // Implicit definition that indicates that this compilation is for the device
399  // (instead of the host).
400  spirv_options.macro_definitions.push_back("IMPELLER_DEVICE");
401  for (const auto& define : source_options.defines) {
402  spirv_options.macro_definitions.push_back(define);
403  }
404 
405  std::vector<std::string> included_file_names;
406  spirv_options.includer = std::make_shared<Includer>(
407  options_.working_directory, options_.include_dirs,
408  [&included_file_names](auto included_name) {
409  included_file_names.emplace_back(std::move(included_name));
410  });
411 
412  // SPIRV Generation.
413  SPIRVCompiler spv_compiler(source_options, source_mapping);
414 
415  spirv_assembly_ = spv_compiler.CompileToSPV(
416  error_stream_, spirv_options.BuildShadercOptions());
417 
418  if (!spirv_assembly_) {
419  return;
420  } else {
421  included_file_names_ = std::move(included_file_names);
422  }
423 
424  // SL Generation.
425  spirv_cross::Parser parser(
426  reinterpret_cast<const uint32_t*>(spirv_assembly_->GetMapping()),
427  spirv_assembly_->GetSize() / sizeof(uint32_t));
428  // The parser and compiler must be run separately because the parser contains
429  // meta information (like type member names) that are useful for reflection.
430  parser.parse();
431 
432  const auto parsed_ir =
433  std::make_shared<spirv_cross::ParsedIR>(parser.get_parsed_ir());
434 
435  auto sl_compiler = CreateCompiler(*parsed_ir, options_);
436 
437  if (!sl_compiler) {
438  COMPILER_ERROR(error_stream_)
439  << "Could not create compiler for target platform.";
440  return;
441  }
442 
443  uint32_t ubo_size = CalculateUBOSize(sl_compiler.GetCompiler());
444  if (ubo_size > kMaxUniformBufferSize) {
445  COMPILER_ERROR(error_stream_) << "Uniform buffer size exceeds max ("
446  << kMaxUniformBufferSize << "): " << ubo_size;
447  return;
448  }
449 
450  // We need to invoke the compiler even if we don't use the SL mapping later
451  // for Vulkan. The reflector needs information that is only valid after a
452  // successful compilation call.
453  auto sl_compilation_result_str = sl_compiler.GetCompiler()->compile();
454  auto sl_compilation_result =
455  CreateMappingWithString(sl_compilation_result_str);
456 
457  // If the target is Vulkan, our shading language is SPIRV which we already
458  // have. We just need to strip it of debug information. If it isn't, we need
459  // to invoke the appropriate compiler to compile the SPIRV to the target SL.
460  if (source_options.target_platform == TargetPlatform::kVulkan ||
462  auto stripped_spirv_options = spirv_options;
463  stripped_spirv_options.generate_debug_info = false;
464  sl_mapping_ = spv_compiler.CompileToSPV(
465  error_stream_, stripped_spirv_options.BuildShadercOptions());
466  } else {
467  sl_mapping_ = sl_compilation_result;
468  }
469 
470  if (!sl_mapping_) {
471  COMPILER_ERROR(error_stream_) << "Could not generate SL from SPIRV";
472  return;
473  }
474 
475  if (sl_compiler.GetType() == CompilerBackend::Type::kSkSL &&
476  !ValidateSkSLResult(sl_compilation_result_str).ok()) {
477  return;
478  }
479 
480  reflector_ = std::make_unique<Reflector>(std::move(reflector_options), //
481  parsed_ir, //
482  GetSLShaderSource(), //
483  sl_compiler //
484  );
485 
486  if (!reflector_->IsValid()) {
487  COMPILER_ERROR(error_stream_)
488  << "Could not complete reflection on generated shader.";
489  return;
490  }
491 
492  is_valid_ = true;
493 }
494 
495 absl::Status Compiler::ValidateSkSLResult(const std::string& sksl) {
496  // Validate compiled SkSL by trying to create a SkRuntimeEffect.
497  SkRuntimeEffect::Result result =
498  SkRuntimeEffect::MakeForShader(SkString(sksl));
499 
500  if (result.effect != nullptr) {
501  return absl::OkStatus();
502  }
503 
504  // SkSL is invalid. Output the SkSL and the error.
505 
506  std::stringstream output;
507  bool is_truncated = false;
508 
509  // Lambda to append text to the output stream, truncating if needed.
510  auto append_and_truncate = [&](const std::string& text) {
511  std::stringstream text_stream(text);
512  std::string line;
513  int lines_outputted = 0;
514  while (std::getline(text_stream, line)) {
515  output << "\n " << line;
516  if (++lines_outputted == kVerboseErrorLineThreshold) {
517  break;
518  }
519  }
520  if (lines_outputted == kVerboseErrorLineThreshold) {
521  auto full_line_count = std::count(text.begin(), text.end(), '\n') + 1;
522  output << "\n... (truncated " << full_line_count - lines_outputted
523  << " lines)";
524  is_truncated = true;
525  }
526  };
527 
528  output << "\nCompiled to invalid SkSL:";
529  append_and_truncate(sksl);
530  output << "\nSkSL Error:";
531  std::string error_text(result.errorText.c_str());
532  append_and_truncate(error_text);
533 
534  // Output maybe-truncated SkSL and error to error_stream_.
535  COMPILER_ERROR(error_stream_) << output.str();
536 
537  // If the output was truncated, output the full SkSL and error to
538  // verbose_error_stream_.
539  if (is_truncated) {
540  COMPILER_ERROR(verbose_error_stream_) << "\nCompiled to invalid SkSL:\n"
541  << sksl << "\nSkSL Error:\n"
542  << error_text;
543  }
544 
545  return absl::InternalError("SkSL validation failed.");
546 }
547 
548 Compiler::~Compiler() = default;
549 
550 std::shared_ptr<fml::Mapping> Compiler::GetSPIRVAssembly() const {
551  return spirv_assembly_;
552 }
553 
554 std::shared_ptr<fml::Mapping> Compiler::GetSLShaderSource() const {
555  return sl_mapping_;
556 }
557 
558 bool Compiler::IsValid() const {
559  return is_valid_;
560 }
561 
562 std::string Compiler::GetSourcePrefix() const {
563  std::stringstream stream;
564  stream << options_.file_name << ": ";
565  return stream.str();
566 }
567 
568 std::string Compiler::GetErrorMessages() const {
569  return error_stream_.str();
570 }
571 
573  return verbose_error_stream_.str();
574 }
575 
576 const std::vector<std::string>& Compiler::GetIncludedFileNames() const {
577  return included_file_names_;
578 }
579 
580 static std::string JoinStrings(std::vector<std::string> items,
581  const std::string& separator) {
582  std::stringstream stream;
583  for (size_t i = 0, count = items.size(); i < count; i++) {
584  const auto is_last = (i == count - 1);
585 
586  stream << items[i];
587  if (!is_last) {
588  stream << separator;
589  }
590  }
591  return stream.str();
592 }
593 
594 std::string Compiler::GetDependencyNames(const std::string& separator) const {
595  std::vector<std::string> dependencies = included_file_names_;
596  dependencies.push_back(Utf8FromPath(options_.file_name));
597  return JoinStrings(dependencies, separator);
598 }
599 
600 std::unique_ptr<fml::Mapping> Compiler::CreateDepfileContents(
601  std::initializer_list<std::string> targets_names) const {
602  // https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28
603  const auto targets = JoinStrings(targets_names, " ");
604  const auto dependencies = GetDependencyNames(" ");
605 
606  std::stringstream stream;
607  stream << targets << ": " << dependencies << "\n";
608 
609  auto contents = std::make_shared<std::string>(stream.str());
610  return std::make_unique<fml::NonOwnedMapping>(
611  reinterpret_cast<const uint8_t*>(contents->data()), contents->size(),
612  [contents](auto, auto) {});
613 }
614 
616  return reflector_.get();
617 }
618 
619 } // namespace compiler
620 } // namespace impeller
std::string GetVerboseErrorMessages() const
Definition: compiler.cc:572
std::shared_ptr< fml::Mapping > GetSPIRVAssembly() const
Definition: compiler.cc:550
const Reflector * GetReflector() const
Definition: compiler.cc:615
Compiler(const std::shared_ptr< const fml::Mapping > &source_mapping, const SourceOptions &options, Reflector::Options reflector_options)
Definition: compiler.cc:285
const std::vector< std::string > & GetIncludedFileNames() const
Definition: compiler.cc:576
std::unique_ptr< fml::Mapping > CreateDepfileContents(std::initializer_list< std::string > targets) const
Definition: compiler.cc:600
std::shared_ptr< fml::Mapping > GetSLShaderSource() const
Definition: compiler.cc:554
std::string GetErrorMessages() const
Definition: compiler.cc:568
std::shared_ptr< fml::Mapping > CompileToSPV(std::stringstream &error_stream, const shaderc::CompileOptions &spirv_options) const
#define COMPILER_ERROR(stream)
Definition: logger.h:39
static CompilerBackend CreateSkSLCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition: compiler.cc:207
static const uint32_t kMaxUniformBufferSize
Definition: compiler.cc:41
static CompilerBackend CreateVulkanCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition: compiler.cc:137
constexpr char kExternalTexturePrefix[]
Definition: constants.h:11
static bool EntryPointMustBeNamedMain(TargetPlatform platform)
Definition: compiler.cc:213
static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options, std::optional< uint32_t > msl_version_override={})
Definition: compiler.cc:66
static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition: compiler.cc:233
std::string Utf8FromPath(const std::filesystem::path &path)
Converts a native format path to a utf8 string.
Definition: utilities.cc:30
static std::string JoinStrings(std::vector< std::string > items, const std::string &separator)
Definition: compiler.cc:580
spirv_cross::CompilerMSL::Options::Platform TargetPlatformToMSLPlatform(TargetPlatform platform)
Definition: types.cc:183
static uint32_t ParseMSLVersion(const std::string &msl_version)
Definition: compiler.cc:43
bool StringStartsWith(const std::string &target, const std::string &prefix)
Definition: utilities.cc:86
static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition: compiler.cc:149
spv::ExecutionModel ToExecutionModel(SourceType type)
Definition: types.cc:169
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.
std::shared_ptr< fml::Mapping > CreateMappingWithString(std::string string)
Creates a mapping with string data.
Definition: allocation.cc:111
spirv_cross::Compiler * GetCompiler()
std::optional< shaderc_source_language > source_langauge
std::vector< std::string > macro_definitions
shaderc_optimization_level optimization_level
std::optional< SPIRVCompilerSourceProfile > source_profile
std::shared_ptr< Includer > includer
shaderc::CompileOptions BuildShadercOptions() const
std::optional< SPIRVCompilerTargetEnv > target
bool use_half_textures
Whether half-precision textures should be supported, requiring opengl semantics. Only used on metal t...
std::vector< IncludeDir > include_dirs
std::filesystem::path file_name
bool require_framebuffer_fetch
Whether the GLSL framebuffer fetch extension will be required.
std::shared_ptr< fml::UniqueFD > working_directory
std::vector< std::string > defines