| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "impeller/compiler/compiler.h" | |
| #include <array> | |
| #include <filesystem> | |
| #include <memory> | |
| #include <sstream> | |
| #include <utility> | |
| #include "flutter/fml/paths.h" | |
| #include "impeller/base/allocation.h" | |
| #include "impeller/compiler/compiler_backend.h" | |
| #include "impeller/compiler/includer.h" | |
| #include "impeller/compiler/logger.h" | |
| #include "impeller/compiler/types.h" | |
| namespace impeller { | |
| namespace compiler { | |
| const uint32_t kFragBindingBase = 128; | |
| const size_t kNumUniformKinds = | |
| static_cast<int>(shaderc_uniform_kind::shaderc_uniform_kind_buffer) + 1; | |
| static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR& ir, | |
| const SourceOptions& source_options) { | |
| auto sl_compiler = std::make_shared<spirv_cross::CompilerMSL>(ir); | |
| spirv_cross::CompilerMSL::Options sl_options; | |
| sl_options.platform = | |
| TargetPlatformToMSLPlatform(source_options.target_platform); | |
| // If this version specification changes, the GN rules that process the | |
| // Metal to AIR must be updated as well. | |
| sl_options.msl_version = | |
| spirv_cross::CompilerMSL::Options::make_msl_version(1, 2); | |
| sl_compiler->set_msl_options(sl_options); | |
| return CompilerBackend(sl_compiler); | |
| } | |
| static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR& ir, | |
| const SourceOptions& source_options) { | |
| auto gl_compiler = std::make_shared<spirv_cross::CompilerGLSL>(ir); | |
| spirv_cross::CompilerGLSL::Options sl_options; | |
| sl_options.force_zero_initialized_variables = true; | |
| sl_options.vertex.fixup_clipspace = true; | |
| if (source_options.target_platform == TargetPlatform::kOpenGLES) { | |
| sl_options.version = source_options.gles_language_version > 0 | |
| ? source_options.gles_language_version | |
| : 100; | |
| sl_options.es = true; | |
| } else { | |
| sl_options.version = source_options.gles_language_version > 0 | |
| ? source_options.gles_language_version | |
| : 120; | |
| sl_options.es = false; | |
| } | |
| gl_compiler->set_common_options(sl_options); | |
| return CompilerBackend(gl_compiler); | |
| } | |
| static CompilerBackend CreateSkSLCompiler(const spirv_cross::ParsedIR& ir, | |
| const SourceOptions& source_options) { | |
| auto sksl_compiler = std::make_shared<CompilerSkSL>(ir); | |
| return CompilerBackend(sksl_compiler); | |
| } | |
| static bool EntryPointMustBeNamedMain(TargetPlatform platform) { | |
| switch (platform) { | |
| case TargetPlatform::kUnknown: | |
| FML_UNREACHABLE(); | |
| case TargetPlatform::kMetalDesktop: | |
| case TargetPlatform::kMetalIOS: | |
| case TargetPlatform::kVulkan: | |
| case TargetPlatform::kRuntimeStageMetal: | |
| return false; | |
| case TargetPlatform::kSkSL: | |
| case TargetPlatform::kOpenGLES: | |
| case TargetPlatform::kOpenGLDesktop: | |
| case TargetPlatform::kRuntimeStageGLES: | |
| return true; | |
| } | |
| FML_UNREACHABLE(); | |
| } | |
| static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir, | |
| const SourceOptions& source_options) { | |
| CompilerBackend compiler; | |
| switch (source_options.target_platform) { | |
| case TargetPlatform::kMetalDesktop: | |
| case TargetPlatform::kMetalIOS: | |
| case TargetPlatform::kRuntimeStageMetal: | |
| case TargetPlatform::kRuntimeStageGLES: | |
| case TargetPlatform::kVulkan: | |
| compiler = CreateMSLCompiler(ir, source_options); | |
| break; | |
| case TargetPlatform::kUnknown: | |
| case TargetPlatform::kOpenGLES: | |
| case TargetPlatform::kOpenGLDesktop: | |
| compiler = CreateGLSLCompiler(ir, source_options); | |
| break; | |
| case TargetPlatform::kSkSL: | |
| compiler = CreateSkSLCompiler(ir, source_options); | |
| } | |
| if (!compiler) { | |
| return {}; | |
| } | |
| auto* backend = compiler.GetCompiler(); | |
| if (!EntryPointMustBeNamedMain(source_options.target_platform) && | |
| source_options.source_language == SourceLanguage::kGLSL) { | |
| backend->rename_entry_point("main", source_options.entry_point_name, | |
| ToExecutionModel(source_options.type)); | |
| } | |
| return compiler; | |
| } | |
| static void SetLimitations(shaderc::CompileOptions& compiler_opts) { | |
| using Limit = std::pair<shaderc_limit, int>; | |
| static constexpr std::array<Limit, 83> limits = { | |
| Limit{shaderc_limit::shaderc_limit_max_lights, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_clip_planes, 6}, | |
| Limit{shaderc_limit::shaderc_limit_max_texture_units, 2}, | |
| Limit{shaderc_limit::shaderc_limit_max_texture_coords, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_attribs, 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_uniform_components, 4096}, | |
| Limit{shaderc_limit::shaderc_limit_max_varying_floats, 60}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_texture_image_units, 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_combined_texture_image_units, 80}, | |
| Limit{shaderc_limit::shaderc_limit_max_texture_image_units, 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_fragment_uniform_components, 1024}, | |
| Limit{shaderc_limit::shaderc_limit_max_draw_buffers, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_uniform_vectors, 256}, | |
| Limit{shaderc_limit::shaderc_limit_max_varying_vectors, 15}, | |
| Limit{shaderc_limit::shaderc_limit_max_fragment_uniform_vectors, 256}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_output_vectors, 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_fragment_input_vectors, 15}, | |
| Limit{shaderc_limit::shaderc_limit_min_program_texel_offset, -8}, | |
| Limit{shaderc_limit::shaderc_limit_max_program_texel_offset, 7}, | |
| Limit{shaderc_limit::shaderc_limit_max_clip_distances, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_x, 65535}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_y, 65535}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_z, 65535}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_x, 1024}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_y, 1024}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_z, 64}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_uniform_components, 512}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_texture_image_units, 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_image_uniforms, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_atomic_counters, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_compute_atomic_counter_buffers, 1}, | |
| Limit{shaderc_limit::shaderc_limit_max_varying_components, 60}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_output_components, 64}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_input_components, 64}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_output_components, 128}, | |
| Limit{shaderc_limit::shaderc_limit_max_fragment_input_components, 128}, | |
| Limit{shaderc_limit::shaderc_limit_max_image_units, 8}, | |
| Limit{shaderc_limit:: | |
| shaderc_limit_max_combined_image_units_and_fragment_outputs, | |
| 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_combined_shader_output_resources, | |
| 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_image_samples, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_image_uniforms, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_control_image_uniforms, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_image_uniforms, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_image_uniforms, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_fragment_image_uniforms, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_combined_image_uniforms, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_texture_image_units, 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_output_vertices, 256}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_total_output_components, | |
| 1024}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_uniform_components, 512}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_varying_components, 60}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_control_input_components, | |
| 128}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_control_output_components, | |
| 128}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_control_texture_image_units, | |
| 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_control_uniform_components, | |
| 1024}, | |
| Limit{ | |
| shaderc_limit::shaderc_limit_max_tess_control_total_output_components, | |
| 4096}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_input_components, | |
| 128}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_output_components, | |
| 128}, | |
| Limit{ | |
| shaderc_limit::shaderc_limit_max_tess_evaluation_texture_image_units, | |
| 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_uniform_components, | |
| 1024}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_patch_components, 120}, | |
| Limit{shaderc_limit::shaderc_limit_max_patch_vertices, 32}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_gen_level, 64}, | |
| Limit{shaderc_limit::shaderc_limit_max_viewports, 16}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_atomic_counters, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_control_atomic_counters, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_atomic_counters, | |
| 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_atomic_counters, 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_fragment_atomic_counters, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_combined_atomic_counters, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_atomic_counter_bindings, 1}, | |
| Limit{shaderc_limit::shaderc_limit_max_vertex_atomic_counter_buffers, 0}, | |
| Limit{ | |
| shaderc_limit::shaderc_limit_max_tess_control_atomic_counter_buffers, | |
| 0}, | |
| Limit{shaderc_limit:: | |
| shaderc_limit_max_tess_evaluation_atomic_counter_buffers, | |
| 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_geometry_atomic_counter_buffers, | |
| 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_fragment_atomic_counter_buffers, | |
| 0}, | |
| Limit{shaderc_limit::shaderc_limit_max_combined_atomic_counter_buffers, | |
| 1}, | |
| Limit{shaderc_limit::shaderc_limit_max_atomic_counter_buffer_size, 32}, | |
| Limit{shaderc_limit::shaderc_limit_max_transform_feedback_buffers, 4}, | |
| Limit{shaderc_limit:: | |
| shaderc_limit_max_transform_feedback_interleaved_components, | |
| 64}, | |
| Limit{shaderc_limit::shaderc_limit_max_cull_distances, 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_combined_clip_and_cull_distances, | |
| 8}, | |
| Limit{shaderc_limit::shaderc_limit_max_samples, 4}, | |
| }; | |
| for (auto& [limit, value] : limits) { | |
| compiler_opts.SetLimit(limit, value); | |
| } | |
| } | |
| void Compiler::SetBindingBase(shaderc::CompileOptions& compiler_opts) const { | |
| for (size_t uniform_kind = 0; uniform_kind < kNumUniformKinds; | |
| uniform_kind++) { | |
| compiler_opts.SetBindingBaseForStage( | |
| ToShaderCShaderKind(SourceType::kFragmentShader), | |
| static_cast<shaderc_uniform_kind>(uniform_kind), kFragBindingBase); | |
| } | |
| } | |
| Compiler::Compiler(const fml::Mapping& source_mapping, | |
| const SourceOptions& source_options, | |
| Reflector::Options reflector_options) | |
| : options_(source_options) { | |
| if (source_mapping.GetMapping() == nullptr) { | |
| COMPILER_ERROR | |
| << "Could not read shader source or shader source was empty."; | |
| return; | |
| } | |
| if (source_options.target_platform == TargetPlatform::kUnknown) { | |
| COMPILER_ERROR << "Target platform not specified."; | |
| return; | |
| } | |
| auto shader_kind = ToShaderCShaderKind(source_options.type); | |
| if (shader_kind == shaderc_shader_kind::shaderc_glsl_infer_from_source) { | |
| COMPILER_ERROR << "Could not figure out shader stage."; | |
| return; | |
| } | |
| shaderc::CompileOptions spirv_options; | |
| // Make sure reflection is as effective as possible. The generated shaders | |
| // will be processed later by backend specific compilers. So optimizations | |
| // here are irrelevant and get in the way of generating reflection code. | |
| spirv_options.SetGenerateDebugInfo(); | |
| switch (options_.source_language) { | |
| case SourceLanguage::kGLSL: | |
| // Expects GLSL 4.60 (Core Profile). | |
| // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf | |
| spirv_options.SetSourceLanguage( | |
| shaderc_source_language::shaderc_source_language_glsl); | |
| spirv_options.SetForcedVersionProfile( | |
| 460, shaderc_profile::shaderc_profile_core); | |
| break; | |
| case SourceLanguage::kHLSL: | |
| spirv_options.SetSourceLanguage( | |
| shaderc_source_language::shaderc_source_language_hlsl); | |
| break; | |
| case SourceLanguage::kUnknown: | |
| COMPILER_ERROR << "Source language invalid."; | |
| return; | |
| } | |
| SetLimitations(spirv_options); | |
| switch (source_options.target_platform) { | |
| case TargetPlatform::kMetalDesktop: | |
| case TargetPlatform::kMetalIOS: | |
| case TargetPlatform::kOpenGLES: | |
| case TargetPlatform::kOpenGLDesktop: | |
| spirv_options.SetOptimizationLevel( | |
| shaderc_optimization_level::shaderc_optimization_level_performance); | |
| spirv_options.SetTargetEnvironment( | |
| shaderc_target_env::shaderc_target_env_vulkan, | |
| shaderc_env_version::shaderc_env_version_vulkan_1_1); | |
| spirv_options.SetTargetSpirv( | |
| shaderc_spirv_version::shaderc_spirv_version_1_3); | |
| break; | |
| case TargetPlatform::kVulkan: | |
| spirv_options.SetOptimizationLevel( | |
| shaderc_optimization_level::shaderc_optimization_level_performance); | |
| spirv_options.SetTargetEnvironment( | |
| shaderc_target_env::shaderc_target_env_vulkan, | |
| shaderc_env_version::shaderc_env_version_vulkan_1_0); | |
| spirv_options.SetTargetSpirv( | |
| shaderc_spirv_version::shaderc_spirv_version_1_0); | |
| break; | |
| case TargetPlatform::kRuntimeStageMetal: | |
| case TargetPlatform::kRuntimeStageGLES: | |
| spirv_options.SetOptimizationLevel( | |
| shaderc_optimization_level::shaderc_optimization_level_performance); | |
| spirv_options.SetTargetEnvironment( | |
| shaderc_target_env::shaderc_target_env_opengl, | |
| shaderc_env_version::shaderc_env_version_opengl_4_5); | |
| spirv_options.SetTargetSpirv( | |
| shaderc_spirv_version::shaderc_spirv_version_1_0); | |
| spirv_options.AddMacroDefinition("IMPELLER_GRAPHICS_BACKEND"); | |
| break; | |
| case TargetPlatform::kSkSL: | |
| // When any optimization level above 'zero' is enabled, the phi merges at | |
| // loop continue blocks are rendered using syntax that is supported in | |
| // GLSL, but not in SkSL. | |
| // https://bugs.chromium.org/p/skia/issues/detail?id=13518. | |
| spirv_options.SetOptimizationLevel( | |
| shaderc_optimization_level::shaderc_optimization_level_zero); | |
| spirv_options.SetTargetEnvironment( | |
| shaderc_target_env::shaderc_target_env_opengl, | |
| shaderc_env_version::shaderc_env_version_opengl_4_5); | |
| spirv_options.SetTargetSpirv( | |
| shaderc_spirv_version::shaderc_spirv_version_1_0); | |
| spirv_options.AddMacroDefinition("SKIA_GRAPHICS_BACKEND"); | |
| break; | |
| case TargetPlatform::kUnknown: | |
| COMPILER_ERROR << "Target platform invalid."; | |
| return; | |
| } | |
| // Implicit definition that indicates that this compilation is for the device | |
| // (instead of the host). | |
| spirv_options.AddMacroDefinition("IMPELLER_DEVICE"); | |
| for (const auto& define : source_options.defines) { | |
| spirv_options.AddMacroDefinition(define); | |
| } | |
| spirv_options.SetAutoBindUniforms(true); | |
| #ifdef IMPELLER_ENABLE_VULKAN | |
| SetBindingBase(spirv_options); | |
| #endif | |
| spirv_options.SetAutoMapLocations(true); | |
| std::vector<std::string> included_file_names; | |
| spirv_options.SetIncluder(std::make_unique<Includer>( | |
| options_.working_directory, options_.include_dirs, | |
| [&included_file_names](auto included_name) { | |
| included_file_names.emplace_back(std::move(included_name)); | |
| })); | |
| shaderc::Compiler spv_compiler; | |
| if (!spv_compiler.IsValid()) { | |
| COMPILER_ERROR << "Could not initialize the " | |
| << SourceLanguageToString(options_.source_language) | |
| << " to SPIRV compiler."; | |
| return; | |
| } | |
| // SPIRV Generation. | |
| spv_result_ = std::make_shared<shaderc::SpvCompilationResult>( | |
| spv_compiler.CompileGlslToSpv( | |
| reinterpret_cast<const char*>( | |
| source_mapping.GetMapping()), // source_text | |
| source_mapping.GetSize(), // source_text_size | |
| shader_kind, // shader_kind | |
| source_options.file_name.c_str(), // input_file_name | |
| source_options.entry_point_name.c_str(), // entry_point_name | |
| spirv_options // options | |
| )); | |
| if (spv_result_->GetCompilationStatus() != | |
| shaderc_compilation_status::shaderc_compilation_status_success) { | |
| COMPILER_ERROR << SourceLanguageToString(options_.source_language) | |
| << " to SPIRV failed; " | |
| << ShaderCErrorToString(spv_result_->GetCompilationStatus()) | |
| << ". " << spv_result_->GetNumErrors() << " error(s) and " | |
| << spv_result_->GetNumWarnings() << " warning(s)."; | |
| if (spv_result_->GetNumErrors() > 0 || spv_result_->GetNumWarnings() > 0) { | |
| COMPILER_ERROR_NO_PREFIX << spv_result_->GetErrorMessage(); | |
| } | |
| return; | |
| } else { | |
| included_file_names_ = std::move(included_file_names); | |
| } | |
| if (!TargetPlatformNeedsSL(source_options.target_platform)) { | |
| is_valid_ = true; | |
| return; | |
| } | |
| // SL Generation. | |
| spirv_cross::Parser parser(spv_result_->cbegin(), | |
| spv_result_->cend() - spv_result_->cbegin()); | |
| // The parser and compiler must be run separately because the parser contains | |
| // meta information (like type member names) that are useful for reflection. | |
| parser.parse(); | |
| const auto parsed_ir = | |
| std::make_shared<spirv_cross::ParsedIR>(parser.get_parsed_ir()); | |
| auto sl_compiler = CreateCompiler(*parsed_ir, options_); | |
| if (!sl_compiler) { | |
| COMPILER_ERROR << "Could not create compiler for target platform."; | |
| return; | |
| } | |
| // We need to invoke the compiler even if we don't use the SL mapping later | |
| // for Vulkan. The reflector needs information that is only valid after a | |
| // successful compilation call. | |
| auto sl_compilation_result = | |
| CreateMappingWithString(sl_compiler.GetCompiler()->compile()); | |
| // If the target is Vulkan, our shading language is SPIRV which we already | |
| // have. If it isn't, we need to invoke the appropriate compiler to compile | |
| // the SPIRV to the target SL. | |
| sl_mapping_ = source_options.target_platform == TargetPlatform::kVulkan | |
| ? GetSPIRVAssembly() | |
| : sl_compilation_result; | |
| if (!sl_mapping_) { | |
| COMPILER_ERROR << "Could not generate SL from SPIRV"; | |
| return; | |
| } | |
| reflector_ = std::make_unique<Reflector>(std::move(reflector_options), // | |
| parsed_ir, // | |
| GetSLShaderSource(), // | |
| sl_compiler // | |
| ); | |
| if (!reflector_->IsValid()) { | |
| COMPILER_ERROR << "Could not complete reflection on generated shader."; | |
| return; | |
| } | |
| is_valid_ = true; | |
| } | |
| Compiler::~Compiler() = default; | |
| std::unique_ptr<fml::Mapping> Compiler::GetSPIRVAssembly() const { | |
| if (!spv_result_) { | |
| return nullptr; | |
| } | |
| const auto data_length = | |
| (spv_result_->cend() - spv_result_->cbegin()) * | |
| sizeof(decltype(spv_result_)::element_type::element_type); | |
| return std::make_unique<fml::NonOwnedMapping>( | |
| reinterpret_cast<const uint8_t*>(spv_result_->cbegin()), data_length, | |
| [result = spv_result_](auto, auto) mutable { result.reset(); }); | |
| } | |
| std::shared_ptr<fml::Mapping> Compiler::GetSLShaderSource() const { | |
| return sl_mapping_; | |
| } | |
| bool Compiler::IsValid() const { | |
| return is_valid_; | |
| } | |
| std::string Compiler::GetSourcePrefix() const { | |
| std::stringstream stream; | |
| stream << options_.file_name << ": "; | |
| return stream.str(); | |
| } | |
| std::string Compiler::GetErrorMessages() const { | |
| return error_stream_.str(); | |
| } | |
| const std::vector<std::string>& Compiler::GetIncludedFileNames() const { | |
| return included_file_names_; | |
| } | |
| static std::string JoinStrings(std::vector<std::string> items, | |
| const std::string& separator) { | |
| std::stringstream stream; | |
| for (size_t i = 0, count = items.size(); i < count; i++) { | |
| const auto is_last = (i == count - 1); | |
| stream << items[i]; | |
| if (!is_last) { | |
| stream << separator; | |
| } | |
| } | |
| return stream.str(); | |
| } | |
| std::string Compiler::GetDependencyNames(const std::string& separator) const { | |
| std::vector<std::string> dependencies = included_file_names_; | |
| dependencies.push_back(options_.file_name); | |
| return JoinStrings(dependencies, separator); | |
| } | |
| std::unique_ptr<fml::Mapping> Compiler::CreateDepfileContents( | |
| std::initializer_list<std::string> targets_names) const { | |
| // https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28 | |
| const auto targets = JoinStrings(targets_names, " "); | |
| const auto dependencies = GetDependencyNames(" "); | |
| std::stringstream stream; | |
| stream << targets << ": " << dependencies << "\n"; | |
| auto contents = std::make_shared<std::string>(stream.str()); | |
| return std::make_unique<fml::NonOwnedMapping>( | |
| reinterpret_cast<const uint8_t*>(contents->data()), contents->size(), | |
| [contents](auto, auto) {}); | |
| } | |
| const Reflector* Compiler::GetReflector() const { | |
| return reflector_.get(); | |
| } | |
| } // namespace compiler | |
| } // namespace impeller |