[Impeller] Add a Stage 2 pass to the Vulkan shader compilation pipeline. (#40873)

[Impeller] Add a Stage 2 pass to the Vulkan shader compilation pipeline.
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index ea07491..387f2de 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -1096,6 +1096,8 @@
 ORIGIN: ../../../flutter/impeller/compiler/shader_lib/impeller/types.glsl + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/compiler/source_options.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/compiler/source_options.h + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/compiler/spirv_compiler.cc + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/compiler/spirv_compiler.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/compiler/spirv_sksl.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/compiler/spirv_sksl.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/compiler/switches.cc + ../../../flutter/LICENSE
@@ -3674,6 +3676,8 @@
 FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/types.glsl
 FILE: ../../../flutter/impeller/compiler/source_options.cc
 FILE: ../../../flutter/impeller/compiler/source_options.h
+FILE: ../../../flutter/impeller/compiler/spirv_compiler.cc
+FILE: ../../../flutter/impeller/compiler/spirv_compiler.h
 FILE: ../../../flutter/impeller/compiler/spirv_sksl.cc
 FILE: ../../../flutter/impeller/compiler/spirv_sksl.h
 FILE: ../../../flutter/impeller/compiler/switches.cc
diff --git a/impeller/compiler/BUILD.gn b/impeller/compiler/BUILD.gn
index 49a5ec2..788248f 100644
--- a/impeller/compiler/BUILD.gn
+++ b/impeller/compiler/BUILD.gn
@@ -46,6 +46,8 @@
     "runtime_stage_data.h",
     "source_options.cc",
     "source_options.h",
+    "spirv_compiler.cc",
+    "spirv_compiler.h",
     "spirv_sksl.cc",
     "spirv_sksl.h",
     "switches.cc",
diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc
index 4a7a618..27e1f97 100644
--- a/impeller/compiler/compiler.cc
+++ b/impeller/compiler/compiler.cc
@@ -4,7 +4,6 @@
 
 #include "impeller/compiler/compiler.h"
 
-#include <array>
 #include <filesystem>
 #include <memory>
 #include <optional>
@@ -17,16 +16,13 @@
 #include "impeller/compiler/compiler_backend.h"
 #include "impeller/compiler/includer.h"
 #include "impeller/compiler/logger.h"
+#include "impeller/compiler/spirv_compiler.h"
 #include "impeller/compiler/types.h"
 #include "impeller/compiler/uniform_sorter.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 uint32_t ParseMSLVersion(const std::string& msl_version) {
   std::stringstream sstream(msl_version);
   std::string version_part;
@@ -210,309 +206,138 @@
   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,
+Compiler::Compiler(const std::shared_ptr<const fml::Mapping>& source_mapping,
                    const SourceOptions& source_options,
                    Reflector::Options reflector_options)
     : options_(source_options) {
-  if (source_mapping.GetMapping() == nullptr) {
-    COMPILER_ERROR
+  if (!source_mapping || source_mapping->GetMapping() == nullptr) {
+    COMPILER_ERROR(error_stream_)
         << "Could not read shader source or shader source was empty.";
     return;
   }
 
   if (source_options.target_platform == TargetPlatform::kUnknown) {
-    COMPILER_ERROR << "Target platform not specified.";
+    COMPILER_ERROR(error_stream_) << "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;
+  SPIRVCompilerOptions spirv_options;
 
   // Make sure reflection is as effective as possible. The generated shaders
   // will be processed later by backend specific compilers.
-  spirv_options.SetGenerateDebugInfo();
+  spirv_options.generate_debug_info = true;
 
   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);
+      spirv_options.source_langauge =
+          shaderc_source_language::shaderc_source_language_glsl;
+      spirv_options.source_profile = SPIRVCompilerSourceProfile{
+          shaderc_profile::shaderc_profile_core,  //
+          460,                                    //
+      };
       break;
     case SourceLanguage::kHLSL:
-      spirv_options.SetSourceLanguage(
-          shaderc_source_language::shaderc_source_language_hlsl);
+      spirv_options.source_langauge =
+          shaderc_source_language::shaderc_source_language_hlsl;
       break;
     case SourceLanguage::kUnknown:
-      COMPILER_ERROR << "Source language invalid.";
+      COMPILER_ERROR(error_stream_) << "Source language invalid.";
       return;
   }
 
-  SetLimitations(spirv_options);
-
   switch (source_options.target_platform) {
     case TargetPlatform::kMetalDesktop:
-    case TargetPlatform::kMetalIOS:
-      spirv_options.SetOptimizationLevel(
-          shaderc_optimization_level::shaderc_optimization_level_performance);
+    case TargetPlatform::kMetalIOS: {
+      SPIRVCompilerTargetEnv target;
+
       if (source_options.use_half_textures) {
-        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);
+        target.env = shaderc_target_env::shaderc_target_env_opengl;
+        target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
+        target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
       } else {
-        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);
+        target.env = shaderc_target_env::shaderc_target_env_vulkan;
+        target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
+        target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
       }
-      break;
+
+      spirv_options.target = target;
+    } break;
     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:
-    case TargetPlatform::kRuntimeStageVulkan:
-      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: {
+      SPIRVCompilerTargetEnv target;
+
+      target.env = shaderc_target_env::shaderc_target_env_vulkan;
+      target.version = shaderc_env_version::shaderc_env_version_vulkan_1_1;
+      target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_3;
+
+      spirv_options.target = target;
+    } 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:
+    case TargetPlatform::kRuntimeStageVulkan: {
+      SPIRVCompilerTargetEnv target;
+
+      target.env = shaderc_target_env::shaderc_target_env_opengl;
+      target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
+      target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
+
+      spirv_options.target = target;
+      spirv_options.macro_definitions.push_back("IMPELLER_GRAPHICS_BACKEND");
+    } break;
+    case TargetPlatform::kSkSL: {
+      SPIRVCompilerTargetEnv target;
+
+      target.env = shaderc_target_env::shaderc_target_env_opengl;
+      target.version = shaderc_env_version::shaderc_env_version_opengl_4_5;
+      target.spirv_version = shaderc_spirv_version::shaderc_spirv_version_1_0;
+
       // 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;
+      spirv_options.optimization_level =
+          shaderc_optimization_level::shaderc_optimization_level_zero;
+      spirv_options.target = target;
+      spirv_options.macro_definitions.push_back("SKIA_GRAPHICS_BACKEND");
+    } break;
     case TargetPlatform::kUnknown:
-      COMPILER_ERROR << "Target platform invalid.";
+      COMPILER_ERROR(error_stream_) << "Target platform invalid.";
       return;
   }
 
   // Implicit definition that indicates that this compilation is for the device
   // (instead of the host).
-  spirv_options.AddMacroDefinition("IMPELLER_DEVICE");
+  spirv_options.macro_definitions.push_back("IMPELLER_DEVICE");
   for (const auto& define : source_options.defines) {
-    spirv_options.AddMacroDefinition(define);
+    spirv_options.macro_definitions.push_back(define);
   }
 
-  spirv_options.SetAutoBindUniforms(true);
-  SetBindingBase(spirv_options);
-  spirv_options.SetAutoMapLocations(true);
-
   std::vector<std::string> included_file_names;
-  spirv_options.SetIncluder(std::make_unique<Includer>(
+  spirv_options.includer = std::make_shared<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).";
-    // It should normally be enough to check that there are errors or warnings,
-    // but some cases result in no errors or warnings and still have an error
-    // message. If there's a message we should print it.
-    if (spv_result_->GetNumErrors() > 0 || spv_result_->GetNumWarnings() > 0 ||
-        !spv_result_->GetErrorMessage().empty()) {
-      COMPILER_ERROR_NO_PREFIX << spv_result_->GetErrorMessage();
-    }
+  SPIRVCompiler spv_compiler(source_options, source_mapping);
+
+  spirv_assembly_ = spv_compiler.CompileToSPV(
+      error_stream_, spirv_options.BuildShadercOptions());
+
+  if (!spirv_assembly_) {
     return;
   } else {
     included_file_names_ = std::move(included_file_names);
   }
 
   // SL Generation.
-  spirv_cross::Parser parser(spv_result_->cbegin(),
-                             spv_result_->cend() - spv_result_->cbegin());
+  spirv_cross::Parser parser(
+      reinterpret_cast<const uint32_t*>(spirv_assembly_->GetMapping()),
+      spirv_assembly_->GetSize() / sizeof(uint32_t));
   // 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();
@@ -523,7 +348,8 @@
   auto sl_compiler = CreateCompiler(*parsed_ir, options_);
 
   if (!sl_compiler) {
-    COMPILER_ERROR << "Could not create compiler for target platform.";
+    COMPILER_ERROR(error_stream_)
+        << "Could not create compiler for target platform.";
     return;
   }
 
@@ -534,14 +360,19 @@
       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;
+  // have. We just need to strip it of debug information. If it isn't, we need
+  // to invoke the appropriate compiler to compile the SPIRV to the target SL.
+  if (source_options.target_platform == TargetPlatform::kVulkan) {
+    auto stripped_spirv_options = spirv_options;
+    stripped_spirv_options.generate_debug_info = false;
+    sl_mapping_ = spv_compiler.CompileToSPV(
+        error_stream_, stripped_spirv_options.BuildShadercOptions());
+  } else {
+    sl_mapping_ = sl_compilation_result;
+  }
 
   if (!sl_mapping_) {
-    COMPILER_ERROR << "Could not generate SL from SPIRV";
+    COMPILER_ERROR(error_stream_) << "Could not generate SL from SPIRV";
     return;
   }
 
@@ -552,7 +383,8 @@
   );
 
   if (!reflector_->IsValid()) {
-    COMPILER_ERROR << "Could not complete reflection on generated shader.";
+    COMPILER_ERROR(error_stream_)
+        << "Could not complete reflection on generated shader.";
     return;
   }
 
@@ -561,17 +393,8 @@
 
 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::GetSPIRVAssembly() const {
+  return spirv_assembly_;
 }
 
 std::shared_ptr<fml::Mapping> Compiler::GetSLShaderSource() const {
diff --git a/impeller/compiler/compiler.h b/impeller/compiler/compiler.h
index d79f0c5..d338cec 100644
--- a/impeller/compiler/compiler.h
+++ b/impeller/compiler/compiler.h
@@ -13,8 +13,8 @@
 #include "impeller/compiler/include_dir.h"
 #include "impeller/compiler/reflector.h"
 #include "impeller/compiler/source_options.h"
+#include "impeller/compiler/spirv_compiler.h"
 #include "impeller/compiler/types.h"
-#include "shaderc/shaderc.hpp"
 #include "spirv_msl.hpp"
 #include "spirv_parser.hpp"
 
@@ -23,7 +23,7 @@
 
 class Compiler {
  public:
-  Compiler(const fml::Mapping& source_mapping,
+  Compiler(const std::shared_ptr<const fml::Mapping>& source_mapping,
            const SourceOptions& options,
            Reflector::Options reflector_options);
 
@@ -31,7 +31,7 @@
 
   bool IsValid() const;
 
-  std::unique_ptr<fml::Mapping> GetSPIRVAssembly() const;
+  std::shared_ptr<fml::Mapping> GetSPIRVAssembly() const;
 
   std::shared_ptr<fml::Mapping> GetSLShaderSource() const;
 
@@ -46,7 +46,7 @@
 
  private:
   SourceOptions options_;
-  std::shared_ptr<shaderc::SpvCompilationResult> spv_result_;
+  std::shared_ptr<fml::Mapping> spirv_assembly_;
   std::shared_ptr<fml::Mapping> sl_mapping_;
   std::stringstream error_stream_;
   std::unique_ptr<Reflector> reflector_;
@@ -57,8 +57,6 @@
 
   std::string GetDependencyNames(const std::string& separator) const;
 
-  void SetBindingBase(shaderc::CompileOptions& compiler_opts) const;
-
   FML_DISALLOW_COPY_AND_ASSIGN(Compiler);
 };
 
diff --git a/impeller/compiler/compiler_test.cc b/impeller/compiler/compiler_test.cc
index abdf72b..024ea63 100644
--- a/impeller/compiler/compiler_test.cc
+++ b/impeller/compiler/compiler_test.cc
@@ -69,7 +69,8 @@
                                         SourceType source_type,
                                         SourceLanguage source_language,
                                         const char* entry_point_name) const {
-  auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name);
+  std::shared_ptr<fml::Mapping> fixture =
+      flutter::testing::OpenFixtureAsMapping(fixture_name);
   if (!fixture || !fixture->GetMapping()) {
     VALIDATION_LOG << "Could not find shader in fixtures: " << fixture_name;
     return false;
@@ -88,7 +89,7 @@
   reflector_options.header_file_name = ReflectionHeaderName(fixture_name);
   reflector_options.shader_name = "shader_name";
 
-  Compiler compiler(*fixture.get(), source_options, reflector_options);
+  Compiler compiler(fixture, source_options, reflector_options);
   if (!compiler.IsValid()) {
     VALIDATION_LOG << "Compilation failed: " << compiler.GetErrorMessages();
     return false;
diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc
index 55b9991..14a78f6 100644
--- a/impeller/compiler/impellerc_main.cc
+++ b/impeller/compiler/impellerc_main.cc
@@ -50,7 +50,7 @@
     return false;
   }
 
-  auto source_file_mapping =
+  std::shared_ptr<fml::FileMapping> source_file_mapping =
       fml::FileMapping::CreateReadOnly(switches.source_file_name);
   if (!source_file_mapping) {
     std::cerr << "Could not open input file." << std::endl;
@@ -95,7 +95,7 @@
     sksl_reflector_options.target_platform = TargetPlatform::kSkSL;
 
     Compiler sksl_compiler =
-        Compiler(*source_file_mapping, sksl_options, sksl_reflector_options);
+        Compiler(source_file_mapping, sksl_options, sksl_reflector_options);
     if (!sksl_compiler.IsValid()) {
       std::cerr << "Compilation to SkSL failed." << std::endl;
       std::cerr << sksl_compiler.GetErrorMessages() << std::endl;
@@ -104,7 +104,7 @@
     sksl_mapping = sksl_compiler.GetSLShaderSource();
   }
 
-  Compiler compiler(*source_file_mapping, options, reflector_options);
+  Compiler compiler(source_file_mapping, options, reflector_options);
   if (!compiler.IsValid()) {
     std::cerr << "Compilation failed." << std::endl;
     std::cerr << compiler.GetErrorMessages() << std::endl;
diff --git a/impeller/compiler/logger.h b/impeller/compiler/logger.h
index fb07dd0..d4ae7cc 100644
--- a/impeller/compiler/logger.h
+++ b/impeller/compiler/logger.h
@@ -34,10 +34,11 @@
   FML_DISALLOW_COPY_AND_ASSIGN(AutoLogger);
 };
 
-#define COMPILER_ERROR \
-  ::impeller::compiler::AutoLogger(error_stream_) << GetSourcePrefix()
+#define COMPILER_ERROR(stream) \
+  ::impeller::compiler::AutoLogger(stream) << GetSourcePrefix()
 
-#define COMPILER_ERROR_NO_PREFIX ::impeller::compiler::AutoLogger(error_stream_)
+#define COMPILER_ERROR_NO_PREFIX(stream) \
+  ::impeller::compiler::AutoLogger(stream)
 
 }  // namespace compiler
 }  // namespace impeller
diff --git a/impeller/compiler/spirv_compiler.cc b/impeller/compiler/spirv_compiler.cc
new file mode 100644
index 0000000..0ddf0bc
--- /dev/null
+++ b/impeller/compiler/spirv_compiler.cc
@@ -0,0 +1,307 @@
+// 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/spirv_compiler.h"
+
+#include <array>
+
+#include "impeller/compiler/logger.h"
+#include "impeller/compiler/types.h"
+
+namespace impeller {
+namespace compiler {
+
+SPIRVCompiler::SPIRVCompiler(const SourceOptions& options,
+                             std::shared_ptr<const fml::Mapping> sources)
+    : options_(options), sources_(std::move(sources)) {}
+
+SPIRVCompiler::~SPIRVCompiler() = default;
+
+std::shared_ptr<fml::Mapping> SPIRVCompiler::CompileToSPV(
+    std::stringstream& stream,
+    const shaderc::CompileOptions& spirv_options) const {
+  if (!sources_ || sources_->GetMapping() == nullptr) {
+    COMPILER_ERROR(stream) << "Invalid sources for SPIRV Compiler.";
+    return nullptr;
+  }
+
+  shaderc::Compiler spv_compiler;
+  if (!spv_compiler.IsValid()) {
+    COMPILER_ERROR(stream) << "Could not initialize the "
+                           << SourceLanguageToString(options_.source_language)
+                           << " to SPIRV compiler.";
+    return nullptr;
+  }
+
+  const auto shader_kind = ToShaderCShaderKind(options_.type);
+
+  if (shader_kind == shaderc_shader_kind::shaderc_glsl_infer_from_source) {
+    COMPILER_ERROR(stream) << "Could not figure out shader stage.";
+    return nullptr;
+  }
+
+  auto result = std::make_shared<shaderc::SpvCompilationResult>(
+      spv_compiler.CompileGlslToSpv(
+          reinterpret_cast<const char*>(sources_->GetMapping()),  // source_text
+          sources_->GetSize(),                // source_text_size
+          shader_kind,                        // shader_kind
+          options_.file_name.c_str(),         // input_file_name
+          options_.entry_point_name.c_str(),  // entry_point_name
+          spirv_options                       // options
+          ));
+  if (result->GetCompilationStatus() !=
+      shaderc_compilation_status::shaderc_compilation_status_success) {
+    COMPILER_ERROR(stream) << SourceLanguageToString(options_.source_language)
+                           << " to SPIRV failed; "
+                           << ShaderCErrorToString(
+                                  result->GetCompilationStatus())
+                           << ". " << result->GetNumErrors() << " error(s) and "
+                           << result->GetNumWarnings() << " warning(s).";
+    // It should normally be enough to check that there are errors or warnings,
+    // but some cases result in no errors or warnings and still have an error
+    // message. If there's a message we should print it.
+    if (result->GetNumErrors() > 0 || result->GetNumWarnings() > 0 ||
+        !result->GetErrorMessage().empty()) {
+      COMPILER_ERROR_NO_PREFIX(stream) << result->GetErrorMessage();
+    }
+    return nullptr;
+  }
+
+  if (!result) {
+    COMPILER_ERROR(stream) << "Could not fetch SPIRV from compile job.";
+    return nullptr;
+  }
+
+  const auto data_length = (result->cend() - result->cbegin()) *
+                           sizeof(decltype(result)::element_type::element_type);
+
+  return std::make_unique<fml::NonOwnedMapping>(
+      reinterpret_cast<const uint8_t*>(result->cbegin()),  //
+      data_length,                                         //
+      [result](auto, auto) {}                              //
+  );
+}
+
+std::string SPIRVCompiler::GetSourcePrefix() const {
+  std::stringstream stream;
+  stream << options_.file_name << ": ";
+  return stream.str();
+}
+
+static void SetDefaultLimitations(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);
+  }
+}
+
+static void SetBindingBaseOffset(shaderc::CompileOptions& options) {
+  constexpr uint32_t kFragBindingBase = 128;
+  constexpr size_t kNumUniformKinds =
+      static_cast<int>(shaderc_uniform_kind::shaderc_uniform_kind_buffer) + 1;
+  for (size_t uniform_kind = 0; uniform_kind < kNumUniformKinds;
+       uniform_kind++) {
+    options.SetBindingBaseForStage(
+        ToShaderCShaderKind(SourceType::kFragmentShader),
+        static_cast<shaderc_uniform_kind>(uniform_kind), kFragBindingBase);
+  }
+}
+
+//------------------------------------------------------------------------------
+/// @brief      Wraps a shared includer so unique includers may be created to
+///             satisfy the shaderc API. This is a simple proxy object and does
+///             nothing.
+///
+class UniqueIncluder final : public shaderc::CompileOptions::IncluderInterface {
+ public:
+  static std::unique_ptr<UniqueIncluder> Make(
+      std::shared_ptr<Includer> includer) {
+    return std::unique_ptr<UniqueIncluder>(
+        new UniqueIncluder(std::move(includer)));
+  }
+
+  // |shaderc::CompileOptions::IncluderInterface|
+  ~UniqueIncluder() = default;
+
+  // |shaderc::CompileOptions::IncluderInterface|
+  shaderc_include_result* GetInclude(const char* requested_source,
+                                     shaderc_include_type type,
+                                     const char* requesting_source,
+                                     size_t include_depth) override {
+    return includer_->GetInclude(requested_source,   //
+                                 type,               //
+                                 requesting_source,  //
+                                 include_depth       //
+    );
+  }
+
+  // |shaderc::CompileOptions::IncluderInterface|
+  void ReleaseInclude(shaderc_include_result* data) override {
+    return includer_->ReleaseInclude(data);
+  }
+
+ private:
+  std::shared_ptr<Includer> includer_;
+
+  explicit UniqueIncluder(std::shared_ptr<Includer> includer)
+      : includer_(std::move(includer)) {
+    FML_CHECK(includer_);
+  }
+
+  FML_DISALLOW_COPY_AND_ASSIGN(UniqueIncluder);
+};
+
+shaderc::CompileOptions SPIRVCompilerOptions::BuildShadercOptions() const {
+  shaderc::CompileOptions options;
+
+  SetDefaultLimitations(options);
+  SetBindingBaseOffset(options);
+
+  options.SetAutoBindUniforms(true);
+  options.SetAutoMapLocations(true);
+
+  options.SetOptimizationLevel(optimization_level);
+
+  if (generate_debug_info) {
+    options.SetGenerateDebugInfo();
+  }
+
+  if (source_langauge.has_value()) {
+    options.SetSourceLanguage(source_langauge.value());
+  }
+
+  if (source_profile.has_value()) {
+    options.SetForcedVersionProfile(source_profile->version,
+                                    source_profile->profile);
+  }
+
+  if (target.has_value()) {
+    options.SetTargetEnvironment(target->env, target->version);
+    options.SetTargetSpirv(target->spirv_version);
+  }
+
+  for (const auto& macro : macro_definitions) {
+    options.AddMacroDefinition(macro);
+  }
+
+  if (includer) {
+    options.SetIncluder(UniqueIncluder::Make(includer));
+  }
+
+  return options;
+}
+
+}  // namespace compiler
+}  // namespace impeller
diff --git a/impeller/compiler/spirv_compiler.h b/impeller/compiler/spirv_compiler.h
new file mode 100644
index 0000000..8157b7b
--- /dev/null
+++ b/impeller/compiler/spirv_compiler.h
@@ -0,0 +1,75 @@
+// 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.
+
+#pragma once
+
+#include <vector>
+
+#include "flutter/fml/macros.h"
+#include "flutter/fml/mapping.h"
+#include "impeller/compiler/includer.h"
+#include "impeller/compiler/source_options.h"
+#include "shaderc/shaderc.hpp"
+
+namespace impeller {
+namespace compiler {
+
+struct SPIRVCompilerSourceProfile {
+  shaderc_profile profile = shaderc_profile_core;
+  uint32_t version = 460;
+};
+
+struct SPIRVCompilerTargetEnv {
+  shaderc_target_env env = shaderc_target_env::shaderc_target_env_vulkan;
+  shaderc_env_version version =
+      shaderc_env_version::shaderc_env_version_vulkan_1_1;
+  shaderc_spirv_version spirv_version =
+      shaderc_spirv_version::shaderc_spirv_version_1_3;
+};
+
+struct SPIRVCompilerOptions {
+  bool generate_debug_info = true;
+  //----------------------------------------------------------------------------
+  // Source Options.
+  //----------------------------------------------------------------------------
+  std::optional<shaderc_source_language> source_langauge;
+  std::optional<SPIRVCompilerSourceProfile> source_profile;
+
+  shaderc_optimization_level optimization_level =
+      shaderc_optimization_level::shaderc_optimization_level_performance;
+
+  //----------------------------------------------------------------------------
+  // Target Options.
+  //----------------------------------------------------------------------------
+  std::optional<SPIRVCompilerTargetEnv> target;
+
+  std::vector<std::string> macro_definitions;
+
+  std::shared_ptr<Includer> includer;
+
+  shaderc::CompileOptions BuildShadercOptions() const;
+};
+
+class SPIRVCompiler {
+ public:
+  SPIRVCompiler(const SourceOptions& options,
+                std::shared_ptr<const fml::Mapping> sources);
+
+  ~SPIRVCompiler();
+
+  std::shared_ptr<fml::Mapping> CompileToSPV(
+      std::stringstream& error_stream,
+      const shaderc::CompileOptions& spirv_options) const;
+
+ private:
+  SourceOptions options_;
+  const std::shared_ptr<const fml::Mapping> sources_;
+
+  std::string GetSourcePrefix() const;
+
+  FML_DISALLOW_COPY_AND_ASSIGN(SPIRVCompiler);
+};
+
+}  // namespace compiler
+}  // namespace impeller