Flutter Impeller
reflector.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_IMPELLER_COMPILER_REFLECTOR_H_
6 #define FLUTTER_IMPELLER_COMPILER_REFLECTOR_H_
7 
8 #include <cstdint>
9 #include <memory>
10 #include <optional>
11 
12 #include "flutter/fml/mapping.h"
13 #include "fml/logging.h"
17 #include "inja/inja.hpp"
18 #include "spirv_common.hpp"
19 #include "spirv_msl.hpp"
20 #include "spirv_parser.hpp"
21 
22 namespace impeller {
23 namespace compiler {
24 
25 struct StructMember {
26  // Runtime stages on Vulkan use this information to validate that a struct
27  // only contains floats and encode where padding gets inserted.
28  enum class UnderlyingType {
29  kPadding,
30  kFloat,
31  kOther,
32  };
33 
34  std::string type;
35  spirv_cross::SPIRType::BaseType base_type;
36  std::string name;
37  size_t offset = 0u;
38  size_t size = 0u;
39  size_t byte_length = 0u;
40  std::optional<size_t> array_elements = std::nullopt;
41  size_t element_padding = 0u;
43 
44  static std::string BaseTypeToString(spirv_cross::SPIRType::BaseType type) {
45  using Type = spirv_cross::SPIRType::BaseType;
46  switch (type) {
47  case Type::Void:
48  return "ShaderType::kVoid";
49  case Type::Boolean:
50  return "ShaderType::kBoolean";
51  case Type::SByte:
52  return "ShaderType::kSignedByte";
53  case Type::UByte:
54  return "ShaderType::kUnsignedByte";
55  case Type::Short:
56  return "ShaderType::kSignedShort";
57  case Type::UShort:
58  return "ShaderType::kUnsignedShort";
59  case Type::Int:
60  return "ShaderType::kSignedInt";
61  case Type::UInt:
62  return "ShaderType::kUnsignedInt";
63  case Type::Int64:
64  return "ShaderType::kSignedInt64";
65  case Type::UInt64:
66  return "ShaderType::kUnsignedInt64";
67  case Type::AtomicCounter:
68  return "ShaderType::kAtomicCounter";
69  case Type::Half:
70  return "ShaderType::kHalfFloat";
71  case Type::Float:
72  return "ShaderType::kFloat";
73  case Type::Double:
74  return "ShaderType::kDouble";
75  case Type::Struct:
76  return "ShaderType::kStruct";
77  case Type::Image:
78  return "ShaderType::kImage";
79  case Type::SampledImage:
80  return "ShaderType::kSampledImage";
81  case Type::Sampler:
82  return "ShaderType::kSampler";
83  default:
84  return "ShaderType::kUnknown";
85  }
86  FML_UNREACHABLE();
87  }
88 
90  spirv_cross::SPIRType::BaseType type) {
91  switch (type) {
92  case spirv_cross::SPIRType::Void:
94  case spirv_cross::SPIRType::Float:
96  case spirv_cross::SPIRType::Unknown:
97  case spirv_cross::SPIRType::Boolean:
98  case spirv_cross::SPIRType::SByte:
99  case spirv_cross::SPIRType::UByte:
100  case spirv_cross::SPIRType::Short:
101  case spirv_cross::SPIRType::UShort:
102  case spirv_cross::SPIRType::Int:
103  case spirv_cross::SPIRType::UInt:
104  case spirv_cross::SPIRType::Int64:
105  case spirv_cross::SPIRType::UInt64:
106  case spirv_cross::SPIRType::AtomicCounter:
107  case spirv_cross::SPIRType::Half:
108  case spirv_cross::SPIRType::Double:
109  case spirv_cross::SPIRType::Struct:
110  case spirv_cross::SPIRType::Image:
111  case spirv_cross::SPIRType::SampledImage:
112  case spirv_cross::SPIRType::Sampler:
113  case spirv_cross::SPIRType::AccelerationStructure:
114  case spirv_cross::SPIRType::RayQuery:
115  case spirv_cross::SPIRType::ControlPointArray:
116  case spirv_cross::SPIRType::Interpolant:
117  case spirv_cross::SPIRType::Char:
118  default:
119  return UnderlyingType::kOther;
120  }
121  FML_UNREACHABLE();
122  }
123 
124  /// @brief Constructs a new StructMember.
125  ///
126  /// @param p_type The string type name (e.g. "float", "Point", "Matrix").
127  /// @param p_base_type The SPIR-V base type.
128  /// @param p_name The name of the struct member.
129  /// @param p_offset The offset in bytes from the start of the parent struct.
130  /// @param p_size The size in bytes of a single element of this type
131  /// (ignoring padding/stride).
132  /// @param p_byte_length The total size in bytes this member occupies in
133  /// the struct, including all array elements and padding.
134  /// @param p_array_elements The number of array elements. For matrices
135  /// treated as arrays of columns, this includes the column count.
136  /// @param p_element_padding The padding in bytes after each array
137  /// element to satisfy alignment requirements (stride - size).
138  /// @param p_underlying_type The underlying type category, used for
139  /// runtime validation.
140  StructMember(std::string p_type,
141  spirv_cross::SPIRType::BaseType p_base_type,
142  std::string p_name,
143  size_t p_offset,
144  size_t p_size,
145  size_t p_byte_length,
146  std::optional<size_t> p_array_elements,
147  size_t p_element_padding,
148  UnderlyingType p_underlying_type = UnderlyingType::kOther)
149  : type(std::move(p_type)),
150  base_type(p_base_type),
151  name(std::move(p_name)),
152  offset(p_offset),
153  size(p_size),
154  byte_length(p_byte_length),
155  array_elements(p_array_elements),
156  element_padding(p_element_padding),
158 };
159 
160 class Reflector {
161  public:
162  struct Options {
164  std::string entry_point_name;
165  std::string shader_name;
166  std::string header_file_name;
167  };
168 
169  Reflector(Options options,
170  const std::shared_ptr<const spirv_cross::ParsedIR>& ir,
171  const std::shared_ptr<fml::Mapping>& shader_data,
172  const CompilerBackend& compiler);
173 
175 
176  bool IsValid() const;
177 
178  std::shared_ptr<fml::Mapping> GetReflectionJSON() const;
179 
180  std::shared_ptr<fml::Mapping> GetReflectionHeader() const;
181 
182  std::shared_ptr<fml::Mapping> GetReflectionCC() const;
183 
184  std::shared_ptr<RuntimeStageData::Shader> GetRuntimeStageShaderData() const;
185 
186  std::shared_ptr<ShaderBundleData> GetShaderBundleData() const;
187 
188  private:
189  struct StructDefinition {
190  std::string name;
191  size_t byte_length = 0u;
192  std::vector<StructMember> members;
193  };
194 
195  struct BindPrototypeArgument {
196  std::string type_name;
197  std::string argument_name;
198  };
199 
200  struct BindPrototype {
201  std::string name;
202  std::string return_type;
203  std::string docstring;
204  std::string descriptor_type = "";
205  std::vector<BindPrototypeArgument> args;
206  };
207 
208  const Options options_;
209  const std::shared_ptr<const spirv_cross::ParsedIR> ir_;
210  const std::shared_ptr<fml::Mapping> shader_data_;
211  const CompilerBackend compiler_;
212  std::unique_ptr<const nlohmann::json> template_arguments_;
213  std::shared_ptr<fml::Mapping> reflection_header_;
214  std::shared_ptr<fml::Mapping> reflection_cc_;
215  std::shared_ptr<RuntimeStageData::Shader> runtime_stage_shader_;
216  std::shared_ptr<ShaderBundleData> shader_bundle_data_;
217  bool is_valid_ = false;
218 
219  std::optional<nlohmann::json> GenerateTemplateArguments() const;
220 
221  std::shared_ptr<fml::Mapping> GenerateReflectionHeader() const;
222 
223  std::shared_ptr<fml::Mapping> GenerateReflectionCC() const;
224 
225  std::shared_ptr<RuntimeStageData::Shader> GenerateRuntimeStageData() const;
226 
227  std::shared_ptr<ShaderBundleData> GenerateShaderBundleData() const;
228 
229  std::shared_ptr<fml::Mapping> InflateTemplate(std::string_view tmpl) const;
230 
231  std::optional<nlohmann::json::object_t> ReflectResource(
232  const spirv_cross::Resource& resource,
233  std::optional<size_t> offset) const;
234 
235  std::optional<nlohmann::json::array_t> ReflectResources(
236  const spirv_cross::SmallVector<spirv_cross::Resource>& resources,
237  bool compute_offsets = false) const;
238 
239  std::vector<size_t> ComputeOffsets(
240  const spirv_cross::SmallVector<spirv_cross::Resource>& resources) const;
241 
242  std::optional<size_t> GetOffset(spirv_cross::ID id,
243  const std::vector<size_t>& offsets) const;
244 
245  std::optional<nlohmann::json::object_t> ReflectType(
246  const spirv_cross::TypeID& type_id) const;
247 
248  nlohmann::json::object_t EmitStructDefinition(
249  std::optional<Reflector::StructDefinition> struc) const;
250 
251  std::optional<StructDefinition> ReflectStructDefinition(
252  const spirv_cross::TypeID& type_id) const;
253 
254  std::vector<BindPrototype> ReflectBindPrototypes(
255  const spirv_cross::ShaderResources& resources,
256  spv::ExecutionModel execution_model) const;
257 
258  nlohmann::json::array_t EmitBindPrototypes(
259  const spirv_cross::ShaderResources& resources,
260  spv::ExecutionModel execution_model) const;
261 
262  std::optional<StructDefinition> ReflectPerVertexStructDefinition(
263  const spirv_cross::SmallVector<spirv_cross::Resource>& stage_inputs)
264  const;
265 
266  std::optional<std::string> GetMemberNameAtIndexIfExists(
267  const spirv_cross::SPIRType& parent_type,
268  size_t index) const;
269 
270  std::string GetMemberNameAtIndex(const spirv_cross::SPIRType& parent_type,
271  size_t index,
272  std::string suffix = "") const;
273 
274  std::vector<StructMember> ReadStructMembers(
275  const spirv_cross::TypeID& type_id) const;
276 
277  std::optional<uint32_t> GetArrayElements(
278  const spirv_cross::SPIRType& type) const;
279 
280  template <uint32_t Size>
281  uint32_t GetArrayStride(const spirv_cross::SPIRType& struct_type,
282  const spirv_cross::SPIRType& member_type,
283  uint32_t index) const {
284  auto element_count = GetArrayElements(member_type).value_or(1);
285  if (element_count <= 1) {
286  return Size;
287  }
288  return compiler_->type_struct_member_array_stride(struct_type, index);
289  };
290 
291  Reflector(const Reflector&) = delete;
292 
293  Reflector& operator=(const Reflector&) = delete;
294 };
295 
296 } // namespace compiler
297 } // namespace impeller
298 
299 #endif // FLUTTER_IMPELLER_COMPILER_REFLECTOR_H_
GLenum type
Reflector(Options options, const std::shared_ptr< const spirv_cross::ParsedIR > &ir, const std::shared_ptr< fml::Mapping > &shader_data, const CompilerBackend &compiler)
Definition: reflector.cc:64
std::shared_ptr< fml::Mapping > GetReflectionJSON() const
Definition: reflector.cc:110
std::shared_ptr< fml::Mapping > GetReflectionCC() const
Definition: reflector.cc:127
std::shared_ptr< RuntimeStageData::Shader > GetRuntimeStageShaderData() const
Definition: reflector.cc:131
std::shared_ptr< ShaderBundleData > GetShaderBundleData() const
Definition: reflector.cc:136
std::shared_ptr< fml::Mapping > GetReflectionHeader() const
Definition: reflector.cc:123
std::string type_name
TSize< Scalar > Size
Definition: size.h:159
Definition: comparable.h:95
UnderlyingType underlying_type
Definition: reflector.h:42
static std::string BaseTypeToString(spirv_cross::SPIRType::BaseType type)
Definition: reflector.h:44
std::optional< size_t > array_elements
Definition: reflector.h:40
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)
Constructs a new StructMember.
Definition: reflector.h:140
static UnderlyingType DetermineUnderlyingType(spirv_cross::SPIRType::BaseType type)
Definition: reflector.h:89
spirv_cross::SPIRType::BaseType base_type
Definition: reflector.h:35