Skip to content

Commit

Permalink
[Flutter GPU] Shader bundle improvements: Uniform structs & member of…
Browse files Browse the repository at this point in the history
…fset reflection, GLES metadata, separate from runtime stage. (flutter#49485)

* Switch from legacy uniform semantics to uniform structs.
* Completely separate shader bundle from runtime stage.
* Packing multiple backends per shader.
* Pack struct and member fields into the shader bundle flatbuffer.
* Bind uniforms with correct metadata for GLES.
* Add uniform struct size and member offset reflection.
  • Loading branch information
bdero authored Jan 8, 2024
1 parent 5199f56 commit 00ff332
Show file tree
Hide file tree
Showing 34 changed files with 1,240 additions and 417 deletions.
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -5016,6 +5016,8 @@ ORIGIN: ../../../flutter/impeller/compiler/runtime_stage_data.cc + ../../../flut
ORIGIN: ../../../flutter/impeller/compiler/runtime_stage_data.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/compiler/shader_bundle.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/compiler/shader_bundle.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/compiler/shader_bundle_data.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/compiler/shader_bundle_data.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/compiler/shader_lib/flutter/runtime_effect.glsl + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/compiler/shader_lib/impeller/blending.glsl + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/compiler/shader_lib/impeller/branching.glsl + ../../../flutter/LICENSE
Expand Down Expand Up @@ -7831,6 +7833,8 @@ FILE: ../../../flutter/impeller/compiler/runtime_stage_data.cc
FILE: ../../../flutter/impeller/compiler/runtime_stage_data.h
FILE: ../../../flutter/impeller/compiler/shader_bundle.cc
FILE: ../../../flutter/impeller/compiler/shader_bundle.h
FILE: ../../../flutter/impeller/compiler/shader_bundle_data.cc
FILE: ../../../flutter/impeller/compiler/shader_bundle_data.h
FILE: ../../../flutter/impeller/compiler/shader_lib/flutter/runtime_effect.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/blending.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/branching.glsl
Expand Down
2 changes: 2 additions & 0 deletions impeller/compiler/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ impeller_component("compiler_lib") {
"runtime_stage_data.h",
"shader_bundle.cc",
"shader_bundle.h",
"shader_bundle_data.cc",
"shader_bundle_data.h",
"source_options.cc",
"source_options.h",
"spirv_compiler.cc",
Expand Down
176 changes: 141 additions & 35 deletions impeller/compiler/reflector.cc

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions impeller/compiler/reflector.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "flutter/fml/mapping.h"
#include "impeller/compiler/compiler_backend.h"
#include "impeller/compiler/runtime_stage_data.h"
#include "impeller/compiler/shader_bundle_data.h"
#include "inja/inja.hpp"
#include "spirv_msl.hpp"
#include "spirv_parser.hpp"
Expand All @@ -22,7 +23,7 @@ namespace compiler {

struct StructMember {
std::string type;
std::string base_type;
spirv_cross::SPIRType::BaseType base_type;
std::string name;
size_t offset = 0u;
size_t size = 0u;
Expand All @@ -31,15 +32,15 @@ struct StructMember {
size_t element_padding = 0u;

StructMember(std::string p_type,
std::string p_base_type,
spirv_cross::SPIRType::BaseType p_base_type,
std::string p_name,
size_t p_offset,
size_t p_size,
size_t p_byte_length,
std::optional<size_t> p_array_elements,
size_t p_element_padding)
: type(std::move(p_type)),
base_type(std::move(p_base_type)),
base_type(p_base_type),
name(std::move(p_name)),
offset(p_offset),
size(p_size),
Expand Down Expand Up @@ -74,6 +75,8 @@ class Reflector {

std::shared_ptr<RuntimeStageData::Shader> GetRuntimeStageShaderData() const;

std::shared_ptr<ShaderBundleData> GetShaderBundleData() const;

private:
struct StructDefinition {
std::string name;
Expand Down Expand Up @@ -101,6 +104,7 @@ class Reflector {
std::shared_ptr<fml::Mapping> reflection_header_;
std::shared_ptr<fml::Mapping> reflection_cc_;
std::shared_ptr<RuntimeStageData::Shader> runtime_stage_shader_;
std::shared_ptr<ShaderBundleData> shader_bundle_data_;
bool is_valid_ = false;

std::optional<nlohmann::json> GenerateTemplateArguments() const;
Expand All @@ -111,6 +115,8 @@ class Reflector {

std::shared_ptr<RuntimeStageData::Shader> GenerateRuntimeStageData() const;

std::shared_ptr<ShaderBundleData> GenerateShaderBundleData() const;

std::shared_ptr<fml::Mapping> InflateTemplate(std::string_view tmpl) const;

std::optional<nlohmann::json::object_t> ReflectResource(
Expand Down
135 changes: 74 additions & 61 deletions impeller/compiler/runtime_stage_data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -293,79 +293,92 @@ std::shared_ptr<fml::Mapping> RuntimeStageData::CreateJsonMapping() const {
json_string->size(), [json_string](auto, auto) {});
}

std::unique_ptr<fb::RuntimeStagesT> RuntimeStageData::CreateFlatbuffer() const {
// The high level object API is used here for writing to the buffer. This is
// just a convenience.
auto runtime_stages = std::make_unique<fb::RuntimeStagesT>();
std::unique_ptr<fb::RuntimeStageT> RuntimeStageData::CreateStageFlatbuffer(
impeller::RuntimeStageBackend backend) const {
auto kvp = data_.find(backend);
if (kvp == data_.end()) {
return nullptr;
}

for (const auto& kvp : data_) {
auto runtime_stage = std::make_unique<fb::RuntimeStageT>();
runtime_stage->entrypoint = kvp.second->entrypoint;
const auto stage = ToStage(kvp.second->stage);
if (!stage.has_value()) {
VALIDATION_LOG << "Invalid runtime stage.";
auto runtime_stage = std::make_unique<fb::RuntimeStageT>();
runtime_stage->entrypoint = kvp->second->entrypoint;
const auto stage = ToStage(kvp->second->stage);
if (!stage.has_value()) {
VALIDATION_LOG << "Invalid runtime stage.";
return nullptr;
}
runtime_stage->stage = stage.value();
if (!kvp->second->shader) {
VALIDATION_LOG << "No shader specified for runtime stage.";
return nullptr;
}
if (kvp->second->shader->GetSize() > 0u) {
runtime_stage->shader = {
kvp->second->shader->GetMapping(),
kvp->second->shader->GetMapping() + kvp->second->shader->GetSize()};
}
for (const auto& uniform : kvp->second->uniforms) {
auto desc = std::make_unique<fb::UniformDescriptionT>();

desc->name = uniform.name;
if (desc->name.empty()) {
VALIDATION_LOG << "Uniform name cannot be empty.";
return nullptr;
}
runtime_stage->stage = stage.value();
if (!kvp.second->shader) {
VALIDATION_LOG << "No shader specified for runtime stage.";
desc->location = uniform.location;
desc->rows = uniform.rows;
desc->columns = uniform.columns;
auto uniform_type = ToUniformType(uniform.type);
if (!uniform_type.has_value()) {
VALIDATION_LOG << "Invalid uniform type for runtime stage.";
return nullptr;
}
if (kvp.second->shader->GetSize() > 0u) {
runtime_stage->shader = {
kvp.second->shader->GetMapping(),
kvp.second->shader->GetMapping() + kvp.second->shader->GetSize()};
desc->type = uniform_type.value();
desc->bit_width = uniform.bit_width;
if (uniform.array_elements.has_value()) {
desc->array_elements = uniform.array_elements.value();
}
for (const auto& uniform : kvp.second->uniforms) {
auto desc = std::make_unique<fb::UniformDescriptionT>();

desc->name = uniform.name;
if (desc->name.empty()) {
VALIDATION_LOG << "Uniform name cannot be empty.";
return nullptr;
}
desc->location = uniform.location;
desc->rows = uniform.rows;
desc->columns = uniform.columns;
auto uniform_type = ToUniformType(uniform.type);
if (!uniform_type.has_value()) {
VALIDATION_LOG << "Invalid uniform type for runtime stage.";
return nullptr;
}
desc->type = uniform_type.value();
desc->bit_width = uniform.bit_width;
if (uniform.array_elements.has_value()) {
desc->array_elements = uniform.array_elements.value();
}
runtime_stage->uniforms.emplace_back(std::move(desc));
}

for (const auto& input : kvp->second->inputs) {
auto desc = std::make_unique<fb::StageInputT>();

desc->name = input.name;

runtime_stage->uniforms.emplace_back(std::move(desc));
if (desc->name.empty()) {
VALIDATION_LOG << "Stage input name cannot be empty.";
return nullptr;
}
desc->location = input.location;
desc->set = input.set;
desc->binding = input.binding;
auto input_type = ToInputType(input.type);
if (!input_type.has_value()) {
VALIDATION_LOG << "Invalid uniform type for runtime stage.";
return nullptr;
}
desc->type = input_type.value();
desc->bit_width = input.bit_width;
desc->vec_size = input.vec_size;
desc->columns = input.columns;
desc->offset = input.offset;

for (const auto& input : kvp.second->inputs) {
auto desc = std::make_unique<fb::StageInputT>();
runtime_stage->inputs.emplace_back(std::move(desc));
}

desc->name = input.name;
return runtime_stage;
}

if (desc->name.empty()) {
VALIDATION_LOG << "Stage input name cannot be empty.";
return nullptr;
}
desc->location = input.location;
desc->set = input.set;
desc->binding = input.binding;
auto input_type = ToInputType(input.type);
if (!input_type.has_value()) {
VALIDATION_LOG << "Invalid uniform type for runtime stage.";
return nullptr;
}
desc->type = input_type.value();
desc->bit_width = input.bit_width;
desc->vec_size = input.vec_size;
desc->columns = input.columns;
desc->offset = input.offset;
std::unique_ptr<fb::RuntimeStagesT>
RuntimeStageData::CreateMultiStageFlatbuffer() const {
// The high level object API is used here for writing to the buffer. This is
// just a convenience.
auto runtime_stages = std::make_unique<fb::RuntimeStagesT>();

runtime_stage->inputs.emplace_back(std::move(desc));
}
for (const auto& kvp : data_) {
auto runtime_stage = CreateStageFlatbuffer(kvp.first);
switch (kvp.first) {
case RuntimeStageBackend::kSkSL:
runtime_stages->sksl = std::move(runtime_stage);
Expand All @@ -385,7 +398,7 @@ std::unique_ptr<fb::RuntimeStagesT> RuntimeStageData::CreateFlatbuffer() const {
}

std::shared_ptr<fml::Mapping> RuntimeStageData::CreateMapping() const {
auto runtime_stages = CreateFlatbuffer();
auto runtime_stages = CreateMultiStageFlatbuffer();
if (!runtime_stages) {
return nullptr;
}
Expand Down
28 changes: 4 additions & 24 deletions impeller/compiler/runtime_stage_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,6 @@
namespace impeller {
namespace compiler {

struct UniformDescription {
std::string name;
size_t location = 0u;
spirv_cross::SPIRType::BaseType type = spirv_cross::SPIRType::BaseType::Float;
size_t rows = 0u;
size_t columns = 0u;
size_t bit_width = 0u;
std::optional<size_t> array_elements = std::nullopt;
};

struct InputDescription {
std::string name;
size_t location;
size_t set;
size_t binding;
spirv_cross::SPIRType::BaseType type =
spirv_cross::SPIRType::BaseType::Unknown;
size_t bit_width;
size_t vec_size;
size_t columns;
size_t offset;
};

class RuntimeStageData {
public:
struct Shader {
Expand All @@ -63,7 +40,10 @@ class RuntimeStageData {

void AddShader(const std::shared_ptr<Shader>& data);

std::unique_ptr<fb::RuntimeStagesT> CreateFlatbuffer() const;
std::unique_ptr<fb::RuntimeStageT> CreateStageFlatbuffer(
impeller::RuntimeStageBackend backend) const;

std::unique_ptr<fb::RuntimeStagesT> CreateMultiStageFlatbuffer() const;

std::shared_ptr<fml::Mapping> CreateJsonMapping() const;

Expand Down
Loading

0 comments on commit 00ff332

Please sign in to comment.