Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 1dce56c

Browse files
committed
[fuchsia][shader warmup] fix for fxbug.dev/90387
Warmup surface was being initialized on the platform thread rather than the raster thread which was causing races in the skia cache, this change just moves the warmup surface intiialization to the raster thread. This change also addresses another minor problem where invoking shader warmup with 0 skps would drop the callback on the floor and that would cause the dart future to hang forever. Simply invoke the dart future if no SKP's are provided.
1 parent e444009 commit 1dce56c

File tree

2 files changed

+59
-26
lines changed

2 files changed

+59
-26
lines changed

shell/platform/fuchsia/flutter/engine.cc

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -860,25 +860,34 @@ void Engine::WarmupSkps(
860860
SkISize size,
861861
std::shared_ptr<flutter::AssetManager> asset_manager,
862862
std::optional<const std::vector<std::string>> skp_names,
863-
std::optional<std::function<void(uint32_t)>> completion_callback) {
864-
// We use a raw pointer here because we want to keep this alive until all gpu
865-
// work is done and the callbacks skia takes for this are function pointers
866-
// so we are unable to use a lambda that captures the smart pointer.
867-
SurfaceProducerSurface* skp_warmup_surface =
868-
surface_producer->ProduceOffscreenSurface(size).release();
869-
if (!skp_warmup_surface) {
870-
FML_LOG(ERROR) << "Failed to create offscreen warmup surface";
871-
// Tell client that zero shaders were warmed up because warmup failed.
872-
if (completion_callback.has_value() && completion_callback.value()) {
873-
completion_callback.value()(0);
863+
std::optional<std::function<void(uint32_t)>> maybe_completion_callback) {
864+
// Wrap the optional validity checks up in a lambda to simplify the various
865+
// callsites below
866+
auto completion_callback = [maybe_completion_callback](uint32_t skp_count) {
867+
if (maybe_completion_callback.has_value() &&
868+
maybe_completion_callback.value()) {
869+
maybe_completion_callback.value()(skp_count);
874870
}
875-
return;
876-
}
871+
};
872+
873+
// We use this bizzare raw pointer to a smart pointer thing here because we
874+
// want to keep the surface alive until all gpu work is done and the
875+
// callbacks skia takes for this are function pointers so we are unable to
876+
// use a lambda that captures the smart pointer. We need two levels of
877+
// indirection because it needs to be the same across all invocations of the
878+
// raster task lambda from a single invocation of WarmupSkps, but be
879+
// different across different invocations of WarmupSkps (so we cant
880+
// statically initialialize it in the lambda itself). Basically the result
881+
// of a mashup of wierd call dynamics, multithreading, and lifecycle
882+
// management with C style Skia callbacks.
883+
std::unique_ptr<SurfaceProducerSurface>* skp_warmup_surface =
884+
new std::unique_ptr<SurfaceProducerSurface>(nullptr);
877885

878886
// tell concurrent task runner to deserialize all skps available from
879887
// the asset manager
880-
concurrent_task_runner->PostTask([raster_task_runner, skp_warmup_surface,
881-
surface_producer, asset_manager, skp_names,
888+
concurrent_task_runner->PostTask([raster_task_runner, size,
889+
skp_warmup_surface, surface_producer,
890+
asset_manager, skp_names,
882891
completion_callback]() {
883892
TRACE_DURATION("flutter", "DeserializeSkps");
884893
std::vector<std::unique_ptr<fml::Mapping>> skp_mappings;
@@ -895,6 +904,13 @@ void Engine::WarmupSkps(
895904
skp_mappings = asset_manager->GetAsMappings(".*\\.skp$", "shaders");
896905
}
897906

907+
if (skp_mappings.size() == 0) {
908+
FML_LOG(WARNING)
909+
<< "Engine::WarmupSkps got zero SKP mappings, returning early";
910+
completion_callback(0);
911+
return;
912+
}
913+
898914
size_t total_size = 0;
899915
for (auto& mapping : skp_mappings) {
900916
total_size += mapping->GetSize();
@@ -920,20 +936,35 @@ void Engine::WarmupSkps(
920936

921937
// Tell raster task runner to warmup have the compositor
922938
// context warm up the newly deserialized picture
923-
raster_task_runner->PostTask([skp_warmup_surface, picture,
939+
raster_task_runner->PostTask([picture, skp_warmup_surface, size,
924940
surface_producer, completion_callback, i,
925941
count = skp_mappings.size()] {
926942
TRACE_DURATION("flutter", "WarmupSkp");
927-
skp_warmup_surface->GetSkiaSurface()->getCanvas()->drawPicture(picture);
943+
if (*skp_warmup_surface == nullptr) {
944+
skp_warmup_surface->reset(
945+
surface_producer->ProduceOffscreenSurface(size).release());
946+
947+
if (*skp_warmup_surface == nullptr) {
948+
FML_LOG(ERROR) << "Failed to create offscreen warmup surface";
949+
// Tell client that zero shaders were warmed up because warmup
950+
// failed.
951+
completion_callback(0);
952+
return;
953+
}
954+
}
955+
956+
// Do the actual warmup
957+
(*skp_warmup_surface)
958+
->GetSkiaSurface()
959+
->getCanvas()
960+
->drawPicture(picture);
928961

929962
if (i == count - 1) {
930963
// We call this here instead of inside fFinishedProc below because
931964
// we want to unblock the dart animation code as soon as the raster
932965
// thread is free to enque work, rather than waiting for the GPU work
933966
// itself to finish.
934-
if (completion_callback.has_value() && completion_callback.value()) {
935-
completion_callback.value()(count);
936-
}
967+
completion_callback(count);
937968
}
938969

939970
if (surface_producer->gr_context()) {

shell/platform/fuchsia/flutter/tests/engine_unittests.cc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class EngineTest : public ::testing::Test {
6969
std::optional<std::function<void(uint32_t)>> completion_callback) {
7070
// Have to create a message loop so default async dispatcher gets set,
7171
// otherwise we segfault creating the VulkanSurfaceProducer
72-
auto loop = fml::MessageLoopImpl::Create();
72+
loop_ = fml::MessageLoopImpl::Create();
7373

7474
context_ = sys::ComponentContext::CreateAndServeOutgoingDirectory();
7575
scenic_ = context_->svc()->Connect<fuchsia::ui::scenic::Scenic>();
@@ -79,10 +79,11 @@ class EngineTest : public ::testing::Test {
7979

8080
Engine::WarmupSkps(&concurrent_task_runner_, &raster_task_runner_,
8181
surface_producer_, SkISize::Make(width, height),
82-
asset_manager, std::nullopt, std::nullopt);
82+
asset_manager, skp_names, completion_callback);
8383
}
8484

8585
protected:
86+
fml::RefPtr<fml::MessageLoopImpl> loop_;
8687
MockTaskRunner concurrent_task_runner_;
8788
MockTaskRunner raster_task_runner_;
8889
std::shared_ptr<VulkanSurfaceProducer> surface_producer_;
@@ -163,7 +164,7 @@ TEST_F(EngineTest, SkpWarmup) {
163164
std::make_unique<DirectoryAssetBundle>(std::move(asset_dir_fd), false));
164165

165166
WarmupSkps(draw_size.width(), draw_size.height(), asset_manager, std::nullopt,
166-
std::nullopt);
167+
[](uint32_t count) { EXPECT_EQ(1u, count); });
167168
concurrent_task_runner_.Run();
168169
raster_task_runner_.Run();
169170

@@ -196,8 +197,9 @@ TEST_F(EngineTest, SkpWarmupAsync) {
196197
fml::ScopedTemporaryDirectory asset_dir;
197198
fml::UniqueFD asset_dir_fd = fml::OpenDirectory(
198199
asset_dir.path().c_str(), false, fml::FilePermission::kRead);
199-
fml::UniqueFD subdir_fd = fml::OpenDirectory(asset_dir_fd, "shaders", true,
200-
fml::FilePermission::kReadWrite);
200+
std::string subdir_name = "shaders";
201+
fml::UniqueFD subdir_fd = fml::OpenDirectory(
202+
asset_dir_fd, subdir_name.c_str(), true, fml::FilePermission::kReadWrite);
201203
std::string skp_name = "test.skp";
202204

203205
bool success = fml::WriteAtomically(subdir_fd, skp_name.c_str(), mapping);
@@ -207,7 +209,7 @@ TEST_F(EngineTest, SkpWarmupAsync) {
207209
asset_manager->PushBack(
208210
std::make_unique<DirectoryAssetBundle>(std::move(asset_dir_fd), false));
209211

210-
std::vector<std::string> skp_names = {skp_name};
212+
std::vector<std::string> skp_names = {subdir_name + "/" + skp_name};
211213

212214
WarmupSkps(draw_size.width(), draw_size.height(), asset_manager, skp_names,
213215
[](uint32_t count) { EXPECT_EQ(1u, count); });

0 commit comments

Comments
 (0)