Flutter Impeller
runtime_stage_data.cc
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 
6 
7 #include <array>
8 #include <cstdint>
9 #include <memory>
10 #include <optional>
11 
12 #include "fml/backtrace.h"
14 #include "inja/inja.hpp"
15 
17 #include "impeller/runtime_stage/runtime_stage_flatbuffers.h"
18 #include "runtime_stage_types_flatbuffers.h"
19 
20 namespace impeller {
21 namespace compiler {
22 
24 
26 
27 void RuntimeStageData::AddShader(const std::shared_ptr<Shader>& data) {
28  FML_DCHECK(data);
29  FML_DCHECK(data_.find(data->backend) == data_.end());
30  data_[data->backend] = data;
31 }
32 
33 static std::optional<fb::Stage> ToStage(spv::ExecutionModel stage) {
34  switch (stage) {
35  case spv::ExecutionModel::ExecutionModelVertex:
36  return fb::Stage::kVertex;
37  case spv::ExecutionModel::ExecutionModelFragment:
38  return fb::Stage::kFragment;
39  case spv::ExecutionModel::ExecutionModelGLCompute:
40  return fb::Stage::kCompute;
41  default:
42  return std::nullopt;
43  }
44  FML_UNREACHABLE();
45 }
46 
47 static std::optional<fb::Stage> ToJsonStage(spv::ExecutionModel stage) {
48  switch (stage) {
49  case spv::ExecutionModel::ExecutionModelVertex:
50  return fb::Stage::kVertex;
51  case spv::ExecutionModel::ExecutionModelFragment:
52  return fb::Stage::kFragment;
53  case spv::ExecutionModel::ExecutionModelGLCompute:
54  return fb::Stage::kCompute;
55  default:
56  return std::nullopt;
57  }
58  FML_UNREACHABLE();
59 }
60 
61 static std::optional<fb::UniformDataType> ToUniformType(
62  spirv_cross::SPIRType::BaseType type) {
63  switch (type) {
64  case spirv_cross::SPIRType::Float:
66  case spirv_cross::SPIRType::SampledImage:
68  case spirv_cross::SPIRType::Struct:
70  case spirv_cross::SPIRType::Boolean:
71  case spirv_cross::SPIRType::SByte:
72  case spirv_cross::SPIRType::UByte:
73  case spirv_cross::SPIRType::Short:
74  case spirv_cross::SPIRType::UShort:
75  case spirv_cross::SPIRType::Int:
76  case spirv_cross::SPIRType::UInt:
77  case spirv_cross::SPIRType::Int64:
78  case spirv_cross::SPIRType::UInt64:
79  case spirv_cross::SPIRType::Half:
80  case spirv_cross::SPIRType::Double:
81  case spirv_cross::SPIRType::AccelerationStructure:
82  case spirv_cross::SPIRType::AtomicCounter:
83  case spirv_cross::SPIRType::Char:
84  case spirv_cross::SPIRType::ControlPointArray:
85  case spirv_cross::SPIRType::Image:
86  case spirv_cross::SPIRType::Interpolant:
87  case spirv_cross::SPIRType::RayQuery:
88  case spirv_cross::SPIRType::Sampler:
89  case spirv_cross::SPIRType::Unknown:
90  case spirv_cross::SPIRType::Void:
91  return std::nullopt;
92  }
93  FML_UNREACHABLE();
94 }
95 static std::optional<fb::InputDataType> ToInputType(
96  spirv_cross::SPIRType::BaseType type) {
97  switch (type) {
98  case spirv_cross::SPIRType::Boolean:
99  return fb::InputDataType::kBoolean;
100  case spirv_cross::SPIRType::SByte:
101  return fb::InputDataType::kSignedByte;
102  case spirv_cross::SPIRType::UByte:
103  return fb::InputDataType::kUnsignedByte;
104  case spirv_cross::SPIRType::Short:
105  return fb::InputDataType::kSignedShort;
106  case spirv_cross::SPIRType::UShort:
107  return fb::InputDataType::kUnsignedShort;
108  case spirv_cross::SPIRType::Int:
109  return fb::InputDataType::kSignedInt;
110  case spirv_cross::SPIRType::UInt:
111  return fb::InputDataType::kUnsignedInt;
112  case spirv_cross::SPIRType::Int64:
113  return fb::InputDataType::kSignedInt64;
114  case spirv_cross::SPIRType::UInt64:
115  return fb::InputDataType::kUnsignedInt64;
116  case spirv_cross::SPIRType::Float:
118  case spirv_cross::SPIRType::Double:
119  return fb::InputDataType::kDouble;
120  case spirv_cross::SPIRType::Unknown:
121  case spirv_cross::SPIRType::Void:
122  case spirv_cross::SPIRType::Half:
123  case spirv_cross::SPIRType::AtomicCounter:
124  case spirv_cross::SPIRType::Struct:
125  case spirv_cross::SPIRType::Image:
126  case spirv_cross::SPIRType::SampledImage:
127  case spirv_cross::SPIRType::Sampler:
128  case spirv_cross::SPIRType::AccelerationStructure:
129  case spirv_cross::SPIRType::RayQuery:
130  case spirv_cross::SPIRType::ControlPointArray:
131  case spirv_cross::SPIRType::Interpolant:
132  case spirv_cross::SPIRType::Char:
133  return std::nullopt;
134  }
135  FML_UNREACHABLE();
136 }
137 
138 static std::optional<uint32_t> ToJsonType(
139  spirv_cross::SPIRType::BaseType type) {
140  switch (type) {
141  case spirv_cross::SPIRType::Boolean:
142  return 0; // fb::UniformDataType::kBoolean;
143  case spirv_cross::SPIRType::SByte:
144  return 1; // fb::UniformDataType::kSignedByte;
145  case spirv_cross::SPIRType::UByte:
146  return 2; // fb::UniformDataType::kUnsignedByte;
147  case spirv_cross::SPIRType::Short:
148  return 3; // fb::UniformDataType::kSignedShort;
149  case spirv_cross::SPIRType::UShort:
150  return 4; // fb::UniformDataType::kUnsignedShort;
151  case spirv_cross::SPIRType::Int:
152  return 5; // fb::UniformDataType::kSignedInt;
153  case spirv_cross::SPIRType::UInt:
154  return 6; // fb::UniformDataType::kUnsignedInt;
155  case spirv_cross::SPIRType::Int64:
156  return 7; // fb::UniformDataType::kSignedInt64;
157  case spirv_cross::SPIRType::UInt64:
158  return 8; // fb::UniformDataType::kUnsignedInt64;
159  case spirv_cross::SPIRType::Half:
160  return 9; // b::UniformDataType::kHalfFloat;
161  case spirv_cross::SPIRType::Float:
162  return 10; // fb::UniformDataType::kFloat;
163  case spirv_cross::SPIRType::Double:
164  return 11; // fb::UniformDataType::kDouble;
165  case spirv_cross::SPIRType::SampledImage:
166  return 12; // fb::UniformDataType::kSampledImage;
167  case spirv_cross::SPIRType::Struct:
168  return 13;
169  case spirv_cross::SPIRType::AccelerationStructure:
170  case spirv_cross::SPIRType::AtomicCounter:
171  case spirv_cross::SPIRType::Char:
172  case spirv_cross::SPIRType::ControlPointArray:
173  case spirv_cross::SPIRType::Image:
174  case spirv_cross::SPIRType::Interpolant:
175  case spirv_cross::SPIRType::RayQuery:
176  case spirv_cross::SPIRType::Sampler:
177  case spirv_cross::SPIRType::Unknown:
178  case spirv_cross::SPIRType::Void:
179  return std::nullopt;
180  }
181  FML_UNREACHABLE();
182 }
183 
184 static const char* kFormatVersionKey = "format_version";
185 static const char* kStageKey = "stage";
186 static const char* kTargetPlatformKey = "target_platform";
187 static const char* kEntrypointKey = "entrypoint";
188 static const char* kUniformsKey = "uniforms";
189 static const char* kShaderKey = "shader";
190 static const char* kUniformNameKey = "name";
191 static const char* kUniformLocationKey = "location";
192 static const char* kUniformTypeKey = "type";
193 static const char* kUniformRowsKey = "rows";
194 static const char* kUniformColumnsKey = "columns";
195 static const char* kUniformBitWidthKey = "bit_width";
196 static const char* kUniformArrayElementsKey = "array_elements";
197 static const char* kUniformStructElementsKey = "struct_elements";
198 
200  switch (backend) {
202  return "sksl";
204  return "metal";
206  return "opengles";
208  return "vulkan";
210  return "opengles3";
211  }
212 }
213 
214 std::shared_ptr<fml::Mapping> RuntimeStageData::CreateJsonMapping() const {
215  // Runtime Stage Data JSON format
216  // {
217  // "format_version": 1,
218  // "sksl": {
219  // "stage": 0,
220  // "entrypoint": "",
221  // "shader": "",
222  // "uniforms": [
223  // {
224  // "name": "..",
225  // "location": 0,
226  // "type": 0,
227  // "rows": 0,
228  // "columns": 0,
229  // "bit_width": 0,
230  // "array_elements": 0,
231  // }
232  // ]
233  // },
234  // "metal": ...
235  // },
236  nlohmann::json root;
237 
238  root[kFormatVersionKey] =
239  static_cast<uint32_t>(fb::RuntimeStagesFormatVersion::kVersion);
240  for (const auto& kvp : data_) {
241  nlohmann::json platform_object;
242 
243  const auto stage = ToJsonStage(kvp.second->stage);
244  if (!stage.has_value()) {
245  VALIDATION_LOG << "Invalid runtime stage.";
246  return nullptr;
247  }
248  platform_object[kStageKey] = static_cast<uint32_t>(stage.value());
249  platform_object[kEntrypointKey] = kvp.second->entrypoint;
250 
251  if (kvp.second->shader->GetSize() > 0u) {
252  std::string shader(
253  reinterpret_cast<const char*>(kvp.second->shader->GetMapping()),
254  kvp.second->shader->GetSize());
255  platform_object[kShaderKey] = shader.c_str();
256  }
257 
258  auto& uniforms = platform_object[kUniformsKey] = nlohmann::json::array_t{};
259  for (const auto& uniform : kvp.second->uniforms) {
260  nlohmann::json uniform_object;
261  uniform_object[kUniformNameKey] = uniform.name.c_str();
262  uniform_object[kUniformLocationKey] = uniform.location;
263  uniform_object[kUniformRowsKey] = uniform.rows;
264  uniform_object[kUniformColumnsKey] = uniform.columns;
265 
266  auto uniform_type = ToJsonType(uniform.type);
267  if (!uniform_type.has_value()) {
268  VALIDATION_LOG << "Invalid uniform type for runtime stage.";
269  return nullptr;
270  }
271 
272  uniform_object[kUniformTypeKey] = uniform_type.value();
273  uniform_object[kUniformBitWidthKey] = uniform.bit_width;
274  uniform_object[kUniformArrayElementsKey] =
275  uniform.array_elements.value_or(0);
276 
277  uniforms.push_back(uniform_object);
278  }
279 
280  root[RuntimeStageBackendToString(kvp.first)] = platform_object;
281  }
282 
283  auto json_string = std::make_shared<std::string>(root.dump(2u));
284 
285  return std::make_shared<fml::NonOwnedMapping>(
286  reinterpret_cast<const uint8_t*>(json_string->data()),
287  json_string->size(), [json_string](auto, auto) {});
288 }
289 
290 std::unique_ptr<fb::RuntimeStageT> RuntimeStageData::CreateStageFlatbuffer(
291  impeller::RuntimeStageBackend backend) const {
292  auto kvp = data_.find(backend);
293  if (kvp == data_.end()) {
294  return nullptr;
295  }
296 
297  auto runtime_stage = std::make_unique<fb::RuntimeStageT>();
298  runtime_stage->entrypoint = kvp->second->entrypoint;
299  const auto stage = ToStage(kvp->second->stage);
300  if (!stage.has_value()) {
301  VALIDATION_LOG << "Invalid runtime stage.";
302  return nullptr;
303  }
304  runtime_stage->stage = stage.value();
305  if (!kvp->second->shader) {
306  VALIDATION_LOG << "No shader specified for runtime stage.";
307  return nullptr;
308  }
309  if (kvp->second->shader->GetSize() > 0u) {
310  runtime_stage->shader = {
311  kvp->second->shader->GetMapping(),
312  kvp->second->shader->GetMapping() + kvp->second->shader->GetSize()};
313  }
314  for (const auto& uniform : kvp->second->uniforms) {
315  auto desc = std::make_unique<fb::UniformDescriptionT>();
316 
317  desc->name = uniform.name;
318  if (desc->name.empty()) {
319  VALIDATION_LOG << "Uniform name cannot be empty.";
320  return nullptr;
321  }
322  desc->location = uniform.location;
323  desc->rows = uniform.rows;
324  desc->columns = uniform.columns;
325  auto uniform_type = ToUniformType(uniform.type);
326  if (!uniform_type.has_value()) {
327  VALIDATION_LOG << "Invalid uniform type for runtime stage.";
328  return nullptr;
329  }
330  desc->type = uniform_type.value();
331  desc->bit_width = uniform.bit_width;
332  if (uniform.array_elements.has_value()) {
333  desc->array_elements = uniform.array_elements.value();
334  }
335 
336  for (const auto& byte_type : uniform.padding_layout) {
337  desc->padding_layout.push_back(static_cast<fb::PaddingType>(byte_type));
338  }
339  desc->struct_float_count = uniform.struct_float_count;
340 
341  for (const StructField& field : uniform.struct_fields) {
342  auto field_desc = std::make_unique<fb::StructFieldT>(fb::StructFieldT{});
343  field_desc->name = field.name;
344  field_desc->byte_size = field.byte_size;
345  desc->struct_fields.emplace_back(std::move(field_desc));
346  }
347 
348  runtime_stage->uniforms.emplace_back(std::move(desc));
349  }
350 
351  for (const auto& input : kvp->second->inputs) {
352  auto desc = std::make_unique<fb::StageInputT>();
353 
354  desc->name = input.name;
355 
356  if (desc->name.empty()) {
357  VALIDATION_LOG << "Stage input name cannot be empty.";
358  return nullptr;
359  }
360  desc->location = input.location;
361  desc->set = input.set;
362  desc->binding = input.binding;
363  auto input_type = ToInputType(input.type);
364  if (!input_type.has_value()) {
365  VALIDATION_LOG << "Invalid uniform type for runtime stage.";
366  return nullptr;
367  }
368  desc->type = input_type.value();
369  desc->bit_width = input.bit_width;
370  desc->vec_size = input.vec_size;
371  desc->columns = input.columns;
372  desc->offset = input.offset;
373 
374  runtime_stage->inputs.emplace_back(std::move(desc));
375  }
376 
377  return runtime_stage;
378 }
379 
380 std::unique_ptr<fb::RuntimeStagesT>
382  // The high level object API is used here for writing to the buffer. This is
383  // just a convenience.
384  auto runtime_stages = std::make_unique<fb::RuntimeStagesT>();
385  runtime_stages->format_version =
386  static_cast<uint32_t>(fb::RuntimeStagesFormatVersion::kVersion);
387 
388  for (const auto& kvp : data_) {
389  auto runtime_stage = CreateStageFlatbuffer(kvp.first);
390  switch (kvp.first) {
392  runtime_stages->sksl = std::move(runtime_stage);
393  break;
395  runtime_stages->metal = std::move(runtime_stage);
396  break;
398  runtime_stages->opengles = std::move(runtime_stage);
399  break;
401  runtime_stages->vulkan = std::move(runtime_stage);
402  break;
404  runtime_stages->opengles3 = std::move(runtime_stage);
405  break;
406  }
407  }
408  return runtime_stages;
409 }
410 
411 std::shared_ptr<fml::Mapping> RuntimeStageData::CreateMapping() const {
412  auto runtime_stages = CreateMultiStageFlatbuffer();
413  if (!runtime_stages) {
414  return nullptr;
415  }
416 
417  auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
418  builder->Finish(fb::RuntimeStages::Pack(*builder.get(), runtime_stages.get()),
419  fb::RuntimeStagesIdentifier());
420  return std::make_shared<fml::NonOwnedMapping>(builder->GetBufferPointer(),
421  builder->GetSize(),
422  [builder](auto, auto) {});
423 }
424 
425 } // namespace compiler
426 } // namespace impeller
GLenum type
std::unique_ptr< fb::RuntimeStagesT > CreateMultiStageFlatbuffer() const
std::shared_ptr< fml::Mapping > CreateMapping() const
std::unique_ptr< fb::RuntimeStageT > CreateStageFlatbuffer(impeller::RuntimeStageBackend backend) const
void AddShader(const std::shared_ptr< Shader > &data)
std::shared_ptr< fml::Mapping > CreateJsonMapping() const
static const char * kFormatVersionKey
static std::optional< fb::Stage > ToStage(spv::ExecutionModel stage)
static std::optional< fb::UniformDataType > ToUniformType(spirv_cross::SPIRType::BaseType type)
static const char * kUniformLocationKey
static const char * kUniformNameKey
static std::optional< fb::InputDataType > ToInputType(spirv_cross::SPIRType::BaseType type)
static std::optional< fb::Stage > ToJsonStage(spv::ExecutionModel stage)
static const char * kEntrypointKey
static const char * kUniformColumnsKey
static std::optional< uint32_t > ToJsonType(spirv_cross::SPIRType::BaseType type)
static std::string RuntimeStageBackendToString(RuntimeStageBackend backend)
static const char * kUniformStructElementsKey
static const char * kUniformTypeKey
static const char * kStageKey
static const char * kUniformsKey
static const char * kUniformRowsKey
static const char * kShaderKey
static const char * kUniformArrayElementsKey
static const char * kTargetPlatformKey
static const char * kUniformBitWidthKey
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:69
#define VALIDATION_LOG
Definition: validation.h:91