Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
shader_library.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 <optional>
8#include <utility>
9
14#include "fml/mapping.h"
15#include "fml/memory/ref_ptr.h"
19#include "impeller/shader_bundle/shader_bundle_flatbuffers.h"
20#include "lib/gpu/context.h"
21
22namespace flutter {
23namespace gpu {
24
26
27fml::RefPtr<ShaderLibrary> ShaderLibrary::override_shader_library_;
28
31 const std::string& name,
32 std::string& out_error) {
33 if (override_shader_library_) {
34 return override_shader_library_;
35 }
36
37 auto dart_state = UIDartState::Current();
38 std::shared_ptr<AssetManager> asset_manager =
39 dart_state->platform_configuration()->client()->GetAssetManager();
40
41 std::unique_ptr<fml::Mapping> data = asset_manager->GetAsMapping(name);
42 if (data == nullptr) {
43 out_error = std::string("Asset '") + name + std::string("' not found.");
44 return nullptr;
45 }
46
47 return MakeFromFlatbuffer(backend_type, std::move(data), name);
48}
49
51 return fml::MakeRefCounted<flutter::gpu::ShaderLibrary>(nullptr,
52 std::move(shaders));
53}
54
56 impeller::fb::shaderbundle::ShaderStage stage) {
57 switch (stage) {
58 case impeller::fb::shaderbundle::ShaderStage::kVertex:
60 case impeller::fb::shaderbundle::ShaderStage::kFragment:
62 case impeller::fb::shaderbundle::ShaderStage::kCompute:
64 }
66}
67
69 impeller::fb::shaderbundle::InputDataType input_type) {
70 switch (input_type) {
71 case impeller::fb::shaderbundle::InputDataType::kBoolean:
73 case impeller::fb::shaderbundle::InputDataType::kSignedByte:
75 case impeller::fb::shaderbundle::InputDataType::kUnsignedByte:
77 case impeller::fb::shaderbundle::InputDataType::kSignedShort:
79 case impeller::fb::shaderbundle::InputDataType::kUnsignedShort:
81 case impeller::fb::shaderbundle::InputDataType::kSignedInt:
83 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt:
85 case impeller::fb::shaderbundle::InputDataType::kSignedInt64:
87 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt64:
89 case impeller::fb::shaderbundle::InputDataType::kFloat:
91 case impeller::fb::shaderbundle::InputDataType::kDouble:
93 }
94}
95
97 impeller::fb::shaderbundle::UniformDataType uniform_type) {
98 switch (uniform_type) {
99 case impeller::fb::shaderbundle::UniformDataType::kBoolean:
101 case impeller::fb::shaderbundle::UniformDataType::kSignedByte:
103 case impeller::fb::shaderbundle::UniformDataType::kUnsignedByte:
105 case impeller::fb::shaderbundle::UniformDataType::kSignedShort:
107 case impeller::fb::shaderbundle::UniformDataType::kUnsignedShort:
109 case impeller::fb::shaderbundle::UniformDataType::kSignedInt:
111 case impeller::fb::shaderbundle::UniformDataType::kUnsignedInt:
113 case impeller::fb::shaderbundle::UniformDataType::kSignedInt64:
115 case impeller::fb::shaderbundle::UniformDataType::kUnsignedInt64:
117 case impeller::fb::shaderbundle::UniformDataType::kFloat:
119 case impeller::fb::shaderbundle::UniformDataType::kDouble:
121 case impeller::fb::shaderbundle::UniformDataType::kHalfFloat:
123 case impeller::fb::shaderbundle::UniformDataType::kSampledImage:
125 }
126}
127
128static size_t SizeOfInputType(
129 impeller::fb::shaderbundle::InputDataType input_type) {
130 switch (input_type) {
131 case impeller::fb::shaderbundle::InputDataType::kBoolean:
132 return 1;
133 case impeller::fb::shaderbundle::InputDataType::kSignedByte:
134 return 1;
135 case impeller::fb::shaderbundle::InputDataType::kUnsignedByte:
136 return 1;
137 case impeller::fb::shaderbundle::InputDataType::kSignedShort:
138 return 2;
139 case impeller::fb::shaderbundle::InputDataType::kUnsignedShort:
140 return 2;
141 case impeller::fb::shaderbundle::InputDataType::kSignedInt:
142 return 4;
143 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt:
144 return 4;
145 case impeller::fb::shaderbundle::InputDataType::kSignedInt64:
146 return 8;
147 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt64:
148 return 8;
149 case impeller::fb::shaderbundle::InputDataType::kFloat:
150 return 4;
151 case impeller::fb::shaderbundle::InputDataType::kDouble:
152 return 8;
153 }
154}
155
156static const impeller::fb::shaderbundle::BackendShader* GetShaderBackend(
158 const impeller::fb::shaderbundle::Shader* shader) {
159 switch (backend_type) {
161#ifdef FML_OS_IOS
162 return shader->metal_ios();
163#else
164 return shader->metal_desktop();
165#endif
167 return shader->opengl_es();
169 return shader->vulkan();
170 }
171}
172
175 const std::shared_ptr<fml::Mapping>& payload,
176 const std::string& library_id) {
177 ShaderLibrary::ShaderMap shader_map;
178 if (payload == nullptr || !payload->GetMapping()) {
179 return shader_map;
180 }
181 if (!impeller::fb::shaderbundle::ShaderBundleBufferHasIdentifier(
182 payload->GetMapping())) {
183 return shader_map;
184 }
185 auto* bundle =
186 impeller::fb::shaderbundle::GetShaderBundle(payload->GetMapping());
187 if (!bundle) {
188 return shader_map;
189 }
190
191 const auto version = bundle->format_version();
192 const auto expected = static_cast<uint32_t>(
193 impeller::fb::shaderbundle::ShaderBundleFormatVersion::kVersion);
194 if (version != expected) {
195 VALIDATION_LOG << "Unsupported shader bundle format version: " << version
196 << ", expected: " << expected
197 << ". This shader bundle was compiled with an incompatible "
198 "version of impellerc. Please rebuild the shader bundle "
199 "with the version of impellerc that ships with the "
200 "current Flutter SDK.";
201 return shader_map;
202 }
203
204 for (const auto* bundled_shader : *bundle->shaders()) {
205 const impeller::fb::shaderbundle::BackendShader* backend_shader =
206 GetShaderBackend(backend_type, bundled_shader);
207 if (!backend_shader) {
208 VALIDATION_LOG << "Failed to unpack shader \""
209 << bundled_shader->name()->c_str() << "\" from bundle.";
210 continue;
211 }
212
213 auto code_mapping = std::make_shared<fml::NonOwnedMapping>(
214 backend_shader->shader()->data(), //
215 backend_shader->shader()->size(), //
216 [payload = payload](auto, auto) {} //
217 );
218
219 std::vector<impeller::DescriptorSetLayout> descriptor_set_layouts;
220
221 std::unordered_map<std::string, Shader::UniformBinding> uniform_structs;
222 if (backend_shader->uniform_structs() != nullptr) {
223 for (const auto& uniform : *backend_shader->uniform_structs()) {
224 std::vector<impeller::ShaderStructMemberMetadata> members;
225 if (uniform->fields() != nullptr) {
226 for (const auto& struct_member : *uniform->fields()) {
228 FromUniformType(struct_member->type());
229 members.push_back(impeller::ShaderStructMemberMetadata{
230 .type = type,
231 .name = struct_member->name()->c_str(),
232 .offset = static_cast<size_t>(struct_member->offset_in_bytes()),
233 .size =
234 static_cast<size_t>(struct_member->element_size_in_bytes()),
235 .byte_length =
236 static_cast<size_t>(struct_member->total_size_in_bytes()),
237 .array_elements =
238 struct_member->array_elements() == 0
239 ? std::optional<size_t>(std::nullopt)
240 : static_cast<size_t>(struct_member->array_elements()),
242 type, static_cast<size_t>(struct_member->vec_size()),
243 static_cast<size_t>(struct_member->columns())),
244 });
245 }
246 }
247
248 uniform_structs[uniform->name()->str()] = Shader::UniformBinding{
249 .slot =
251 .name = uniform->name()->c_str(),
252 .ext_res_0 = static_cast<size_t>(uniform->ext_res_0()),
253 .set = static_cast<size_t>(uniform->set()),
254 .binding = static_cast<size_t>(uniform->binding()),
255 },
256 .metadata =
258 .name = uniform->name()->c_str(),
259 .members = members,
260 },
261 .size_in_bytes = static_cast<size_t>(uniform->size_in_bytes()),
262 };
263
264 descriptor_set_layouts.push_back(impeller::DescriptorSetLayout{
265 static_cast<uint32_t>(uniform->binding()),
267 ToShaderStage(backend_shader->stage()),
268 });
269 }
270 }
271
272 std::unordered_map<std::string, Shader::TextureBinding> uniform_textures;
273 if (backend_shader->uniform_textures() != nullptr) {
274 for (const auto& uniform : *backend_shader->uniform_textures()) {
275 Shader::TextureBinding texture_binding;
276 texture_binding.slot = impeller::SampledImageSlot{
277 .name = uniform->name()->c_str(),
278 .texture_index = static_cast<size_t>(uniform->ext_res_0()),
279 .set = static_cast<size_t>(uniform->set()),
280 .binding = static_cast<size_t>(uniform->binding()),
281 };
282 texture_binding.metadata = impeller::ShaderMetadata{
283 .name = uniform->name()->c_str(),
284 .members = {},
285 };
286
287 uniform_textures[uniform->name()->str()] = texture_binding;
288
289 descriptor_set_layouts.push_back(impeller::DescriptorSetLayout{
290 static_cast<uint32_t>(uniform->binding()),
292 ToShaderStage(backend_shader->stage()),
293 });
294 }
295 }
296
297 std::vector<impeller::ShaderStageIOSlot> inputs;
298 std::vector<impeller::ShaderStageBufferLayout> layouts;
299 if (backend_shader->stage() ==
300 impeller::fb::shaderbundle::ShaderStage::kVertex) {
301 auto inputs_fb = backend_shader->inputs();
302
303 inputs.reserve(inputs_fb->size());
304 size_t default_stride = 0;
305 for (const auto& input : *inputs_fb) {
307 slot.name = input->name()->c_str();
308 slot.location = input->location();
309 slot.set = input->set();
310 slot.binding = input->binding();
311 slot.type = FromInputType(input->type());
312 slot.bit_width = input->bit_width();
313 slot.vec_size = input->vec_size();
314 slot.columns = input->columns();
315 slot.offset = input->offset();
316 inputs.emplace_back(slot);
317
318 default_stride +=
319 SizeOfInputType(input->type()) * slot.vec_size * slot.columns;
320 }
322 .stride = default_stride,
323 .binding = 0u,
324 }};
325 }
326
327 auto shader = flutter::gpu::Shader::Make(
328 library_id, backend_shader->entrypoint()->str(),
329 ToShaderStage(backend_shader->stage()), std::move(code_mapping),
330 std::move(inputs), std::move(layouts), std::move(uniform_structs),
331 std::move(uniform_textures), std::move(descriptor_set_layouts));
332 shader_map[bundled_shader->name()->str()] = std::move(shader);
333 }
334
335 return shader_map;
336}
337
340 std::shared_ptr<fml::Mapping> payload,
341 std::string library_id) {
342 if (payload == nullptr || !payload->GetMapping()) {
343 return nullptr;
344 }
345 if (library_id.empty()) {
347 }
348 ShaderMap shader_map = ParseShaderBundle(backend_type, payload, library_id);
349 if (shader_map.empty()) {
350 return nullptr;
351 }
352 return fml::MakeRefCounted<flutter::gpu::ShaderLibrary>(
353 std::move(payload), std::move(shader_map), std::move(library_id));
354}
355
358 const std::string& name) {
359 auto dart_state = UIDartState::Current();
360 std::shared_ptr<AssetManager> asset_manager =
361 dart_state->platform_configuration()->client()->GetAssetManager();
362
363 std::unique_ptr<fml::Mapping> data = asset_manager->GetAsMapping(name);
364 if (data == nullptr) {
365 return "Asset '" + name + "' not found.";
366 }
367 return ReloadFromFlatbuffer(backend_type, std::move(data));
368}
369
372 std::shared_ptr<fml::Mapping> payload) {
373 if (payload == nullptr || !payload->GetMapping()) {
374 return "Empty shader bundle payload.";
375 }
376 ShaderMap new_shaders = ParseShaderBundle(backend_type, payload, library_id_);
377 if (new_shaders.empty()) {
378 return "Shader bundle could not be parsed.";
379 }
380
381 // Reuse the existing Shader instance for any name that survives the
382 // reload so user-held Dart wrappers stay attached to live data. Names
383 // that disappeared in the new bundle drop out of the map; names that
384 // are new get added. The eviction of old shader functions happens
385 // lazily in `Shader::RegisterSync` when the dirty bit is observed.
386 ShaderMap merged;
387 for (auto& [name, parsed] : new_shaders) {
388 auto it = shaders_.find(name);
389 if (it != shaders_.end()) {
390 it->second->ResetFrom(*parsed);
391 merged[name] = it->second;
392 } else {
393 merged[name] = std::move(parsed);
394 }
395 }
396 shaders_ = std::move(merged);
397 payload_ = std::move(payload);
398 return "";
399}
400
402 fml::RefPtr<ShaderLibrary> override_shader_library) {
403 override_shader_library_ = std::move(override_shader_library);
404}
405
406fml::RefPtr<Shader> ShaderLibrary::GetShader(const std::string& shader_name,
407 Dart_Handle shader_wrapper) {
408 auto it = shaders_.find(shader_name);
409 if (it == shaders_.end()) {
410 return nullptr; // No matching shaders.
411 }
412 auto shader = it->second;
413
414 if (shader->dart_wrapper() == nullptr) {
415 shader->AssociateWithDartWrapper(shader_wrapper);
416 }
417 return shader;
418}
419
420ShaderLibrary::ShaderLibrary(std::shared_ptr<fml::Mapping> payload,
421 ShaderMap shaders,
422 std::string library_id)
423 : payload_(std::move(payload)),
424 shaders_(std::move(shaders)),
425 library_id_(std::move(library_id)) {}
426
428
429} // namespace gpu
430} // namespace flutter
431
432//----------------------------------------------------------------------------
433/// Exports
434///
435
437 Dart_Handle wrapper,
438 Dart_Handle asset_name) {
439 if (!Dart_IsString(asset_name)) {
440 return tonic::ToDart("Asset name must be a string");
441 }
442
443 std::optional<std::string> out_error;
444 auto impeller_context = flutter::gpu::Context::GetDefaultContext(out_error);
445 if (out_error.has_value()) {
446 return tonic::ToDart(out_error.value());
447 }
448
449 std::string error;
451 impeller_context->GetBackendType(), tonic::StdStringFromDart(asset_name),
452 error);
453 if (!res) {
454 return tonic::ToDart(error);
455 }
456 res->AssociateWithDartWrapper(wrapper);
457 return Dart_Null();
458}
459
462 Dart_Handle asset_name) {
463 if (!Dart_IsString(asset_name)) {
464 return tonic::ToDart("Asset name must be a string");
465 }
466
467 std::optional<std::string> out_error;
468 auto impeller_context = flutter::gpu::Context::GetDefaultContext(out_error);
469 if (out_error.has_value()) {
470 return tonic::ToDart(out_error.value());
471 }
472
473 std::string error = wrapper->ReloadFromAsset(
474 impeller_context->GetBackendType(), tonic::StdStringFromDart(asset_name));
475 if (!error.empty()) {
476 return tonic::ToDart(error);
477 }
478 return Dart_Null();
479}
480
483 Dart_Handle shader_name,
484 Dart_Handle shader_wrapper) {
485 FML_DCHECK(Dart_IsString(shader_name));
486 auto shader =
487 wrapper->GetShader(tonic::StdStringFromDart(shader_name), shader_wrapper);
488 if (!shader) {
489 return Dart_Null();
490 }
491 return tonic::ToDart(shader.get());
492}
static UIDartState * Current()
static std::shared_ptr< impeller::Context > GetDefaultContext(std::optional< std::string > &out_error)
Definition context.cc:39
static fml::RefPtr< Shader > Make(std::string library_id, std::string entrypoint, impeller::ShaderStage stage, std::shared_ptr< fml::Mapping > code_mapping, std::vector< impeller::ShaderStageIOSlot > inputs, std::vector< impeller::ShaderStageBufferLayout > layouts, std::unordered_map< std::string, UniformBinding > uniform_structs, std::unordered_map< std::string, TextureBinding > uniform_textures, std::vector< impeller::DescriptorSetLayout > descriptor_set_layouts)
Definition shader.cc:41
An immutable collection of shaders loaded from a shader bundle asset.
static void SetOverride(fml::RefPtr< ShaderLibrary > override_shader_library)
Sets a return override for MakeFromAsset for testing purposes.
std::string ReloadFromFlatbuffer(impeller::Context::BackendType backend_type, std::shared_ptr< fml::Mapping > payload)
static fml::RefPtr< ShaderLibrary > MakeFromAsset(impeller::Context::BackendType backend_type, const std::string &name, std::string &out_error)
static fml::RefPtr< ShaderLibrary > MakeFromFlatbuffer(impeller::Context::BackendType backend_type, std::shared_ptr< fml::Mapping > payload, std::string library_id="")
static fml::RefPtr< ShaderLibrary > MakeFromShaders(ShaderMap shaders)
std::string ReloadFromAsset(impeller::Context::BackendType backend_type, const std::string &name)
std::unordered_map< std::string, fml::RefPtr< Shader > > ShaderMap
fml::RefPtr< Shader > GetShader(const std::string &shader_name, Dart_Handle shader_wrapper)
static int input(yyscan_t yyscanner)
#define IMPLEMENT_WRAPPERTYPEINFO(LibraryName, ClassName)
const uint8_t uint32_t uint32_t GError ** error
#define FML_UNREACHABLE()
Definition logging.h:128
#define FML_DCHECK(condition)
Definition logging.h:122
Dart_Handle InternalFlutterGpu_ShaderLibrary_InitializeWithAsset(Dart_Handle wrapper, Dart_Handle asset_name)
Dart_Handle InternalFlutterGpu_ShaderLibrary_GetShader(flutter::gpu::ShaderLibrary *wrapper, Dart_Handle shader_name, Dart_Handle shader_wrapper)
Dart_Handle InternalFlutterGpu_ShaderLibrary_ReinitializeWithAsset(flutter::gpu::ShaderLibrary *wrapper, Dart_Handle asset_name)
static const impeller::fb::shaderbundle::BackendShader * GetShaderBackend(impeller::Context::BackendType backend_type, const impeller::fb::shaderbundle::Shader *shader)
static impeller::ShaderType FromUniformType(impeller::fb::shaderbundle::UniformDataType uniform_type)
static impeller::ShaderType FromInputType(impeller::fb::shaderbundle::InputDataType input_type)
static ShaderLibrary::ShaderMap ParseShaderBundle(impeller::Context::BackendType backend_type, const std::shared_ptr< fml::Mapping > &payload, const std::string &library_id)
static impeller::ShaderStage ToShaderStage(impeller::fb::shaderbundle::ShaderStage stage)
static size_t SizeOfInputType(impeller::fb::shaderbundle::InputDataType input_type)
DEF_SWITCHES_START aot vmservice shared library name
Definition switch_defs.h:27
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition switch_defs.h:71
constexpr std::optional< ShaderFloatType > DeriveShaderFloatType(ShaderType type, size_t vec_size, size_t columns)
Derive the ShaderFloatType from the base ShaderType and the (vec_size, columns) dimensions reported b...
Definition ref_ptr.h:261
Dart_Handle ToDart(const T &object)
std::string StdStringFromDart(Dart_Handle handle)
impeller::ShaderType type
impeller::SampledImageSlot slot
Definition shader.h:38
impeller::ShaderMetadata metadata
Definition shader.h:39
impeller::ShaderUniformSlot slot
Definition shader.h:29
Metadata required to bind a combined texture and sampler.
const char * name
The name of the uniform slot.
static std::string MakeFallbackLibraryId()
Definition shader_key.cc:14
Metadata required to bind a buffer.
const char * name
The name of the uniform slot.
#define VALIDATION_LOG
Definition validation.h:91