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 <optional>
9 
10 #include "inja/inja.hpp"
11 
13 #include "impeller/runtime_stage/runtime_stage_flatbuffers.h"
14 
15 namespace impeller {
16 namespace compiler {
17 
18 RuntimeStageData::RuntimeStageData(std::string entrypoint,
19  spv::ExecutionModel stage,
20  TargetPlatform target_platform)
21  : entrypoint_(std::move(entrypoint)),
22  stage_(stage),
23  target_platform_(target_platform) {}
24 
26 
28  uniforms_.emplace_back(std::move(uniform));
29 }
30 
31 void RuntimeStageData::SetShaderData(std::shared_ptr<fml::Mapping> shader) {
32  shader_ = std::move(shader);
33 }
34 
35 void RuntimeStageData::SetSkSLData(std::shared_ptr<fml::Mapping> sksl) {
36  sksl_ = std::move(sksl);
37 }
38 
39 static std::optional<fb::Stage> ToStage(spv::ExecutionModel stage) {
40  switch (stage) {
41  case spv::ExecutionModel::ExecutionModelVertex:
42  return fb::Stage::kVertex;
43  case spv::ExecutionModel::ExecutionModelFragment:
44  return fb::Stage::kFragment;
45  case spv::ExecutionModel::ExecutionModelGLCompute:
46  return fb::Stage::kCompute;
47  case spv::ExecutionModel::ExecutionModelTessellationControl:
48  return fb::Stage::kTessellationControl;
49  case spv::ExecutionModel::ExecutionModelTessellationEvaluation:
50  return fb::Stage::kTessellationEvaluation;
51  default:
52  return std::nullopt;
53  }
54  FML_UNREACHABLE();
55 }
56 
57 static std::optional<uint32_t> ToJsonStage(spv::ExecutionModel stage) {
58  switch (stage) {
59  case spv::ExecutionModel::ExecutionModelVertex:
60  return 0; // fb::Stage::kVertex;
61  case spv::ExecutionModel::ExecutionModelFragment:
62  return 1; // fb::Stage::kFragment;
63  case spv::ExecutionModel::ExecutionModelGLCompute:
64  return 2; // fb::Stage::kCompute;
65  case spv::ExecutionModel::ExecutionModelTessellationControl:
66  return 3; // fb::Stage::kTessellationControl;
67  case spv::ExecutionModel::ExecutionModelTessellationEvaluation:
68  return 4; // fb::Stage::kTessellationEvaluation;
69  default:
70  return std::nullopt;
71  }
72  FML_UNREACHABLE();
73 }
74 
75 static std::optional<fb::TargetPlatform> ToTargetPlatform(
76  TargetPlatform platform) {
77  switch (platform) {
84  return std::nullopt;
86  return fb::TargetPlatform::kSkSL;
88  return fb::TargetPlatform::kMetal;
90  return fb::TargetPlatform::kOpenGLES;
92  return fb::TargetPlatform::kVulkan;
93  }
94  FML_UNREACHABLE();
95 }
96 
97 static std::optional<uint32_t> ToJsonTargetPlatform(TargetPlatform platform) {
98  switch (platform) {
105  return std::nullopt;
107  return static_cast<uint32_t>(fb::TargetPlatform::kSkSL);
109  return static_cast<uint32_t>(fb::TargetPlatform::kMetal);
111  return static_cast<uint32_t>(fb::TargetPlatform::kOpenGLES);
113  return static_cast<uint32_t>(fb::TargetPlatform::kVulkan);
114  }
115  FML_UNREACHABLE();
116 }
117 
118 static std::optional<fb::UniformDataType> ToType(
119  spirv_cross::SPIRType::BaseType type) {
120  switch (type) {
121  case spirv_cross::SPIRType::Boolean:
123  case spirv_cross::SPIRType::SByte:
125  case spirv_cross::SPIRType::UByte:
127  case spirv_cross::SPIRType::Short:
129  case spirv_cross::SPIRType::UShort:
131  case spirv_cross::SPIRType::Int:
133  case spirv_cross::SPIRType::UInt:
135  case spirv_cross::SPIRType::Int64:
137  case spirv_cross::SPIRType::UInt64:
139  case spirv_cross::SPIRType::Half:
141  case spirv_cross::SPIRType::Float:
143  case spirv_cross::SPIRType::Double:
145  case spirv_cross::SPIRType::SampledImage:
147  case spirv_cross::SPIRType::AccelerationStructure:
148  case spirv_cross::SPIRType::AtomicCounter:
149  case spirv_cross::SPIRType::Char:
150  case spirv_cross::SPIRType::ControlPointArray:
151  case spirv_cross::SPIRType::Image:
152  case spirv_cross::SPIRType::Interpolant:
153  case spirv_cross::SPIRType::RayQuery:
154  case spirv_cross::SPIRType::Sampler:
155  case spirv_cross::SPIRType::Struct:
156  case spirv_cross::SPIRType::Unknown:
157  case spirv_cross::SPIRType::Void:
158  return std::nullopt;
159  }
160  FML_UNREACHABLE();
161 }
162 
163 static std::optional<uint32_t> ToJsonType(
164  spirv_cross::SPIRType::BaseType type) {
165  switch (type) {
166  case spirv_cross::SPIRType::Boolean:
167  return 0; // fb::UniformDataType::kBoolean;
168  case spirv_cross::SPIRType::SByte:
169  return 1; // fb::UniformDataType::kSignedByte;
170  case spirv_cross::SPIRType::UByte:
171  return 2; // fb::UniformDataType::kUnsignedByte;
172  case spirv_cross::SPIRType::Short:
173  return 3; // fb::UniformDataType::kSignedShort;
174  case spirv_cross::SPIRType::UShort:
175  return 4; // fb::UniformDataType::kUnsignedShort;
176  case spirv_cross::SPIRType::Int:
177  return 5; // fb::UniformDataType::kSignedInt;
178  case spirv_cross::SPIRType::UInt:
179  return 6; // fb::UniformDataType::kUnsignedInt;
180  case spirv_cross::SPIRType::Int64:
181  return 7; // fb::UniformDataType::kSignedInt64;
182  case spirv_cross::SPIRType::UInt64:
183  return 8; // fb::UniformDataType::kUnsignedInt64;
184  case spirv_cross::SPIRType::Half:
185  return 9; // b::UniformDataType::kHalfFloat;
186  case spirv_cross::SPIRType::Float:
187  return 10; // fb::UniformDataType::kFloat;
188  case spirv_cross::SPIRType::Double:
189  return 11; // fb::UniformDataType::kDouble;
190  case spirv_cross::SPIRType::SampledImage:
191  return 12; // fb::UniformDataType::kSampledImage;
192  case spirv_cross::SPIRType::AccelerationStructure:
193  case spirv_cross::SPIRType::AtomicCounter:
194  case spirv_cross::SPIRType::Char:
195  case spirv_cross::SPIRType::ControlPointArray:
196  case spirv_cross::SPIRType::Image:
197  case spirv_cross::SPIRType::Interpolant:
198  case spirv_cross::SPIRType::RayQuery:
199  case spirv_cross::SPIRType::Sampler:
200  case spirv_cross::SPIRType::Struct:
201  case spirv_cross::SPIRType::Unknown:
202  case spirv_cross::SPIRType::Void:
203  return std::nullopt;
204  }
205  FML_UNREACHABLE();
206 }
207 
208 static const char* kStageKey = "stage";
209 static const char* kTargetPlatformKey = "target_platform";
210 static const char* kEntrypointKey = "entrypoint";
211 static const char* kUniformsKey = "uniforms";
212 static const char* kShaderKey = "sksl";
213 static const char* kUniformNameKey = "name";
214 static const char* kUniformLocationKey = "location";
215 static const char* kUniformTypeKey = "type";
216 static const char* kUniformRowsKey = "rows";
217 static const char* kUniformColumnsKey = "columns";
218 static const char* kUniformBitWidthKey = "bit_width";
219 static const char* kUniformArrayElementsKey = "array_elements";
220 
221 std::shared_ptr<fml::Mapping> RuntimeStageData::CreateJsonMapping() const {
222  // Runtime Stage Data JSON format
223  // {
224  // "stage": 0,
225  // "target_platform": "",
226  // "entrypoint": "",
227  // "shader": "",
228  // "sksl": "",
229  // "uniforms": [
230  // {
231  // "name": "..",
232  // "location": 0,
233  // "type": 0,
234  // "rows": 0,
235  // "columns": 0,
236  // "bit_width": 0,
237  // "array_elements": 0,
238  // }
239  // ]
240  // },
241  nlohmann::json root;
242 
243  const auto stage = ToJsonStage(stage_);
244  if (!stage.has_value()) {
245  VALIDATION_LOG << "Invalid runtime stage.";
246  return nullptr;
247  }
248  root[kStageKey] = stage.value();
249 
250  const auto target_platform = ToJsonTargetPlatform(target_platform_);
251  if (!target_platform.has_value()) {
252  VALIDATION_LOG << "Invalid target platform for runtime stage.";
253  return nullptr;
254  }
255  root[kTargetPlatformKey] = target_platform.value();
256 
257  if (shader_->GetSize() > 0u) {
258  std::string shader(reinterpret_cast<const char*>(shader_->GetMapping()),
259  shader_->GetSize());
260  root[kShaderKey] = shader.c_str();
261  }
262 
263  auto& uniforms = root[kUniformsKey] = nlohmann::json::array_t{};
264  for (const auto& uniform : uniforms_) {
265  nlohmann::json uniform_object;
266  uniform_object[kUniformNameKey] = uniform.name.c_str();
267  uniform_object[kUniformLocationKey] = uniform.location;
268  uniform_object[kUniformRowsKey] = uniform.rows;
269  uniform_object[kUniformColumnsKey] = uniform.columns;
270 
271  auto uniform_type = ToJsonType(uniform.type);
272  if (!uniform_type.has_value()) {
273  VALIDATION_LOG << "Invalid uniform type for runtime stage.";
274  return nullptr;
275  }
276 
277  uniform_object[kUniformTypeKey] = uniform_type.value();
278  uniform_object[kUniformBitWidthKey] = uniform.bit_width;
279 
280  if (uniform.array_elements.has_value()) {
281  uniform_object[kUniformArrayElementsKey] = uniform.array_elements.value();
282  } else {
283  uniform_object[kUniformArrayElementsKey] = 0;
284  }
285  uniforms.push_back(uniform_object);
286  }
287 
288  auto json_string = std::make_shared<std::string>(root.dump(2u));
289 
290  return std::make_shared<fml::NonOwnedMapping>(
291  reinterpret_cast<const uint8_t*>(json_string->data()),
292  json_string->size(), [json_string](auto, auto) {});
293 }
294 
295 std::shared_ptr<fml::Mapping> RuntimeStageData::CreateMapping() const {
296  // The high level object API is used here for writing to the buffer. This is
297  // just a convenience.
298  fb::RuntimeStageT runtime_stage;
299  runtime_stage.entrypoint = entrypoint_;
300  const auto stage = ToStage(stage_);
301  if (!stage.has_value()) {
302  VALIDATION_LOG << "Invalid runtime stage.";
303  return nullptr;
304  }
305  runtime_stage.stage = stage.value();
306  const auto target_platform = ToTargetPlatform(target_platform_);
307  if (!target_platform.has_value()) {
308  VALIDATION_LOG << "Invalid target platform for runtime stage.";
309  return nullptr;
310  }
311  runtime_stage.target_platform = target_platform.value();
312  if (!shader_) {
313  VALIDATION_LOG << "No shader specified for runtime stage.";
314  return nullptr;
315  }
316  if (shader_->GetSize() > 0u) {
317  runtime_stage.shader = {shader_->GetMapping(),
318  shader_->GetMapping() + shader_->GetSize()};
319  }
320  // It is not an error for the SkSL to be ommitted.
321  if (sksl_->GetSize() > 0u) {
322  runtime_stage.sksl = {sksl_->GetMapping(),
323  sksl_->GetMapping() + sksl_->GetSize()};
324  }
325  for (const auto& uniform : uniforms_) {
326  auto desc = std::make_unique<fb::UniformDescriptionT>();
327 
328  desc->name = uniform.name;
329  if (desc->name.empty()) {
330  VALIDATION_LOG << "Uniform name cannot be empty.";
331  return nullptr;
332  }
333  desc->location = uniform.location;
334  desc->rows = uniform.rows;
335  desc->columns = uniform.columns;
336  auto uniform_type = ToType(uniform.type);
337  if (!uniform_type.has_value()) {
338  VALIDATION_LOG << "Invalid uniform type for runtime stage.";
339  return nullptr;
340  }
341  desc->type = uniform_type.value();
342  desc->bit_width = uniform.bit_width;
343  if (uniform.array_elements.has_value()) {
344  desc->array_elements = uniform.array_elements.value();
345  }
346 
347  runtime_stage.uniforms.emplace_back(std::move(desc));
348  }
349  auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
350  builder->Finish(fb::RuntimeStage::Pack(*builder.get(), &runtime_stage),
351  fb::RuntimeStageIdentifier());
352  return std::make_shared<fml::NonOwnedMapping>(builder->GetBufferPointer(),
353  builder->GetSize(),
354  [builder](auto, auto) {});
355 }
356 
357 } // namespace compiler
358 } // namespace impeller
impeller::kBoolean
@ kBoolean
Definition: runtime_types.h:14
impeller::kFloat
@ kFloat
Definition: runtime_types.h:24
runtime_stage_data.h
impeller::compiler::RuntimeStageData::~RuntimeStageData
~RuntimeStageData()
impeller::compiler::RuntimeStageData::CreateJsonMapping
std::shared_ptr< fml::Mapping > CreateJsonMapping() const
Definition: runtime_stage_data.cc:221
impeller::kUnsignedShort
@ kUnsignedShort
Definition: runtime_types.h:18
impeller::compiler::RuntimeStageData::SetSkSLData
void SetSkSLData(std::shared_ptr< fml::Mapping > sksl)
Definition: runtime_stage_data.cc:35
impeller::compiler::RuntimeStageData::SetShaderData
void SetShaderData(std::shared_ptr< fml::Mapping > shader)
Definition: runtime_stage_data.cc:31
impeller::compiler::kUniformBitWidthKey
static const char * kUniformBitWidthKey
Definition: runtime_stage_data.cc:218
impeller::compiler::TargetPlatform::kMetalDesktop
@ kMetalDesktop
impeller::kSignedByte
@ kSignedByte
Definition: runtime_types.h:15
impeller::compiler::RuntimeStageData::RuntimeStageData
RuntimeStageData(std::string entrypoint, spv::ExecutionModel stage, TargetPlatform target_platform)
Definition: runtime_stage_data.cc:18
impeller::kSampledImage
@ kSampledImage
Definition: runtime_types.h:26
impeller::compiler::kEntrypointKey
static const char * kEntrypointKey
Definition: runtime_stage_data.cc:210
impeller::compiler::kTargetPlatformKey
static const char * kTargetPlatformKey
Definition: runtime_stage_data.cc:209
impeller::compiler::TargetPlatform::kMetalIOS
@ kMetalIOS
validation.h
impeller::compiler::TargetPlatform
TargetPlatform
Definition: types.h:28
impeller::compiler::RuntimeStageData::CreateMapping
std::shared_ptr< fml::Mapping > CreateMapping() const
Definition: runtime_stage_data.cc:295
impeller::compiler::ToTargetPlatform
static std::optional< fb::TargetPlatform > ToTargetPlatform(TargetPlatform platform)
Definition: runtime_stage_data.cc:75
impeller::compiler::kUniformNameKey
static const char * kUniformNameKey
Definition: runtime_stage_data.cc:213
impeller::kSignedInt
@ kSignedInt
Definition: runtime_types.h:19
impeller::compiler::kUniformColumnsKey
static const char * kUniformColumnsKey
Definition: runtime_stage_data.cc:217
impeller::compiler::kShaderKey
static const char * kShaderKey
Definition: runtime_stage_data.cc:212
impeller::compiler::TargetPlatform::kVulkan
@ kVulkan
impeller::compiler::kUniformTypeKey
static const char * kUniformTypeKey
Definition: runtime_stage_data.cc:215
impeller::compiler::TargetPlatform::kRuntimeStageVulkan
@ kRuntimeStageVulkan
impeller::compiler::kStageKey
static const char * kStageKey
Definition: runtime_stage_data.cc:208
impeller::compiler::ToStage
static std::optional< fb::Stage > ToStage(spv::ExecutionModel stage)
Definition: runtime_stage_data.cc:39
impeller::kUnsignedByte
@ kUnsignedByte
Definition: runtime_types.h:16
impeller::kUnsignedInt64
@ kUnsignedInt64
Definition: runtime_types.h:22
impeller::compiler::kUniformArrayElementsKey
static const char * kUniformArrayElementsKey
Definition: runtime_stage_data.cc:219
impeller::compiler::ToType
static std::optional< fb::UniformDataType > ToType(spirv_cross::SPIRType::BaseType type)
Definition: runtime_stage_data.cc:118
impeller::kHalfFloat
@ kHalfFloat
Definition: runtime_types.h:23
impeller::kUnsignedInt
@ kUnsignedInt
Definition: runtime_types.h:20
impeller::compiler::RuntimeStageData::AddUniformDescription
void AddUniformDescription(UniformDescription uniform)
Definition: runtime_stage_data.cc:27
impeller::kSignedShort
@ kSignedShort
Definition: runtime_types.h:17
impeller::compiler::UniformDescription
Definition: runtime_stage_data.h:18
impeller::compiler::ToJsonType
static std::optional< uint32_t > ToJsonType(spirv_cross::SPIRType::BaseType type)
Definition: runtime_stage_data.cc:163
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::compiler::kUniformLocationKey
static const char * kUniformLocationKey
Definition: runtime_stage_data.cc:214
impeller::kDouble
@ kDouble
Definition: runtime_types.h:25
std
Definition: comparable.h:98
impeller::compiler::TargetPlatform::kOpenGLDesktop
@ kOpenGLDesktop
impeller::kSignedInt64
@ kSignedInt64
Definition: runtime_types.h:21
impeller::compiler::TargetPlatform::kUnknown
@ kUnknown
impeller::compiler::ToJsonStage
static std::optional< uint32_t > ToJsonStage(spv::ExecutionModel stage)
Definition: runtime_stage_data.cc:57
impeller::compiler::TargetPlatform::kOpenGLES
@ kOpenGLES
impeller::compiler::kUniformsKey
static const char * kUniformsKey
Definition: runtime_stage_data.cc:211
impeller::compiler::kUniformRowsKey
static const char * kUniformRowsKey
Definition: runtime_stage_data.cc:216
impeller::compiler::TargetPlatform::kRuntimeStageMetal
@ kRuntimeStageMetal
impeller
Definition: aiks_context.cc:10
impeller::compiler::TargetPlatform::kSkSL
@ kSkSL
impeller::compiler::TargetPlatform::kRuntimeStageGLES
@ kRuntimeStageGLES
impeller::compiler::ToJsonTargetPlatform
static std::optional< uint32_t > ToJsonTargetPlatform(TargetPlatform platform)
Definition: runtime_stage_data.cc:97