Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
runtime_stage.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 <atomic>
9#include <cstdint>
10#include <memory>
11#include <sstream>
12#include <string>
13
14#include "fml/mapping.h"
18#include "impeller/runtime_stage/runtime_stage_flatbuffers.h"
19#include "runtime_stage_types_flatbuffers.h"
20
21namespace impeller {
22
23namespace {
24// Process-unique fallback library id for runtime stages decoded without an
25// asset path (e.g. tests, future in-memory APIs). Kept local to this
26// translation unit because `impeller::renderer` (where the equivalent
27// `ShaderKey::MakeFallbackLibraryId` lives) already depends on
28// `impeller::runtime_stage`, so it is not reachable from here.
29std::string MakeFallbackLibraryId() {
30 static std::atomic<uint64_t> counter{0};
31 return "auto:" +
32 std::to_string(counter.fetch_add(1, std::memory_order_relaxed));
33}
34} // namespace
35
36static RuntimeUniformType ToType(fb::UniformDataType type) {
37 switch (type) {
38 case fb::UniformDataType::kFloat:
40 case fb::UniformDataType::kSampledImage:
42 case fb::UniformDataType::kStruct:
44 }
46}
47
48static RuntimeShaderStage ToShaderStage(fb::Stage stage) {
49 switch (stage) {
50 case fb::Stage::kVertex:
52 case fb::Stage::kFragment:
54 case fb::Stage::kCompute:
56 }
58}
59
60/// The generated name from GLSLang/shaderc for the UBO containing non-opaque
61/// uniforms specified in the user-written runtime effect shader.
62///
63/// Vulkan does not allow non-opaque uniforms outside of a UBO.
65 "_RESERVED_IDENTIFIER_FIXUP_gl_DefaultUniformBlock";
66
67absl::StatusOr<RuntimeStage> RuntimeStage::Create(
68 const fb::RuntimeStage* runtime_stage,
69 const std::shared_ptr<fml::Mapping>& payload) {
70 if (!runtime_stage) {
71 return absl::InvalidArgumentError("Runtime stage is null.");
72 }
73
74 RuntimeStage stage(payload);
75 stage.stage_ = ToShaderStage(runtime_stage->stage());
76 stage.entrypoint_ = runtime_stage->entrypoint()->str();
77 stage.library_id_ = MakeFallbackLibraryId();
78
79 auto* uniforms = runtime_stage->uniforms();
80
81 // Note: image bindings are screwy and will always have the same offset.
82 // track the binding of the UBO to determine where the image bindings go.
83 // This is only guaranteed to give us the correct bindings if there is a
84 // single sampler2D.
85 std::optional<size_t> ubo_id;
86 if (uniforms) {
87 for (auto i = uniforms->begin(), end = uniforms->end(); i != end; i++) {
89 desc.name = i->name()->str();
90 desc.location = i->location();
91 desc.binding = i->binding();
92 desc.type = ToType(i->type());
93 if (desc.type == kStruct) {
94 ubo_id = desc.location;
95 desc.binding = desc.location;
96 }
98 static_cast<size_t>(i->rows()), static_cast<size_t>(i->columns())};
99 desc.bit_width = i->bit_width();
100 desc.array_elements = i->array_elements();
101 if (i->padding_layout()) {
102 for (const auto& byte_type : *i->padding_layout()) {
104 switch (byte_type) {
105 case fb::PaddingType::kPadding:
107 break;
108 case fb::PaddingType::kFloat:
110 break;
111 }
112 desc.padding_layout.push_back(type);
113 }
114 }
115 if (i->struct_fields()) {
116 for (const auto& elem : *i->struct_fields()) {
117 desc.struct_fields.emplace_back(
118 StructField{.name = elem->name()->str(),
119 .byte_size = static_cast<size_t>(elem->byte_size())});
120 }
121 }
122 desc.struct_float_count = i->struct_float_count();
123 stage.uniforms_.push_back(std::move(desc));
124 }
125 }
126
127 stage.code_mapping_ = std::make_shared<fml::NonOwnedMapping>(
128 runtime_stage->shader()->data(), //
129 runtime_stage->shader()->size(), //
130 [payload = stage.payload_](auto, auto) {} //
131 );
132
133 size_t binding = 64;
134 if (ubo_id.has_value() && ubo_id.value() == binding) {
135 binding++;
136 }
137 for (auto& uniform : stage.uniforms_) {
138 if (uniform.type == kSampledImage) {
139 uniform.binding = binding;
140 binding++;
141 if (ubo_id.has_value() && ubo_id.value() == binding) {
142 binding++;
143 }
144 }
145 }
146
147 for (const auto& uniform : stage.GetUniforms()) {
148 if (uniform.type == kStruct) {
149 stage.descriptor_set_layouts_.push_back(DescriptorSetLayout{
150 static_cast<uint32_t>(uniform.location),
153 });
154 } else if (uniform.type == kSampledImage) {
155 stage.descriptor_set_layouts_.push_back(DescriptorSetLayout{
156 static_cast<uint32_t>(uniform.binding),
159 });
160 }
161 }
162
163 return stage;
164}
165
166std::unique_ptr<RuntimeStage> RuntimeStage::RuntimeStageIfPresent(
167 const fb::RuntimeStage* runtime_stage,
168 const std::shared_ptr<fml::Mapping>& payload) {
169 auto stage = Create(runtime_stage, payload);
170 if (!stage.ok()) {
171 return nullptr;
172 }
173 return std::make_unique<RuntimeStage>(std::move(*stage));
174}
175
176absl::StatusOr<RuntimeStage::Map> RuntimeStage::DecodeRuntimeStages(
177 const std::shared_ptr<fml::Mapping>& payload) {
178 if (payload == nullptr || !payload->GetMapping()) {
179 return absl::InvalidArgumentError("Payload is null or empty.");
180 }
181 if (!fb::RuntimeStagesBufferHasIdentifier(payload->GetMapping())) {
182 return absl::InvalidArgumentError(
183 "Payload does not have valid identifier.");
184 }
185
186 auto raw_stages = fb::GetRuntimeStages(payload->GetMapping());
187 if (!raw_stages) {
188 return absl::InvalidArgumentError("Failed to get runtime stages.");
189 }
190
191 const uint32_t version = raw_stages->format_version();
192 const auto expected =
193 static_cast<uint32_t>(fb::RuntimeStagesFormatVersion::kVersion);
194 if (version != expected) {
195 std::stringstream stream;
196 stream << "Unsupported runtime stages format version. Expected " << expected
197 << ", got " << version << ".";
198 return absl::InvalidArgumentError(stream.str());
199 }
200
201 return Map{
203 RuntimeStageIfPresent(raw_stages->sksl(), payload)},
205 RuntimeStageIfPresent(raw_stages->metal(), payload)},
207 RuntimeStageIfPresent(raw_stages->opengles(), payload)},
209 RuntimeStageIfPresent(raw_stages->opengles3(), payload)},
211 RuntimeStageIfPresent(raw_stages->vulkan(), payload)},
212 };
213}
214
215RuntimeStage::RuntimeStage(std::shared_ptr<fml::Mapping> payload)
216 : payload_(std::move(payload)) {}
217
219RuntimeStage::RuntimeStage(RuntimeStage&&) = default;
220RuntimeStage& RuntimeStage::operator=(RuntimeStage&&) = default;
221
222const std::shared_ptr<fml::Mapping>& RuntimeStage::GetCodeMapping() const {
223 return code_mapping_;
224}
225
226const std::vector<RuntimeUniformDescription>& RuntimeStage::GetUniforms()
227 const {
228 return uniforms_;
229}
230
232 const std::string& name) const {
233 for (const auto& uniform : uniforms_) {
234 if (uniform.name == name) {
235 return &uniform;
236 }
237 }
238 return nullptr;
239}
240
241const std::string& RuntimeStage::GetEntrypoint() const {
242 return entrypoint_;
243}
244
246 return stage_;
247}
248
250 return is_dirty_;
251}
252
254 is_dirty_ = false;
255}
256
257void RuntimeStage::SetLibraryId(std::string library_id) {
258 library_id_ = std::move(library_id);
259}
260
261const std::string& RuntimeStage::GetLibraryId() const {
262 return library_id_;
263}
264
265const std::vector<DescriptorSetLayout>& RuntimeStage::GetDescriptorSetLayouts()
266 const {
267 return descriptor_set_layouts_;
268}
269
270} // namespace impeller
RuntimeStage(RuntimeStage &&)
const std::string & GetEntrypoint() const
const std::string & GetLibraryId() const
RuntimeStage & operator=(RuntimeStage &&)
static absl::StatusOr< RuntimeStage > Create(const fb::RuntimeStage *runtime_stage, const std::shared_ptr< fml::Mapping > &payload)
const std::vector< RuntimeUniformDescription > & GetUniforms() const
void SetLibraryId(std::string library_id)
const RuntimeUniformDescription * GetUniform(const std::string &name) const
std::map< RuntimeStageBackend, std::shared_ptr< RuntimeStage > > Map
static const char * kVulkanUBOName
const std::shared_ptr< fml::Mapping > & GetCodeMapping() const
const std::vector< DescriptorSetLayout > & GetDescriptorSetLayouts() const
static absl::StatusOr< Map > DecodeRuntimeStages(const std::shared_ptr< fml::Mapping > &payload)
RuntimeShaderStage GetShaderStage() const
#define FML_UNREACHABLE()
Definition logging.h:128
const char * name
Definition fuchsia.cc:50
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
static RuntimeUniformType ToType(fb::UniformDataType type)
Definition ref_ptr.h:261
impeller::ShaderType type
RuntimeUniformDimensions dimensions
std::vector< StructField > struct_fields
std::vector< RuntimePaddingType > padding_layout
std::optional< size_t > array_elements
size_t binding
Location, but for Vulkan.
const size_t end