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

Commit 838ee77

Browse files
committed
[fuchsia] use custom image serialization when writing out skp's
This change adds custom image serialization macros for skp serialization which write out onlythe image metadata and not the contents of the images themselves. This allows skp's to be used for shader warmup with a significantly reduced disk space footprint.
1 parent cfaed8d commit 838ee77

File tree

6 files changed

+174
-18
lines changed

6 files changed

+174
-18
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ FILE: ../../../flutter/shell/common/rasterizer.cc
611611
FILE: ../../../flutter/shell/common/rasterizer.h
612612
FILE: ../../../flutter/shell/common/run_configuration.cc
613613
FILE: ../../../flutter/shell/common/run_configuration.h
614+
FILE: ../../../flutter/shell/common/serialization_callbacks.cc
615+
FILE: ../../../flutter/shell/common/serialization_callbacks.h
614616
FILE: ../../../flutter/shell/common/shell.cc
615617
FILE: ../../../flutter/shell/common/shell.h
616618
FILE: ../../../flutter/shell/common/shell_benchmarks.cc
@@ -629,6 +631,7 @@ FILE: ../../../flutter/shell/common/shell_test_platform_view_vulkan.h
629631
FILE: ../../../flutter/shell/common/shell_unittests.cc
630632
FILE: ../../../flutter/shell/common/skia_event_tracer_impl.cc
631633
FILE: ../../../flutter/shell/common/skia_event_tracer_impl.h
634+
FILE: ../../../flutter/shell/common/skp_shader_warmup_unittests.cc
632635
FILE: ../../../flutter/shell/common/switches.cc
633636
FILE: ../../../flutter/shell/common/switches.h
634637
FILE: ../../../flutter/shell/common/thread_host.cc

shell/common/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ source_set_maybe_fuchsia_legacy("common") {
8282
"rasterizer.h",
8383
"run_configuration.cc",
8484
"run_configuration.h",
85+
"serialization_callbacks.cc",
86+
"serialization_callbacks.h",
8587
"shell.cc",
8688
"shell.h",
8789
"shell_io_manager.cc",

shell/common/rasterizer.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "flutter/fml/time/time_delta.h"
1010
#include "flutter/fml/time/time_point.h"
1111
#include "flutter/shell/common/persistent_cache.h"
12+
#include "flutter/shell/common/serialization_callbacks.h"
1213
#include "third_party/skia/include/core/SkEncodedImageFormat.h"
1314
#include "third_party/skia/include/core/SkImageEncoder.h"
1415
#include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -447,10 +448,6 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
447448
return RasterStatus::kFailed;
448449
}
449450

450-
static sk_sp<SkData> SerializeTypeface(SkTypeface* typeface, void* ctx) {
451-
return typeface->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
452-
}
453-
454451
static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
455452
flutter::LayerTree* tree,
456453
flutter::CompositorContext& compositor_context) {
@@ -479,8 +476,13 @@ static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
479476

480477
frame->Raster(*tree, true);
481478

479+
#if defined(OS_FUCHSIA)
482480
SkSerialProcs procs = {0};
483-
procs.fTypefaceProc = SerializeTypeface;
481+
procs.fImageProc = SerializeImageWithoutData;
482+
#else
483+
SkSerialProcs procs = {0};
484+
procs.fTypefaceProc = SerializeTypefaceWithData;
485+
#endif
484486

485487
return recorder.finishRecordingAsPicture()->serialize(&procs);
486488
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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/fml/logging.h"
6+
#include "include/core/SkImage.h"
7+
#include "include/core/SkPicture.h"
8+
#include "include/core/SkStream.h"
9+
#include "include/core/SkTypeface.h"
10+
11+
namespace flutter {
12+
13+
sk_sp<SkData> SerializeTypefaceWithoutData(SkTypeface* typeface, void* ctx) {
14+
return typeface->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
15+
}
16+
17+
sk_sp<SkData> SerializeTypefaceWithData(SkTypeface* typeface, void* ctx) {
18+
return typeface->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
19+
}
20+
21+
struct ImageMetaData {
22+
int32_t width;
23+
int32_t height;
24+
uint32_t color_type;
25+
uint32_t alpha_type;
26+
bool has_color_space;
27+
} __attribute__((packed));
28+
29+
sk_sp<SkData> SerializeImageWithoutData(SkImage* image, void* ctx) {
30+
auto info = image->imageInfo();
31+
SkDynamicMemoryWStream stream;
32+
33+
ImageMetaData metadata = {info.width(), info.height(),
34+
static_cast<uint32_t>(info.colorType()),
35+
static_cast<uint32_t>(info.alphaType()),
36+
static_cast<bool>(info.colorSpace())};
37+
stream.write(&metadata, sizeof(ImageMetaData));
38+
39+
if (info.colorSpace()) {
40+
auto color_space_data = info.colorSpace()->serialize();
41+
FML_CHECK(color_space_data);
42+
SkMemoryStream color_space_stream(color_space_data);
43+
stream.writeStream(&color_space_stream, color_space_data->size());
44+
}
45+
46+
return stream.detachAsData();
47+
};
48+
49+
sk_sp<SkImage> DeserializeImageWithoutData(const void* data,
50+
size_t length,
51+
void* ctx) {
52+
FML_CHECK(length >= sizeof(ImageMetaData));
53+
auto metadata = static_cast<const ImageMetaData*>(data);
54+
sk_sp<SkColorSpace> color_space = nullptr;
55+
if (metadata->has_color_space) {
56+
color_space = SkColorSpace::Deserialize(
57+
static_cast<const uint8_t*>(data) + sizeof(ImageMetaData),
58+
length - sizeof(ImageMetaData));
59+
}
60+
61+
auto image_size = SkISize::Make(metadata->width, metadata->height);
62+
auto info = SkImageInfo::Make(
63+
image_size, static_cast<SkColorType>(metadata->color_type),
64+
static_cast<SkAlphaType>(metadata->alpha_type), color_space);
65+
sk_sp<SkData> image_data =
66+
SkData::MakeUninitialized(image_size.width() * image_size.height() * 4);
67+
memset(image_data->writable_data(), 0x0f, image_data->size());
68+
sk_sp<SkImage> image =
69+
SkImage::MakeRasterData(info, image_data, image_size.width() * 4);
70+
71+
return image;
72+
};
73+
74+
} // namespace flutter
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
#ifndef FLUTTER_SHELL_COMMON_SERIALIZATION_CALLBACKS_H_
6+
#define FLUTTER_SHELL_COMMON_SERIALIZATION_CALLBACKS_H_
7+
8+
#include "flutter/fml/logging.h"
9+
#include "include/core/SkImage.h"
10+
#include "include/core/SkPicture.h"
11+
#include "include/core/SkStream.h"
12+
#include "include/core/SkTypeface.h"
13+
14+
namespace flutter {
15+
16+
sk_sp<SkData> SerializeTypefaceWithoutData(SkTypeface* typeface, void* ctx);
17+
sk_sp<SkData> SerializeTypefaceWithData(SkTypeface* typeface, void* ctx);
18+
19+
// Serializes only the metadata of the image and not the underlying pixel data.
20+
sk_sp<SkData> SerializeImageWithoutData(SkImage* image, void* ctx);
21+
sk_sp<SkImage> DeserializeImageWithoutData(const void* data,
22+
size_t length,
23+
void* ctx);
24+
25+
} // namespace flutter
26+
27+
#endif // FLUTTER_SHELL_COMMON_SERIALIZATION_CALLBACKS_H_

shell/common/skp_shader_warmup_unittests.cc

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@
1414
#include "flutter/fml/log_settings.h"
1515
#include "flutter/fml/unique_fd.h"
1616
#include "flutter/shell/common/persistent_cache.h"
17+
#include "flutter/shell/common/serialization_callbacks.h"
1718
#include "flutter/shell/common/shell_test.h"
1819
#include "flutter/shell/common/switches.h"
1920
#include "flutter/shell/version/version.h"
2021
#include "flutter/testing/testing.h"
2122
#include "include/core/SkPicture.h"
23+
#include "include/core/SkPictureRecorder.h"
24+
#include "include/core/SkSerialProcs.h"
2225

2326
namespace flutter {
2427
namespace testing {
@@ -36,7 +39,7 @@ class SkpWarmupTest : public ShellTest {
3639
public:
3740
SkpWarmupTest() {}
3841

39-
void TestWarmup(const LayerTreeBuilder& builder) {
42+
void TestWarmup(const SkISize& draw_size, const LayerTreeBuilder& builder) {
4043
// Create a temp dir to store the persistent cache
4144
fml::ScopedTemporaryDirectory dir;
4245
PersistentCache::SetCacheDirectoryPath(dir.path());
@@ -60,7 +63,7 @@ class SkpWarmupTest : public ShellTest {
6063
auto cache = PersistentCache::GetCacheForProcess()->LoadSkSLs();
6164
ASSERT_EQ(cache.size(), 0u);
6265

63-
PumpOneFrame(shell.get(), 100, 100, builder);
66+
PumpOneFrame(shell.get(), draw_size.width(), draw_size.height(), builder);
6467
firstFrameLatch.Wait();
6568
WaitForIO(shell.get());
6669

@@ -97,8 +100,11 @@ class SkpWarmupTest : public ShellTest {
97100
// Deserialize
98101
sk_sp<SkData> data = SkData::MakeFromFD(fd.get());
99102
std::unique_ptr<SkMemoryStream> stream = SkMemoryStream::Make(data);
100-
sk_sp<SkPicture> picture = SkPicture::MakeFromStream(
101-
stream.get(), /*const SkDeserialProcs* */ nullptr);
103+
104+
SkDeserialProcs procs = {0};
105+
procs.fImageProc = DeserializeImageWithoutData;
106+
sk_sp<SkPicture> picture =
107+
SkPicture::MakeFromStream(stream.get(), &procs);
102108
pictures.push_back(std::move(picture));
103109
fd.reset();
104110
}
@@ -118,7 +124,7 @@ class SkpWarmupTest : public ShellTest {
118124
PlatformViewNotifyCreated(shell.get());
119125
RunEngine(shell.get(), std::move(config2));
120126
firstFrameLatch.Reset();
121-
PumpOneFrame(shell.get(), 100, 100, builder);
127+
PumpOneFrame(shell.get(), draw_size.width(), draw_size.height(), builder);
122128
firstFrameLatch.Wait();
123129
WaitForIO(shell.get());
124130

@@ -167,7 +173,8 @@ class SkpWarmupTest : public ShellTest {
167173

168174
// Draw orignal material again
169175
firstFrameLatch.Reset();
170-
PumpOneFrame(shell.get(), 100, 100, builder);
176+
PumpOneFrame(shell.get(), draw_size.width(), draw_size.height(), builder);
177+
171178
firstFrameLatch.Wait();
172179
WaitForIO(shell.get());
173180

@@ -183,15 +190,56 @@ class SkpWarmupTest : public ShellTest {
183190
};
184191

185192
TEST_F(SkpWarmupTest, Basic) {
193+
SkISize draw_size = SkISize::Make(100, 100);
186194
// Draw something to trigger shader compilations.
187-
LayerTreeBuilder builder = [](std::shared_ptr<ContainerLayer> root) {
188-
SkPath path;
189-
path.addCircle(50, 50, 20);
190-
auto physical_shape_layer = std::make_shared<PhysicalShapeLayer>(
191-
SK_ColorRED, SK_ColorBLUE, 1.0f, path, Clip::antiAlias);
192-
root->Add(physical_shape_layer);
195+
LayerTreeBuilder builder =
196+
[&draw_size](std::shared_ptr<ContainerLayer> root) {
197+
SkPath path;
198+
path.addCircle(draw_size.width() / 2, draw_size.height() / 2, 20);
199+
auto physical_shape_layer = std::make_shared<PhysicalShapeLayer>(
200+
SK_ColorRED, SK_ColorBLUE, 1.0f, path, Clip::antiAlias);
201+
root->Add(physical_shape_layer);
202+
};
203+
TestWarmup(draw_size, builder);
204+
}
205+
206+
TEST_F(SkpWarmupTest, Image) {
207+
SkISize draw_size = SkISize::Make(100, 100);
208+
// We reuse this builder to draw the same content sever times in this test
209+
LayerTreeBuilder builder = [&draw_size,
210+
this](std::shared_ptr<ContainerLayer> root) {
211+
SkPictureRecorder recorder;
212+
auto canvas =
213+
recorder.beginRecording(draw_size.width(), draw_size.height());
214+
215+
// include an image so we can test that the warmup works even with image
216+
// data excluded from the skp
217+
auto image_size =
218+
SkISize::Make(draw_size.width() / 2, draw_size.height() / 2);
219+
auto color_space = SkColorSpace::MakeSRGB();
220+
auto info =
221+
SkImageInfo::Make(image_size, SkColorType::kRGBA_8888_SkColorType,
222+
SkAlphaType::kPremul_SkAlphaType, color_space);
223+
sk_sp<SkData> image_data =
224+
SkData::MakeUninitialized(image_size.width() * image_size.height() * 4);
225+
memset(image_data->writable_data(), 0x0f, image_data->size());
226+
sk_sp<SkImage> image =
227+
SkImage::MakeRasterData(info, image_data, image_size.width() * 4);
228+
229+
canvas->drawImage(image, image_size.width(), image_size.height());
230+
231+
auto picture = recorder.finishRecordingAsPicture();
232+
233+
fml::RefPtr<SkiaUnrefQueue> queue = fml::MakeRefCounted<SkiaUnrefQueue>(
234+
this->GetCurrentTaskRunner(), fml::TimeDelta::FromSeconds(0));
235+
auto picture_layer = std::make_shared<PictureLayer>(
236+
SkPoint::Make(0, 0), SkiaGPUObject<SkPicture>(picture, queue),
237+
/* is_complex */ false,
238+
/* will_change */ false);
239+
root->Add(picture_layer);
193240
};
194-
TestWarmup(builder);
241+
242+
TestWarmup(draw_size, builder);
195243
}
196244

197245
#endif

0 commit comments

Comments
 (0)