Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions flow/raster_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -299,35 +299,34 @@ void RasterCache::SetCheckboardCacheImages(bool checkerboard) {

void RasterCache::TraceStatsToTimeline() const {
#if !FLUTTER_RELEASE
constexpr double kMegaBytes = (1 << 20);
FML_TRACE_COUNTER("flutter", "RasterCache", reinterpret_cast<int64_t>(this),
"LayerCount", layer_cache_.size(), "LayerMBytes",
EstimateLayerCacheByteSize() / kMegaBytes, "PictureCount",
picture_cache_.size(), "PictureMBytes",
EstimatePictureCacheByteSize() / kMegaBytes);

size_t layer_cache_count = 0;
size_t layer_cache_bytes = 0;
size_t picture_cache_count = 0;
size_t picture_cache_bytes = 0;
#endif // !FLUTTER_RELEASE
}

size_t RasterCache::EstimateLayerCacheByteSize() const {
size_t layer_cache_bytes = 0;
for (const auto& item : layer_cache_) {
layer_cache_count++;
if (item.second.image) {
layer_cache_bytes += item.second.image->image_bytes();
}
}
return layer_cache_bytes;
}

size_t RasterCache::EstimatePictureCacheByteSize() const {
size_t picture_cache_bytes = 0;
for (const auto& item : picture_cache_) {
picture_cache_count++;
if (item.second.image) {
picture_cache_bytes += item.second.image->image_bytes();
}
}

FML_TRACE_COUNTER("flutter", "RasterCache",
reinterpret_cast<int64_t>(this), //
"LayerCount", layer_cache_count, //
"LayerMBytes", layer_cache_bytes * 1e-6, //
"PictureCount", picture_cache_count, //
"PictureMBytes", picture_cache_bytes * 1e-6 //
);

#endif // !FLUTTER_RELEASE
return picture_cache_bytes;
}

} // namespace flutter
24 changes: 21 additions & 3 deletions flow/raster_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ class RasterCacheResult {
};

virtual int64_t image_bytes() const {
return image_ ? image_->dimensions().area() *
image_->imageInfo().bytesPerPixel()
: 0;
return image_ ? image_->imageInfo().computeMinByteSize() : 0;
};

private:
Expand Down Expand Up @@ -170,6 +168,26 @@ class RasterCache {

size_t GetPictureCachedEntriesCount() const;

/**
* @brief Estimate how much memory is used by picture raster cache entries in
* bytes.
*
* Only SkImage's memory usage is counted as other objects are often much
* smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to
* estimate the SkImage memory usage.
*/
size_t EstimatePictureCacheByteSize() const;

/**
* @brief Estimate how much memory is used by layer raster cache entries in
* bytes.
*
* Only SkImage's memory usage is counted as other objects are often much
* smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to
* estimate the SkImage memory usage.
*/
size_t EstimateLayerCacheByteSize() const;

private:
struct Entry {
bool used_this_frame = false;
Expand Down
4 changes: 4 additions & 0 deletions runtime/service_protocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ const std::string_view ServiceProtocol::kGetDisplayRefreshRateExtensionName =
"_flutter.getDisplayRefreshRate";
const std::string_view ServiceProtocol::kGetSkSLsExtensionName =
"_flutter.getSkSLs";
const std::string_view
ServiceProtocol::kEstimateRasterCacheMemoryExtensionName =
"_flutter.estimateRasterCacheMemory";

static constexpr std::string_view kViewIdPrefx = "_flutterView/";
static constexpr std::string_view kListViewsExtensionName =
Expand All @@ -53,6 +56,7 @@ ServiceProtocol::ServiceProtocol()
kSetAssetBundlePathExtensionName,
kGetDisplayRefreshRateExtensionName,
kGetSkSLsExtensionName,
kEstimateRasterCacheMemoryExtensionName,
}),
handlers_mutex_(fml::SharedMutex::Create()) {}

Expand Down
1 change: 1 addition & 0 deletions runtime/service_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ServiceProtocol {
static const std::string_view kSetAssetBundlePathExtensionName;
static const std::string_view kGetDisplayRefreshRateExtensionName;
static const std::string_view kGetSkSLsExtensionName;
static const std::string_view kEstimateRasterCacheMemoryExtensionName;

class Handler {
public:
Expand Down
22 changes: 22 additions & 0 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,11 @@ Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
task_runners_.GetIOTaskRunner(),
std::bind(&Shell::OnServiceProtocolGetSkSLs, this, std::placeholders::_1,
std::placeholders::_2)};
service_protocol_handlers_
[ServiceProtocol::kEstimateRasterCacheMemoryExtensionName] = {
task_runners_.GetRasterTaskRunner(),
std::bind(&Shell::OnServiceProtocolEstimateRasterCacheMemory, this,
std::placeholders::_1, std::placeholders::_2)};
}

Shell::~Shell() {
Expand Down Expand Up @@ -1424,6 +1429,23 @@ bool Shell::OnServiceProtocolGetSkSLs(
return true;
}

bool Shell::OnServiceProtocolEstimateRasterCacheMemory(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document* response) {
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
const auto& raster_cache = rasterizer_->compositor_context()->raster_cache();
response->SetObject();
response->AddMember("type", "EstimateRasterCacheMemory",
response->GetAllocator());
response->AddMember<uint64_t>("layerBytes",
raster_cache.EstimateLayerCacheByteSize(),
response->GetAllocator());
response->AddMember<uint64_t>("pictureBytes",
raster_cache.EstimatePictureCacheByteSize(),
response->GetAllocator());
return true;
}

// Service protocol handler
bool Shell::OnServiceProtocolSetAssetBundlePath(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
Expand Down
5 changes: 5 additions & 0 deletions shell/common/shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,11 @@ class Shell final : public PlatformView::Delegate,
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document* response);

// Service protocol handler
bool OnServiceProtocolEstimateRasterCacheMemory(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document* response);

fml::WeakPtrFactory<Shell> weak_factory_;

// For accessing the Shell via the raster thread, necessary for various
Expand Down
3 changes: 3 additions & 0 deletions shell/common/shell_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ void ShellTest::OnServiceProtocol(
case ServiceProtocolEnum::kGetSkSLs:
shell->OnServiceProtocolGetSkSLs(params, response);
break;
case ServiceProtocolEnum::kEstimateRasterCacheMemory:
shell->OnServiceProtocolEstimateRasterCacheMemory(params, response);
break;
case ServiceProtocolEnum::kSetAssetBundlePath:
shell->OnServiceProtocolSetAssetBundlePath(params, response);
break;
Expand Down
1 change: 1 addition & 0 deletions shell/common/shell_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class ShellTest : public FixtureTest {

enum ServiceProtocolEnum {
kGetSkSLs,
kEstimateRasterCacheMemory,
kSetAssetBundlePath,
kRunInView,
};
Expand Down
88 changes: 88 additions & 0 deletions shell/common/shell_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1345,5 +1345,93 @@ TEST_F(ShellTest, RasterizerMakeRasterSnapshot) {
DestroyShell(std::move(shell), std::move(task_runners));
}

static sk_sp<SkPicture> MakeSizedPicture(int width, int height) {
SkPictureRecorder recorder;
SkCanvas* recording_canvas =
recorder.beginRecording(SkRect::MakeXYWH(0, 0, width, height));
recording_canvas->drawRect(SkRect::MakeXYWH(0, 0, width, height),
SkPaint(SkColor4f::FromColor(SK_ColorRED)));
return recorder.finishRecordingAsPicture();
}

TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) {
Settings settings = CreateSettingsForFixture();
std::unique_ptr<Shell> shell = CreateShell(settings);

// 1. Construct a picture and a picture layer to be raster cached.
sk_sp<SkPicture> picture = MakeSizedPicture(10, 10);
fml::RefPtr<SkiaUnrefQueue> queue = fml::MakeRefCounted<SkiaUnrefQueue>(
GetCurrentTaskRunner(), fml::TimeDelta::FromSeconds(0));
auto picture_layer = std::make_shared<PictureLayer>(
SkPoint::Make(0, 0),
flutter::SkiaGPUObject<SkPicture>({MakeSizedPicture(100, 100), queue}),
false, false);
picture_layer->set_paint_bounds(SkRect::MakeWH(100, 100));

// 2. Rasterize the picture and the picture layer in the raster cache.
std::promise<bool> rasterized;
shell->GetTaskRunners().GetRasterTaskRunner()->PostTask(
[&shell, &rasterized, &picture, &picture_layer] {
auto* compositor_context = shell->GetRasterizer()->compositor_context();
auto& raster_cache = compositor_context->raster_cache();
// 2.1. Rasterize the picture. Call Draw multiple times to pass the
// access threshold (default to 3) so a cache can be generated.
SkCanvas dummy_canvas;
bool picture_cache_generated;
for (int i = 0; i < 4; i += 1) {
picture_cache_generated =
raster_cache.Prepare(nullptr, // GrDirectContext
picture.get(), SkMatrix::I(),
nullptr, // SkColorSpace
true, // isComplex
false // willChange
);
raster_cache.Draw(*picture, dummy_canvas);
}
ASSERT_TRUE(picture_cache_generated);

// 2.2. Rasterize the picture layer.
Stopwatch raster_time;
Stopwatch ui_time;
MutatorsStack mutators_stack;
TextureRegistry texture_registry;
PrerollContext preroll_context = {
nullptr, /* raster_cache */
nullptr, /* gr_context */
nullptr, /* external_view_embedder */
mutators_stack, nullptr, /* color_space */
kGiantRect, /* cull_rect */
false, /* layer reads from surface */
raster_time, ui_time, texture_registry,
false, /* checkerboard_offscreen_layers */
100.0f, /* frame_physical_depth */
1.0f, /* frame_device_pixel_ratio */
0.0f, /* total_elevation */
false, /* has_platform_view */
};
raster_cache.Prepare(&preroll_context, picture_layer.get(),
SkMatrix::I());
rasterized.set_value(true);
});
rasterized.get_future().wait();

// 3. Call the service protocol and check its output.
ServiceProtocol::Handler::ServiceProtocolMap empty_params;
rapidjson::Document document;
OnServiceProtocol(
shell.get(), ServiceProtocolEnum::kEstimateRasterCacheMemory,
shell->GetTaskRunners().GetRasterTaskRunner(), empty_params, &document);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);
std::string expected_json =
"{\"type\":\"EstimateRasterCacheMemory\",\"layerBytes\":40000,\"picture"
"Bytes\":400}";
std::string actual_json = buffer.GetString();
ASSERT_EQ(actual_json, expected_json);

DestroyShell(std::move(shell));
}

} // namespace testing
} // namespace flutter