Skip to content

Commit f644d03

Browse files
authored
Add a service protocol for raster cache memory (flutter#20466)
Related issue: flutter#56719
1 parent 9e30383 commit f644d03

File tree

9 files changed

+160
-19
lines changed

9 files changed

+160
-19
lines changed

flow/raster_cache.cc

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -299,35 +299,34 @@ void RasterCache::SetCheckboardCacheImages(bool checkerboard) {
299299

300300
void RasterCache::TraceStatsToTimeline() const {
301301
#if !FLUTTER_RELEASE
302+
constexpr double kMegaBytes = (1 << 20);
303+
FML_TRACE_COUNTER("flutter", "RasterCache", reinterpret_cast<int64_t>(this),
304+
"LayerCount", layer_cache_.size(), "LayerMBytes",
305+
EstimateLayerCacheByteSize() / kMegaBytes, "PictureCount",
306+
picture_cache_.size(), "PictureMBytes",
307+
EstimatePictureCacheByteSize() / kMegaBytes);
302308

303-
size_t layer_cache_count = 0;
304-
size_t layer_cache_bytes = 0;
305-
size_t picture_cache_count = 0;
306-
size_t picture_cache_bytes = 0;
309+
#endif // !FLUTTER_RELEASE
310+
}
307311

312+
size_t RasterCache::EstimateLayerCacheByteSize() const {
313+
size_t layer_cache_bytes = 0;
308314
for (const auto& item : layer_cache_) {
309-
layer_cache_count++;
310315
if (item.second.image) {
311316
layer_cache_bytes += item.second.image->image_bytes();
312317
}
313318
}
319+
return layer_cache_bytes;
320+
}
314321

322+
size_t RasterCache::EstimatePictureCacheByteSize() const {
323+
size_t picture_cache_bytes = 0;
315324
for (const auto& item : picture_cache_) {
316-
picture_cache_count++;
317325
if (item.second.image) {
318326
picture_cache_bytes += item.second.image->image_bytes();
319327
}
320328
}
321-
322-
FML_TRACE_COUNTER("flutter", "RasterCache",
323-
reinterpret_cast<int64_t>(this), //
324-
"LayerCount", layer_cache_count, //
325-
"LayerMBytes", layer_cache_bytes * 1e-6, //
326-
"PictureCount", picture_cache_count, //
327-
"PictureMBytes", picture_cache_bytes * 1e-6 //
328-
);
329-
330-
#endif // !FLUTTER_RELEASE
329+
return picture_cache_bytes;
331330
}
332331

333332
} // namespace flutter

flow/raster_cache.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ class RasterCacheResult {
2929
};
3030

3131
virtual int64_t image_bytes() const {
32-
return image_ ? image_->dimensions().area() *
33-
image_->imageInfo().bytesPerPixel()
34-
: 0;
32+
return image_ ? image_->imageInfo().computeMinByteSize() : 0;
3533
};
3634

3735
private:
@@ -170,6 +168,26 @@ class RasterCache {
170168

171169
size_t GetPictureCachedEntriesCount() const;
172170

171+
/**
172+
* @brief Estimate how much memory is used by picture raster cache entries in
173+
* bytes.
174+
*
175+
* Only SkImage's memory usage is counted as other objects are often much
176+
* smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to
177+
* estimate the SkImage memory usage.
178+
*/
179+
size_t EstimatePictureCacheByteSize() const;
180+
181+
/**
182+
* @brief Estimate how much memory is used by layer raster cache entries in
183+
* bytes.
184+
*
185+
* Only SkImage's memory usage is counted as other objects are often much
186+
* smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to
187+
* estimate the SkImage memory usage.
188+
*/
189+
size_t EstimateLayerCacheByteSize() const;
190+
173191
private:
174192
struct Entry {
175193
bool used_this_frame = false;

runtime/service_protocol.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ const std::string_view ServiceProtocol::kGetDisplayRefreshRateExtensionName =
3535
"_flutter.getDisplayRefreshRate";
3636
const std::string_view ServiceProtocol::kGetSkSLsExtensionName =
3737
"_flutter.getSkSLs";
38+
const std::string_view
39+
ServiceProtocol::kEstimateRasterCacheMemoryExtensionName =
40+
"_flutter.estimateRasterCacheMemory";
3841

3942
static constexpr std::string_view kViewIdPrefx = "_flutterView/";
4043
static constexpr std::string_view kListViewsExtensionName =
@@ -53,6 +56,7 @@ ServiceProtocol::ServiceProtocol()
5356
kSetAssetBundlePathExtensionName,
5457
kGetDisplayRefreshRateExtensionName,
5558
kGetSkSLsExtensionName,
59+
kEstimateRasterCacheMemoryExtensionName,
5660
}),
5761
handlers_mutex_(fml::SharedMutex::Create()) {}
5862

runtime/service_protocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ServiceProtocol {
2828
static const std::string_view kSetAssetBundlePathExtensionName;
2929
static const std::string_view kGetDisplayRefreshRateExtensionName;
3030
static const std::string_view kGetSkSLsExtensionName;
31+
static const std::string_view kEstimateRasterCacheMemoryExtensionName;
3132

3233
class Handler {
3334
public:

shell/common/shell.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,11 @@ Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
375375
task_runners_.GetIOTaskRunner(),
376376
std::bind(&Shell::OnServiceProtocolGetSkSLs, this, std::placeholders::_1,
377377
std::placeholders::_2)};
378+
service_protocol_handlers_
379+
[ServiceProtocol::kEstimateRasterCacheMemoryExtensionName] = {
380+
task_runners_.GetRasterTaskRunner(),
381+
std::bind(&Shell::OnServiceProtocolEstimateRasterCacheMemory, this,
382+
std::placeholders::_1, std::placeholders::_2)};
378383
}
379384

380385
Shell::~Shell() {
@@ -1424,6 +1429,23 @@ bool Shell::OnServiceProtocolGetSkSLs(
14241429
return true;
14251430
}
14261431

1432+
bool Shell::OnServiceProtocolEstimateRasterCacheMemory(
1433+
const ServiceProtocol::Handler::ServiceProtocolMap& params,
1434+
rapidjson::Document* response) {
1435+
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
1436+
const auto& raster_cache = rasterizer_->compositor_context()->raster_cache();
1437+
response->SetObject();
1438+
response->AddMember("type", "EstimateRasterCacheMemory",
1439+
response->GetAllocator());
1440+
response->AddMember<uint64_t>("layerBytes",
1441+
raster_cache.EstimateLayerCacheByteSize(),
1442+
response->GetAllocator());
1443+
response->AddMember<uint64_t>("pictureBytes",
1444+
raster_cache.EstimatePictureCacheByteSize(),
1445+
response->GetAllocator());
1446+
return true;
1447+
}
1448+
14271449
// Service protocol handler
14281450
bool Shell::OnServiceProtocolSetAssetBundlePath(
14291451
const ServiceProtocol::Handler::ServiceProtocolMap& params,

shell/common/shell.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,11 @@ class Shell final : public PlatformView::Delegate,
584584
const ServiceProtocol::Handler::ServiceProtocolMap& params,
585585
rapidjson::Document* response);
586586

587+
// Service protocol handler
588+
bool OnServiceProtocolEstimateRasterCacheMemory(
589+
const ServiceProtocol::Handler::ServiceProtocolMap& params,
590+
rapidjson::Document* response);
591+
587592
fml::WeakPtrFactory<Shell> weak_factory_;
588593

589594
// For accessing the Shell via the raster thread, necessary for various

shell/common/shell_test.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ void ShellTest::OnServiceProtocol(
186186
case ServiceProtocolEnum::kGetSkSLs:
187187
shell->OnServiceProtocolGetSkSLs(params, response);
188188
break;
189+
case ServiceProtocolEnum::kEstimateRasterCacheMemory:
190+
shell->OnServiceProtocolEstimateRasterCacheMemory(params, response);
191+
break;
189192
case ServiceProtocolEnum::kSetAssetBundlePath:
190193
shell->OnServiceProtocolSetAssetBundlePath(params, response);
191194
break;

shell/common/shell_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class ShellTest : public FixtureTest {
8080

8181
enum ServiceProtocolEnum {
8282
kGetSkSLs,
83+
kEstimateRasterCacheMemory,
8384
kSetAssetBundlePath,
8485
kRunInView,
8586
};

shell/common/shell_unittests.cc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,5 +1345,93 @@ TEST_F(ShellTest, RasterizerMakeRasterSnapshot) {
13451345
DestroyShell(std::move(shell), std::move(task_runners));
13461346
}
13471347

1348+
static sk_sp<SkPicture> MakeSizedPicture(int width, int height) {
1349+
SkPictureRecorder recorder;
1350+
SkCanvas* recording_canvas =
1351+
recorder.beginRecording(SkRect::MakeXYWH(0, 0, width, height));
1352+
recording_canvas->drawRect(SkRect::MakeXYWH(0, 0, width, height),
1353+
SkPaint(SkColor4f::FromColor(SK_ColorRED)));
1354+
return recorder.finishRecordingAsPicture();
1355+
}
1356+
1357+
TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) {
1358+
Settings settings = CreateSettingsForFixture();
1359+
std::unique_ptr<Shell> shell = CreateShell(settings);
1360+
1361+
// 1. Construct a picture and a picture layer to be raster cached.
1362+
sk_sp<SkPicture> picture = MakeSizedPicture(10, 10);
1363+
fml::RefPtr<SkiaUnrefQueue> queue = fml::MakeRefCounted<SkiaUnrefQueue>(
1364+
GetCurrentTaskRunner(), fml::TimeDelta::FromSeconds(0));
1365+
auto picture_layer = std::make_shared<PictureLayer>(
1366+
SkPoint::Make(0, 0),
1367+
flutter::SkiaGPUObject<SkPicture>({MakeSizedPicture(100, 100), queue}),
1368+
false, false);
1369+
picture_layer->set_paint_bounds(SkRect::MakeWH(100, 100));
1370+
1371+
// 2. Rasterize the picture and the picture layer in the raster cache.
1372+
std::promise<bool> rasterized;
1373+
shell->GetTaskRunners().GetRasterTaskRunner()->PostTask(
1374+
[&shell, &rasterized, &picture, &picture_layer] {
1375+
auto* compositor_context = shell->GetRasterizer()->compositor_context();
1376+
auto& raster_cache = compositor_context->raster_cache();
1377+
// 2.1. Rasterize the picture. Call Draw multiple times to pass the
1378+
// access threshold (default to 3) so a cache can be generated.
1379+
SkCanvas dummy_canvas;
1380+
bool picture_cache_generated;
1381+
for (int i = 0; i < 4; i += 1) {
1382+
picture_cache_generated =
1383+
raster_cache.Prepare(nullptr, // GrDirectContext
1384+
picture.get(), SkMatrix::I(),
1385+
nullptr, // SkColorSpace
1386+
true, // isComplex
1387+
false // willChange
1388+
);
1389+
raster_cache.Draw(*picture, dummy_canvas);
1390+
}
1391+
ASSERT_TRUE(picture_cache_generated);
1392+
1393+
// 2.2. Rasterize the picture layer.
1394+
Stopwatch raster_time;
1395+
Stopwatch ui_time;
1396+
MutatorsStack mutators_stack;
1397+
TextureRegistry texture_registry;
1398+
PrerollContext preroll_context = {
1399+
nullptr, /* raster_cache */
1400+
nullptr, /* gr_context */
1401+
nullptr, /* external_view_embedder */
1402+
mutators_stack, nullptr, /* color_space */
1403+
kGiantRect, /* cull_rect */
1404+
false, /* layer reads from surface */
1405+
raster_time, ui_time, texture_registry,
1406+
false, /* checkerboard_offscreen_layers */
1407+
100.0f, /* frame_physical_depth */
1408+
1.0f, /* frame_device_pixel_ratio */
1409+
0.0f, /* total_elevation */
1410+
false, /* has_platform_view */
1411+
};
1412+
raster_cache.Prepare(&preroll_context, picture_layer.get(),
1413+
SkMatrix::I());
1414+
rasterized.set_value(true);
1415+
});
1416+
rasterized.get_future().wait();
1417+
1418+
// 3. Call the service protocol and check its output.
1419+
ServiceProtocol::Handler::ServiceProtocolMap empty_params;
1420+
rapidjson::Document document;
1421+
OnServiceProtocol(
1422+
shell.get(), ServiceProtocolEnum::kEstimateRasterCacheMemory,
1423+
shell->GetTaskRunners().GetRasterTaskRunner(), empty_params, &document);
1424+
rapidjson::StringBuffer buffer;
1425+
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
1426+
document.Accept(writer);
1427+
std::string expected_json =
1428+
"{\"type\":\"EstimateRasterCacheMemory\",\"layerBytes\":40000,\"picture"
1429+
"Bytes\":400}";
1430+
std::string actual_json = buffer.GetString();
1431+
ASSERT_EQ(actual_json, expected_json);
1432+
1433+
DestroyShell(std::move(shell));
1434+
}
1435+
13481436
} // namespace testing
13491437
} // namespace flutter

0 commit comments

Comments
 (0)