| // 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. |
| |
| #ifndef FLUTTER_IMPELLER_COMPILER_REFLECTOR_H_ |
| #define FLUTTER_IMPELLER_COMPILER_REFLECTOR_H_ |
| |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| |
| #include "flutter/fml/macros.h" |
| #include "flutter/fml/mapping.h" |
| #include "fml/logging.h" |
| #include "impeller/base/strings.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_common.hpp" |
| #include "spirv_msl.hpp" |
| #include "spirv_parser.hpp" |
| |
| namespace impeller { |
| namespace compiler { |
| |
| struct StructMember { |
| // Runtime stages on Vulkan use this information to validate that a struct |
| // only contains floats and encode where padding gets inserted. |
| enum class UnderlyingType { |
| kPadding, |
| kFloat, |
| kOther, |
| }; |
| |
| std::string type; |
| spirv_cross::SPIRType::BaseType base_type; |
| std::string name; |
| size_t offset = 0u; |
| size_t size = 0u; |
| size_t byte_length = 0u; |
| std::optional<size_t> array_elements = std::nullopt; |
| size_t element_padding = 0u; |
| UnderlyingType underlying_type = UnderlyingType::kOther; |
| |
| static std::string BaseTypeToString(spirv_cross::SPIRType::BaseType type) { |
| using Type = spirv_cross::SPIRType::BaseType; |
| switch (type) { |
| case Type::Void: |
| return "ShaderType::kVoid"; |
| case Type::Boolean: |
| return "ShaderType::kBoolean"; |
| case Type::SByte: |
| return "ShaderType::kSignedByte"; |
| case Type::UByte: |
| return "ShaderType::kUnsignedByte"; |
| case Type::Short: |
| return "ShaderType::kSignedShort"; |
| case Type::UShort: |
| return "ShaderType::kUnsignedShort"; |
| case Type::Int: |
| return "ShaderType::kSignedInt"; |
| case Type::UInt: |
| return "ShaderType::kUnsignedInt"; |
| case Type::Int64: |
| return "ShaderType::kSignedInt64"; |
| case Type::UInt64: |
| return "ShaderType::kUnsignedInt64"; |
| case Type::AtomicCounter: |
| return "ShaderType::kAtomicCounter"; |
| case Type::Half: |
| return "ShaderType::kHalfFloat"; |
| case Type::Float: |
| return "ShaderType::kFloat"; |
| case Type::Double: |
| return "ShaderType::kDouble"; |
| case Type::Struct: |
| return "ShaderType::kStruct"; |
| case Type::Image: |
| return "ShaderType::kImage"; |
| case Type::SampledImage: |
| return "ShaderType::kSampledImage"; |
| case Type::Sampler: |
| return "ShaderType::kSampler"; |
| default: |
| return "ShaderType::kUnknown"; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| static UnderlyingType DetermineUnderlyingType( |
| spirv_cross::SPIRType::BaseType type) { |
| switch (type) { |
| case spirv_cross::SPIRType::Void: |
| return UnderlyingType::kPadding; |
| case spirv_cross::SPIRType::Float: |
| return UnderlyingType::kFloat; |
| case spirv_cross::SPIRType::Unknown: |
| case spirv_cross::SPIRType::Boolean: |
| case spirv_cross::SPIRType::SByte: |
| case spirv_cross::SPIRType::UByte: |
| case spirv_cross::SPIRType::Short: |
| case spirv_cross::SPIRType::UShort: |
| case spirv_cross::SPIRType::Int: |
| case spirv_cross::SPIRType::UInt: |
| case spirv_cross::SPIRType::Int64: |
| case spirv_cross::SPIRType::UInt64: |
| case spirv_cross::SPIRType::AtomicCounter: |
| case spirv_cross::SPIRType::Half: |
| case spirv_cross::SPIRType::Double: |
| case spirv_cross::SPIRType::Struct: |
| case spirv_cross::SPIRType::Image: |
| case spirv_cross::SPIRType::SampledImage: |
| case spirv_cross::SPIRType::Sampler: |
| case spirv_cross::SPIRType::AccelerationStructure: |
| case spirv_cross::SPIRType::RayQuery: |
| case spirv_cross::SPIRType::ControlPointArray: |
| case spirv_cross::SPIRType::Interpolant: |
| case spirv_cross::SPIRType::Char: |
| default: |
| return UnderlyingType::kOther; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| StructMember(std::string p_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, |
| UnderlyingType p_underlying_type = UnderlyingType::kOther) |
| : type(std::move(p_type)), |
| base_type(p_base_type), |
| name(std::move(p_name)), |
| offset(p_offset), |
| size(p_size), |
| byte_length(p_byte_length), |
| array_elements(p_array_elements), |
| element_padding(p_element_padding), |
| underlying_type(DetermineUnderlyingType(p_base_type)) {} |
| }; |
| |
| class Reflector { |
| public: |
| struct Options { |
| TargetPlatform target_platform = TargetPlatform::kUnknown; |
| std::string entry_point_name; |
| std::string shader_name; |
| std::string header_file_name; |
| }; |
| |
| Reflector(Options options, |
| const std::shared_ptr<const spirv_cross::ParsedIR>& ir, |
| const std::shared_ptr<fml::Mapping>& shader_data, |
| const CompilerBackend& compiler); |
| |
| ~Reflector(); |
| |
| bool IsValid() const; |
| |
| std::shared_ptr<fml::Mapping> GetReflectionJSON() const; |
| |
| std::shared_ptr<fml::Mapping> GetReflectionHeader() const; |
| |
| std::shared_ptr<fml::Mapping> GetReflectionCC() const; |
| |
| std::shared_ptr<RuntimeStageData::Shader> GetRuntimeStageShaderData() const; |
| |
| std::shared_ptr<ShaderBundleData> GetShaderBundleData() const; |
| |
| private: |
| struct StructDefinition { |
| std::string name; |
| size_t byte_length = 0u; |
| std::vector<StructMember> members; |
| }; |
| |
| struct BindPrototypeArgument { |
| std::string type_name; |
| std::string argument_name; |
| }; |
| |
| struct BindPrototype { |
| std::string name; |
| std::string return_type; |
| std::string docstring; |
| std::string descriptor_type = ""; |
| std::vector<BindPrototypeArgument> args; |
| }; |
| |
| const Options options_; |
| const std::shared_ptr<const spirv_cross::ParsedIR> ir_; |
| const std::shared_ptr<fml::Mapping> shader_data_; |
| const CompilerBackend compiler_; |
| std::unique_ptr<const nlohmann::json> template_arguments_; |
| 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; |
| |
| std::shared_ptr<fml::Mapping> GenerateReflectionHeader() const; |
| |
| std::shared_ptr<fml::Mapping> GenerateReflectionCC() const; |
| |
| 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( |
| const spirv_cross::Resource& resource, |
| std::optional<size_t> offset) const; |
| |
| std::optional<nlohmann::json::array_t> ReflectResources( |
| const spirv_cross::SmallVector<spirv_cross::Resource>& resources, |
| bool compute_offsets = false) const; |
| |
| std::vector<size_t> ComputeOffsets( |
| const spirv_cross::SmallVector<spirv_cross::Resource>& resources) const; |
| |
| std::optional<size_t> GetOffset(spirv_cross::ID id, |
| const std::vector<size_t>& offsets) const; |
| |
| std::optional<nlohmann::json::object_t> ReflectType( |
| const spirv_cross::TypeID& type_id) const; |
| |
| nlohmann::json::object_t EmitStructDefinition( |
| std::optional<Reflector::StructDefinition> struc) const; |
| |
| std::optional<StructDefinition> ReflectStructDefinition( |
| const spirv_cross::TypeID& type_id) const; |
| |
| std::vector<BindPrototype> ReflectBindPrototypes( |
| const spirv_cross::ShaderResources& resources, |
| spv::ExecutionModel execution_model) const; |
| |
| nlohmann::json::array_t EmitBindPrototypes( |
| const spirv_cross::ShaderResources& resources, |
| spv::ExecutionModel execution_model) const; |
| |
| std::optional<StructDefinition> ReflectPerVertexStructDefinition( |
| const spirv_cross::SmallVector<spirv_cross::Resource>& stage_inputs) |
| const; |
| |
| std::optional<std::string> GetMemberNameAtIndexIfExists( |
| const spirv_cross::SPIRType& parent_type, |
| size_t index) const; |
| |
| std::string GetMemberNameAtIndex(const spirv_cross::SPIRType& parent_type, |
| size_t index, |
| std::string suffix = "") const; |
| |
| std::vector<StructMember> ReadStructMembers( |
| const spirv_cross::TypeID& type_id) const; |
| |
| std::optional<uint32_t> GetArrayElements( |
| const spirv_cross::SPIRType& type) const; |
| |
| template <uint32_t Size> |
| uint32_t GetArrayStride(const spirv_cross::SPIRType& struct_type, |
| const spirv_cross::SPIRType& member_type, |
| uint32_t index) const { |
| auto element_count = GetArrayElements(member_type).value_or(1); |
| if (element_count <= 1) { |
| return Size; |
| } |
| return compiler_->type_struct_member_array_stride(struct_type, index); |
| }; |
| |
| Reflector(const Reflector&) = delete; |
| |
| Reflector& operator=(const Reflector&) = delete; |
| }; |
| |
| } // namespace compiler |
| } // namespace impeller |
| |
| #endif // FLUTTER_IMPELLER_COMPILER_REFLECTOR_H_ |