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