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"
18#include "impeller/shader_bundle/shader_bundle_flatbuffers.h"
19#include "lib/gpu/context.h"
20
21namespace flutter {
22namespace gpu {
23
25
26fml::RefPtr<ShaderLibrary> ShaderLibrary::override_shader_library_;
27
30 const std::string& name,
31 std::string& out_error) {
32 if (override_shader_library_) {
33 return override_shader_library_;
34 }
35
36 auto dart_state = UIDartState::Current();
37 std::shared_ptr<AssetManager> asset_manager =
38 dart_state->platform_configuration()->client()->GetAssetManager();
39
40 std::unique_ptr<fml::Mapping> data = asset_manager->GetAsMapping(name);
41 if (data == nullptr) {
42 out_error = std::string("Asset '") + name + std::string("' not found.");
43 return nullptr;
44 }
45
46 return MakeFromFlatbuffer(backend_type, std::move(data));
47}
48
50 return fml::MakeRefCounted<flutter::gpu::ShaderLibrary>(nullptr,
51 std::move(shaders));
52}
53
55 impeller::fb::shaderbundle::ShaderStage stage) {
56 switch (stage) {
57 case impeller::fb::shaderbundle::ShaderStage::kVertex:
59 case impeller::fb::shaderbundle::ShaderStage::kFragment:
61 case impeller::fb::shaderbundle::ShaderStage::kCompute:
63 }
65}
66
68 impeller::fb::shaderbundle::InputDataType input_type) {
69 switch (input_type) {
70 case impeller::fb::shaderbundle::InputDataType::kBoolean:
72 case impeller::fb::shaderbundle::InputDataType::kSignedByte:
74 case impeller::fb::shaderbundle::InputDataType::kUnsignedByte:
76 case impeller::fb::shaderbundle::InputDataType::kSignedShort:
78 case impeller::fb::shaderbundle::InputDataType::kUnsignedShort:
80 case impeller::fb::shaderbundle::InputDataType::kSignedInt:
82 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt:
84 case impeller::fb::shaderbundle::InputDataType::kSignedInt64:
86 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt64:
88 case impeller::fb::shaderbundle::InputDataType::kFloat:
90 case impeller::fb::shaderbundle::InputDataType::kDouble:
92 }
93}
94
96 impeller::fb::shaderbundle::UniformDataType uniform_type) {
97 switch (uniform_type) {
98 case impeller::fb::shaderbundle::UniformDataType::kBoolean:
100 case impeller::fb::shaderbundle::UniformDataType::kSignedByte:
102 case impeller::fb::shaderbundle::UniformDataType::kUnsignedByte:
104 case impeller::fb::shaderbundle::UniformDataType::kSignedShort:
106 case impeller::fb::shaderbundle::UniformDataType::kUnsignedShort:
108 case impeller::fb::shaderbundle::UniformDataType::kSignedInt:
110 case impeller::fb::shaderbundle::UniformDataType::kUnsignedInt:
112 case impeller::fb::shaderbundle::UniformDataType::kSignedInt64:
114 case impeller::fb::shaderbundle::UniformDataType::kUnsignedInt64:
116 case impeller::fb::shaderbundle::UniformDataType::kFloat:
118 case impeller::fb::shaderbundle::UniformDataType::kDouble:
120 case impeller::fb::shaderbundle::UniformDataType::kHalfFloat:
122 case impeller::fb::shaderbundle::UniformDataType::kSampledImage:
124 }
125}
126
127static size_t SizeOfInputType(
128 impeller::fb::shaderbundle::InputDataType input_type) {
129 switch (input_type) {
130 case impeller::fb::shaderbundle::InputDataType::kBoolean:
131 return 1;
132 case impeller::fb::shaderbundle::InputDataType::kSignedByte:
133 return 1;
134 case impeller::fb::shaderbundle::InputDataType::kUnsignedByte:
135 return 1;
136 case impeller::fb::shaderbundle::InputDataType::kSignedShort:
137 return 2;
138 case impeller::fb::shaderbundle::InputDataType::kUnsignedShort:
139 return 2;
140 case impeller::fb::shaderbundle::InputDataType::kSignedInt:
141 return 4;
142 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt:
143 return 4;
144 case impeller::fb::shaderbundle::InputDataType::kSignedInt64:
145 return 8;
146 case impeller::fb::shaderbundle::InputDataType::kUnsignedInt64:
147 return 8;
148 case impeller::fb::shaderbundle::InputDataType::kFloat:
149 return 4;
150 case impeller::fb::shaderbundle::InputDataType::kDouble:
151 return 8;
152 }
153}
154
155static const impeller::fb::shaderbundle::BackendShader* GetShaderBackend(
157 const impeller::fb::shaderbundle::Shader* shader) {
158 switch (backend_type) {
160#ifdef FML_OS_IOS
161 return shader->metal_ios();
162#else
163 return shader->metal_desktop();
164#endif
166 return shader->opengl_es();
168 return shader->vulkan();
169 }
170}
171
174 std::shared_ptr<fml::Mapping> payload) {
175 if (payload == nullptr || !payload->GetMapping()) {
176 return nullptr;
177 }
178 if (!impeller::fb::shaderbundle::ShaderBundleBufferHasIdentifier(
179 payload->GetMapping())) {
180 return nullptr;
181 }
182 auto* bundle =
183 impeller::fb::shaderbundle::GetShaderBundle(payload->GetMapping());
184 if (!bundle) {
185 return nullptr;
186 }
187
188 const auto version = bundle->format_version();
189 const auto expected = static_cast<uint32_t>(
190 impeller::fb::shaderbundle::ShaderBundleFormatVersion::kVersion);
191 if (version != expected) {
192 VALIDATION_LOG << "Unsupported shader bundle format version: " << version
193 << ", expected: " << expected;
194 return nullptr;
195 }
196
197 ShaderLibrary::ShaderMap shader_map;
198
199 for (const auto* bundled_shader : *bundle->shaders()) {
200 const impeller::fb::shaderbundle::BackendShader* backend_shader =
201 GetShaderBackend(backend_type, bundled_shader);
202 if (!backend_shader) {
203 VALIDATION_LOG << "Failed to unpack shader \""
204 << bundled_shader->name()->c_str() << "\" from bundle.";
205 continue;
206 }
207
208 auto code_mapping = std::make_shared<fml::NonOwnedMapping>(
209 backend_shader->shader()->data(), //
210 backend_shader->shader()->size(), //
211 [payload = payload](auto, auto) {} //
212 );
213
214 std::vector<impeller::DescriptorSetLayout> descriptor_set_layouts;
215
216 std::unordered_map<std::string, Shader::UniformBinding> uniform_structs;
217 if (backend_shader->uniform_structs() != nullptr) {
218 for (const auto& uniform : *backend_shader->uniform_structs()) {
219 std::vector<impeller::ShaderStructMemberMetadata> members;
220 if (uniform->fields() != nullptr) {
221 for (const auto& struct_member : *uniform->fields()) {
222 members.push_back(impeller::ShaderStructMemberMetadata{
223 .type = FromUniformType(struct_member->type()),
224 .name = struct_member->name()->c_str(),
225 .offset = static_cast<size_t>(struct_member->offset_in_bytes()),
226 .size =
227 static_cast<size_t>(struct_member->element_size_in_bytes()),
228 .byte_length =
229 static_cast<size_t>(struct_member->total_size_in_bytes()),
230 .array_elements =
231 struct_member->array_elements() == 0
232 ? std::optional<size_t>(std::nullopt)
233 : static_cast<size_t>(struct_member->array_elements()),
234 });
235 }
236 }
237
238 uniform_structs[uniform->name()->str()] = Shader::UniformBinding{
239 .slot =
241 .name = uniform->name()->c_str(),
242 .ext_res_0 = static_cast<size_t>(uniform->ext_res_0()),
243 .set = static_cast<size_t>(uniform->set()),
244 .binding = static_cast<size_t>(uniform->binding()),
245 },
246 .metadata =
248 .name = uniform->name()->c_str(),
249 .members = members,
250 },
251 .size_in_bytes = static_cast<size_t>(uniform->size_in_bytes()),
252 };
253
254 descriptor_set_layouts.push_back(impeller::DescriptorSetLayout{
255 static_cast<uint32_t>(uniform->binding()),
257 ToShaderStage(backend_shader->stage()),
258 });
259 }
260 }
261
262 std::unordered_map<std::string, Shader::TextureBinding> uniform_textures;
263 if (backend_shader->uniform_textures() != nullptr) {
264 for (const auto& uniform : *backend_shader->uniform_textures()) {
265 Shader::TextureBinding texture_binding;
266 texture_binding.slot = impeller::SampledImageSlot{
267 .name = uniform->name()->c_str(),
268 .texture_index = static_cast<size_t>(uniform->ext_res_0()),
269 .set = static_cast<size_t>(uniform->set()),
270 .binding = static_cast<size_t>(uniform->binding()),
271 };
272 texture_binding.metadata = impeller::ShaderMetadata{
273 .name = uniform->name()->c_str(),
274 .members = {},
275 };
276
277 uniform_textures[uniform->name()->str()] = texture_binding;
278
279 descriptor_set_layouts.push_back(impeller::DescriptorSetLayout{
280 static_cast<uint32_t>(uniform->binding()),
282 ToShaderStage(backend_shader->stage()),
283 });
284 }
285 }
286
287 std::vector<impeller::ShaderStageIOSlot> inputs;
288 std::vector<impeller::ShaderStageBufferLayout> layouts;
289 if (backend_shader->stage() ==
290 impeller::fb::shaderbundle::ShaderStage::kVertex) {
291 auto inputs_fb = backend_shader->inputs();
292
293 inputs.reserve(inputs_fb->size());
294 size_t default_stride = 0;
295 for (const auto& input : *inputs_fb) {
297 slot.name = input->name()->c_str();
298 slot.location = input->location();
299 slot.set = input->set();
300 slot.binding = input->binding();
301 slot.type = FromInputType(input->type());
302 slot.bit_width = input->bit_width();
303 slot.vec_size = input->vec_size();
304 slot.columns = input->columns();
305 slot.offset = input->offset();
306 inputs.emplace_back(slot);
307
308 default_stride +=
309 SizeOfInputType(input->type()) * slot.vec_size * slot.columns;
310 }
312 .stride = default_stride,
313 .binding = 0u,
314 }};
315 }
316
317 auto shader = flutter::gpu::Shader::Make(
318 backend_shader->entrypoint()->str(),
319 ToShaderStage(backend_shader->stage()), std::move(code_mapping),
320 std::move(inputs), std::move(layouts), std::move(uniform_structs),
321 std::move(uniform_textures), std::move(descriptor_set_layouts));
322 shader_map[bundled_shader->name()->str()] = std::move(shader);
323 }
324
325 return fml::MakeRefCounted<flutter::gpu::ShaderLibrary>(
326 std::move(payload), std::move(shader_map));
327}
328
330 fml::RefPtr<ShaderLibrary> override_shader_library) {
331 override_shader_library_ = std::move(override_shader_library);
332}
333
334fml::RefPtr<Shader> ShaderLibrary::GetShader(const std::string& shader_name,
335 Dart_Handle shader_wrapper) const {
336 auto it = shaders_.find(shader_name);
337 if (it == shaders_.end()) {
338 return nullptr; // No matching shaders.
339 }
340 auto shader = it->second;
341
342 if (shader->dart_wrapper() == nullptr) {
343 shader->AssociateWithDartWrapper(shader_wrapper);
344 }
345 return shader;
346}
347
348ShaderLibrary::ShaderLibrary(std::shared_ptr<fml::Mapping> payload,
349 ShaderMap shaders)
350 : payload_(std::move(payload)), shaders_(std::move(shaders)) {}
351
353
354} // namespace gpu
355} // namespace flutter
356
357//----------------------------------------------------------------------------
358/// Exports
359///
360
362 Dart_Handle wrapper,
363 Dart_Handle asset_name) {
364 if (!Dart_IsString(asset_name)) {
365 return tonic::ToDart("Asset name must be a string");
366 }
367
368 std::optional<std::string> out_error;
369 auto impeller_context = flutter::gpu::Context::GetDefaultContext(out_error);
370 if (out_error.has_value()) {
371 return tonic::ToDart(out_error.value());
372 }
373
374 std::string error;
376 impeller_context->GetBackendType(), tonic::StdStringFromDart(asset_name),
377 error);
378 if (!res) {
379 return tonic::ToDart(error);
380 }
381 res->AssociateWithDartWrapper(wrapper);
382 return Dart_Null();
383}
384
387 Dart_Handle shader_name,
388 Dart_Handle shader_wrapper) {
389 FML_DCHECK(Dart_IsString(shader_name));
390 auto shader =
391 wrapper->GetShader(tonic::StdStringFromDart(shader_name), shader_wrapper);
392 if (!shader) {
393 return Dart_Null();
394 }
395 return tonic::ToDart(shader.get());
396}
static UIDartState * Current()
static std::shared_ptr< impeller::Context > GetDefaultContext(std::optional< std::string > &out_error)
Definition context.cc:36
static fml::RefPtr< Shader > Make(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:38
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.
static fml::RefPtr< ShaderLibrary > MakeFromAsset(impeller::Context::BackendType backend_type, const std::string &name, std::string &out_error)
static fml::RefPtr< ShaderLibrary > MakeFromShaders(ShaderMap shaders)
static fml::RefPtr< ShaderLibrary > MakeFromFlatbuffer(impeller::Context::BackendType backend_type, std::shared_ptr< fml::Mapping > payload)
std::unordered_map< std::string, fml::RefPtr< Shader > > ShaderMap
fml::RefPtr< Shader > GetShader(const std::string &shader_name, Dart_Handle shader_wrapper) const
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)
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 impeller::ShaderStage ToShaderStage(impeller::fb::shaderbundle::ShaderStage stage)
static size_t SizeOfInputType(impeller::fb::shaderbundle::InputDataType input_type)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
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
Definition ref_ptr.h:261
Dart_Handle ToDart(const T &object)
std::string StdStringFromDart(Dart_Handle handle)
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.
Metadata required to bind a buffer.
const char * name
The name of the uniform slot.
#define VALIDATION_LOG
Definition validation.h:91