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