Flutter Engine
The Flutter Engine
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
5#include "flutter/lib/gpu/shader_library.h"
6
7#include <optional>
8#include <utility>
9
10#include "flutter/assets/asset_manager.h"
11#include "flutter/lib/gpu/fixtures.h"
12#include "flutter/lib/gpu/shader.h"
13#include "flutter/lib/ui/ui_dart_state.h"
14#include "flutter/lib/ui/window/platform_configuration.h"
15#include "fml/mapping.h"
16#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));
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#ifdef FML_OS_ANDROID
168 return shader->opengl_es();
169#else
170 return shader->opengl_desktop();
171#endif
173 return shader->vulkan();
174 }
175}
176
179 std::shared_ptr<fml::Mapping> payload) {
180 if (payload == nullptr || !payload->GetMapping()) {
181 return nullptr;
182 }
183 if (!impeller::fb::shaderbundle::ShaderBundleBufferHasIdentifier(
184 payload->GetMapping())) {
185 return nullptr;
186 }
187 auto* bundle =
188 impeller::fb::shaderbundle::GetShaderBundle(payload->GetMapping());
189 if (!bundle) {
190 return nullptr;
191 }
192
193 ShaderLibrary::ShaderMap shader_map;
194
195 for (const auto* bundled_shader : *bundle->shaders()) {
196 const impeller::fb::shaderbundle::BackendShader* backend_shader =
197 GetShaderBackend(backend_type, bundled_shader);
198 if (!backend_shader) {
199 VALIDATION_LOG << "Failed to unpack shader \""
200 << bundled_shader->name()->c_str() << "\" from bundle.";
201 continue;
202 }
203
204 auto code_mapping = std::make_shared<fml::NonOwnedMapping>(
205 backend_shader->shader()->data(), //
206 backend_shader->shader()->size(), //
207 [payload = payload](auto, auto) {} //
208 );
209
210 std::unordered_map<std::string, Shader::UniformBinding> uniform_structs;
211 if (backend_shader->uniform_structs() != nullptr) {
212 for (const auto& uniform : *backend_shader->uniform_structs()) {
213 std::vector<impeller::ShaderStructMemberMetadata> members;
214 if (uniform->fields() != nullptr) {
215 for (const auto& struct_member : *uniform->fields()) {
216 members.push_back(impeller::ShaderStructMemberMetadata{
217 .type = FromUniformType(struct_member->type()),
218 .name = struct_member->name()->c_str(),
219 .offset = static_cast<size_t>(struct_member->offset_in_bytes()),
220 .size =
221 static_cast<size_t>(struct_member->element_size_in_bytes()),
222 .byte_length =
223 static_cast<size_t>(struct_member->total_size_in_bytes()),
224 .array_elements =
225 struct_member->array_elements() != 0
226 ? std::optional<size_t>(std::nullopt)
227 : static_cast<size_t>(struct_member->array_elements()),
228 });
229 }
230 }
231
232 uniform_structs[uniform->name()->str()] = Shader::UniformBinding{
233 .slot =
235 .name = uniform->name()->c_str(),
236 .ext_res_0 = static_cast<size_t>(uniform->ext_res_0()),
237 .set = static_cast<size_t>(uniform->set()),
238 .binding = static_cast<size_t>(uniform->binding()),
239 },
240 .metadata =
242 .name = uniform->name()->c_str(),
243 .members = members,
244 },
245 .size_in_bytes = static_cast<size_t>(uniform->size_in_bytes()),
246 };
247 }
248 }
249
250 std::unordered_map<std::string, impeller::SampledImageSlot>
251 uniform_textures;
252 if (backend_shader->uniform_textures() != nullptr) {
253 for (const auto& uniform : *backend_shader->uniform_textures()) {
254 uniform_textures[uniform->name()->str()] = impeller::SampledImageSlot{
255 .name = uniform->name()->c_str(),
256 .texture_index = static_cast<size_t>(uniform->ext_res_0()),
257 .set = static_cast<size_t>(uniform->set()),
258 .binding = static_cast<size_t>(uniform->binding()),
259 };
260 }
261 }
262
263 std::shared_ptr<impeller::VertexDescriptor> vertex_descriptor = nullptr;
264 if (backend_shader->stage() ==
265 impeller::fb::shaderbundle::ShaderStage::kVertex) {
266 vertex_descriptor = std::make_shared<impeller::VertexDescriptor>();
267 auto inputs_fb = backend_shader->inputs();
268
269 std::vector<impeller::ShaderStageIOSlot> inputs;
270 inputs.reserve(inputs_fb->size());
271 size_t default_stride = 0;
272 for (const auto& input : *inputs_fb) {
274 slot.name = input->name()->c_str();
275 slot.location = input->location();
276 slot.set = input->set();
277 slot.binding = input->binding();
278 slot.type = FromInputType(input->type());
279 slot.bit_width = input->bit_width();
280 slot.vec_size = input->vec_size();
281 slot.columns = input->columns();
282 slot.offset = input->offset();
283 inputs.emplace_back(slot);
284
285 default_stride +=
286 SizeOfInputType(input->type()) * slot.vec_size * slot.columns;
287 }
288 std::vector<impeller::ShaderStageBufferLayout> layouts = {
290 .stride = default_stride,
291 .binding = 0u,
292 }};
293
294 vertex_descriptor->SetStageInputs(inputs, layouts);
295 }
296
297 auto shader = flutter::gpu::Shader::Make(
298 backend_shader->entrypoint()->str(),
299 ToShaderStage(backend_shader->stage()), std::move(code_mapping),
300 std::move(vertex_descriptor), std::move(uniform_structs),
301 std::move(uniform_textures));
302 shader_map[bundled_shader->name()->str()] = std::move(shader);
303 }
304
305 return fml::MakeRefCounted<flutter::gpu::ShaderLibrary>(
306 std::move(payload), std::move(shader_map));
307}
308
310 fml::RefPtr<ShaderLibrary> override_shader_library) {
311 override_shader_library_ = std::move(override_shader_library);
312}
313
314fml::RefPtr<Shader> ShaderLibrary::GetShader(const std::string& shader_name,
315 Dart_Handle shader_wrapper) const {
316 auto it = shaders_.find(shader_name);
317 if (it == shaders_.end()) {
318 return nullptr; // No matching shaders.
319 }
320 auto shader = it->second;
321
322 if (shader->dart_wrapper() == nullptr) {
323 shader->AssociateWithDartWrapper(shader_wrapper);
324 }
325 return shader;
326}
327
328ShaderLibrary::ShaderLibrary(std::shared_ptr<fml::Mapping> payload,
329 ShaderMap shaders)
330 : payload_(std::move(payload)), shaders_(std::move(shaders)) {}
331
333
334} // namespace gpu
335} // namespace flutter
336
337//----------------------------------------------------------------------------
338/// Exports
339///
340
342 Dart_Handle wrapper,
343 Dart_Handle asset_name) {
344 if (!Dart_IsString(asset_name)) {
345 return tonic::ToDart("Asset name must be a string");
346 }
347
348 std::optional<std::string> out_error;
349 auto impeller_context = flutter::gpu::Context::GetDefaultContext(out_error);
350 if (out_error.has_value()) {
351 return tonic::ToDart(out_error.value());
352 }
353
354 std::string error;
356 impeller_context->GetBackendType(), tonic::StdStringFromDart(asset_name),
357 error);
358 if (!res) {
359 return tonic::ToDart(error);
360 }
361 res->AssociateWithDartWrapper(wrapper);
362 return Dart_Null();
363}
364
367 Dart_Handle shader_name,
368 Dart_Handle shader_wrapper) {
369 FML_DCHECK(Dart_IsString(shader_name));
370 auto shader =
371 wrapper->GetShader(tonic::StdStringFromDart(shader_name), shader_wrapper);
372 if (!shader) {
373 return Dart_Null();
374 }
375 return tonic::ToDart(shader.get());
376}
static UIDartState * Current()
static std::shared_ptr< impeller::Context > GetDefaultContext(std::optional< std::string > &out_error)
Definition context.cc:29
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 fml::RefPtr< Shader > Make(std::string entrypoint, impeller::ShaderStage stage, std::shared_ptr< fml::Mapping > code_mapping, std::shared_ptr< impeller::VertexDescriptor > vertex_desc, std::unordered_map< std::string, UniformBinding > uniform_structs, std::unordered_map< std::string, impeller::SampledImageSlot > uniform_textures)
Definition shader.cc:38
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
DART_EXPORT Dart_Handle Dart_Null(void)
DART_EXPORT bool Dart_IsString(Dart_Handle object)
#define IMPLEMENT_WRAPPERTYPEINFO(LibraryName, ClassName)
const uint8_t uint32_t uint32_t GError ** error
#define FML_UNREACHABLE()
Definition logging.h:109
#define FML_DCHECK(condition)
Definition logging.h:103
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)
DEF_SWITCHES_START aot vmservice shared library name
Definition switches.h:32
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 switches.h:41
it will be possible to load the file into Perfetto s trace viewer 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
Definition switches.h:259
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 switches.h:76
Definition ref_ptr.h:256
Dart_Handle ToDart(const T &object)
std::string StdStringFromDart(Dart_Handle handle)
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:73