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

Commit 8d1126f

Browse files
committed
[fuchsia] implement SKP based shader warmup
Make Engine load all .skp files from persistent cache and draw them on an offscreen surface to warm up shaders.
1 parent 24b2604 commit 8d1126f

File tree

12 files changed

+224
-15
lines changed

12 files changed

+224
-15
lines changed

fml/concurrent_message_loop.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "flutter/fml/closure.h"
1414
#include "flutter/fml/macros.h"
15+
#include "flutter/fml/task_runner.h"
1516

1617
namespace fml {
1718

@@ -58,13 +59,13 @@ class ConcurrentMessageLoop
5859
FML_DISALLOW_COPY_AND_ASSIGN(ConcurrentMessageLoop);
5960
};
6061

61-
class ConcurrentTaskRunner {
62+
class ConcurrentTaskRunner : public BasicTaskRunner {
6263
public:
6364
ConcurrentTaskRunner(std::weak_ptr<ConcurrentMessageLoop> weak_loop);
6465

65-
~ConcurrentTaskRunner();
66+
virtual ~ConcurrentTaskRunner();
6667

67-
void PostTask(const fml::closure& task);
68+
void PostTask(const fml::closure& task) override;
6869

6970
private:
7071
friend ConcurrentMessageLoop;

fml/task_runner.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@ namespace fml {
1616

1717
class MessageLoopImpl;
1818

19-
class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner> {
19+
class BasicTaskRunner {
20+
public:
21+
virtual void PostTask(const fml::closure& task);
22+
};
23+
24+
class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner>,
25+
public BasicTaskRunner {
2026
public:
2127
virtual ~TaskRunner();
2228

23-
virtual void PostTask(const fml::closure& task);
29+
virtual void PostTask(const fml::closure& task) override;
2430

2531
virtual void PostTaskForTime(const fml::closure& task,
2632
fml::TimePoint target_time);

shell/platform/fuchsia/flutter/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ executable("flutter_runner_unittests") {
449449
"runner_unittest.cc",
450450
"tests/flutter_runner_product_configuration_unittests.cc",
451451
"tests/vsync_recorder_unittests.cc",
452+
"tests/engine_unittests.cc",
452453
"vsync_waiter_unittests.cc",
453454
]
454455

@@ -463,6 +464,7 @@ executable("flutter_runner_unittests") {
463464
"//flutter/shell/common",
464465
"//third_party/dart/runtime:libdart_jit",
465466
"//third_party/dart/runtime/platform:libdart_platform_jit",
467+
"//flutter/assets:assets",
466468
]
467469

468470
deps = [

shell/platform/fuchsia/flutter/compositor_context.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,13 @@ CompositorContext::CompositorContext(
145145
std::shared_ptr<flutter::SceneUpdateContext> scene_update_context)
146146
: session_connection_(session_connection),
147147
surface_producer_(surface_producer),
148-
scene_update_context_(scene_update_context) {}
148+
scene_update_context_(scene_update_context) {
149+
SkISize size = SkISize::Make(1024, 600);
150+
skp_warmup_surface_ = surface_producer_.ProduceOffscreenSurface(size);
151+
if (!skp_warmup_surface_) {
152+
FML_LOG(ERROR) << "SkSurface::MakeRenderTarget returned null";
153+
}
154+
}
149155

150156
CompositorContext::~CompositorContext() = default;
151157

@@ -164,4 +170,9 @@ CompositorContext::AcquireFrame(
164170
session_connection_, surface_producer_, scene_update_context_);
165171
}
166172

173+
void CompositorContext::WarmupSkp(const sk_sp<SkPicture> picture) {
174+
skp_warmup_surface_->getCanvas()->drawPicture(picture);
175+
surface_producer_.gr_context()->flush();
176+
}
177+
167178
} // namespace flutter_runner

shell/platform/fuchsia/flutter/compositor_context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ class CompositorContext final : public flutter::CompositorContext {
2727
std::shared_ptr<flutter::SceneUpdateContext> scene_update_context);
2828

2929
~CompositorContext() override;
30+
void WarmupSkp(sk_sp<SkPicture> picture);
3031

3132
private:
3233
SessionConnection& session_connection_;
3334
VulkanSurfaceProducer& surface_producer_;
3435
std::shared_ptr<flutter::SceneUpdateContext> scene_update_context_;
36+
sk_sp<SkSurface> skp_warmup_surface_;
3537

3638
// |flutter::CompositorContext|
3739
std::unique_ptr<ScopedFrame> AcquireFrame(

shell/platform/fuchsia/flutter/engine.cc

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@
1414
#include "flutter/fml/synchronization/waitable_event.h"
1515
#include "flutter/fml/task_runner.h"
1616
#include "flutter/runtime/dart_vm_lifecycle.h"
17+
#include "flutter/shell/common/persistent_cache.h"
1718
#include "flutter/shell/common/rasterizer.h"
1819
#include "flutter/shell/common/run_configuration.h"
19-
#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"
20-
20+
#include "flutter/shell/common/serialization_callbacks.h"
2121
#include "flutter_runner_product_configuration.h"
2222
#include "fuchsia_external_view_embedder.h"
2323
#include "fuchsia_intl.h"
24+
#include "include/core/SkPicture.h"
25+
#include "include/core/SkSerialProcs.h"
2426
#include "platform_view.h"
2527
#include "surface.h"
2628
#include "task_runner_adapter.h"
29+
#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"
2730
#include "thread.h"
2831

2932
#if defined(LEGACY_FUCHSIA_EMBEDDER)
@@ -248,15 +251,23 @@ Engine::Engine(Delegate& delegate,
248251
auto compositor_context =
249252
std::make_unique<flutter_runner::CompositorContext>(
250253
session_connection_.value(), surface_producer_.value(),
251-
legacy_external_view_embedder_);
254+
legacy_external_view_embedder_.value());
255+
252256
return std::make_unique<flutter::Rasterizer>(
253257
shell, std::move(compositor_context));
254258
} else {
255259
return std::make_unique<flutter::Rasterizer>(shell);
256260
}
257261
};
258262
#else
259-
on_create_rasterizer = [](flutter::Shell& shell) {
263+
on_create_rasterizer = [this](flutter::Shell& shell) {
264+
FML_DCHECK(surface_producer_);
265+
266+
WarmupSkps(
267+
shell.GetDartVM()->GetConcurrentMessageLoop()->GetTaskRunner().get(),
268+
shell.GetTaskRunners().GetRasterTaskRunner().get(),
269+
surface_producer_.value());
270+
260271
return std::make_unique<flutter::Rasterizer>(shell);
261272
};
262273
#endif
@@ -623,4 +634,50 @@ void Engine::WriteProfileToTrace() const {
623634
}
624635
#endif // !defined(DART_PRODUCT)
625636

637+
void Engine::WarmupSkps(fml::BasicTaskRunner* concurrent_task_runner,
638+
fml::BasicTaskRunner* raster_task_runner,
639+
VulkanSurfaceProducer& surface_producer) {
640+
SkISize size = SkISize::Make(1024, 600);
641+
auto skp_warmup_surface = surface_producer.ProduceOffscreenSurface(size);
642+
if (!skp_warmup_surface) {
643+
FML_LOG(ERROR) << "SkSurface::MakeRenderTarget returned null";
644+
return;
645+
}
646+
647+
// tell concurrent task runner to deserialize all skps available from
648+
// the asset manager
649+
concurrent_task_runner->PostTask([&raster_task_runner, skp_warmup_surface,
650+
&surface_producer]() {
651+
TRACE_DURATION("flutter", "DeserializeSkps");
652+
std::vector<std::unique_ptr<fml::Mapping>> skp_mappings =
653+
flutter::PersistentCache::GetCacheForProcess()
654+
->GetSkpsFromAssetManager();
655+
std::vector<sk_sp<SkPicture>> pictures;
656+
int i = 0;
657+
for (auto& mapping : skp_mappings) {
658+
std::unique_ptr<SkMemoryStream> stream =
659+
SkMemoryStream::MakeDirect(mapping->GetMapping(), mapping->GetSize());
660+
SkDeserialProcs procs = {0};
661+
procs.fImageProc = flutter::DeserializeImageWithoutData;
662+
procs.fTypefaceProc = flutter::DeserializeTypefaceWithoutData;
663+
sk_sp<SkPicture> picture =
664+
SkPicture::MakeFromStream(stream.get(), &procs);
665+
if (!picture) {
666+
FML_LOG(ERROR) << "Failed to deserialize picture " << i;
667+
continue;
668+
}
669+
670+
// Tell raster task runner to warmup have the compositor
671+
// context warm up the newly deserialized picture
672+
raster_task_runner->PostTask(
673+
[skp_warmup_surface, picture, &surface_producer] {
674+
TRACE_DURATION("flutter", "WarmupSkp");
675+
skp_warmup_surface->getCanvas()->drawPicture(picture);
676+
surface_producer.gr_context()->flush();
677+
});
678+
i++;
679+
}
680+
});
681+
}
682+
626683
} // namespace flutter_runner

shell/platform/fuchsia/flutter/engine.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434

3535
namespace flutter_runner {
3636

37+
namespace testing {
38+
class EngineTest;
39+
}
40+
3741
// Represents an instance of running Flutter engine along with the threads
3842
// that host the same.
3943
class Engine final {
@@ -90,6 +94,10 @@ class Engine final {
9094

9195
fml::WeakPtrFactory<Engine> weak_factory_;
9296

97+
static void WarmupSkps(fml::BasicTaskRunner* concurrent_task_runner,
98+
fml::BasicTaskRunner* raster_task_runner,
99+
VulkanSurfaceProducer& surface_producer);
100+
93101
void OnMainIsolateStart();
94102

95103
void OnMainIsolateShutdown();
@@ -104,6 +112,8 @@ class Engine final {
104112

105113
std::unique_ptr<flutter::Surface> CreateSurface();
106114

115+
friend class testing::EngineTest;
116+
107117
FML_DISALLOW_COPY_AND_ASSIGN(Engine);
108118
};
109119

shell/platform/fuchsia/flutter/meta/flutter_runner_tests.cmx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88
"sandbox": {
99
"features": [
1010
"deprecated-ambient-replace-as-executable",
11-
"vulkan"
11+
"vulkan",
12+
"isolated-cache-storage",
13+
"isolated-temp"
1214
],
1315
"services": [
1416
"fuchsia.accessibility.semantics.SemanticsManager",
1517
"fuchsia.intl.PropertyProvider",
16-
"fuchsia.process.Launcher"
18+
"fuchsia.process.Launcher",
19+
"fuchsia.vulkan.loader.Loader",
20+
"fuchsia.logger.LogSink",
21+
"fuchsia.sysmem.Allocator"
1722
]
1823
}
1924
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2020 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 <fuchsia/scenic/scheduling/cpp/fidl.h>
6+
#include <fuchsia/ui/policy/cpp/fidl.h>
7+
#include <fuchsia/ui/scenic/cpp/fidl.h>
8+
#include <lib/async-loop/default.h>
9+
#include <lib/sys/cpp/component_context.h>
10+
11+
#include "assets/directory_asset_bundle.h"
12+
#include "flutter/fml/memory/ref_ptr.h"
13+
#include "flutter/fml/message_loop_impl.h"
14+
#include "flutter/fml/task_runner.h"
15+
#include "flutter/shell/common/persistent_cache.h"
16+
#include "flutter/shell/common/serialization_callbacks.h"
17+
#include "flutter/shell/platform/fuchsia/flutter/logging.h"
18+
#include "flutter/shell/platform/fuchsia/flutter/runner.h"
19+
#include "flutter/shell/platform/fuchsia/flutter/session_connection.h"
20+
#include "gtest/gtest.h"
21+
#include "include/core/SkPicture.h"
22+
#include "include/core/SkPictureRecorder.h"
23+
#include "include/core/SkSerialProcs.h"
24+
25+
using namespace flutter_runner;
26+
using namespace flutter;
27+
28+
namespace flutter_runner {
29+
namespace testing {
30+
31+
class MockTaskRunner : public fml::BasicTaskRunner {
32+
public:
33+
MockTaskRunner() {}
34+
virtual ~MockTaskRunner() {}
35+
36+
void PostTask(const fml::closure& task) override {
37+
task_count_++;
38+
task();
39+
}
40+
41+
int GetTaskCount() { return task_count_; }
42+
43+
private:
44+
int task_count_ = 0;
45+
};
46+
47+
class EngineTest : public ::testing::Test {
48+
public:
49+
void WarmupSkps() {
50+
// Have to create a message loop so default async dispatcher gets set,
51+
// otherwise we segfault creating the VulkanSurfaceProducer
52+
auto loop = fml::MessageLoopImpl::Create();
53+
54+
fuchsia::ui::scenic::SessionPtr session_ptr;
55+
scenic::Session session(std::move(session_ptr));
56+
VulkanSurfaceProducer surface_producer(&session);
57+
58+
Engine::WarmupSkps(&concurrent_task_runner_, &raster_task_runner_,
59+
surface_producer);
60+
}
61+
62+
protected:
63+
MockTaskRunner concurrent_task_runner_;
64+
MockTaskRunner raster_task_runner_;
65+
};
66+
67+
TEST_F(EngineTest, SkpWarmup) {
68+
SkISize draw_size = SkISize::Make(100, 100);
69+
SkPictureRecorder recorder;
70+
auto canvas = recorder.beginRecording(draw_size.width(), draw_size.height());
71+
72+
// adapted from https://fiddle.skia.org/c/@Canvas_drawLine
73+
SkPaint paint;
74+
paint.setColor(0xFF9a67be);
75+
paint.setStrokeWidth(20);
76+
canvas->drawLine(0, 0, draw_size.width(), draw_size.height(), paint);
77+
canvas->drawLine(0, draw_size.height(), draw_size.width(), 0, paint);
78+
79+
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
80+
SkSerialProcs procs = {0};
81+
procs.fImageProc = SerializeImageWithoutData;
82+
procs.fTypefaceProc = SerializeTypefaceWithoutData;
83+
sk_sp<SkData> data = picture->serialize(&procs);
84+
ASSERT_TRUE(data);
85+
ASSERT_GT(data->size(), 0u);
86+
87+
fml::NonOwnedMapping mapping(data->bytes(), data->size());
88+
89+
fml::ScopedTemporaryDirectory asset_dir;
90+
fml::UniqueFD asset_dir_fd = fml::OpenDirectory(
91+
asset_dir.path().c_str(), false, fml::FilePermission::kRead);
92+
93+
bool success = fml::WriteAtomically(asset_dir_fd, "test.skp", mapping);
94+
ASSERT_TRUE(success);
95+
96+
auto asset_manager = std::make_shared<AssetManager>();
97+
asset_manager->PushBack(
98+
std::make_unique<DirectoryAssetBundle>(std::move(asset_dir_fd), false));
99+
100+
PersistentCache::GetCacheForProcess()->SetAssetManager(asset_manager);
101+
102+
WarmupSkps();
103+
104+
EXPECT_EQ(concurrent_task_runner_.GetTaskCount(), 1);
105+
EXPECT_EQ(raster_task_runner_.GetTaskCount(), 1);
106+
}
107+
108+
} // namespace testing
109+
} // namespace flutter_runner

shell/platform/fuchsia/flutter/vulkan_surface_pool.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class VulkanSurfacePool final {
2626

2727
~VulkanSurfacePool();
2828

29+
std::unique_ptr<VulkanSurface> CreateSurface(const SkISize& size);
2930
std::unique_ptr<VulkanSurface> AcquireSurface(const SkISize& size);
3031

3132
void SubmitSurface(std::unique_ptr<SurfaceProducerSurface> surface);
@@ -49,8 +50,6 @@ class VulkanSurfacePool final {
4950

5051
std::unique_ptr<VulkanSurface> GetCachedOrCreateSurface(const SkISize& size);
5152

52-
std::unique_ptr<VulkanSurface> CreateSurface(const SkISize& size);
53-
5453
void RecycleSurface(std::unique_ptr<VulkanSurface> surface);
5554

5655
void RecyclePendingSurface(uintptr_t surface_key);

0 commit comments

Comments
 (0)