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

Hint freed #19842

Merged
merged 23 commits into from
Aug 19, 2020
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
15 changes: 10 additions & 5 deletions flow/compositor_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

namespace flutter {

CompositorContext::CompositorContext(fml::Milliseconds frame_budget)
: raster_time_(frame_budget), ui_time_(frame_budget) {}
CompositorContext::CompositorContext(Delegate& delegate)
: delegate_(delegate),
raster_time_(delegate.GetFrameBudget()),
ui_time_(delegate.GetFrameBudget()) {}

CompositorContext::~CompositorContext() = default;

Expand All @@ -23,8 +25,11 @@ void CompositorContext::BeginFrame(ScopedFrame& frame,
}

void CompositorContext::EndFrame(ScopedFrame& frame,
bool enable_instrumentation) {
raster_cache_.SweepAfterFrame();
bool enable_instrumentation,
size_t freed_hint) {
freed_hint += raster_cache_.SweepAfterFrame();
delegate_.OnCompositorEndFrame(freed_hint);

if (enable_instrumentation) {
raster_time_.Stop();
}
Expand Down Expand Up @@ -64,7 +69,7 @@ CompositorContext::ScopedFrame::ScopedFrame(
}

CompositorContext::ScopedFrame::~ScopedFrame() {
context_.EndFrame(*this, instrumentation_enabled_);
context_.EndFrame(*this, instrumentation_enabled_, uncached_external_size_);
}

RasterStatus CompositorContext::ScopedFrame::Raster(
Expand Down
22 changes: 20 additions & 2 deletions flow/compositor_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ enum class RasterStatus {

class CompositorContext {
public:
class Delegate {
public:
/// Called at the end of a frame with approximately how many bytes mightbe
/// freed if a GC ran now.
///
/// This method is called from the raster task runner.
virtual void OnCompositorEndFrame(size_t freed_hint) = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the threading restrictions that implementors must adhere to. I believe the shell is not thread-unsafe. Details below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what thread restrictions to document here. This is just called when there's a hint available for bytes freed - shouldn't it be up to the implementer what threads it uses when processing that information?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant whoever implements the delegate protocol will receive events on the raster thread. This might be unexpected to the implementer.


/// Time limit for a smooth frame. See `Engine::GetDisplayRefreshRate`.
virtual fml::Milliseconds GetFrameBudget() = 0;
};

class ScopedFrame {
public:
ScopedFrame(CompositorContext& context,
Expand Down Expand Up @@ -67,6 +79,8 @@ class CompositorContext {
virtual RasterStatus Raster(LayerTree& layer_tree,
bool ignore_raster_cache);

void add_external_size(size_t size) { uncached_external_size_ += size; }

private:
CompositorContext& context_;
GrDirectContext* gr_context_;
Expand All @@ -76,11 +90,12 @@ class CompositorContext {
const bool instrumentation_enabled_;
const bool surface_supports_readback_;
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger_;
size_t uncached_external_size_ = 0;

FML_DISALLOW_COPY_AND_ASSIGN(ScopedFrame);
};

CompositorContext(fml::Milliseconds frame_budget = fml::kDefaultFrameBudget);
explicit CompositorContext(Delegate& delegate);

virtual ~CompositorContext();

Expand Down Expand Up @@ -108,6 +123,7 @@ class CompositorContext {
Stopwatch& ui_time() { return ui_time_; }

private:
Delegate& delegate_;
RasterCache raster_cache_;
TextureRegistry texture_registry_;
Counter frame_count_;
Expand All @@ -116,7 +132,9 @@ class CompositorContext {

void BeginFrame(ScopedFrame& frame, bool enable_instrumentation);

void EndFrame(ScopedFrame& frame, bool enable_instrumentation);
void EndFrame(ScopedFrame& frame,
bool enable_instrumentation,
size_t freed_hint);

FML_DISALLOW_COPY_AND_ASSIGN(CompositorContext);
};
Expand Down
5 changes: 3 additions & 2 deletions flow/layers/layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@

namespace flutter {

Layer::Layer()
Layer::Layer(size_t external_size)
: paint_bounds_(SkRect::MakeEmpty()),
unique_id_(NextUniqueID()),
needs_system_composite_(false) {}
needs_system_composite_(false),
external_size_(external_size) {}

Layer::~Layer() = default;

Expand Down
6 changes: 5 additions & 1 deletion flow/layers/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,14 @@ struct PrerollContext {
// Informs whether a layer needs to be system composited.
bool child_scene_layer_exists_below = false;
#endif
size_t uncached_external_size = 0;
};

// Represents a single composited layer. Created on the UI thread but then
// subquently used on the Rasterizer thread.
class Layer {
public:
Layer();
Layer(size_t external_size = 0);
virtual ~Layer();

virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);
Expand Down Expand Up @@ -178,6 +179,8 @@ class Layer {

uint64_t unique_id() const { return unique_id_; }

size_t external_size() const { return external_size_; }

protected:
#if defined(LEGACY_FUCHSIA_EMBEDDER)
bool child_layer_exists_below_ = false;
Expand All @@ -187,6 +190,7 @@ class Layer {
SkRect paint_bounds_;
uint64_t unique_id_;
bool needs_system_composite_;
size_t external_size_ = 0;

static uint64_t NextUniqueID();

Expand Down
1 change: 1 addition & 0 deletions flow/layers/layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
device_pixel_ratio_};

root_layer_->Preroll(&context, frame.root_surface_transformation());
frame.add_external_size(context.uncached_external_size);
return context.surface_needs_readback;
}

Expand Down
17 changes: 15 additions & 2 deletions flow/layers/layer_tree_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
namespace flutter {
namespace testing {

class LayerTreeTest : public CanvasTest {
class LayerTreeTest : public CanvasTest, public CompositorContext::Delegate {
public:
LayerTreeTest()
: layer_tree_(SkISize::Make(64, 64), 1.0f),
compositor_context_(fml::kDefaultFrameBudget),
compositor_context_(*this),
root_transform_(SkMatrix::Translate(1.0f, 1.0f)),
scoped_frame_(compositor_context_.AcquireFrame(nullptr,
&mock_canvas(),
Expand All @@ -33,11 +33,24 @@ class LayerTreeTest : public CanvasTest {
CompositorContext::ScopedFrame& frame() { return *scoped_frame_.get(); }
const SkMatrix& root_transform() { return root_transform_; }

// |CompositorContext::Delegate|
void OnCompositorEndFrame(size_t freed_hint) override {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// |CompositorContext::Delegate|

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done and done

last_freed_hint_ = freed_hint;
}

// |CompositorContext::Delegate|
fml::Milliseconds GetFrameBudget() override {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

return fml::kDefaultFrameBudget;
}

size_t last_freed_hint() { return last_freed_hint_; }

private:
LayerTree layer_tree_;
CompositorContext compositor_context_;
SkMatrix root_transform_;
std::unique_ptr<CompositorContext::ScopedFrame> scoped_frame_;
size_t last_freed_hint_ = 0;
};

TEST_F(LayerTreeTest, PaintingEmptyLayerDies) {
Expand Down
16 changes: 12 additions & 4 deletions flow/layers/picture_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ namespace flutter {
PictureLayer::PictureLayer(const SkPoint& offset,
SkiaGPUObject<SkPicture> picture,
bool is_complex,
bool will_change)
: offset_(offset),
bool will_change,
size_t external_size)
: Layer(external_size),
offset_(offset),
picture_(std::move(picture)),
is_complex_(is_complex),
will_change_(will_change) {}
Expand All @@ -26,6 +28,7 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {

SkPicture* sk_picture = picture();

bool cached = false;
if (auto* cache = context->raster_cache) {
TRACE_EVENT0("flutter", "PictureLayer::RasterCache (Preroll)");

Expand All @@ -34,8 +37,13 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
ctm = RasterCache::GetIntegralTransCTM(ctm);
#endif
cache->Prepare(context->gr_context, sk_picture, ctm,
context->dst_color_space, is_complex_, will_change_);
cached = cache->Prepare(context->gr_context, sk_picture, ctm,
context->dst_color_space, is_complex_, will_change_,
external_size());
}

if (!cached) {
context->uncached_external_size += external_size();
}

SkRect bounds = sk_picture->cullRect().makeOffset(offset_.x(), offset_.y());
Expand Down
3 changes: 2 additions & 1 deletion flow/layers/picture_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class PictureLayer : public Layer {
PictureLayer(const SkPoint& offset,
SkiaGPUObject<SkPicture> picture,
bool is_complex,
bool will_change);
bool will_change,
size_t external_size);

SkPicture* picture() const { return picture_.get().get(); }

Expand Down
15 changes: 10 additions & 5 deletions flow/layers/picture_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ using PictureLayerTest = SkiaGPUObjectLayerTest;
TEST_F(PictureLayerTest, PaintBeforePrerollInvalidPictureDies) {
const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
auto layer = std::make_shared<PictureLayer>(
layer_offset, SkiaGPUObject<SkPicture>(), false, false);
layer_offset, SkiaGPUObject<SkPicture>(), false, false, 0);

EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
"picture_\\.get\\(\\)");
Expand All @@ -35,7 +35,8 @@ TEST_F(PictureLayerTest, PaintBeforePreollDies) {
const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
auto mock_picture = SkPicture::MakePlaceholder(picture_bounds);
auto layer = std::make_shared<PictureLayer>(
layer_offset, SkiaGPUObject(mock_picture, unref_queue()), false, false);
layer_offset, SkiaGPUObject(mock_picture, unref_queue()), false, false,
0);

EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
Expand All @@ -47,7 +48,8 @@ TEST_F(PictureLayerTest, PaintingEmptyLayerDies) {
const SkRect picture_bounds = SkRect::MakeEmpty();
auto mock_picture = SkPicture::MakePlaceholder(picture_bounds);
auto layer = std::make_shared<PictureLayer>(
layer_offset, SkiaGPUObject(mock_picture, unref_queue()), false, false);
layer_offset, SkiaGPUObject(mock_picture, unref_queue()), false, false,
0);

layer->Preroll(preroll_context(), SkMatrix());
EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
Expand All @@ -62,7 +64,7 @@ TEST_F(PictureLayerTest, PaintingEmptyLayerDies) {
TEST_F(PictureLayerTest, InvalidPictureDies) {
const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
auto layer = std::make_shared<PictureLayer>(
layer_offset, SkiaGPUObject<SkPicture>(), false, false);
layer_offset, SkiaGPUObject<SkPicture>(), false, false, 0);

// Crashes reading a nullptr.
EXPECT_DEATH_IF_SUPPORTED(layer->Preroll(preroll_context(), SkMatrix()), "");
Expand All @@ -75,7 +77,10 @@ TEST_F(PictureLayerTest, SimplePicture) {
const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
auto mock_picture = SkPicture::MakePlaceholder(picture_bounds);
auto layer = std::make_shared<PictureLayer>(
layer_offset, SkiaGPUObject(mock_picture, unref_queue()), false, false);
layer_offset, SkiaGPUObject(mock_picture, unref_queue()), false, false,
1000);

EXPECT_EQ(layer->external_size(), 1000ul);

layer->Preroll(preroll_context(), SkMatrix());
EXPECT_EQ(layer->paint_bounds(),
Expand Down
12 changes: 8 additions & 4 deletions flow/raster_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ void RasterCache::Prepare(PrerollContext* context,
Entry& entry = layer_cache_[cache_key];
entry.access_count++;
entry.used_this_frame = true;
entry.external_size = layer->external_size();
if (!entry.image) {
entry.image = RasterizeLayer(context, layer, ctm, checkerboard_images_);
}
Expand Down Expand Up @@ -181,7 +182,8 @@ bool RasterCache::Prepare(GrDirectContext* context,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change) {
bool will_change,
size_t external_size) {
// Disabling caching when access_threshold is zero is historic behavior.
if (access_threshold_ == 0) {
return false;
Expand All @@ -207,6 +209,7 @@ bool RasterCache::Prepare(GrDirectContext* context,

// Creates an entry, if not present prior.
Entry& entry = picture_cache_[cache_key];
entry.external_size = external_size;
if (entry.access_count < access_threshold_) {
// Frame threshold has not yet been reached.
return false;
Expand Down Expand Up @@ -260,11 +263,12 @@ bool RasterCache::Draw(const Layer* layer,
return false;
}

void RasterCache::SweepAfterFrame() {
SweepOneCacheAfterFrame(picture_cache_);
SweepOneCacheAfterFrame(layer_cache_);
size_t RasterCache::SweepAfterFrame() {
size_t removed_size = SweepOneCacheAfterFrame(picture_cache_);
removed_size += SweepOneCacheAfterFrame(layer_cache_);
picture_cached_this_frame_ = 0;
TraceStatsToTimeline();
return removed_size;
}

void RasterCache::Clear() {
Expand Down
12 changes: 9 additions & 3 deletions flow/raster_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ class RasterCache {
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change);
bool will_change,
size_t external_size = 0);

void Prepare(PrerollContext* context, Layer* layer, const SkMatrix& ctm);

Expand All @@ -156,7 +157,8 @@ class RasterCache {
SkCanvas& canvas,
SkPaint* paint = nullptr) const;

void SweepAfterFrame();
/// Returns the amount of external bytes freed by the sweep.
size_t SweepAfterFrame();

void Clear();

Expand Down Expand Up @@ -192,24 +194,28 @@ class RasterCache {
struct Entry {
bool used_this_frame = false;
size_t access_count = 0;
size_t external_size = 0;
std::unique_ptr<RasterCacheResult> image;
};

template <class Cache>
static void SweepOneCacheAfterFrame(Cache& cache) {
static size_t SweepOneCacheAfterFrame(Cache& cache) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to document what size is returned from this function. Currently, it seems to only return the layer external size, and one might ask why not also include the image size of the raster cache. Is it because we only want to report the memory size that's managed by Dart VM so the SkImage memory size is irrelevant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The image size is included in the layer external size. The SkImage size is really of primary importance here.

However, we have to figure out how to get that out of what the Dart VM sees - @jason-simmons has a patch open to remove that, but we'd still want it here.

std::vector<typename Cache::iterator> dead;
size_t removed_size = 0;

for (auto it = cache.begin(); it != cache.end(); ++it) {
Entry& entry = it->second;
if (!entry.used_this_frame) {
dead.push_back(it);
removed_size += entry.external_size;
}
entry.used_this_frame = false;
}

for (auto it : dead) {
cache.erase(it);
}
return removed_size;
}

const size_t access_threshold_;
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/compositing/scene_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ void SceneBuilder::addPicture(double dx,
pictureRect.offset(offset.x(), offset.y());
auto layer = std::make_unique<flutter::PictureLayer>(
offset, UIDartState::CreateGPUObject(picture->picture()), !!(hints & 1),
!!(hints & 2));
!!(hints & 2), picture->GetAllocationSize());
AddLayer(std::move(layer));
}

Expand Down
Loading