Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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 <string_view>
14#include <utility>
15
16#include "flutter/fml/paths.h"
26#include "third_party/skia/include/core/SkString.h"
27#include "third_party/skia/include/effects/SkRuntimeEffect.h"
28
29namespace impeller {
30namespace compiler {
31
32namespace {
33constexpr const char* kEGLImageExternalExtension = "GL_OES_EGL_image_external";
34constexpr const char* kEGLImageExternalExtension300 =
35 "GL_OES_EGL_image_external_essl3";
36constexpr int kVerboseErrorLineThreshold = 6;
37
38// Set per pass by RenderPassGLES: +1.0 swapchain, -1.0 offscreen FBO. See
39// flutter/flutter#186554.
40constexpr const char* kYFlipUniformName = "_impeller_y_flip";
41constexpr const char* kUserMainName = "_impeller_user_main";
42
43bool IsGLTargetPlatform(TargetPlatform platform) {
44 return platform == TargetPlatform::kOpenGLES ||
48}
49
50// Wraps the SPIRV-Cross-emitted entry point so `gl_Position.y *=
51// _impeller_y_flip;` runs on every exit, including early returns. Renames
52// `void main(` to `void _impeller_user_main(` and appends a wrapper that
53// calls it then applies the flip.
54std::string InjectYFlipForGLESVertexShader(std::string source) {
55 // Anchor on leading newline; spirv-cross emits the entry point at file
56 // scope, so the match is unambiguous in its comment-free output.
57 constexpr std::string_view kMainPattern = "\nvoid main(";
58 const size_t main_pos = source.find(kMainPattern);
59 if (main_pos == std::string::npos) {
60 return source;
61 }
62 const std::string user_main_decl =
63 std::string("\nvoid ") + kUserMainName + "(";
64 source.replace(main_pos, kMainPattern.size(), user_main_decl);
65
66 std::string wrapper = "\nvoid main() {\n ";
67 wrapper += kUserMainName;
68 wrapper += "();\n gl_Position.y *= ";
69 wrapper += kYFlipUniformName;
70 wrapper += ";\n}\n";
71 source.append(wrapper);
72
73 // Declare the uniform after the last `precision` directive, falling
74 // back to right after `#version`, falling back to the top.
75 const std::string declaration =
76 std::string("\nuniform float ") + kYFlipUniformName + ";\n";
77 size_t inject_at = std::string::npos;
78 for (size_t pos = source.find("\nprecision "); pos != std::string::npos;
79 pos = source.find("\nprecision ", pos + 1)) {
80 const size_t eol = source.find('\n', pos + 1);
81 if (eol == std::string::npos) {
82 break;
83 }
84 inject_at = eol;
85 }
86 if (inject_at == std::string::npos) {
87 const size_t version_pos = source.find("#version");
88 if (version_pos != std::string::npos) {
89 inject_at = source.find('\n', version_pos);
90 }
91 }
92 if (inject_at == std::string::npos) {
93 inject_at = 0;
94 }
95 source.insert(inject_at, declaration);
96 return source;
97}
98} // namespace
99
100// This value should be <= 7372. UBOs can be larger on some devices but a
101// performance cost will be paid.
102// https://docs.qualcomm.com/bundle/publicresource/topics/80-78185-2/best_practices.html?product=1601111740035277#buffer-best-practices
103static const uint32_t kMaxUniformBufferSize = 6208;
104
105static uint32_t ParseMSLVersion(const std::string& msl_version) {
106 std::stringstream sstream(msl_version);
107 std::string version_part;
108 uint32_t major = 1;
109 uint32_t minor = 2;
110 uint32_t patch = 0;
111 if (std::getline(sstream, version_part, '.')) {
112 major = std::stoi(version_part);
113 if (std::getline(sstream, version_part, '.')) {
114 minor = std::stoi(version_part);
115 if (std::getline(sstream, version_part, '.')) {
116 patch = std::stoi(version_part);
117 }
118 }
119 }
120 if (major < 1 || (major == 1 && minor < 2)) {
121 std::cerr << "--metal-version version must be at least 1.2. Have "
122 << msl_version << std::endl;
123 }
124 return spirv_cross::CompilerMSL::Options::make_msl_version(major, minor,
125 patch);
126}
127
129 const spirv_cross::ParsedIR& ir,
130 const SourceOptions& source_options,
131 std::optional<uint32_t> msl_version_override = {}) {
132 auto sl_compiler = std::make_shared<spirv_cross::CompilerMSL>(ir);
133 spirv_cross::CompilerMSL::Options sl_options;
134 sl_options.platform =
136 sl_options.msl_version = msl_version_override.value_or(
137 ParseMSLVersion(source_options.metal_version));
138 sl_options.ios_use_simdgroup_functions =
139 sl_options.is_ios() &&
140 sl_options.msl_version >=
141 spirv_cross::CompilerMSL::Options::make_msl_version(2, 4, 0);
142 sl_options.use_framebuffer_fetch_subpasses = true;
143 sl_compiler->set_msl_options(sl_options);
144
145 // Sort the float and sampler uniforms according to their declared/decorated
146 // order. For user authored fragment shaders, the API for setting uniform
147 // values uses the index of the uniform in the declared order. By default, the
148 // metal backend of spirv-cross will order uniforms according to usage. To fix
149 // this, we use the sorted order and the add_msl_resource_binding API to force
150 // the ordering to match the declared order. Note that while this code runs
151 // for all compiled shaders, it will only affect vertex and fragment shaders
152 // due to the specified stage.
153 auto floats =
154 SortUniforms(&ir, sl_compiler.get(), spirv_cross::SPIRType::Float);
155 auto images =
156 SortUniforms(&ir, sl_compiler.get(), spirv_cross::SPIRType::SampledImage);
157
158 spv::ExecutionModel execution_model =
159 spv::ExecutionModel::ExecutionModelFragment;
160 if (source_options.type == SourceType::kVertexShader) {
161 execution_model = spv::ExecutionModel::ExecutionModelVertex;
162 }
163
164 uint32_t buffer_offset = 0;
165 uint32_t sampler_offset = 0;
166 for (auto& float_id : floats) {
167 sl_compiler->add_msl_resource_binding(
168 {.stage = execution_model,
169 .basetype = spirv_cross::SPIRType::BaseType::Float,
170 .desc_set = sl_compiler->get_decoration(float_id,
171 spv::DecorationDescriptorSet),
172 .binding =
173 sl_compiler->get_decoration(float_id, spv::DecorationBinding),
174 .count = 1u,
175 .msl_buffer = buffer_offset});
176 buffer_offset++;
177 }
178 for (auto& image_id : images) {
179 sl_compiler->add_msl_resource_binding({
180 .stage = execution_model,
181 .basetype = spirv_cross::SPIRType::BaseType::SampledImage,
182 .desc_set =
183 sl_compiler->get_decoration(image_id, spv::DecorationDescriptorSet),
184 .binding =
185 sl_compiler->get_decoration(image_id, spv::DecorationBinding),
186 .count = 1u,
187 // A sampled image is both an image and a sampler, so both
188 // offsets need to be set or depending on the partiular shader
189 // the bindings may be incorrect.
190 .msl_texture = sampler_offset,
191 .msl_sampler = sampler_offset,
192 });
193 sampler_offset++;
194 }
195
196 return CompilerBackend(sl_compiler);
197}
198
200 const spirv_cross::ParsedIR& ir,
201 const SourceOptions& source_options) {
202 auto gl_compiler = std::make_shared<spirv_cross::CompilerGLSL>(ir);
203 spirv_cross::CompilerGLSL::Options sl_options;
204 sl_options.force_zero_initialized_variables = true;
205 sl_options.vertex.fixup_clipspace = true;
206 sl_options.vulkan_semantics = true;
207 gl_compiler->set_common_options(sl_options);
208 return CompilerBackend(gl_compiler);
209}
210
211static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR& ir,
212 const SourceOptions& source_options) {
213 auto gl_compiler = std::make_shared<spirv_cross::CompilerGLSL>(ir);
214
215 // Walk the variables and insert the external image extension if any of them
216 // begins with the external texture prefix. Unfortunately, we can't walk
217 // `gl_compiler->get_shader_resources().separate_samplers` until the compiler
218 // is further along.
219 //
220 // Unfortunately, we can't just let the shader author add this extension and
221 // use `samplerExternalOES` directly because compiling to spirv requires the
222 // source language profile to be at least 310 ES, but this extension is
223 // incompatible with ES 310+.
224 for (auto& id : ir.ids_for_constant_or_variable) {
225 if (StringStartsWith(ir.get_name(id), kExternalTexturePrefix)) {
226 if (source_options.gles_language_version >= 300) {
227 gl_compiler->require_extension(kEGLImageExternalExtension300);
228 } else {
229 gl_compiler->require_extension(kEGLImageExternalExtension);
230 }
231 break;
232 }
233 }
234
235 spirv_cross::CompilerGLSL::Options sl_options;
236 sl_options.force_zero_initialized_variables = true;
237 sl_options.vertex.fixup_clipspace = true;
238 if (source_options.target_platform == TargetPlatform::kOpenGLES ||
241 sl_options.version = source_options.gles_language_version > 0
242 ? source_options.gles_language_version
243 : 100;
244 // If we have requested GLES3 and/or Compute Shaders,
245 // promote the language version accordingly
246 if (source_options.type == SourceType::kComputeShader &&
247 sl_options.version < 310) {
248 sl_options.version = 310;
249 } else if (source_options.target_platform ==
251 sl_options.version < 300) {
252 sl_options.version = 300;
253 }
254 sl_options.es = true;
255 if (source_options.require_framebuffer_fetch &&
256 source_options.type == SourceType::kFragmentShader) {
257 gl_compiler->remap_ext_framebuffer_fetch(0, 0, true);
258 }
259 gl_compiler->set_variable_type_remap_callback(
260 [&](const spirv_cross::SPIRType& type, const std::string& var_name,
261 std::string& name_of_type) {
263 name_of_type = "samplerExternalOES";
264 }
265 });
266 } else {
267 sl_options.version = source_options.gles_language_version > 0
268 ? source_options.gles_language_version
269 : 120;
270 if (source_options.type == SourceType::kComputeShader &&
271 sl_options.version < 430) {
272 sl_options.version = 430;
273 }
274 sl_options.es = false;
275 }
276 gl_compiler->set_common_options(sl_options);
277 return CompilerBackend(gl_compiler);
278}
279
280static CompilerBackend CreateSkSLCompiler(const spirv_cross::ParsedIR& ir,
281 const SourceOptions& source_options) {
282 auto sksl_compiler = std::make_shared<CompilerSkSL>(ir);
283 return CompilerBackend(sksl_compiler);
284}
285
305
306static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir,
307 const SourceOptions& source_options) {
308 CompilerBackend compiler;
309 switch (source_options.target_platform) {
313 compiler = CreateMSLCompiler(ir, source_options);
314 break;
317 compiler = CreateVulkanCompiler(ir, source_options);
318 break;
323 compiler = CreateGLSLCompiler(ir, source_options);
324 break;
326 compiler = CreateSkSLCompiler(ir, source_options);
327 break;
330 }
331 if (!compiler) {
332 return {};
333 }
334 auto* backend = compiler.GetCompiler();
335 if (!EntryPointMustBeNamedMain(source_options.target_platform) &&
336 source_options.source_language == SourceLanguage::kGLSL) {
337 backend->rename_entry_point("main", source_options.entry_point_name,
338 ToExecutionModel(source_options.type));
339 }
340 return compiler;
341}
342
343namespace {
344uint32_t CalculateUBOSize(const spirv_cross::Compiler* compiler) {
345 spirv_cross::ShaderResources resources = compiler->get_shader_resources();
346 uint32_t result = 0;
347 for (const spirv_cross::Resource& ubo : resources.uniform_buffers) {
348 const spirv_cross::SPIRType& ubo_type =
349 compiler->get_type(ubo.base_type_id);
350 uint32_t size = compiler->get_declared_struct_size(ubo_type);
351 result += size;
352 }
353 return result;
354}
355
356// Mirrors BufferBindingsGLES's uniform key normalization: ASCII uppercase
357// and drop underscores. GLSL identifiers are ASCII, so this is locale-safe.
358std::string StripUnderscoresAndUpper(std::string_view name) {
359 std::string result;
360 result.reserve(name.size());
361 for (char ch : name) {
362 if (ch == '_') {
363 continue;
364 }
365 if (ch >= 'a' && ch <= 'z') {
366 result.push_back(static_cast<char>(ch - 'a' + 'A'));
367 } else {
368 result.push_back(ch);
369 }
370 }
371 return result;
372}
373
374// On pre-`#version 140` GL targets, SPIRV-Cross lowers each uniform block to a
375// flat `uniform StructType instanceName;` and BufferBindingsGLES resolves
376// members by the block name modulo `StripUnderscoresAndUpper`. A
377// non-conforming instance name (e.g. `uniform ToonInfo { ... } toon;`) causes
378// every member to silently bind to GL location `-1`. Rename the instance to
379// `_<BlockName>`, which reduces to the block name under the same fold.
380// See flutter/flutter#186393.
381void CanonicalizeUniformBlockInstanceNamesForGL(
382 TargetPlatform target_platform,
383 spirv_cross::Compiler* compiler) {
384 if (target_platform != TargetPlatform::kOpenGLES &&
385 target_platform != TargetPlatform::kOpenGLDesktop) {
386 return;
387 }
388 for (const spirv_cross::Resource& ubo :
389 compiler->get_shader_resources().uniform_buffers) {
390 const std::string block_name = compiler->get_name(ubo.base_type_id);
391 const std::string instance_name = compiler->get_name(ubo.id);
392 if (StripUnderscoresAndUpper(instance_name) ==
393 StripUnderscoresAndUpper(block_name)) {
394 continue;
395 }
396 compiler->set_name(ubo.id, "_" + block_name);
397 }
398}
399
400} // namespace
401
402Compiler::Compiler(const std::shared_ptr<const fml::Mapping>& source_mapping,
403 const SourceOptions& source_options,
404 Reflector::Options reflector_options)
405 : options_(source_options) {
406 if (!source_mapping || source_mapping->GetMapping() == nullptr) {
407 COMPILER_ERROR(error_stream_)
408 << "Could not read shader source or shader source was empty.";
409 return;
410 }
411
412 if (source_options.target_platform == TargetPlatform::kUnknown) {
413 COMPILER_ERROR(error_stream_) << "Target platform not specified.";
414 return;
415 }
416
417 SPIRVCompilerOptions spirv_options;
418
419 // Make sure reflection is as effective as possible. The generated shaders
420 // will be processed later by backend specific compilers.
421 spirv_options.generate_debug_info = true;
422
423 switch (options_.source_language) {
425 // Expects GLSL 4.60 (Core Profile).
426 // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
427 spirv_options.source_langauge =
428 shaderc_source_language::shaderc_source_language_glsl;
430 shaderc_profile::shaderc_profile_core, //
431 460, //
432 };
433 break;
435 spirv_options.source_langauge =
436 shaderc_source_language::shaderc_source_language_hlsl;
437 break;
439 COMPILER_ERROR(error_stream_) << "Source language invalid.";
440 return;
441 }
442
443 switch (source_options.target_platform) {
447
448 if (source_options.use_half_textures) {
449 target.env = shaderc_target_env::shaderc_target_env_opengl;
450 target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
451 target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
452 } else {
453 target.env = shaderc_target_env::shaderc_target_env_vulkan;
454 target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
455 target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
456 }
457
458 spirv_options.target = target;
459 } break;
465
466 target.env = shaderc_target_env::shaderc_target_env_vulkan;
467 target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
468 target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
469
470 if (source_options.target_platform ==
472 spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
473 spirv_options.relaxed_vulkan_rules = true;
474 }
475 spirv_options.target = target;
476 } break;
481
482 target.env = shaderc_target_env::shaderc_target_env_opengl;
483 target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
484 target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
485
486 spirv_options.target = target;
487 spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
489 source_options.target_platform ==
491 spirv_options.macro_definitions.push_back("IMPELLER_TARGET_OPENGLES");
492 // A temporary macro that allows fragment shader authors to target
493 // Flutter <= 3.44 before the OpenGLES flip was removed.
494 spirv_options.macro_definitions.push_back(
495 "IMPELLER_OPENGLES_UNFLIPPED_DEPRECATED");
496 }
497 } break;
500
501 target.env = shaderc_target_env::shaderc_target_env_opengl;
502 target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
503 target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
504
505 // When any optimization level above 'zero' is enabled, the phi merges at
506 // loop continue blocks are rendered using syntax that is supported in
507 // GLSL, but not in SkSL.
508 // https://bugs.chromium.org/p/skia/issues/detail?id=13518.
509 spirv_options.optimization_level =
510 shaderc_optimization_level::shaderc_optimization_level_zero;
511 spirv_options.target = target;
512 spirv_options.macro_definitions.push_back("SKIA_GRAPHICS_BACKEND");
513 } break;
515 COMPILER_ERROR(error_stream_) << "Target platform invalid.";
516 return;
517 }
518
519 // Implicit definition that indicates that this compilation is for the device
520 // (instead of the host).
521 spirv_options.macro_definitions.push_back("IMPELLER_DEVICE");
522 for (const auto& define : source_options.defines) {
523 spirv_options.macro_definitions.push_back(define);
524 }
525
526 std::vector<std::string> included_file_names;
527 spirv_options.includer = std::make_shared<Includer>(
528 options_.working_directory, options_.include_dirs,
529 [&included_file_names](auto included_name) {
530 included_file_names.emplace_back(std::move(included_name));
531 });
532
533 // SPIRV Generation.
534 SPIRVCompiler spv_compiler(source_options, source_mapping);
535
536 spirv_assembly_ = spv_compiler.CompileToSPV(
537 error_stream_, spirv_options.BuildShadercOptions());
538
539 if (!spirv_assembly_) {
540 return;
541 } else {
542 included_file_names_ = std::move(included_file_names);
543 }
544
545 // SL Generation.
546 spirv_cross::Parser parser(
547 reinterpret_cast<const uint32_t*>(spirv_assembly_->GetMapping()),
548 spirv_assembly_->GetSize() / sizeof(uint32_t));
549 // The parser and compiler must be run separately because the parser contains
550 // meta information (like type member names) that are useful for reflection.
551 parser.parse();
552
553 const auto parsed_ir =
554 std::make_shared<spirv_cross::ParsedIR>(parser.get_parsed_ir());
555
556 auto sl_compiler = CreateCompiler(*parsed_ir, options_);
557
558 if (!sl_compiler) {
559 COMPILER_ERROR(error_stream_)
560 << "Could not create compiler for target platform.";
561 return;
562 }
563
564 CanonicalizeUniformBlockInstanceNamesForGL(source_options.target_platform,
565 sl_compiler.GetCompiler());
566
567 uint32_t ubo_size = CalculateUBOSize(sl_compiler.GetCompiler());
568 if (ubo_size > kMaxUniformBufferSize) {
569 COMPILER_ERROR(error_stream_) << "Uniform buffer size exceeds max ("
570 << kMaxUniformBufferSize << "): " << ubo_size;
571 return;
572 }
573
574 // We need to invoke the compiler even if we don't use the SL mapping later
575 // for Vulkan. The reflector needs information that is only valid after a
576 // successful compilation call.
577 auto sl_compilation_result_str = sl_compiler.GetCompiler()->compile();
578
579 // GL vertex shaders get a y-flip epilogue; see
580 // https://github.com/flutter/flutter/issues/186554.
581 if (IsGLTargetPlatform(source_options.target_platform) &&
582 source_options.type == SourceType::kVertexShader) {
583 sl_compilation_result_str =
584 InjectYFlipForGLESVertexShader(std::move(sl_compilation_result_str));
585 }
586
587 auto sl_compilation_result =
588 CreateMappingWithString(sl_compilation_result_str);
589
590 // If the target is Vulkan, our shading language is SPIRV which we already
591 // have. We just need to strip it of debug information. If it isn't, we need
592 // to invoke the appropriate compiler to compile the SPIRV to the target SL.
593 if (source_options.target_platform == TargetPlatform::kVulkan ||
595 auto stripped_spirv_options = spirv_options;
596 stripped_spirv_options.generate_debug_info = false;
597 sl_mapping_ = spv_compiler.CompileToSPV(
598 error_stream_, stripped_spirv_options.BuildShadercOptions());
599 } else {
600 sl_mapping_ = sl_compilation_result;
601 }
602
603 if (!sl_mapping_) {
604 COMPILER_ERROR(error_stream_) << "Could not generate SL from SPIRV";
605 return;
606 }
607
608 if (sl_compiler.GetType() == CompilerBackend::Type::kSkSL &&
609 !ValidateSkSLResult(sl_compilation_result_str).ok()) {
610 return;
611 }
612
613 reflector_ = std::make_unique<Reflector>(std::move(reflector_options), //
614 parsed_ir, //
616 sl_compiler //
617 );
618
619 if (!reflector_->IsValid()) {
620 COMPILER_ERROR(error_stream_)
621 << "Could not complete reflection on generated shader.";
622 return;
623 }
624
625 is_valid_ = true;
626}
627
628absl::Status Compiler::ValidateSkSLResult(const std::string& sksl) {
629 // Validate compiled SkSL by trying to create a SkRuntimeEffect.
630 SkRuntimeEffect::Result result =
631 SkRuntimeEffect::MakeForShader(SkString(sksl));
632
633 if (result.effect != nullptr) {
634 return absl::OkStatus();
635 }
636
637 // SkSL is invalid. Output the SkSL and the error.
638
639 std::stringstream output;
640 bool is_truncated = false;
641
642 // Lambda to append text to the output stream, truncating if needed.
643 auto append_and_truncate = [&](const std::string& text) {
644 std::stringstream text_stream(text);
645 std::string line;
646 int lines_outputted = 0;
647 while (std::getline(text_stream, line)) {
648 output << "\n " << line;
649 if (++lines_outputted == kVerboseErrorLineThreshold) {
650 break;
651 }
652 }
653 if (lines_outputted == kVerboseErrorLineThreshold) {
654 auto full_line_count = std::count(text.begin(), text.end(), '\n') + 1;
655 output << "\n... (truncated " << full_line_count - lines_outputted
656 << " lines)";
657 is_truncated = true;
658 }
659 };
660
661 output << "\nCompiled to invalid SkSL:";
662 append_and_truncate(sksl);
663 output << "\nSkSL Error:";
664 std::string error_text(result.errorText.c_str());
665 append_and_truncate(error_text);
666
667 // Output maybe-truncated SkSL and error to error_stream_.
668 COMPILER_ERROR(error_stream_) << output.str();
669
670 // If the output was truncated, output the full SkSL and error to
671 // verbose_error_stream_.
672 if (is_truncated) {
673 COMPILER_ERROR(verbose_error_stream_) << "\nCompiled to invalid SkSL:\n"
674 << sksl << "\nSkSL Error:\n"
675 << error_text;
676 }
677
678 return absl::InternalError("SkSL validation failed.");
679}
680
681Compiler::~Compiler() = default;
682
683std::shared_ptr<fml::Mapping> Compiler::GetSPIRVAssembly() const {
684 return spirv_assembly_;
685}
686
687std::shared_ptr<fml::Mapping> Compiler::GetSLShaderSource() const {
688 return sl_mapping_;
689}
690
691bool Compiler::IsValid() const {
692 return is_valid_;
693}
694
695std::string Compiler::GetSourcePrefix() const {
696 std::stringstream stream;
697 stream << options_.file_name << ": ";
698 return stream.str();
699}
700
701std::string Compiler::GetErrorMessages() const {
702 return error_stream_.str();
703}
704
706 return verbose_error_stream_.str();
707}
708
709const std::vector<std::string>& Compiler::GetIncludedFileNames() const {
710 return included_file_names_;
711}
712
713static std::string JoinStrings(std::vector<std::string> items,
714 const std::string& separator) {
715 std::stringstream stream;
716 for (size_t i = 0, count = items.size(); i < count; i++) {
717 const auto is_last = (i == count - 1);
718
719 stream << items[i];
720 if (!is_last) {
721 stream << separator;
722 }
723 }
724 return stream.str();
725}
726
727std::string Compiler::GetDependencyNames(const std::string& separator) const {
728 std::vector<std::string> dependencies = included_file_names_;
729 dependencies.push_back(Utf8FromPath(options_.file_name));
730 return JoinStrings(dependencies, separator);
731}
732
733std::unique_ptr<fml::Mapping> Compiler::CreateDepfileContents(
734 std::initializer_list<std::string> targets_names) const {
735 // https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28
736 const auto targets = JoinStrings(targets_names, " ");
737 const auto dependencies = GetDependencyNames(" ");
738
739 std::stringstream stream;
740 stream << targets << ": " << dependencies << "\n";
741
742 auto contents = std::make_shared<std::string>(stream.str());
743 return std::make_unique<fml::NonOwnedMapping>(
744 reinterpret_cast<const uint8_t*>(contents->data()), contents->size(),
745 [contents](auto, auto) {});
746}
747
749 return reflector_.get();
750}
751
752} // namespace compiler
753} // namespace impeller
std::string GetVerboseErrorMessages() const
Definition compiler.cc:705
std::shared_ptr< fml::Mapping > GetSPIRVAssembly() const
Definition compiler.cc:683
const Reflector * GetReflector() const
Definition compiler.cc:748
Compiler(const std::shared_ptr< const fml::Mapping > &source_mapping, const SourceOptions &options, Reflector::Options reflector_options)
Definition compiler.cc:402
const std::vector< std::string > & GetIncludedFileNames() const
Definition compiler.cc:709
std::unique_ptr< fml::Mapping > CreateDepfileContents(std::initializer_list< std::string > targets) const
Definition compiler.cc:733
std::shared_ptr< fml::Mapping > GetSLShaderSource() const
Definition compiler.cc:687
std::string GetErrorMessages() const
Definition compiler.cc:701
std::shared_ptr< fml::Mapping > CompileToSPV(std::stringstream &error_stream, const shaderc::CompileOptions &spirv_options) const
uint32_t * target
#define FML_UNREACHABLE()
Definition logging.h:128
const char * name
Definition fuchsia.cc:50
std::u16string text
#define COMPILER_ERROR(stream)
Definition logger.h:39
std::array< MockImage, 3 > images
static CompilerBackend CreateSkSLCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition compiler.cc:280
static const uint32_t kMaxUniformBufferSize
Definition compiler.cc:103
static CompilerBackend CreateVulkanCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition compiler.cc:199
constexpr char kExternalTexturePrefix[]
Definition constants.h:11
static bool EntryPointMustBeNamedMain(TargetPlatform platform)
Definition compiler.cc:286
static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options, std::optional< uint32_t > msl_version_override={})
Definition compiler.cc:128
static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR &ir, const SourceOptions &source_options)
Definition compiler.cc:306
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:713
spirv_cross::CompilerMSL::Options::Platform TargetPlatformToMSLPlatform(TargetPlatform platform)
Definition types.cc:183
static uint32_t ParseMSLVersion(const std::string &msl_version)
Definition compiler.cc:105
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:211
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.
impeller::ShaderType type
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