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 std::shared_ptr<fml::Mapping> payload,
176 std::string library_id) {
177 if (payload == nullptr || !payload->GetMapping()) {
178 return nullptr;
179 }
180 if (library_id.empty()) {
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 const auto version = bundle->format_version();
194 const auto expected = static_cast<uint32_t>(
195 impeller::fb::shaderbundle::ShaderBundleFormatVersion::kVersion);
196 if (version != expected) {
197 VALIDATION_LOG << "Unsupported shader bundle format version: " << version
198 << ", expected: " << expected
199 << ". This shader bundle was compiled with an incompatible "
200 "version of impellerc. Please rebuild the shader bundle "
201 "with the version of impellerc that ships with the "
202 "current Flutter SDK.";
203 return nullptr;
204 }
205
206 ShaderLibrary::ShaderMap shader_map;
207
208 for (const auto* bundled_shader : *bundle->shaders()) {
209 const impeller::fb::shaderbundle::BackendShader* backend_shader =
210 GetShaderBackend(backend_type, bundled_shader);
211 if (!backend_shader) {
212 VALIDATION_LOG << "Failed to unpack shader \""
213 << bundled_shader->name()->c_str() << "\" from bundle.";
214 continue;
215 }
216
217 auto code_mapping = std::make_shared<fml::NonOwnedMapping>(
218 backend_shader->shader()->data(), //
219 backend_shader->shader()->size(), //
220 [payload = payload](auto, auto) {} //
221 );
222
223 std::vector<impeller::DescriptorSetLayout> descriptor_set_layouts;
224
225 std::unordered_map<std::string, Shader::UniformBinding> uniform_structs;
226 if (backend_shader->uniform_structs() != nullptr) {
227 for (const auto& uniform : *backend_shader->uniform_structs()) {
228 std::vector<impeller::ShaderStructMemberMetadata> members;
229 if (uniform->fields() != nullptr) {
230 for (const auto& struct_member : *uniform->fields()) {
232 FromUniformType(struct_member->type());
233 members.push_back(impeller::ShaderStructMemberMetadata{
234 .type = type,
235 .name = struct_member->name()->c_str(),
236 .offset = static_cast<size_t>(struct_member->offset_in_bytes()),
237 .size =
238 static_cast<size_t>(struct_member->element_size_in_bytes()),
239 .byte_length =
240 static_cast<size_t>(struct_member->total_size_in_bytes()),
241 .array_elements =
242 struct_member->array_elements() == 0
243 ? std::optional<size_t>(std::nullopt)
244 : static_cast<size_t>(struct_member->array_elements()),
246 type, static_cast<size_t>(struct_member->vec_size()),
247 static_cast<size_t>(struct_member->columns())),
248 });
249 }
250 }
251
252 uniform_structs[uniform->name()->str()] = Shader::UniformBinding{
253 .slot =
255 .name = uniform->name()->c_str(),
256 .ext_res_0 = 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 .metadata =
262 .name = uniform->name()->c_str(),
263 .members = members,
264 },
265 .size_in_bytes = static_cast<size_t>(uniform->size_in_bytes()),
266 };
267
268 descriptor_set_layouts.push_back(impeller::DescriptorSetLayout{
269 static_cast<uint32_t>(uniform->binding()),
271 ToShaderStage(backend_shader->stage()),
272 });
273 }
274 }
275
276 std::unordered_map<std::string, Shader::TextureBinding> uniform_textures;
277 if (backend_shader->uniform_textures() != nullptr) {
278 for (const auto& uniform : *backend_shader->uniform_textures()) {
279 Shader::TextureBinding texture_binding;
280 texture_binding.slot = impeller::SampledImageSlot{
281 .name = uniform->name()->c_str(),
282 .texture_index = static_cast<size_t>(uniform->ext_res_0()),
283 .set = static_cast<size_t>(uniform->set()),
284 .binding = static_cast<size_t>(uniform->binding()),
285 };
286 texture_binding.metadata = impeller::ShaderMetadata{
287 .name = uniform->name()->c_str(),
288 .members = {},
289 };
290
291 uniform_textures[uniform->name()->str()] = texture_binding;
292
293 descriptor_set_layouts.push_back(impeller::DescriptorSetLayout{
294 static_cast<uint32_t>(uniform->binding()),
296 ToShaderStage(backend_shader->stage()),
297 });
298 }
299 }
300
301 std::vector<impeller::ShaderStageIOSlot> inputs;
302 std::vector<impeller::ShaderStageBufferLayout> layouts;
303 if (backend_shader->stage() ==
304 impeller::fb::shaderbundle::ShaderStage::kVertex) {
305 auto inputs_fb = backend_shader->inputs();
306
307 inputs.reserve(inputs_fb->size());
308 size_t default_stride = 0;
309 for (const auto& input : *inputs_fb) {
311 slot.name = input->name()->c_str();
312 slot.location = input->location();
313 slot.set = input->set();
314 slot.binding = input->binding();
315 slot.type = FromInputType(input->type());
316 slot.bit_width = input->bit_width();
317 slot.vec_size = input->vec_size();
318 slot.columns = input->columns();
319 slot.offset = input->offset();
320 inputs.emplace_back(slot);
321
322 default_stride +=
323 SizeOfInputType(input->type()) * slot.vec_size * slot.columns;
324 }
326 .stride = default_stride,
327 .binding = 0u,
328 }};
329 }
330
331 auto shader = flutter::gpu::Shader::Make(
332 library_id, backend_shader->entrypoint()->str(),
333 ToShaderStage(backend_shader->stage()), std::move(code_mapping),
334 std::move(inputs), std::move(layouts), std::move(uniform_structs),
335 std::move(uniform_textures), std::move(descriptor_set_layouts));
336 shader_map[bundled_shader->name()->str()] = std::move(shader);
337 }
338
339 return fml::MakeRefCounted<flutter::gpu::ShaderLibrary>(
340 std::move(payload), std::move(shader_map));
341}
342
344 fml::RefPtr<ShaderLibrary> override_shader_library) {
345 override_shader_library_ = std::move(override_shader_library);
346}
347
348fml::RefPtr<Shader> ShaderLibrary::GetShader(const std::string& shader_name,
349 Dart_Handle shader_wrapper) const {
350 auto it = shaders_.find(shader_name);
351 if (it == shaders_.end()) {
352 return nullptr; // No matching shaders.
353 }
354 auto shader = it->second;
355
356 if (shader->dart_wrapper() == nullptr) {
357 shader->AssociateWithDartWrapper(shader_wrapper);
358 }
359 return shader;
360}
361
362ShaderLibrary::ShaderLibrary(std::shared_ptr<fml::Mapping> payload,
363 ShaderMap shaders)
364 : payload_(std::move(payload)), shaders_(std::move(shaders)) {}
365
367
368} // namespace gpu
369} // namespace flutter
370
371//----------------------------------------------------------------------------
372/// Exports
373///
374
376 Dart_Handle wrapper,
377 Dart_Handle asset_name) {
378 if (!Dart_IsString(asset_name)) {
379 return tonic::ToDart("Asset name must be a string");
380 }
381
382 std::optional<std::string> out_error;
383 auto impeller_context = flutter::gpu::Context::GetDefaultContext(out_error);
384 if (out_error.has_value()) {
385 return tonic::ToDart(out_error.value());
386 }
387
388 std::string error;
390 impeller_context->GetBackendType(), tonic::StdStringFromDart(asset_name),
391 error);
392 if (!res) {
393 return tonic::ToDart(error);
394 }
395 res->AssociateWithDartWrapper(wrapper);
396 return Dart_Null();
397}
398
401 Dart_Handle shader_name,
402 Dart_Handle shader_wrapper) {
403 FML_DCHECK(Dart_IsString(shader_name));
404 auto shader =
405 wrapper->GetShader(tonic::StdStringFromDart(shader_name), shader_wrapper);
406 if (!shader) {
407 return Dart_Null();
408 }
409 return tonic::ToDart(shader.get());
410}
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 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:39
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 > MakeFromFlatbuffer(impeller::Context::BackendType backend_type, std::shared_ptr< fml::Mapping > payload, std::string library_id="")
static fml::RefPtr< ShaderLibrary > MakeFromShaders(ShaderMap shaders)
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)
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