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;
42  std::optional<std::string> float_type = std::nullopt;
43  // Component count of a single column. For non-matrix types this is the
44  // vector length; for matrices this is the row count. Combined with
45  // `columns`, this disambiguates types that share the same `size`, e.g.
46  // vec4 and mat2.
47  size_t vec_size = 0u;
48  // The number of columns. 1 for scalars and vectors; N for an NxN matrix.
49  size_t columns = 0u;
51 
52  static std::string BaseTypeToString(spirv_cross::SPIRType::BaseType type) {
53  using Type = spirv_cross::SPIRType::BaseType;
54  switch (type) {
55  case Type::Void:
56  return "ShaderType::kVoid";
57  case Type::Boolean:
58  return "ShaderType::kBoolean";
59  case Type::SByte:
60  return "ShaderType::kSignedByte";
61  case Type::UByte:
62  return "ShaderType::kUnsignedByte";
63  case Type::Short:
64  return "ShaderType::kSignedShort";
65  case Type::UShort:
66  return "ShaderType::kUnsignedShort";
67  case Type::Int:
68  return "ShaderType::kSignedInt";
69  case Type::UInt:
70  return "ShaderType::kUnsignedInt";
71  case Type::Int64:
72  return "ShaderType::kSignedInt64";
73  case Type::UInt64:
74  return "ShaderType::kUnsignedInt64";
75  case Type::AtomicCounter:
76  return "ShaderType::kAtomicCounter";
77  case Type::Half:
78  return "ShaderType::kHalfFloat";
79  case Type::Float:
80  return "ShaderType::kFloat";
81  case Type::Double:
82  return "ShaderType::kDouble";
83  case Type::Struct:
84  return "ShaderType::kStruct";
85  case Type::Image:
86  return "ShaderType::kImage";
87  case Type::SampledImage:
88  return "ShaderType::kSampledImage";
89  case Type::Sampler:
90  return "ShaderType::kSampler";
91  default:
92  return "ShaderType::kUnknown";
93  }
94  FML_UNREACHABLE();
95  }
96 
98  spirv_cross::SPIRType::BaseType type) {
99  switch (type) {
100  case spirv_cross::SPIRType::Void:
102  case spirv_cross::SPIRType::Float:
103  return UnderlyingType::kFloat;
104  case spirv_cross::SPIRType::Unknown:
105  case spirv_cross::SPIRType::Boolean:
106  case spirv_cross::SPIRType::SByte:
107  case spirv_cross::SPIRType::UByte:
108  case spirv_cross::SPIRType::Short:
109  case spirv_cross::SPIRType::UShort:
110  case spirv_cross::SPIRType::Int:
111  case spirv_cross::SPIRType::UInt:
112  case spirv_cross::SPIRType::Int64:
113  case spirv_cross::SPIRType::UInt64:
114  case spirv_cross::SPIRType::AtomicCounter:
115  case spirv_cross::SPIRType::Half:
116  case spirv_cross::SPIRType::Double:
117  case spirv_cross::SPIRType::Struct:
118  case spirv_cross::SPIRType::Image:
119  case spirv_cross::SPIRType::SampledImage:
120  case spirv_cross::SPIRType::Sampler:
121  case spirv_cross::SPIRType::AccelerationStructure:
122  case spirv_cross::SPIRType::RayQuery:
123  case spirv_cross::SPIRType::ControlPointArray:
124  case spirv_cross::SPIRType::Interpolant:
125  case spirv_cross::SPIRType::Char:
126  default:
127  return UnderlyingType::kOther;
128  }
129  FML_UNREACHABLE();
130  }
131 
132  /// @brief Constructs a new StructMember.
133  ///
134  /// @param p_type The string type name (e.g. "float", "Point", "Matrix").
135  /// @param p_base_type The SPIR-V base type.
136  /// @param p_name The name of the struct member.
137  /// @param p_offset The offset in bytes from the start of the parent struct.
138  /// @param p_size The size in bytes of a single element of this type
139  /// (ignoring padding/stride).
140  /// @param p_byte_length The total size in bytes this member occupies in
141  /// the struct, including all array elements and padding.
142  /// @param p_array_elements The number of array elements. For matrices
143  /// treated as arrays of columns, this includes the column count.
144  /// @param p_element_padding The padding in bytes after each array
145  /// element to satisfy alignment requirements (stride - size).
146  /// @param p_float_type The float type of the member.
147  /// @param p_vec_size The component count of a single column (vector
148  /// length for non-matrix types, row count for matrices). 0 if not
149  /// applicable.
150  /// @param p_columns The number of columns. 1 for scalars and vectors;
151  /// N for an NxN matrix. 0 if not applicable.
152  /// @param p_underlying_type The underlying type category, used for
153  /// runtime validation.
154  StructMember(std::string p_type,
155  spirv_cross::SPIRType::BaseType p_base_type,
156  std::string p_name,
157  size_t p_offset,
158  size_t p_size,
159  size_t p_byte_length,
160  std::optional<size_t> p_array_elements,
161  size_t p_element_padding,
162  std::optional<std::string> p_float_type = std::nullopt,
163  size_t p_vec_size = 0u,
164  size_t p_columns = 0u,
165  UnderlyingType p_underlying_type = UnderlyingType::kOther)
166  : type(std::move(p_type)),
167  base_type(p_base_type),
168  name(std::move(p_name)),
169  offset(p_offset),
170  size(p_size),
171  byte_length(p_byte_length),
172  array_elements(p_array_elements),
173  element_padding(p_element_padding),
174  float_type(std::move(p_float_type)),
175  vec_size(p_vec_size),
176  columns(p_columns),
178 };
179 
180 class Reflector {
181  public:
182  struct Options {
184  std::string entry_point_name;
185  std::string shader_name;
186  std::string header_file_name;
187  };
188 
189  Reflector(Options options,
190  const std::shared_ptr<const spirv_cross::ParsedIR>& ir,
191  const std::shared_ptr<fml::Mapping>& shader_data,
192  const CompilerBackend& compiler);
193 
195 
196  bool IsValid() const;
197 
198  std::shared_ptr<fml::Mapping> GetReflectionJSON() const;
199 
200  std::shared_ptr<fml::Mapping> GetReflectionHeader() const;
201 
202  std::shared_ptr<fml::Mapping> GetReflectionCC() const;
203 
204  std::shared_ptr<RuntimeStageData::Shader> GetRuntimeStageShaderData() const;
205 
206  std::shared_ptr<ShaderBundleData> GetShaderBundleData() const;
207 
208  private:
209  struct StructDefinition {
210  std::string name;
211  size_t byte_length = 0u;
212  std::vector<StructMember> members;
213  };
214 
215  struct BindPrototypeArgument {
216  std::string type_name;
217  std::string argument_name;
218  };
219 
220  struct BindPrototype {
221  std::string name;
222  std::string return_type;
223  std::string docstring;
224  std::string descriptor_type = "";
225  std::vector<BindPrototypeArgument> args;
226  };
227 
228  const Options options_;
229  const std::shared_ptr<const spirv_cross::ParsedIR> ir_;
230  const std::shared_ptr<fml::Mapping> shader_data_;
231  const CompilerBackend compiler_;
232  std::unique_ptr<const nlohmann::json> template_arguments_;
233  std::shared_ptr<fml::Mapping> reflection_header_;
234  std::shared_ptr<fml::Mapping> reflection_cc_;
235  std::shared_ptr<RuntimeStageData::Shader> runtime_stage_shader_;
236  std::shared_ptr<ShaderBundleData> shader_bundle_data_;
237  bool is_valid_ = false;
238 
239  std::optional<nlohmann::json> GenerateTemplateArguments() const;
240 
241  std::shared_ptr<fml::Mapping> GenerateReflectionHeader() const;
242 
243  std::shared_ptr<fml::Mapping> GenerateReflectionCC() const;
244 
245  std::shared_ptr<RuntimeStageData::Shader> GenerateRuntimeStageData() const;
246 
247  std::shared_ptr<ShaderBundleData> GenerateShaderBundleData() const;
248 
249  std::shared_ptr<fml::Mapping> InflateTemplate(std::string_view tmpl) const;
250 
251  std::optional<nlohmann::json::object_t> ReflectResource(
252  const spirv_cross::Resource& resource,
253  std::optional<size_t> offset) const;
254 
255  std::optional<nlohmann::json::array_t> ReflectResources(
256  const spirv_cross::SmallVector<spirv_cross::Resource>& resources,
257  bool compute_offsets = false) const;
258 
259  std::vector<size_t> ComputeOffsets(
260  const spirv_cross::SmallVector<spirv_cross::Resource>& resources) const;
261 
262  std::optional<size_t> GetOffset(spirv_cross::ID id,
263  const std::vector<size_t>& offsets) const;
264 
265  std::optional<nlohmann::json::object_t> ReflectType(
266  const spirv_cross::TypeID& type_id) const;
267 
268  nlohmann::json::object_t EmitStructDefinition(
269  std::optional<Reflector::StructDefinition> struc) const;
270 
271  std::optional<StructDefinition> ReflectStructDefinition(
272  const spirv_cross::TypeID& type_id) const;
273 
274  std::vector<BindPrototype> ReflectBindPrototypes(
275  const spirv_cross::ShaderResources& resources,
276  spv::ExecutionModel execution_model) const;
277 
278  nlohmann::json::array_t EmitBindPrototypes(
279  const spirv_cross::ShaderResources& resources,
280  spv::ExecutionModel execution_model) const;
281 
282  std::optional<StructDefinition> ReflectPerVertexStructDefinition(
283  const spirv_cross::SmallVector<spirv_cross::Resource>& stage_inputs)
284  const;
285 
286  std::optional<std::string> GetMemberNameAtIndexIfExists(
287  const spirv_cross::SPIRType& parent_type,
288  size_t index) const;
289 
290  std::string GetMemberNameAtIndex(const spirv_cross::SPIRType& parent_type,
291  size_t index,
292  std::string suffix = "") const;
293 
294  std::vector<StructMember> ReadStructMembers(
295  const spirv_cross::TypeID& type_id) const;
296 
297  std::optional<uint32_t> GetArrayElements(
298  const spirv_cross::SPIRType& type) const;
299 
300  template <uint32_t Size>
301  uint32_t GetArrayStride(const spirv_cross::SPIRType& struct_type,
302  const spirv_cross::SPIRType& member_type,
303  uint32_t index) const {
304  auto element_count = GetArrayElements(member_type).value_or(1);
305  if (element_count <= 1) {
306  return Size;
307  }
308  return compiler_->type_struct_member_array_stride(struct_type, index);
309  };
310 
311  Reflector(const Reflector&) = delete;
312 
313  Reflector& operator=(const Reflector&) = delete;
314 };
315 
316 } // namespace compiler
317 } // namespace impeller
318 
319 #endif // FLUTTER_IMPELLER_COMPILER_REFLECTOR_H_
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:93
UnderlyingType underlying_type
Definition: reflector.h:50
static std::string BaseTypeToString(spirv_cross::SPIRType::BaseType type)
Definition: reflector.h:52
std::optional< size_t > array_elements
Definition: reflector.h:40
std::optional< std::string > float_type
Definition: reflector.h:42
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, std::optional< std::string > p_float_type=std::nullopt, size_t p_vec_size=0u, size_t p_columns=0u, UnderlyingType p_underlying_type=UnderlyingType::kOther)
Constructs a new StructMember.
Definition: reflector.h:154
static UnderlyingType DetermineUnderlyingType(spirv_cross::SPIRType::BaseType type)
Definition: reflector.h:97
spirv_cross::SPIRType::BaseType base_type
Definition: reflector.h:35