Skip to content

Commit

Permalink
Compute cull_rect and optimize in Layer::Preroll (flutter#6923)
Browse files Browse the repository at this point in the history
This PR replaces the unused `PrerollContext::child_paint_bounds` with `PrerollContext::cull_rect` so we can prune unnecessary preroll tasks (especially cache) based on clips. This PR fixes flutter/flutter#24712

Performance test has been added (flutter/flutter#25381) to make sure that we won't regress again in the future.

Note that the cull_rect here is very similar to those removed in flutter#6352 .     We can't compute cull rects in SceneBuilder because of retained layers. But we can still compute and use them to optimize performance in Preroll.
  • Loading branch information
liyuqian authored Dec 18, 2018
1 parent fbce2bf commit ba11736
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 19 deletions.
15 changes: 10 additions & 5 deletions flow/layers/clip_path_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@ ClipPathLayer::ClipPathLayer(Clip clip_behavior)
ClipPathLayer::~ClipPathLayer() = default;

void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);

if (child_paint_bounds.intersect(clip_path_.getBounds())) {
set_paint_bounds(child_paint_bounds);
SkRect previous_cull_rect = context->cull_rect;
SkRect clip_path_bounds = clip_path_.getBounds();
if (context->cull_rect.intersect(clip_path_bounds)) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);

if (child_paint_bounds.intersect(clip_path_bounds)) {
set_paint_bounds(child_paint_bounds);
}
}
context->cull_rect = previous_cull_rect;
}

#if defined(OS_FUCHSIA)
Expand Down
14 changes: 9 additions & 5 deletions flow/layers/clip_rect_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ ClipRectLayer::ClipRectLayer(Clip clip_behavior)
ClipRectLayer::~ClipRectLayer() = default;

void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);

if (child_paint_bounds.intersect(clip_rect_)) {
set_paint_bounds(child_paint_bounds);
SkRect previous_cull_rect = context->cull_rect;
if (context->cull_rect.intersect(clip_rect_)) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);

if (child_paint_bounds.intersect(clip_rect_)) {
set_paint_bounds(child_paint_bounds);
}
}
context->cull_rect = previous_cull_rect;
}

#if defined(OS_FUCHSIA)
Expand Down
13 changes: 9 additions & 4 deletions flow/layers/clip_rrect_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ ClipRRectLayer::ClipRRectLayer(Clip clip_behavior)
ClipRRectLayer::~ClipRRectLayer() = default;

void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
SkRect previous_cull_rect = context->cull_rect;
SkRect clip_rrect_bounds = clip_rrect_.getBounds();
if (context->cull_rect.intersect(clip_rrect_bounds)) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);

if (child_paint_bounds.intersect(clip_rrect_.getBounds())) {
set_paint_bounds(child_paint_bounds);
if (child_paint_bounds.intersect(clip_rrect_bounds)) {
set_paint_bounds(child_paint_bounds);
}
}
context->cull_rect = previous_cull_rect;
}

#if defined(OS_FUCHSIA)
Expand Down
4 changes: 3 additions & 1 deletion flow/layers/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

namespace flow {

static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);

// This should be an exact copy of the Clip enum in painting.dart.
enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer };

Expand All @@ -47,7 +49,7 @@ struct PrerollContext {
GrContext* gr_context;
ExternalViewEmbedder* view_embedder;
SkColorSpace* dst_color_space;
SkRect child_paint_bounds;
SkRect cull_rect;

// The following allows us to paint in the end of subtree preroll
const Stopwatch& frame_time;
Expand Down
4 changes: 2 additions & 2 deletions flow/layers/layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
frame.gr_context(),
frame.view_embedder(),
color_space,
SkRect::MakeEmpty(),
kGiantRect,
frame.context().frame_time(),
frame.context().engine_time(),
frame.context().texture_registry(),
Expand Down Expand Up @@ -113,7 +113,7 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
nullptr, // gr_context (used for the raster cache)
nullptr, // external view embedder
nullptr, // SkColorSpace* dst_color_space
SkRect::MakeEmpty(), // SkRect child_paint_bounds
kGiantRect, // SkRect cull_rect
unused_stopwatch, // frame time (dont care)
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
Expand Down
3 changes: 2 additions & 1 deletion flow/layers/opacity_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
child_matrix.postTranslate(offset_.fX, offset_.fY);
ContainerLayer::Preroll(context, child_matrix);
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
if (context->raster_cache && layers().size() == 1) {
if (context->raster_cache && layers().size() == 1 &&
SkRect::Intersects(context->cull_rect, paint_bounds())) {
Layer* child = layers()[0].get();
SkMatrix ctm = child_matrix;
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
Expand Down
10 changes: 10 additions & 0 deletions flow/layers/transform_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,21 @@ void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkMatrix child_matrix;
child_matrix.setConcat(matrix, transform_);

SkRect previous_cull_rect = context->cull_rect;
SkMatrix inverse_transform_;
if (transform_.invert(&inverse_transform_)) {
inverse_transform_.mapRect(&context->cull_rect);
} else {
context->cull_rect = kGiantRect;
}

SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, child_matrix, &child_paint_bounds);

transform_.mapRect(&child_paint_bounds);
set_paint_bounds(child_paint_bounds);

context->cull_rect = previous_cull_rect;
}

#if defined(OS_FUCHSIA)
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/geometry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ class Rect {
/// A rectangle with left, top, right, and bottom edges all at zero.
static final Rect zero = new Rect._();

static const double _giantScalar = 1.0E+9; // matches kGiantRect from default_layer_builder.cc
static const double _giantScalar = 1.0E+9; // matches kGiantRect from layer.h

/// A rectangle that covers the entire coordinate space.
///
Expand Down

0 comments on commit ba11736

Please sign in to comment.