[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