| 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::Float:
65 return fb::UniformDataType::kFloat;
66 case spirv_cross::SPIRType::SampledImage:
67 return fb::UniformDataType::kSampledImage;
68 case spirv_cross::SPIRType::Struct:
69 return fb::UniformDataType::kStruct;
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:
117 return fb::InputDataType::kFloat;
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
198 static std::string RuntimeStageBackendToString(RuntimeStageBackend backend) {
199 switch (backend) {
200 case RuntimeStageBackend::kSkSL:
201 return "sksl";
202 case RuntimeStageBackend::kMetal:
203 return "metal";
204 case RuntimeStageBackend::kOpenGLES:
205 return "opengles";
206 case RuntimeStageBackend::kVulkan:
207 return "vulkan";
208 case RuntimeStageBackend::kOpenGLES3:
209 return "opengles3";
210 }
211 }
212
213 std::shared_ptr<fml::Mapping> RuntimeStageData::CreateJsonMapping() const {
214 // Runtime Stage Data JSON format
215 // {
216 // "format_version": 1,
217 // "sksl": {
218 // "stage": 0,
219 // "entrypoint": "",
220 // "shader": "",
221 // "uniforms": [
222 // {
223 // "name": "..",
224 // "location": 0,
225 // "type": 0,
226 // "rows": 0,
227 // "columns": 0,
228 // "bit_width": 0,
229 // "array_elements": 0,
230 // }
231 // ]
232 // },
233 // "metal": ...
234 // },
235 nlohmann::json root;
236
237 root[kFormatVersionKey] =
238 static_cast<uint32_t>(fb::RuntimeStagesFormatVersion::kVersion);
239 for (const auto& kvp : data_) {
240 nlohmann::json platform_object;
241
242 const auto stage = ToJsonStage(kvp.second->stage);
243 if (!stage.has_value()) {
244 VALIDATION_LOG << "Invalid runtime stage.";
245 return nullptr;
246 }
247 platform_object[kStageKey] = static_cast<uint32_t>(stage.value());
248 platform_object[kEntrypointKey] = kvp.second->entrypoint;
249
250 if (kvp.second->shader->GetSize() > 0u) {
251 std::string shader(
252 reinterpret_cast<const char*>(kvp.second->shader->GetMapping()),
253 kvp.second->shader->GetSize());
254 platform_object[kShaderKey] = shader.c_str();
255 }
256
257 auto& uniforms = platform_object[kUniformsKey] = nlohmann::json::array_t{};
258 for (const auto& uniform : kvp.second->uniforms) {
259 nlohmann::json uniform_object;
260 uniform_object[kUniformNameKey] = uniform.name.c_str();
261 uniform_object[kUniformLocationKey] = uniform.location;
262 uniform_object[kUniformRowsKey] = uniform.rows;
263 uniform_object[kUniformColumnsKey] = uniform.columns;
264
265 auto uniform_type = ToJsonType(uniform.type);
266 if (!uniform_type.has_value()) {
267 VALIDATION_LOG << "Invalid uniform type for runtime stage.";
268 return nullptr;
269 }
270
271 uniform_object[kUniformTypeKey] = uniform_type.value();
272 uniform_object[kUniformBitWidthKey] = uniform.bit_width;
273 uniform_object[kUniformArrayElementsKey] =
274 uniform.array_elements.value_or(0);
275
276 uniforms.push_back(uniform_object);
277 }
278
279 root[RuntimeStageBackendToString(kvp.first)] = platform_object;
280 }
281
282 auto json_string = std::make_shared<std::string>(root.dump(2u));
283
284 return std::make_shared<fml::NonOwnedMapping>(
285 reinterpret_cast<const uint8_t*>(json_string->data()),
286 json_string->size(), [json_string](auto, auto) {});
287 }
288
289 std::unique_ptr<fb::RuntimeStageT> RuntimeStageData::CreateStageFlatbuffer(
290 impeller::RuntimeStageBackend backend) const {
291 auto kvp = data_.find(backend);
292 if (kvp == data_.end()) {
293 return nullptr;
294 }
295
296 auto runtime_stage = std::make_unique<fb::RuntimeStageT>();
297 runtime_stage->entrypoint = kvp->second->entrypoint;
298 const auto stage = ToStage(kvp->second->stage);
299 if (!stage.has_value()) {
300 VALIDATION_LOG << "Invalid runtime stage.";
301 return nullptr;
302 }
303 runtime_stage->stage = stage.value();
304 if (!kvp->second->shader) {
305 VALIDATION_LOG << "No shader specified for runtime stage.";
306 return nullptr;
307 }
308 if (kvp->second->shader->GetSize() > 0u) {
309 runtime_stage->shader = {
310 kvp->second->shader->GetMapping(),
311 kvp->second->shader->GetMapping() + kvp->second->shader->GetSize()};
312 }
313 for (const auto& uniform : kvp->second->uniforms) {
314 auto desc = std::make_unique<fb::UniformDescriptionT>();
315
316 desc->name = uniform.name;
317 if (desc->name.empty()) {
318 VALIDATION_LOG << "Uniform name cannot be empty.";
319 return nullptr;
320 }
321 desc->location = uniform.location;
322 desc->rows = uniform.rows;
323 desc->columns = uniform.columns;
324 auto uniform_type = ToUniformType(uniform.type);
325 if (!uniform_type.has_value()) {
326 VALIDATION_LOG << "Invalid uniform type for runtime stage.";
327 return nullptr;
328 }
329 desc->type = uniform_type.value();
330 desc->bit_width = uniform.bit_width;
331 if (uniform.array_elements.has_value()) {
332 desc->array_elements = uniform.array_elements.value();
333 }
334
335 for (const auto& byte_type : uniform.struct_layout) {
336 desc->struct_layout.push_back(static_cast<fb::StructByteType>(byte_type));
337 }
338 desc->struct_float_count = uniform.struct_float_count;
339
340 runtime_stage->uniforms.emplace_back(std::move(desc));
341 }
342
343 for (const auto& input : kvp->second->inputs) {
344 auto desc = std::make_unique<fb::StageInputT>();
345
346 desc->name = input.name;
347
348 if (desc->name.empty()) {
349 VALIDATION_LOG << "Stage input name cannot be empty.";
350 return nullptr;
351 }
352 desc->location = input.location;
353 desc->set = input.set;
354 desc->binding = input.binding;
355 auto input_type = ToInputType(input.type);
356 if (!input_type.has_value()) {
357 VALIDATION_LOG << "Invalid uniform type for runtime stage.";
358 return nullptr;
359 }
360 desc->type = input_type.value();
361 desc->bit_width = input.bit_width;
362 desc->vec_size = input.vec_size;
363 desc->columns = input.columns;
364 desc->offset = input.offset;
365
366 runtime_stage->inputs.emplace_back(std::move(desc));
367 }
368
369 return runtime_stage;
370 }
371
372 std::unique_ptr<fb::RuntimeStagesT>
373 RuntimeStageData::CreateMultiStageFlatbuffer() const {
374 // The high level object API is used here for writing to the buffer. This is
375 // just a convenience.
376 auto runtime_stages = std::make_unique<fb::RuntimeStagesT>();
377 runtime_stages->format_version =
378 static_cast<uint32_t>(fb::RuntimeStagesFormatVersion::kVersion);
379
380 for (const auto& kvp : data_) {
381 auto runtime_stage = CreateStageFlatbuffer(kvp.first);
382 switch (kvp.first) {
383 case RuntimeStageBackend::kSkSL:
384 runtime_stages->sksl = std::move(runtime_stage);
385 break;
386 case RuntimeStageBackend::kMetal:
387 runtime_stages->metal = std::move(runtime_stage);
388 break;
389 case RuntimeStageBackend::kOpenGLES:
390 runtime_stages->opengles = std::move(runtime_stage);
391 break;
392 case RuntimeStageBackend::kVulkan:
393 runtime_stages->vulkan = std::move(runtime_stage);
394 break;
395 case RuntimeStageBackend::kOpenGLES3:
396 runtime_stages->opengles3 = std::move(runtime_stage);
397 break;
398 }
399 }
400 return runtime_stages;
401 }
402
403 std::shared_ptr<fml::Mapping> RuntimeStageData::CreateMapping() const {
404 auto runtime_stages = CreateMultiStageFlatbuffer();
405 if (!runtime_stages) {
406 return nullptr;
407 }
408
409 auto builder = std::make_shared<flatbuffers::FlatBufferBuilder>();
410 builder->Finish(fb::RuntimeStages::Pack(*builder.get(), runtime_stages.get()),
411 fb::RuntimeStagesIdentifier());
412 return std::make_shared<fml::NonOwnedMapping>(builder->GetBufferPointer(),
413 builder->GetSize(),
414 [builder](auto, auto) {});
415 }
416
417 } // namespace compiler
418 } // namespace impeller
type
GLenum type
Definition: blit_command_gles.cc:153
impeller::compiler::RuntimeStageData::CreateMultiStageFlatbuffer
std::unique_ptr< fb::RuntimeStagesT > CreateMultiStageFlatbuffer() const
Definition: runtime_stage_data.cc:373
impeller::compiler::RuntimeStageData::CreateMapping
std::shared_ptr< fml::Mapping > CreateMapping() const
Definition: runtime_stage_data.cc:403
impeller::compiler::RuntimeStageData::CreateStageFlatbuffer
std::unique_ptr< fb::RuntimeStageT > CreateStageFlatbuffer(impeller::RuntimeStageBackend backend) const
Definition: runtime_stage_data.cc:289
impeller::compiler::RuntimeStageData::RuntimeStageData
RuntimeStageData()
impeller::compiler::RuntimeStageData::AddShader
void AddShader(const std::shared_ptr< Shader > &data)
Definition: runtime_stage_data.cc:27
impeller::compiler::RuntimeStageData::~RuntimeStageData
~RuntimeStageData()
impeller::compiler::RuntimeStageData::CreateJsonMapping
std::shared_ptr< fml::Mapping > CreateJsonMapping() const
Definition: runtime_stage_data.cc:213
impeller::compiler::kFormatVersionKey
static const char * kFormatVersionKey
Definition: runtime_stage_data.cc:184
impeller::compiler::ToStage
static std::optional< fb::Stage > ToStage(spv::ExecutionModel stage)
Definition: runtime_stage_data.cc:33
impeller::compiler::ToUniformType
static std::optional< fb::UniformDataType > ToUniformType(spirv_cross::SPIRType::BaseType type)
Definition: runtime_stage_data.cc:61
impeller::compiler::kUniformLocationKey
static const char * kUniformLocationKey
Definition: runtime_stage_data.cc:191
impeller::compiler::kUniformNameKey
static const char * kUniformNameKey
Definition: runtime_stage_data.cc:190
impeller::compiler::ToInputType
static std::optional< fb::InputDataType > ToInputType(spirv_cross::SPIRType::BaseType type)
Definition: runtime_stage_data.cc:95
impeller::compiler::ToJsonStage
static std::optional< fb::Stage > ToJsonStage(spv::ExecutionModel stage)
Definition: runtime_stage_data.cc:47
impeller::compiler::kEntrypointKey
static const char * kEntrypointKey
Definition: runtime_stage_data.cc:187
impeller::compiler::kUniformColumnsKey
static const char * kUniformColumnsKey
Definition: runtime_stage_data.cc:194
impeller::compiler::ToJsonType
static std::optional< uint32_t > ToJsonType(spirv_cross::SPIRType::BaseType type)
Definition: runtime_stage_data.cc:138
impeller::compiler::RuntimeStageBackendToString
static std::string RuntimeStageBackendToString(RuntimeStageBackend backend)
Definition: runtime_stage_data.cc:198
impeller::compiler::kUniformTypeKey
static const char * kUniformTypeKey
Definition: runtime_stage_data.cc:192
impeller::compiler::kStageKey
static const char * kStageKey
Definition: runtime_stage_data.cc:185
impeller::compiler::kUniformsKey
static const char * kUniformsKey
Definition: runtime_stage_data.cc:188
impeller::compiler::kUniformRowsKey
static const char * kUniformRowsKey
Definition: runtime_stage_data.cc:193
impeller::compiler::kShaderKey
static const char * kShaderKey
Definition: runtime_stage_data.cc:189
impeller::compiler::kUniformArrayElementsKey
static const char * kUniformArrayElementsKey
Definition: runtime_stage_data.cc:196
impeller::compiler::kTargetPlatformKey
static const char * kTargetPlatformKey
Definition: runtime_stage_data.cc:186
impeller::compiler::kUniformBitWidthKey
static const char * kUniformBitWidthKey
Definition: runtime_stage_data.cc:195
impeller
Definition: allocation.cc:12
impeller::RuntimeStageBackend
RuntimeStageBackend
Definition: runtime_types.h:16
impeller::RuntimeStageBackend::kOpenGLES
@ kOpenGLES
impeller::RuntimeStageBackend::kMetal
@ kMetal
impeller::RuntimeStageBackend::kVulkan
@ kVulkan
impeller::RuntimeStageBackend::kSkSL
@ kSkSL
impeller::RuntimeStageBackend::kOpenGLES3
@ kOpenGLES3
impeller::kSampledImage
@ kSampledImage
Definition: runtime_types.h:26
impeller::kFloat
@ kFloat
Definition: runtime_types.h:25
impeller::kStruct
@ kStruct
Definition: runtime_types.h:27
runtime_stage_data.h
runtime_types.h
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:69
validation.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91