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

Raster cache should preserve RTree for overlay layers #42552

Merged
merged 8 commits into from
Jun 15, 2023
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
8 changes: 8 additions & 0 deletions display_list/geometry/dl_rtree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,12 @@ void DlRTree::search(const Node& parent,
}
}

const SkRect& DlRTree::bounds() const {
if (!nodes_.empty()) {
return nodes_.back().bounds;
} else {
return empty_;
}
}

} // namespace flutter
4 changes: 4 additions & 0 deletions display_list/geometry/dl_rtree.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ class DlRTree : public SkRefCnt {
: invalid_id_;
}

/// Returns maximum and minimum axis values of rectangles in this R-Tree.
/// If R-Tree is empty returns an empty SkRect.
const SkRect& bounds() const;

/// Return the rectangle bounds for the indicated result of a query
/// or an empty rect if the index is not a valid leaf node index.
const SkRect& bounds(int result_index) const {
Expand Down
58 changes: 58 additions & 0 deletions flow/layers/display_list_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,64 @@ TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) {
EXPECT_TRUE(DisplayListsEQ_Verbose(expected.Build(), this->display_list()));
}

TEST_F(DisplayListLayerTest, RasterCachePreservesRTree) {
const SkRect picture1_bounds = SkRect::MakeXYWH(10, 10, 10, 10);
const SkRect picture2_bounds = SkRect::MakeXYWH(15, 15, 10, 10);
DisplayListBuilder builder(true);
builder.DrawRect(picture1_bounds, DlPaint());
builder.DrawRect(picture2_bounds, DlPaint());
auto display_list = builder.Build();
auto display_list_layer = std::make_shared<DisplayListLayer>(
SkPoint::Make(3, 3), display_list, true, false);

use_skia_raster_cache();

auto context = preroll_context();
{
auto mutator = context->state_stack.save();
mutator.transform(SkMatrix::Scale(2.0, 2.0));
display_list_layer->Preroll(preroll_context());
EXPECT_EQ(context->renderable_state_flags, 0);

// Pump the DisplayListLayer until it is ready to cache its DL
display_list_layer->Preroll(preroll_context());
display_list_layer->Preroll(preroll_context());
display_list_layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(*preroll_context()->raster_cached_entries,
&paint_context(), false);
}

DisplayListBuilder expected_root_canvas(true);
expected_root_canvas.Scale(2.0, 2.0);
ASSERT_TRUE(context->raster_cache->Draw(display_list_layer->caching_key_id(),
expected_root_canvas, nullptr,
false));
auto root_canvas_dl = expected_root_canvas.Build();
const auto root_canvas_rects =
root_canvas_dl->rtree()->searchAndConsolidateRects(kGiantRect, true);
std::list<SkRect> root_canvas_rects_expected = {
SkRect::MakeLTRB(26, 26, 56, 56),
};
EXPECT_EQ(root_canvas_rects_expected, root_canvas_rects);

DisplayListBuilder expected_overlay_canvas(true);
expected_overlay_canvas.Scale(2.0, 2.0);
ASSERT_TRUE(context->raster_cache->Draw(display_list_layer->caching_key_id(),
expected_overlay_canvas, nullptr,
true));
auto overlay_canvas_dl = expected_overlay_canvas.Build();
const auto overlay_canvas_rects =
overlay_canvas_dl->rtree()->searchAndConsolidateRects(kGiantRect, true);

// Same bounds as root canvas, but preserves individual rects.
std::list<SkRect> overlay_canvas_rects_expected = {
SkRect::MakeLTRB(26, 26, 46, 36),
SkRect::MakeLTRB(26, 36, 56, 46),
SkRect::MakeLTRB(36, 46, 56, 56),
};
EXPECT_EQ(overlay_canvas_rects_expected, overlay_canvas_rects);
};

using DisplayListLayerDiffTest = DiffContextTest;

TEST_F(DisplayListLayerDiffTest, SimpleDisplayList) {
Expand Down
9 changes: 6 additions & 3 deletions flow/layers/display_list_raster_cache_item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ bool DisplayListRasterCacheItem::Draw(const PaintContext& context,
return false;
}
if (cache_state_ == CacheState::kCurrent) {
return context.raster_cache->Draw(key_id_, *canvas, paint);
return context.raster_cache->Draw(key_id_, *canvas, paint,
context.rendering_above_platform_view);
}
return false;
}
Expand Down Expand Up @@ -166,8 +167,10 @@ bool DisplayListRasterCacheItem::TryToPrepareRasterCache(
// clang-format on
};
return context.raster_cache->UpdateCacheEntry(
id.value(), r_context, [display_list = display_list_](DlCanvas* canvas) {
id.value(), r_context,
[display_list = display_list_](DlCanvas* canvas) {
canvas->DrawDisplayList(display_list);
});
},
display_list_->rtree());
}
} // namespace flutter
5 changes: 5 additions & 0 deletions flow/layers/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ struct PaintContext {
LayerStateStack& state_stack;
DlCanvas* canvas;

// Whether current canvas is an overlay canvas. Used to determine if the
// raster cache is painting to a surface that will be displayed above a
// platform view, in which case it will attempt to preserve the R-Tree.
bool rendering_above_platform_view = false;

GrDirectContext* gr_context;
SkColorSpace* dst_color_space;
ExternalViewEmbedder* view_embedder;
Expand Down
6 changes: 4 additions & 2 deletions flow/layers/layer_raster_cache_item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,16 @@ bool LayerRasterCacheItem::Draw(const PaintContext& context,
case RasterCacheItem::kNone:
return false;
case RasterCacheItem::kCurrent: {
return context.raster_cache->Draw(key_id_, *canvas, paint);
return context.raster_cache->Draw(key_id_, *canvas, paint,
context.rendering_above_platform_view);
}
case RasterCacheItem::kChildren: {
if (!layer_children_id_.has_value()) {
return false;
}
return context.raster_cache->Draw(layer_children_id_.value(), *canvas,
paint);
paint,
context.rendering_above_platform_view);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions flow/layers/platform_view_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ void PlatformViewLayer::Paint(PaintContext& context) const {
DlCanvas* canvas = context.view_embedder->CompositeEmbeddedView(view_id_);
context.canvas = canvas;
context.state_stack.set_delegate(canvas);
context.rendering_above_platform_view = true;
}

} // namespace flutter
54 changes: 42 additions & 12 deletions flow/raster_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <vector>

#include "flutter/common/constants.h"
#include "flutter/display_list/skia/dl_sk_dispatcher.h"
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/layers/layer.h"
#include "flutter/flow/paint_utils.h"
Expand All @@ -26,10 +27,16 @@ namespace flutter {

RasterCacheResult::RasterCacheResult(sk_sp<DlImage> image,
const SkRect& logical_rect,
const char* type)
: image_(std::move(image)), logical_rect_(logical_rect), flow_(type) {}

void RasterCacheResult::draw(DlCanvas& canvas, const DlPaint* paint) const {
const char* type,
sk_sp<const DlRTree> rtree)
: image_(std::move(image)),
logical_rect_(logical_rect),
flow_(type),
rtree_(std::move(rtree)) {}

void RasterCacheResult::draw(DlCanvas& canvas,
const DlPaint* paint,
bool preserve_rtree) const {
DlAutoCanvasRestore auto_restore(&canvas, true);

auto matrix = RasterCacheUtil::GetIntegralTransCTM(canvas.GetTransform());
Expand All @@ -39,8 +46,26 @@ void RasterCacheResult::draw(DlCanvas& canvas, const DlPaint* paint) const {
std::abs(bounds.height() - image_->dimensions().height()) <= 1);
canvas.TransformReset();
flow_.Step();
canvas.DrawImage(image_, {bounds.fLeft, bounds.fTop},
DlImageSampling::kNearestNeighbor, paint);
if (!preserve_rtree || !rtree_) {
canvas.DrawImage(image_, {bounds.fLeft, bounds.fTop},
DlImageSampling::kNearestNeighbor, paint);
} else {
// On some platforms RTree from overlay layers is used for unobstructed
// platform views and hit testing. To preserve the RTree raster cache must
// paint individual rects instead of the whole image.
auto rects = rtree_->searchAndConsolidateRects(kGiantRect);

canvas.Translate(bounds.fLeft, bounds.fTop);

SkRect rtree_bounds =
RasterCacheUtil::GetRoundedOutDeviceBounds(rtree_->bounds(), matrix);
for (auto rect : rects) {
rect = RasterCacheUtil::GetRoundedOutDeviceBounds(rect, matrix);
rect.offset(-rtree_bounds.fLeft, -rtree_bounds.fTop);
canvas.DrawImageRect(image_, rect, rect,
DlImageSampling::kNearestNeighbor, paint);
}
}
}

RasterCache::RasterCache(size_t access_threshold,
Expand All @@ -52,6 +77,7 @@ RasterCache::RasterCache(size_t access_threshold,
/// @note Procedure doesn't copy all closures.
std::unique_ptr<RasterCacheResult> RasterCache::Rasterize(
const RasterCache::Context& context,
sk_sp<const DlRTree> rtree,
const std::function<void(DlCanvas*)>& draw_function,
const std::function<void(DlCanvas*, const SkRect& rect)>& draw_checkerboard)
const {
Expand All @@ -75,6 +101,7 @@ std::unique_ptr<RasterCacheResult> RasterCache::Rasterize(

DlSkCanvasAdapter canvas(surface->getCanvas());
canvas.Clear(DlColor::kTransparent());

canvas.Translate(-dest_rect.left(), -dest_rect.top());
canvas.Transform(matrix);
draw_function(&canvas);
Expand All @@ -84,19 +111,21 @@ std::unique_ptr<RasterCacheResult> RasterCache::Rasterize(
}

auto image = DlImage::Make(surface->makeImageSnapshot());
return std::make_unique<RasterCacheResult>(image, context.logical_rect,
context.flow_type);
return std::make_unique<RasterCacheResult>(
image, context.logical_rect, context.flow_type, std::move(rtree));
}

bool RasterCache::UpdateCacheEntry(
const RasterCacheKeyID& id,
const Context& raster_cache_context,
const std::function<void(DlCanvas*)>& render_function) const {
const std::function<void(DlCanvas*)>& render_function,
sk_sp<const DlRTree> rtree) const {
RasterCacheKey key = RasterCacheKey(id, raster_cache_context.matrix);
Entry& entry = cache_[key];
if (!entry.image) {
void (*func)(DlCanvas*, const SkRect& rect) = DrawCheckerboard;
entry.image = Rasterize(raster_cache_context, render_function, func);
entry.image = Rasterize(raster_cache_context, std::move(rtree),
render_function, func);
if (entry.image != nullptr) {
switch (id.type()) {
case RasterCacheKeyType::kDisplayList: {
Expand Down Expand Up @@ -146,7 +175,8 @@ bool RasterCache::HasEntry(const RasterCacheKeyID& id,

bool RasterCache::Draw(const RasterCacheKeyID& id,
DlCanvas& canvas,
const DlPaint* paint) const {
const DlPaint* paint,
bool preserve_rtree) const {
auto it = cache_.find(RasterCacheKey(id, canvas.GetTransform()));
if (it == cache_.end()) {
return false;
Expand All @@ -155,7 +185,7 @@ bool RasterCache::Draw(const RasterCacheKeyID& id,
Entry& entry = it->second;

if (entry.image) {
entry.image->draw(canvas, paint);
entry.image->draw(canvas, paint, preserve_rtree);
return true;
}

Expand Down
25 changes: 18 additions & 7 deletions flow/raster_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ class RasterCacheResult {
public:
RasterCacheResult(sk_sp<DlImage> image,
const SkRect& logical_rect,
const char* type);
const char* type,
sk_sp<const DlRTree> rtree = nullptr);

virtual ~RasterCacheResult() = default;

virtual void draw(DlCanvas& canvas, const DlPaint* paint) const;
virtual void draw(DlCanvas& canvas,
const DlPaint* paint,
bool preserve_rtree) const;

virtual SkISize image_dimensions() const {
return image_ ? image_->dimensions() : SkISize::Make(0, 0);
Expand All @@ -48,6 +51,7 @@ class RasterCacheResult {
sk_sp<DlImage> image_;
SkRect logical_rect_;
fml::tracing::TraceFlow flow_;
sk_sp<const DlRTree> rtree_;
};

class Layer;
Expand Down Expand Up @@ -127,6 +131,7 @@ class RasterCache {

std::unique_ptr<RasterCacheResult> Rasterize(
const RasterCache::Context& context,
sk_sp<const DlRTree> rtree,
const std::function<void(DlCanvas*)>& draw_function,
const std::function<void(DlCanvas*, const SkRect& rect)>&
draw_checkerboard) const;
Expand All @@ -143,9 +148,15 @@ class RasterCache {
// if the item was disabled due to conditions discovered during |Preroll|
// or if the attempt to populate the entry failed due to bounds overflow
// conditions.
// If |preserve_rtree| is true, the raster cache will preserve the original
// RTree of cached content by blitting individual rectangles from the cached
// image to the canvas according to the original layer R-Tree (if present).
// This is to ensure that the target surface R-Tree will not be clobbered with
// one large blit as it can affect platform view overlays and hit testing.
bool Draw(const RasterCacheKeyID& id,
DlCanvas& canvas,
const DlPaint* paint) const;
const DlPaint* paint,
bool preserve_rtree = false) const;

bool HasEntry(const RasterCacheKeyID& id, const SkMatrix&) const;

Expand Down Expand Up @@ -234,10 +245,10 @@ class RasterCache {
*/
int GetAccessCount(const RasterCacheKeyID& id, const SkMatrix& matrix) const;

bool UpdateCacheEntry(
const RasterCacheKeyID& id,
const Context& raster_cache_context,
const std::function<void(DlCanvas*)>& render_function) const;
bool UpdateCacheEntry(const RasterCacheKeyID& id,
const Context& raster_cache_context,
const std::function<void(DlCanvas*)>& render_function,
sk_sp<const DlRTree> rtree = nullptr) const;

private:
struct Entry {
Expand Down
4 changes: 2 additions & 2 deletions flow/raster_cache_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ TEST(RasterCache, SetCheckboardCacheImages) {
};

cache.SetCheckboardCacheImages(false);
cache.Rasterize(r_context, dummy_draw_function, draw_checkerboard);
cache.Rasterize(r_context, nullptr, dummy_draw_function, draw_checkerboard);
ASSERT_FALSE(did_draw_checkerboard);

cache.SetCheckboardCacheImages(true);
cache.Rasterize(r_context, dummy_draw_function, draw_checkerboard);
cache.Rasterize(r_context, nullptr, dummy_draw_function, draw_checkerboard);
ASSERT_TRUE(did_draw_checkerboard);
}

Expand Down
4 changes: 3 additions & 1 deletion flow/testing/mock_raster_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class MockRasterCacheResult : public RasterCacheResult {
public:
explicit MockRasterCacheResult(SkRect device_rect);

void draw(DlCanvas& canvas, const DlPaint* paint = nullptr) const override{};
void draw(DlCanvas& canvas,
const DlPaint* paint = nullptr,
bool preserve_rtree = false) const override{};

SkISize image_dimensions() const override {
return SkSize::Make(device_rect_.width(), device_rect_.height()).toCeil();
Expand Down