Skip to content

Commit

Permalink
[Impeller] Allow for the specification of pipeline stage information …
Browse files Browse the repository at this point in the history
…at runtime. (flutter#33882)

Towards implementing the FragmentProgram API in Impeller.

Specifies an Impeller specific format for data the renderer can use to create
pipelines with user supplied shader stages at runtime.

The data is in the form of a flatbuffer with a known schema.

This patch implements the wire format, creating and loading the program
payloads, and creating pipeline state objects using these payloads.

If the user supplied SPIRV intended for the older API, the loader will reject
this invalid payload. This is probably not going to be too much of an issue
because the FragmentProgram API will probably be modified to only allow buffers
loaded from asset managers. But still, in the meantime, I am using the old API
to pass these new buffers.

Fixes flutter/flutter#104750
Fixes flutter/flutter#105542
Towards resolving flutter/flutter#102853
  • Loading branch information
chinmaygarde authored Jun 14, 2022
1 parent ccbcd0b commit b43cf27
Show file tree
Hide file tree
Showing 43 changed files with 4,284 additions and 2,049 deletions.
4 changes: 3 additions & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ allowed_hosts = [
]

deps = {
'src': 'https://github.com/flutter/buildroot.git' + '@' + '8ce3dadcb6bb3e05570e1b5748fbc2716d264bb0',
'src': 'https://github.com/flutter/buildroot.git' + '@' + 'a41648143b1095abf4e19d5fc8608be408e1fa20',

# Fuchsia compatibility
#
Expand Down Expand Up @@ -149,6 +149,8 @@ deps = {
'src/third_party/spirv_cross':
Var('github_git') + '/KhronosGroup/SPIRV-Cross.git' + '@' + '418542eaefdb609f548d25a1e3962fb69d80da63',

'src/third_party/flatbuffers':
Var('github_git') + '/google/flatbuffers.git' + '@' + '967df08b1dbddc62f867464c2e0d58d8027438ad',

# Chromium-style
#
Expand Down
8 changes: 8 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ FILE: ../../../flutter/impeller/compiler/includer.h
FILE: ../../../flutter/impeller/compiler/logger.h
FILE: ../../../flutter/impeller/compiler/reflector.cc
FILE: ../../../flutter/impeller/compiler/reflector.h
FILE: ../../../flutter/impeller/compiler/runtime_stage_data.cc
FILE: ../../../flutter/impeller/compiler/runtime_stage_data.h
FILE: ../../../flutter/impeller/compiler/source_options.cc
FILE: ../../../flutter/impeller/compiler/source_options.h
FILE: ../../../flutter/impeller/compiler/switches.cc
Expand Down Expand Up @@ -780,6 +782,12 @@ FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.cc
FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.h
FILE: ../../../flutter/impeller/renderer/vertex_descriptor.cc
FILE: ../../../flutter/impeller/renderer/vertex_descriptor.h
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage.cc
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage.fbs
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage.h
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_playground.cc
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_playground.h
FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_unittests.cc
FILE: ../../../flutter/impeller/tessellator/c/tessellator.cc
FILE: ../../../flutter/impeller/tessellator/c/tessellator.h
FILE: ../../../flutter/impeller/tessellator/dart/lib/tessellator.dart
Expand Down
4,678 changes: 2,698 additions & 1,980 deletions ci/licenses_golden/licenses_third_party

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ci/licenses_golden/tool_signature
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Signature: 2b69b9b3b985d18a9c148d38f9cefb46
Signature: 1177a4d90f87bc4a0198864901db40ab

5 changes: 4 additions & 1 deletion impeller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ group("impeller") {
}
}

executable("impeller_unittests") {
impeller_component("impeller_unittests") {
target_type = "executable"

testonly = true

deps = [
Expand All @@ -73,6 +75,7 @@ executable("impeller_unittests") {
"blobcat:blobcat_unittests",
"compiler:compiler_unittests",
"geometry:geometry_unittests",
"runtime_stage:runtime_stage_unittests",
"tessellator:tessellator_unittests",
]

Expand Down
8 changes: 8 additions & 0 deletions impeller/base/strings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ bool HasPrefix(const std::string& string, const std::string& prefix) {
return string.find(prefix) == 0u;
}

bool HasSuffix(const std::string& string, const std::string& suffix) {
auto position = string.rfind(suffix);
if (position == std::string::npos) {
return false;
}
return position == string.size() - suffix.size();
}

std::string StripPrefix(const std::string& string,
const std::string& to_strip) {
if (!HasPrefix(string, to_strip)) {
Expand Down
2 changes: 2 additions & 0 deletions impeller/base/strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ std::string SPrintF(const char* format, ...);

bool HasPrefix(const std::string& string, const std::string& prefix);

bool HasSuffix(const std::string& string, const std::string& suffix);

std::string StripPrefix(const std::string& string, const std::string& to_strip);

} // namespace impeller
18 changes: 16 additions & 2 deletions impeller/base/validation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,29 @@

#include "impeller/base/validation.h"

#include <atomic>

#include "flutter/fml/logging.h"

namespace impeller {

static std::atomic_int32_t sValidationLogsDisabledCount = 0;

ScopedValidationDisable::ScopedValidationDisable() {
sValidationLogsDisabledCount++;
}

ScopedValidationDisable::~ScopedValidationDisable() {
sValidationLogsDisabledCount--;
}

ValidationLog::ValidationLog() = default;

ValidationLog::~ValidationLog() {
FML_LOG(ERROR) << stream_.str();
ImpellerValidationBreak();
if (sValidationLogsDisabledCount <= 0) {
FML_LOG(ERROR) << stream_.str();
ImpellerValidationBreak();
}
}

std::ostream& ValidationLog::GetStream() {
Expand Down
8 changes: 8 additions & 0 deletions impeller/base/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ class ValidationLog {

void ImpellerValidationBreak();

struct ScopedValidationDisable {
ScopedValidationDisable();

~ScopedValidationDisable();

FML_DISALLOW_COPY_AND_ASSIGN(ScopedValidationDisable);
};

} // namespace impeller

#define VALIDATION_LOG ::impeller::ValidationLog{}.GetStream()
3 changes: 3 additions & 0 deletions impeller/compiler/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ impeller_component("compiler_lib") {
"logger.h",
"reflector.cc",
"reflector.h",
"runtime_stage_data.cc",
"runtime_stage_data.h",
"source_options.cc",
"source_options.h",
"switches.cc",
Expand All @@ -31,6 +33,7 @@ impeller_component("compiler_lib") {
public_deps = [
"../base",
"../geometry",
"../runtime_stage",
"//flutter/fml",

# All third_party deps must be reflected below in the impellerc_license
Expand Down
18 changes: 16 additions & 2 deletions impeller/compiler/compiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ static bool EntryPointMustBeNamedMain(TargetPlatform platform) {
FML_UNREACHABLE();
case TargetPlatform::kMetalDesktop:
case TargetPlatform::kMetalIOS:
case TargetPlatform::kRuntimeStageMetal:
return false;
case TargetPlatform::kFlutterSPIRV:
case TargetPlatform::kOpenGLES:
case TargetPlatform::kOpenGLDesktop:
case TargetPlatform::kRuntimeStageGLES:
return true;
}
FML_UNREACHABLE();
Expand All @@ -68,6 +70,8 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir,
switch (source_options.target_platform) {
case TargetPlatform::kMetalDesktop:
case TargetPlatform::kMetalIOS:
case TargetPlatform::kRuntimeStageMetal:
case TargetPlatform::kRuntimeStageGLES:
compiler = CreateMSLCompiler(ir, source_options);
break;
case TargetPlatform::kUnknown:
Expand All @@ -85,7 +89,6 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir,
backend->rename_entry_point("main", source_options.entry_point_name,
ToExecutionModel(source_options.type));
}

return compiler;
}

Expand Down Expand Up @@ -130,13 +133,23 @@ Compiler::Compiler(const fml::Mapping& source_mapping,
case TargetPlatform::kOpenGLES:
case TargetPlatform::kOpenGLDesktop:
spirv_options.SetOptimizationLevel(
shaderc_optimization_level::shaderc_optimization_level_zero);
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::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);
break;
case TargetPlatform::kFlutterSPIRV:
// With any optimization level above 'zero' enabled, shaderc will emit
// ops that are not supported by the Engine's SPIR-V -> SkSL transpiler.
Expand Down Expand Up @@ -237,6 +250,7 @@ Compiler::Compiler(const fml::Mapping& source_mapping,

reflector_ = std::make_unique<Reflector>(std::move(reflector_options), //
parsed_ir, //
GetSLShaderSource(), //
sl_compiler //
);

Expand Down
1 change: 1 addition & 0 deletions impeller/compiler/compiler_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) {
// This is a failure of reflection which this target doesn't perform.
GTEST_SKIP();
}
ScopedValidationDisable disable_validation;
ASSERT_FALSE(CanCompileAndReflect("struct_def_bug.vert"));
}

Expand Down
43 changes: 37 additions & 6 deletions impeller/compiler/impellerc_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "flutter/fml/file.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "impeller/base/strings.h"
#include "impeller/compiler/compiler.h"
#include "impeller/compiler/source_options.h"
#include "impeller/compiler/switches.h"
Expand Down Expand Up @@ -51,6 +52,7 @@ bool Main(const fml::CommandLine& command_line) {
SourceTypeFromFileName(switches.source_file_name));

Reflector::Options reflector_options;
reflector_options.target_platform = switches.target_platform;
reflector_options.entry_point_name = options.entry_point_name;
reflector_options.shader_name =
InferShaderNameFromPath(switches.source_file_name);
Expand Down Expand Up @@ -79,12 +81,39 @@ bool Main(const fml::CommandLine& command_line) {
if (TargetPlatformNeedsSL(options.target_platform)) {
auto sl_file_name = std::filesystem::absolute(
std::filesystem::current_path() / switches.sl_file_name);
if (!fml::WriteAtomically(*switches.working_directory,
sl_file_name.string().c_str(),
*compiler.GetSLShaderSource())) {
std::cerr << "Could not write file to " << switches.spirv_file_name
<< std::endl;
return false;
const bool is_runtime_stage_data = HasSuffix(switches.sl_file_name, "iplr");
if (is_runtime_stage_data) {
auto reflector = compiler.GetReflector();
if (reflector == nullptr) {
std::cerr << "Could not create reflector." << std::endl;
return false;
}
auto stage_data = reflector->GetRuntimeStageData();
if (!stage_data) {
std::cerr << "Runtime stage information was nil." << std::endl;
return false;
}
auto stage_data_mapping = stage_data->CreateMapping();
if (!stage_data_mapping) {
std::cerr << "Runtime stage data could not be created." << std::endl;
return false;
}
if (!fml::WriteAtomically(*switches.working_directory, //
sl_file_name.string().c_str(), //
*stage_data_mapping //
)) {
std::cerr << "Could not write file to " << switches.sl_file_name
<< std::endl;
return false;
}
} else {
if (!fml::WriteAtomically(*switches.working_directory,
sl_file_name.string().c_str(),
*compiler.GetSLShaderSource())) {
std::cerr << "Could not write file to " << switches.sl_file_name
<< std::endl;
return false;
}
}
}

Expand Down Expand Up @@ -137,6 +166,8 @@ bool Main(const fml::CommandLine& command_line) {
case TargetPlatform::kMetalIOS:
case TargetPlatform::kOpenGLES:
case TargetPlatform::kOpenGLDesktop:
case TargetPlatform::kRuntimeStageMetal:
case TargetPlatform::kRuntimeStageGLES:
result_file = switches.sl_file_name;
break;
case TargetPlatform::kFlutterSPIRV:
Expand Down
41 changes: 41 additions & 0 deletions impeller/compiler/reflector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,11 @@ static std::string StringToShaderStage(std::string str) {

Reflector::Reflector(Options options,
std::shared_ptr<const spirv_cross::ParsedIR> ir,
std::shared_ptr<fml::Mapping> shader_data,
CompilerBackend compiler)
: options_(std::move(options)),
ir_(std::move(ir)),
shader_data_(std::move(shader_data)),
compiler_(std::move(compiler)) {
if (!ir_ || !compiler_) {
return;
Expand All @@ -134,6 +136,11 @@ Reflector::Reflector(Options options,
return;
}

runtime_stage_data_ = GenerateRuntimeStageData();
if (!runtime_stage_data_) {
return;
}

is_valid_ = true;
}

Expand Down Expand Up @@ -164,6 +171,10 @@ std::shared_ptr<fml::Mapping> Reflector::GetReflectionCC() const {
return reflection_cc_;
}

std::shared_ptr<RuntimeStageData> Reflector::GetRuntimeStageData() const {
return runtime_stage_data_;
}

std::optional<nlohmann::json> Reflector::GenerateTemplateArguments() const {
nlohmann::json root;

Expand Down Expand Up @@ -293,6 +304,36 @@ std::shared_ptr<fml::Mapping> Reflector::GenerateReflectionCC() const {
return InflateTemplate(kReflectionCCTemplate);
}

std::shared_ptr<RuntimeStageData> Reflector::GenerateRuntimeStageData() const {
const auto& entrypoints = compiler_->get_entry_points_and_stages();
if (entrypoints.size() != 1u) {
VALIDATION_LOG << "Single entrypoint not found.";
return nullptr;
}
auto data = std::make_shared<RuntimeStageData>(
options_.entry_point_name, //
entrypoints.front().execution_model, //
options_.target_platform //
);
data->SetShaderData(shader_data_);
ir_->for_each_typed_id<spirv_cross::SPIRVariable>(
[&](uint32_t, const spirv_cross::SPIRVariable& var) {
if (var.storage != spv::StorageClassUniformConstant) {
return;
}
const auto spir_type = compiler_->get_type(var.basetype);
UniformDescription uniform_description;
uniform_description.name = compiler_->get_name(var.self);
uniform_description.location = compiler_->get_decoration(
var.self, spv::Decoration::DecorationLocation);
uniform_description.type = spir_type.basetype;
uniform_description.rows = spir_type.vecsize;
uniform_description.columns = spir_type.columns;
data->AddUniformDescription(std::move(uniform_description));
});
return data;
}

static std::string ToString(CompilerBackend::Type type) {
switch (type) {
case CompilerBackend::Type::kMSL:
Expand Down
Loading

0 comments on commit b43cf27

Please sign in to comment.