From 56df9b740cd4911cbf6b88e0387d4e7b6930cf6c Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Tue, 13 Oct 2020 20:09:37 +0200 Subject: [PATCH 01/43] Add DiffContext --- flow/BUILD.gn | 2 + flow/diff_context.cc | 157 +++++++++++++++ flow/diff_context.h | 232 +++++++++++++++++++++++ flow/layers/backdrop_filter_layer.cc | 24 +++ flow/layers/backdrop_filter_layer.h | 6 + flow/layers/clip_path_layer.cc | 20 ++ flow/layers/clip_path_layer.h | 6 + flow/layers/clip_rect_layer.cc | 20 ++ flow/layers/clip_rect_layer.h | 6 + flow/layers/clip_rrect_layer.cc | 20 ++ flow/layers/clip_rrect_layer.h | 6 + flow/layers/color_filter_layer.cc | 19 ++ flow/layers/color_filter_layer.h | 6 + flow/layers/container_layer.cc | 102 ++++++++++ flow/layers/container_layer.h | 15 ++ flow/layers/image_filter_layer.cc | 29 +++ flow/layers/image_filter_layer.h | 6 + flow/layers/layer.cc | 1 + flow/layers/layer.h | 41 ++++ flow/layers/layer_tree.h | 11 ++ flow/layers/opacity_layer.cc | 18 ++ flow/layers/opacity_layer.h | 6 + flow/layers/performance_overlay_layer.cc | 16 ++ flow/layers/performance_overlay_layer.h | 14 ++ flow/layers/physical_shape_layer.cc | 32 ++++ flow/layers/physical_shape_layer.h | 6 + flow/layers/picture_layer.cc | 79 ++++++++ flow/layers/picture_layer.h | 22 +++ flow/layers/shader_mask_layer.cc | 20 ++ flow/layers/shader_mask_layer.h | 6 + flow/layers/texture_layer.cc | 18 ++ flow/layers/texture_layer.h | 12 ++ flow/layers/transform_layer.cc | 18 ++ flow/layers/transform_layer.h | 6 + lib/ui/compositing.dart | 70 ++++--- lib/ui/compositing/scene_builder.cc | 79 ++++++-- lib/ui/compositing/scene_builder.h | 39 ++-- 37 files changed, 1137 insertions(+), 53 deletions(-) create mode 100644 flow/diff_context.cc create mode 100644 flow/diff_context.h diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 94b7827bb7e05..819eced5f8d65 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -10,6 +10,8 @@ source_set("flow") { sources = [ "compositor_context.cc", "compositor_context.h", + "diff_context.cc", + "diff_context.h", "embedded_views.cc", "embedded_views.h", "instrumentation.cc", diff --git a/flow/diff_context.cc b/flow/diff_context.cc new file mode 100644 index 0000000000000..bf1a9d760eb4c --- /dev/null +++ b/flow/diff_context.cc @@ -0,0 +1,157 @@ +#include "diff_context.h" +#include "flutter/flow/layers/layer.h" + +namespace flutter { + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +SkRect PaintRegion::GetBounds() const { + SkRect res = SkRect::MakeEmpty(); + for (const auto& r : *this) { + res.join(r); + } + return res; +} + +DiffContext::DiffContext(double frame_device_pixel_ratio, + PaintRegionMap& this_frame_paint_region_map, + const PaintRegionMap& last_frame_paint_region_map) + : rects_(std::make_shared>()), + frame_device_pixel_ratio_(frame_device_pixel_ratio), + this_frame_paint_region_map_(this_frame_paint_region_map), + last_frame_paint_region_map_(last_frame_paint_region_map) {} + +void DiffContext::BeginSubtree() { + state_stack_.push_back(state_); + state_.rect_index_ = rects_->size(); +} + +void DiffContext::EndSubtree() { + assert(!state_stack_.empty()); + state_ = std::move(state_stack_.back()); + state_stack_.pop_back(); +} + +DiffContext::State::State() + : dirty(false), cull_rect(kGiantRect), rect_index_(0) {} + +void DiffContext::PushTransform(const SkMatrix& transform) { + state_.transform.preConcat(transform); + SkMatrix inverse_transform; + // Perspective projections don't produce rectangles that are useful for + // culling for some reason. + if (!transform.hasPerspective() && transform.invert(&inverse_transform)) { + inverse_transform.mapRect(&state_.cull_rect); + } else { + state_.cull_rect = kGiantRect; + } +} + +Damage DiffContext::GetDamage(const SkIRect& accumulated_buffer_damage) const { + SkRect framebuffer = SkRect::Make(accumulated_buffer_damage); + framebuffer.join(damage_); + SkRect net(damage_); + + for (const auto& r : readbacks_) { + if (r.rect.intersects(net)) { + net.join(r.rect); + } + if (r.rect.intersects(framebuffer)) { + framebuffer.join(r.rect); + } + } + + Damage res; + framebuffer.roundOut(&res.buffer_damage); + net.roundOut(&res.surface_damage); + return res; +} + +bool DiffContext::PushCullRect(const SkRect& clip) { + return state_.cull_rect.intersect(clip); +} + +void DiffContext::MarkSubtreeDirty(const PaintRegion& previous_paint_region) { + FML_DCHECK(!IsSubtreeDirty()); + if (previous_paint_region.is_valid()) { + AddDamage(previous_paint_region); + } + state_.dirty = true; +} + +void DiffContext::AddPaintRegion(const SkRect& rect) { + SkRect r(rect); + if (r.intersect(state_.cull_rect)) { + state_.transform.mapRect(&r); + if (!r.isEmpty()) { + rects_->push_back(r); + if (IsSubtreeDirty()) { + AddDamage(r); + } + } + } +} + +void DiffContext::AddPaintRegion(const PaintRegion& region) { + FML_DCHECK(region.is_valid()); + rects_->insert(rects_->end(), region.begin(), region.end()); +} + +void DiffContext::AddReadbackRegion(const SkRect& rect) { + SkRect r(rect); + state_.transform.mapRect(&r); + Readback readback; + readback.rect = r; + readback.position = rects_->size(); + // Push empty rect as a placeholder for position in current subtree + rects_->push_back(SkRect::MakeEmpty()); + readbacks_.push_back(std::move(readback)); +} + +PaintRegion DiffContext::CurrentSubtreeRegion() const { + bool has_readback = std::any_of( + readbacks_.begin(), readbacks_.end(), + [&](const Readback& r) { return r.position >= state_.rect_index_; }); + return PaintRegion(rects_, state_.rect_index_, rects_->size(), has_readback); +} + +void DiffContext::AddDamage(const PaintRegion& damage) { + FML_DCHECK(damage.is_valid()); + for (const auto& r : damage) { + damage_.join(r); + } +} + +void DiffContext::AddDamage(const SkRect& rect) { + damage_.join(rect); +} + +void DiffContext::SetLayerPaintRegion(const Layer* layer, + const PaintRegion& region) { + this_frame_paint_region_map_[layer->unique_id()] = region; +} + +PaintRegion DiffContext::GetOldLayerPaintRegion(const Layer* layer) const { + auto i = last_frame_paint_region_map_.find(layer->unique_id()); + if (i != last_frame_paint_region_map_.end()) { + return i->second; + } else { + return PaintRegion(); + } +} + +void DiffContext::Statistics::LogStatistics() { +#if !FLUTTER_RELEASE + FML_TRACE_COUNTER("flutter", "DiffContext", reinterpret_cast(this), + "NewPictures", new_pictures_, "PicturesTooComplexToCompare", + picture_too_complex_to_compare_, "DeepComparePictures", + deep_compare_pictures_, "SameInstancePictures", + same_instance_pictures_, + "DifferentInstanceButEqualPictures", + difference_instance_but_equal_pictures_); +#endif // !FLUTTER_RELEASE +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + +} // namespace flutter diff --git a/flow/diff_context.h b/flow/diff_context.h new file mode 100644 index 0000000000000..330dd36428e43 --- /dev/null +++ b/flow/diff_context.h @@ -0,0 +1,232 @@ +#ifndef FLUTTER_FLOW_DIFF_CONTEXT_H_ +#define FLUTTER_FLOW_DIFF_CONTEXT_H_ + +#include +#include +#include "flutter/fml/macros.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkRect.h" + +namespace flutter { + +#ifndef NDEBUG +#define FLUTTER_ENABLE_DIFF_CONTEXT +#endif + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +class Layer; + +struct Damage { + // This is the damage between current and previous frame; + // If embedder supports partial update, this is the region that needs to be + // swapped. + SkIRect surface_damage; + + // Reflects actual change to target framebuffer; This is surface_damage + + // damage previously acumulated for target framebuffer. + // All drawing will be clipped to this region. Knowing the affected area + // upfront may be useful for tile based GPUs. + SkIRect buffer_damage; +}; + +// Every layer has a PaintRegion that covers screen area where the layer subtree +// painted anything. +// +// The area is used when adding damage of removed or dirty later. +// +// Because there is PaintRegion for each layer, it must be able to represent +// the area with minimal overhead. This is accomplished by having one +// vector of SkRect shared between all paint regions, and each paint region +// keeping begin and end index of rects relevant to particular subtree. +// +// All rects are in screen coordinates. +class PaintRegion { + public: + PaintRegion() {} + PaintRegion(std::shared_ptr> rects, + size_t from, + size_t to, + bool has_readback) + : rects_(rects), from_(from), to_(to), has_readback_(has_readback) {} + + std::vector::const_iterator begin() const { + assert(is_valid()); + return rects_->begin() + from_; + } + + std::vector::const_iterator end() const { + assert(is_valid()); + return rects_->begin() + to_; + } + + // Compute bounds for this region + SkRect GetBounds() const; + + bool is_valid() const { return rects_ != nullptr; } + + // Returns true if there is a layer in subtree represented by this region + // that performs readback + bool has_readback() const { return has_readback_; } + + private: + std::shared_ptr> rects_; + size_t from_ = 0; + size_t to_ = 0; + bool has_readback_ = false; +}; + +using PaintRegionMap = std::map; + +// Tracks state during tree diffing process and computes resulting damage +class DiffContext { + public: + explicit DiffContext(double device_pixel_aspect_ratio, + PaintRegionMap& this_frame_paint_region_map, + const PaintRegionMap& last_frame_paint_region_map); + + // Starts a new subtree. + void BeginSubtree(); + + // Ends current subtree; All modifications to state (transform, cullrect, + // dirty) will be restored + void EndSubtree(); + + // Creates subtree in current scope and closes it on scope exit + class AutoSubtreeRestore { + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(AutoSubtreeRestore); + + public: + explicit AutoSubtreeRestore(DiffContext* context) : context_(context) { + context->BeginSubtree(); + } + ~AutoSubtreeRestore() { context_->EndSubtree(); } + + private: + DiffContext* context_; + }; + + // Pushes additional transform for current subtree + void PushTransform(const SkMatrix& transform); + + // Pushes cull rect for current subtree + bool PushCullRect(const SkRect& clip); + + // Returns transform matrix for current subtree + SkMatrix GetTransform() const { return state_.transform; } + + // Return cull rect for current subtree (in local coordinates) + SkRect GetCullRect() const { return state_.cull_rect; } + + // Sets the dirty flag on current subtree; + // + // previous_paint_region, which should represent region of previous subtree + // at this level will be added to damage area + // + // Each paint region added to dirty subtree (through AddPaintRegion) is also + // added to damage + void MarkSubtreeDirty( + const PaintRegion& previous_paint_region = PaintRegion()); + + bool IsSubtreeDirty() const { return state_.dirty; } + + // Add paint region for layer; rect is in "local" (layer) coordinates + void AddPaintRegion(const SkRect& rect); + + // Add entire paint region for current subtree + void AddPaintRegion(const PaintRegion& region); + + // The idea of readback region is that if any part of the readback region + // needs to be repainted, then the whole readback region must be repainted; + void AddReadbackRegion(const SkRect& rect); + + // Returns the paint region for current subtree; Each rect in paint region is + // in screen coordinates; The result should be set to layer's paint_region + // before closing the subtree + PaintRegion CurrentSubtreeRegion() const; + + // Computes final damage + // + // additional_damage is the previously accumulated surface_damage for + // current framebuffer + Damage GetDamage(const SkIRect& additional_damage) const; + + double frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }; + + // Adds the region to current damage + void AddDamage(const PaintRegion& damage); + + void SetLayerPaintRegion(const Layer* layer, const PaintRegion& region); + + PaintRegion GetOldLayerPaintRegion(const Layer* layer) const; + + class Statistics { + public: + // Picture replaced by different picture + void AddNewPicture() { ++new_pictures_; } + + // Picture that would require deep comparison but was considered too complex + // to serialize and thus was treated as new picture + void AddPictureTooComplexToCompare() { ++picture_too_complex_to_compare_; } + + // Picture that has identical instance between frames + void AddSameInstancePicture() { ++same_instance_pictures_; }; + + // Pictures that had to be serialized to compare for equality + void AddDeepComparePicture() { ++deep_compare_pictures_; } + + // Pictures that had to be serialized to compare (different instances), + // but were equal + void AddDifferentInstanceButEqualPicture() { + ++difference_instance_but_equal_pictures_; + }; + + // Logs the statistics to trace counter + void LogStatistics(); + + private: + int new_pictures_ = 0; + int picture_too_complex_to_compare_ = 0; + int same_instance_pictures_ = 0; + int deep_compare_pictures_ = 0; + int difference_instance_but_equal_pictures_ = 0; + }; + + Statistics& statistics() { return statistics_; } + + private: + struct State { + State(); + + bool dirty; + SkRect cull_rect; + SkMatrix transform; + size_t rect_index_; + }; + + std::shared_ptr> rects_; + State state_; + double frame_device_pixel_ratio_; + std::vector state_stack_; + + SkRect damage_ = SkRect::MakeEmpty(); + + PaintRegionMap& this_frame_paint_region_map_; + const PaintRegionMap& last_frame_paint_region_map_; + + void AddDamage(const SkRect& rect); + + struct Readback { + size_t position; + SkRect rect; + }; + + std::vector readbacks_; + Statistics statistics_; +}; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + +} // namespace flutter + +#endif // FLUTTER_FLOW_DIFF_CONTEXT_H_ diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index e853a7783fe30..59efa674f3c85 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -9,6 +9,30 @@ namespace flutter { BackdropFilterLayer::BackdropFilterLayer(sk_sp filter) : filter_(std::move(filter)) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (filter_ != prev->filter_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + + // Backdrop filter paints everywhere in cull rect + auto paint_bounds = filter_->computeFastBounds(context->GetCullRect()); + context->AddPaintRegion(paint_bounds); + context->AddReadbackRegion(paint_bounds); + + DiffChildren(context, prev); + + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void BackdropFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = diff --git a/flow/layers/backdrop_filter_layer.h b/flow/layers/backdrop_filter_layer.h index e1fd667d712e9..0788a683c94ac 100644 --- a/flow/layers/backdrop_filter_layer.h +++ b/flow/layers/backdrop_filter_layer.h @@ -14,6 +14,12 @@ class BackdropFilterLayer : public ContainerLayer { public: BackdropFilterLayer(sk_sp filter); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 3e6cf4570a842..7e1a26a1d2d72 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -16,6 +16,26 @@ ClipPathLayer::ClipPathLayer(const SkPath& clip_path, Clip clip_behavior) FML_DCHECK(clip_behavior != Clip::none); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void ClipPathLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (clip_behavior_ != prev->clip_behavior_ || + clip_path_ != prev->clip_path_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + if (context->PushCullRect(clip_path_.getBounds())) { + DiffChildren(context, prev); + } + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "ClipPathLayer::Preroll"); diff --git a/flow/layers/clip_path_layer.h b/flow/layers/clip_path_layer.h index c2af6ce3ffd62..b22bed957048c 100644 --- a/flow/layers/clip_path_layer.h +++ b/flow/layers/clip_path_layer.h @@ -13,6 +13,12 @@ class ClipPathLayer : public ContainerLayer { public: ClipPathLayer(const SkPath& clip_path, Clip clip_behavior = Clip::antiAlias); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index b95a340f33dae..85d7d6ac02ae9 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -12,6 +12,26 @@ ClipRectLayer::ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior) FML_DCHECK(clip_behavior != Clip::none); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void ClipRectLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (clip_behavior_ != prev->clip_behavior_ || + clip_rect_ != prev->clip_rect_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + if (context->PushCullRect(clip_rect_)) { + DiffChildren(context, prev); + } + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "ClipRectLayer::Preroll"); diff --git a/flow/layers/clip_rect_layer.h b/flow/layers/clip_rect_layer.h index 17917b232992e..54c319ef1d16c 100644 --- a/flow/layers/clip_rect_layer.h +++ b/flow/layers/clip_rect_layer.h @@ -13,6 +13,12 @@ class ClipRectLayer : public ContainerLayer { public: ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 39b838be28478..4680ece931086 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -12,6 +12,26 @@ ClipRRectLayer::ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior) FML_DCHECK(clip_behavior != Clip::none); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void ClipRRectLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (clip_behavior_ != prev->clip_behavior_ || + clip_rrect_ != prev->clip_rrect_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + if (context->PushCullRect(clip_rrect_.getBounds())) { + DiffChildren(context, prev); + } + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "ClipRRectLayer::Preroll"); diff --git a/flow/layers/clip_rrect_layer.h b/flow/layers/clip_rrect_layer.h index c308f21c7bfdd..e5045bfa45d0c 100644 --- a/flow/layers/clip_rrect_layer.h +++ b/flow/layers/clip_rrect_layer.h @@ -13,6 +13,12 @@ class ClipRRectLayer : public ContainerLayer { public: ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 17ff3e6d5547b..1c4e9e220a6ef 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -9,6 +9,25 @@ namespace flutter { ColorFilterLayer::ColorFilterLayer(sk_sp filter) : filter_(std::move(filter)) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void ColorFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (filter_ != prev->filter_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + + DiffChildren(context, prev); + + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void ColorFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = diff --git a/flow/layers/color_filter_layer.h b/flow/layers/color_filter_layer.h index cd3c584b4405b..b1fb32acfbcad 100644 --- a/flow/layers/color_filter_layer.h +++ b/flow/layers/color_filter_layer.h @@ -14,6 +14,12 @@ class ColorFilterLayer : public ContainerLayer { public: ColorFilterLayer(sk_sp filter); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 7e09f41737343..7e0fe1231b744 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -10,6 +10,102 @@ namespace flutter { ContainerLayer::ContainerLayer() {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void ContainerLayer::Diff(DiffContext* context, const Layer* old_layer) { + auto old_container = static_cast(old_layer); + DiffContext::AutoSubtreeRestore subtree(context); + DiffChildren(context, old_container); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +void ContainerLayer::PreservePaintRegion(DiffContext* context) { + Layer::PreservePaintRegion(context); + for (auto& layer : layers_) { + layer->PreservePaintRegion(context); + } +} + +void ContainerLayer::DiffChildren(DiffContext* context, + const ContainerLayer* old_layer) { + if (context->IsSubtreeDirty()) { + for (auto& layer : layers_) { + layer->Diff(context, nullptr); + } + return; + } + assert(old_layer); + + const auto& prev_layers = old_layer->layers_; + + // first mismatched element + int new_children_top = 0; + int old_children_top = 0; + + // last mismatched element + int new_children_bottom = layers_.size() - 1; + int old_children_bottom = prev_layers.size() - 1; + + while ((old_children_top <= old_children_bottom) && + (new_children_top <= new_children_bottom)) { + if (!layers_[new_children_top]->CanDiff( + prev_layers[old_children_top].get())) { + break; + } + ++new_children_top; + ++old_children_top; + } + + while ((old_children_top <= old_children_bottom) && + (new_children_top <= new_children_bottom)) { + if (!layers_[new_children_bottom]->CanDiff( + prev_layers[old_children_bottom].get())) { + break; + } + --new_children_bottom; + --old_children_bottom; + } + + // old layers that don't match + for (int i = old_children_top; i <= old_children_bottom; ++i) { + auto layer = prev_layers[i]; + context->AddDamage(context->GetOldLayerPaintRegion(layer.get())); + } + + for (int i = 0; i < static_cast(layers_.size()); ++i) { + if (i < new_children_top || i > new_children_bottom) { + int i_prev = + i < new_children_top ? i : prev_layers.size() - (layers_.size() - i); + auto layer = layers_[i]; + auto prev_layer = prev_layers[i_prev]; + auto paint_region = context->GetOldLayerPaintRegion(layer.get()); + if (layer == prev_layer && !paint_region.has_readback()) { + // for retained layers, stop processing the subtree and add existing + // region; We know current subtree is not dirty (every ancestor up to + // here matches) so the retained subtree will render identically to + // previous frame; We can only do this if there is no readback in the + // subtree. Layers that do readback must be able to register readback + // inside Diff + context->AddPaintRegion(paint_region); + + // While we don't need to diff retained layers, we still need to + // associate their paint region with current layer tree so that we can + // retrieve it in next frame diff + layer->PreservePaintRegion(context); + } else { + layer->Diff(context, prev_layer.get()); + } + } else { + DiffContext::AutoSubtreeRestore subtree(context); + context->MarkSubtreeDirty(); + auto layer = layers_[i]; + layer->Diff(context, nullptr); + } + } +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void ContainerLayer::Add(std::shared_ptr layer) { layers_.emplace_back(std::move(layer)); } @@ -145,6 +241,12 @@ MergedContainerLayer::MergedContainerLayer() { ContainerLayer::Add(std::make_shared()); } +void MergedContainerLayer::AssignOldLayer(Layer* old_layer) { + ContainerLayer::AssignOldLayer(old_layer); + auto layer = static_cast(old_layer); + GetChildContainer()->AssignOldLayer(layer->GetChildContainer()); +} + void MergedContainerLayer::Add(std::shared_ptr layer) { GetChildContainer()->Add(std::move(layer)); } diff --git a/flow/layers/container_layer.h b/flow/layers/container_layer.h index 11eae5f3fe123..e068560ee27c8 100644 --- a/flow/layers/container_layer.h +++ b/flow/layers/container_layer.h @@ -15,6 +15,13 @@ class ContainerLayer : public Layer { public: ContainerLayer(); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + void PreservePaintRegion(DiffContext* context) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + virtual void Add(std::shared_ptr layer); void Preroll(PrerollContext* context, const SkMatrix& matrix) override; @@ -27,6 +34,12 @@ class ContainerLayer : public Layer { const std::vector>& layers() const { return layers_; } protected: +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void DiffChildren(DiffContext* context, const ContainerLayer* old_layer); + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void PrerollChildren(PrerollContext* context, const SkMatrix& child_matrix, SkRect* child_paint_bounds); @@ -101,6 +114,8 @@ class MergedContainerLayer : public ContainerLayer { public: MergedContainerLayer(); + void AssignOldLayer(Layer* old_layer) override; + void Add(std::shared_ptr layer) override; protected: diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index da6d354d075d7..b1741cf6f23d9 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -11,6 +11,35 @@ ImageFilterLayer::ImageFilterLayer(sk_sp filter) transformed_filter_(nullptr), render_count_(1) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (filter_ != prev->filter_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + + DiffChildren(context, prev); + + SkMatrix inverse; + if (context->GetTransform().invert(&inverse)) { + auto paint_bounds = context->CurrentSubtreeRegion().GetBounds(); + inverse.mapRect(&paint_bounds); + paint_bounds = filter_->computeFastBounds(paint_bounds); + + context->AddPaintRegion(paint_bounds); + context->AddReadbackRegion(paint_bounds); + } + + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void ImageFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "ImageFilterLayer::Preroll"); diff --git a/flow/layers/image_filter_layer.h b/flow/layers/image_filter_layer.h index 4b274fef8fdc3..635d57a432365 100644 --- a/flow/layers/image_filter_layer.h +++ b/flow/layers/image_filter_layer.h @@ -14,6 +14,12 @@ class ImageFilterLayer : public MergedContainerLayer { public: ImageFilterLayer(sk_sp filter); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index 006f5cb84e916..a81607b2982df 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -12,6 +12,7 @@ namespace flutter { Layer::Layer() : paint_bounds_(SkRect::MakeEmpty()), unique_id_(NextUniqueID()), + original_layer_id_(unique_id_), needs_system_composite_(false) {} Layer::~Layer() = default; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 60c949f9d5c5e..57c22cfa9a513 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -9,6 +9,7 @@ #include #include "flutter/common/graphics/texture.h" +#include "flutter/flow/diff_context.h" #include "flutter/flow/embedded_views.h" #include "flutter/flow/instrumentation.h" #include "flutter/flow/raster_cache.h" @@ -69,6 +70,10 @@ struct PrerollContext { bool has_texture_layer = false; }; +class PictureLayer; +class PerformanceOverlayLayer; +class TextureLayer; + // Represents a single composited layer. Created on the UI thread but then // subquently used on the Rasterizer thread. class Layer { @@ -76,6 +81,27 @@ class Layer { Layer(); virtual ~Layer(); + virtual void AssignOldLayer(Layer* old_layer) { + original_layer_id_ = old_layer->original_layer_id_; + } + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + virtual bool CanDiff(const Layer* layer) const { + return original_layer_id_ == layer->original_layer_id_; + } + + virtual void Diff(DiffContext* context, const Layer* old_layer) {} + + // Used when diffing retained layer; In case the layer is identical, it + // doesn't need to be diffed, but the paint region needs to be stored in diff + // context so that it can be used in next frame + virtual void PreservePaintRegion(DiffContext* context) { + context->SetLayerPaintRegion(this, context->GetOldLayerPaintRegion(this)); + } + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + virtual void Preroll(PrerollContext* context, const SkMatrix& matrix); // Used during Preroll by layers that employ a saveLayer to manage the @@ -201,8 +227,22 @@ class Layer { return !context.leaf_nodes_canvas->quickReject(paint_bounds_); } + // Propagated unique_id of the first layer in "chain" of replacement layers + // that can be diffed. + uint64_t original_layer_id() const { return original_layer_id_; } + uint64_t unique_id() const { return unique_id_; } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + virtual const PictureLayer* as_picture_layer() const { return nullptr; } + virtual const TextureLayer* as_texture_layer() const { return nullptr; } + virtual const PerformanceOverlayLayer* as_performance_overlay_layer() const { + return nullptr; + } + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + protected: #if defined(LEGACY_FUCHSIA_EMBEDDER) bool child_layer_exists_below_ = false; @@ -211,6 +251,7 @@ class Layer { private: SkRect paint_bounds_; uint64_t unique_id_; + uint64_t original_layer_id_; bool needs_system_composite_; static uint64_t NextUniqueID(); diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index b59f278296381..db8a33b4506c8 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -49,6 +49,13 @@ class LayerTree { const SkISize& frame_size() const { return frame_size_; } float device_pixel_ratio() const { return device_pixel_ratio_; } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + const PaintRegionMap& paint_region_map() const { return paint_region_map_; } + PaintRegionMap& paint_region_map() { return paint_region_map_; } + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void RecordBuildTime(fml::TimePoint vsync_start, fml::TimePoint build_start, fml::TimePoint target_time); @@ -90,6 +97,10 @@ class LayerTree { bool checkerboard_raster_cache_images_; bool checkerboard_offscreen_layers_; +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + PaintRegionMap paint_region_map_; +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + FML_DISALLOW_COPY_AND_ASSIGN(LayerTree); }; diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index cc9ec4a42f152..a4e1456638eba 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -12,6 +12,24 @@ namespace flutter { OpacityLayer::OpacityLayer(SkAlpha alpha, const SkPoint& offset) : alpha_(alpha), offset_(offset) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void OpacityLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (alpha_ != prev->alpha_ || offset_ != prev->offset_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + context->PushTransform(SkMatrix::Translate(offset_.fX, offset_.fY)); + DiffChildren(context, prev); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "OpacityLayer::Preroll"); FML_DCHECK(!GetChildContainer()->layers().empty()); // We can't be a leaf. diff --git a/flow/layers/opacity_layer.h b/flow/layers/opacity_layer.h index 25f1c7944a829..3821dba531ef3 100644 --- a/flow/layers/opacity_layer.h +++ b/flow/layers/opacity_layer.h @@ -27,6 +27,12 @@ class OpacityLayer : public MergedContainerLayer { // the propagation as repainting the OpacityLayer is expensive. OpacityLayer(SkAlpha alpha, const SkPoint& offset); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index a2e4a33adfc16..fbfe71ef44803 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -74,6 +74,22 @@ PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options, } } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void PerformanceOverlayLayer::Diff(DiffContext* context, + const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + if (!context->IsSubtreeDirty()) { + assert(old_layer); + auto prev = old_layer->as_performance_overlay_layer(); + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); + } + context->AddPaintRegion(paint_bounds()); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void PerformanceOverlayLayer::Paint(PaintContext& context) const { const int padding = 8; diff --git a/flow/layers/performance_overlay_layer.h b/flow/layers/performance_overlay_layer.h index b1434a221e688..75976cf16387f 100644 --- a/flow/layers/performance_overlay_layer.h +++ b/flow/layers/performance_overlay_layer.h @@ -26,6 +26,20 @@ class PerformanceOverlayLayer : public Layer { const std::string& label_prefix, const std::string& font_path); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + bool CanDiff(const Layer* layer) const override { + return layer->as_performance_overlay_layer() != nullptr; + } + + void Diff(DiffContext* context, const Layer* old_layer) override; + + const PerformanceOverlayLayer* as_performance_overlay_layer() const override { + return this; + } + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + explicit PerformanceOverlayLayer(uint64_t options, const char* font_path = nullptr); diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index 8f8ecbb5e91cd..9e40838749fa0 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -23,6 +23,38 @@ PhysicalShapeLayer::PhysicalShapeLayer(SkColor color, path_(path), clip_behavior_(clip_behavior) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void PhysicalShapeLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (color_ != prev->color_ || shadow_color_ != prev->shadow_color_ || + elevation_ != prev->elevation() || path_ != prev->path_ || + clip_behavior_ != prev->clip_behavior_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + + SkRect bounds; + if (elevation_ == 0) { + bounds = path_.getBounds(); + } else { + bounds = ComputeShadowBounds(path_.getBounds(), elevation_, + context->frame_device_pixel_ratio()); + } + + context->AddPaintRegion(bounds); + + if (context->PushCullRect(bounds)) { + DiffChildren(context, prev); + } + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void PhysicalShapeLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "PhysicalShapeLayer::Preroll"); diff --git a/flow/layers/physical_shape_layer.h b/flow/layers/physical_shape_layer.h index ce49af1a003ae..a090367db1bb6 100644 --- a/flow/layers/physical_shape_layer.h +++ b/flow/layers/physical_shape_layer.h @@ -27,6 +27,12 @@ class PhysicalShapeLayer : public ContainerLayer { bool transparentOccluder, SkScalar dpr); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index f28c47045c65e..c59322f6854b3 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -5,6 +5,7 @@ #include "flutter/flow/layers/picture_layer.h" #include "flutter/fml/logging.h" +#include "third_party/skia/include/core/SkSerialProcs.h" namespace flutter { @@ -17,6 +18,84 @@ PictureLayer::PictureLayer(const SkPoint& offset, is_complex_(is_complex), will_change_(will_change) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void PictureLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + if (!context->IsSubtreeDirty()) { + assert(old_layer); + auto prev = old_layer->as_picture_layer(); + if (prev->offset_ != offset_ || !Compare(context, this, prev)) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); + } + } + context->PushTransform(SkMatrix::Translate(offset_.x(), offset_.y())); + context->AddPaintRegion(picture()->cullRect()); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +bool PictureLayer::Compare(DiffContext* context, + const PictureLayer* l1, + const PictureLayer* l2) { + const auto& pic1 = l1->picture_.get(); + const auto& pic2 = l2->picture_.get(); + if (pic1.get() == pic2.get()) { + context->statistics().AddSameInstancePicture(); + return true; + } + auto op_cnt_1 = pic1->approximateOpCount(); + auto op_cnt_2 = pic2->approximateOpCount(); + if (op_cnt_1 != op_cnt_2 || pic1->cullRect() != pic2->cullRect()) { + context->statistics().AddNewPicture(); + return false; + } + + if (op_cnt_1 > 10) { + context->statistics().AddPictureTooComplexToCompare(); + return false; + } + + context->statistics().AddDeepComparePicture(); + + // TODO(knopp) we don't actually need the data; this could be done without + // allocations by implementing stream that calculates SHA hash and + // comparing those hashes + auto d1 = l1->SerializedPicture(); + auto d2 = l2->SerializedPicture(); + auto res = d1->equals(d2.get()); + if (res) { + context->statistics().AddDifferentInstanceButEqualPicture(); + } else { + context->statistics().AddNewPicture(); + } + return res; +} + +sk_sp PictureLayer::SerializedPicture() const { + SkSerialProcs procs = { + nullptr, + nullptr, + [](SkImage* i, void* ctx) { + auto id = i->uniqueID(); + return SkData::MakeWithCopy(&id, sizeof(id)); + }, + nullptr, + [](SkTypeface* tf, void* ctx) { + auto id = tf->uniqueID(); + return SkData::MakeWithCopy(&id, sizeof(id)); + }, + nullptr, + }; + + if (!cached_serialized_picture_) { + cached_serialized_picture_ = picture_.get()->serialize(&procs); + } else { + } + return cached_serialized_picture_; +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "PictureLayer::Preroll"); diff --git a/flow/layers/picture_layer.h b/flow/layers/picture_layer.h index e733e7455ca6c..22473ec6ebd8d 100644 --- a/flow/layers/picture_layer.h +++ b/flow/layers/picture_layer.h @@ -22,6 +22,18 @@ class PictureLayer : public Layer { SkPicture* picture() const { return picture_.get().get(); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + bool CanDiff(const Layer* layer) const override { + return layer->as_picture_layer() != nullptr; + } + + void Diff(DiffContext* context, const Layer* old_layer) override; + + const PictureLayer* as_picture_layer() const override { return this; } + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* frame, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; @@ -34,6 +46,16 @@ class PictureLayer : public Layer { bool is_complex_ = false; bool will_change_ = false; +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + sk_sp SerializedPicture() const; + mutable sk_sp cached_serialized_picture_; + static bool Compare(DiffContext* context, + const PictureLayer* l1, + const PictureLayer* l2); + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + FML_DISALLOW_COPY_AND_ASSIGN(PictureLayer); }; diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index 091b447ac31c0..d878eaa292f06 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -11,6 +11,26 @@ ShaderMaskLayer::ShaderMaskLayer(sk_sp shader, SkBlendMode blend_mode) : shader_(shader), mask_rect_(mask_rect), blend_mode_(blend_mode) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void ShaderMaskLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (shader_ != prev->shader_ || mask_rect_ != prev->mask_rect_ || + blend_mode_ != prev->blend_mode_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + + DiffChildren(context, prev); + + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void ShaderMaskLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { #if defined(LEGACY_FUCHSIA_EMBEDDER) CheckForChildLayerBelow(context); diff --git a/flow/layers/shader_mask_layer.h b/flow/layers/shader_mask_layer.h index 9bfce9644bc5a..193ba5baf1cfd 100644 --- a/flow/layers/shader_mask_layer.h +++ b/flow/layers/shader_mask_layer.h @@ -16,6 +16,12 @@ class ShaderMaskLayer : public ContainerLayer { const SkRect& mask_rect, SkBlendMode blend_mode); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index 2ddc8a7b400fe..b9022fb053562 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -19,6 +19,24 @@ TextureLayer::TextureLayer(const SkPoint& offset, freeze_(freeze), sampling_(sampling) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void TextureLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + if (!context->IsSubtreeDirty()) { + assert(old_layer); + auto prev = old_layer->as_texture_layer(); + // TODO(knopp) It would be nice to be able to determine that a texture is + // dirty + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); + } + context->AddPaintRegion(SkRect::MakeXYWH(offset_.x(), offset_.y(), + size_.width(), size_.height())); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void TextureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "TextureLayer::Preroll"); diff --git a/flow/layers/texture_layer.h b/flow/layers/texture_layer.h index ed6f027064aff..737b9bec2ef77 100644 --- a/flow/layers/texture_layer.h +++ b/flow/layers/texture_layer.h @@ -20,6 +20,18 @@ class TextureLayer : public Layer { bool freeze, const SkSamplingOptions& sampling); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + bool CanDiff(const Layer* layer) const override { + return layer->as_texture_layer() != nullptr; + } + + void Diff(DiffContext* context, const Layer* old_layer) override; + + const TextureLayer* as_texture_layer() const override { return this; } + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index 839fbe05af292..300652c0c759c 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -26,6 +26,24 @@ TransformLayer::TransformLayer(const SkMatrix& transform) } } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void TransformLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + assert(prev); + if (transform_ != prev->transform_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + context->PushTransform(transform_); + DiffChildren(context, prev); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "TransformLayer::Preroll"); diff --git a/flow/layers/transform_layer.h b/flow/layers/transform_layer.h index 7956e3906a680..f628edbc34a33 100644 --- a/flow/layers/transform_layer.h +++ b/flow/layers/transform_layer.h @@ -15,6 +15,12 @@ class TransformLayer : public ContainerLayer { public: TransformLayer(const SkMatrix& transform); +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 626e61ef4f6cc..59a6e2fee8ba6 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -286,13 +286,14 @@ class SceneBuilder extends NativeFieldWrapperClass2 { assert(_matrix4IsValid(matrix4)); assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushTransform')); final EngineLayer engineLayer = EngineLayer._(); - _pushTransform(engineLayer, matrix4); + _pushTransform(engineLayer, matrix4, oldLayer?._nativeLayer); final TransformEngineLayer layer = TransformEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushTransform(EngineLayer layer, Float64List matrix4) native 'SceneBuilder_pushTransform'; + void _pushTransform(EngineLayer layer, Float64List matrix4, EngineLayer? oldLayer) + native 'SceneBuilder_pushTransform'; /// Pushes an offset operation onto the operation stack. /// @@ -310,13 +311,14 @@ class SceneBuilder extends NativeFieldWrapperClass2 { }) { assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOffset')); final EngineLayer engineLayer = EngineLayer._(); - _pushOffset(engineLayer, dx, dy); + _pushOffset(engineLayer, dx, dy, oldLayer?._nativeLayer); final OffsetEngineLayer layer = OffsetEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushOffset(EngineLayer layer, double dx, double dy) native 'SceneBuilder_pushOffset'; + void _pushOffset(EngineLayer layer, double dx, double dy, EngineLayer? oldLayer) + native 'SceneBuilder_pushOffset'; /// Pushes a rectangular clip operation onto the operation stack. /// @@ -337,14 +339,15 @@ class SceneBuilder extends NativeFieldWrapperClass2 { assert(clipBehavior != Clip.none); assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipRect')); final EngineLayer engineLayer = EngineLayer._(); - _pushClipRect(engineLayer, rect.left, rect.right, rect.top, rect.bottom, clipBehavior.index); + _pushClipRect(engineLayer, rect.left, rect.right, rect.top, rect.bottom, clipBehavior.index, + oldLayer?._nativeLayer); final ClipRectEngineLayer layer = ClipRectEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushClipRect(EngineLayer outEngineLayer, double left, double right, double top, double bottom, int clipBehavior) - native 'SceneBuilder_pushClipRect'; + void _pushClipRect(EngineLayer outEngineLayer, double left, double right, double top, + double bottom, int clipBehavior, EngineLayer? oldLayer) native 'SceneBuilder_pushClipRect'; /// Pushes a rounded-rectangular clip operation onto the operation stack. /// @@ -365,13 +368,13 @@ class SceneBuilder extends NativeFieldWrapperClass2 { assert(clipBehavior != Clip.none); assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipRRect')); final EngineLayer engineLayer = EngineLayer._(); - _pushClipRRect(engineLayer, rrect._value32, clipBehavior.index); + _pushClipRRect(engineLayer, rrect._value32, clipBehavior.index, oldLayer?._nativeLayer); final ClipRRectEngineLayer layer = ClipRRectEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushClipRRect(EngineLayer layer, Float32List rrect, int clipBehavior) + void _pushClipRRect(EngineLayer layer, Float32List rrect, int clipBehavior, EngineLayer? oldLayer) native 'SceneBuilder_pushClipRRect'; /// Pushes a path clip operation onto the operation stack. @@ -393,13 +396,14 @@ class SceneBuilder extends NativeFieldWrapperClass2 { assert(clipBehavior != Clip.none); assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipPath')); final EngineLayer engineLayer = EngineLayer._(); - _pushClipPath(engineLayer, path, clipBehavior.index); + _pushClipPath(engineLayer, path, clipBehavior.index, oldLayer?._nativeLayer); final ClipPathEngineLayer layer = ClipPathEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushClipPath(EngineLayer layer, Path path, int clipBehavior) native 'SceneBuilder_pushClipPath'; + void _pushClipPath(EngineLayer layer, Path path, int clipBehavior, EngineLayer? oldLayer) + native 'SceneBuilder_pushClipPath'; /// Pushes an opacity operation onto the operation stack. /// @@ -420,13 +424,14 @@ class SceneBuilder extends NativeFieldWrapperClass2 { }) { assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOpacity')); final EngineLayer engineLayer = EngineLayer._(); - _pushOpacity(engineLayer, alpha, offset!.dx, offset.dy); + _pushOpacity(engineLayer, alpha, offset!.dx, offset.dy, oldLayer?._nativeLayer); final OpacityEngineLayer layer = OpacityEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushOpacity(EngineLayer layer, int alpha, double dx, double dy) native 'SceneBuilder_pushOpacity'; + void _pushOpacity(EngineLayer layer, int alpha, double dx, double dy, EngineLayer? oldLayer) + native 'SceneBuilder_pushOpacity'; /// Pushes a color filter operation onto the operation stack. /// @@ -447,13 +452,14 @@ class SceneBuilder extends NativeFieldWrapperClass2 { final _ColorFilter nativeFilter = filter._toNativeColorFilter()!; assert(nativeFilter != null); // ignore: unnecessary_null_comparison final EngineLayer engineLayer = EngineLayer._(); - _pushColorFilter(engineLayer, nativeFilter); + _pushColorFilter(engineLayer, nativeFilter, oldLayer?._nativeLayer); final ColorFilterEngineLayer layer = ColorFilterEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushColorFilter(EngineLayer layer, _ColorFilter filter) native 'SceneBuilder_pushColorFilter'; + void _pushColorFilter(EngineLayer layer, _ColorFilter filter, EngineLayer? oldLayer) + native 'SceneBuilder_pushColorFilter'; /// Pushes an image filter operation onto the operation stack. /// @@ -474,13 +480,14 @@ class SceneBuilder extends NativeFieldWrapperClass2 { final _ImageFilter nativeFilter = filter._toNativeImageFilter(); assert(nativeFilter != null); // ignore: unnecessary_null_comparison final EngineLayer engineLayer = EngineLayer._(); - _pushImageFilter(engineLayer, nativeFilter); + _pushImageFilter(engineLayer, nativeFilter, oldLayer?._nativeLayer); final ImageFilterEngineLayer layer = ImageFilterEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushImageFilter(EngineLayer outEngineLayer, _ImageFilter filter) native 'SceneBuilder_pushImageFilter'; + void _pushImageFilter(EngineLayer outEngineLayer, _ImageFilter filter, EngineLayer? oldLayer) + native 'SceneBuilder_pushImageFilter'; /// Pushes a backdrop filter operation onto the operation stack. /// @@ -498,13 +505,14 @@ class SceneBuilder extends NativeFieldWrapperClass2 { }) { assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushBackdropFilter')); final EngineLayer engineLayer = EngineLayer._(); - _pushBackdropFilter(engineLayer, filter._toNativeImageFilter()); + _pushBackdropFilter(engineLayer, filter._toNativeImageFilter(), oldLayer?._nativeLayer); final BackdropFilterEngineLayer layer = BackdropFilterEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter) native 'SceneBuilder_pushBackdropFilter'; + void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter, EngineLayer? oldLayer) + native 'SceneBuilder_pushBackdropFilter'; /// Pushes a shader mask operation onto the operation stack. /// @@ -532,6 +540,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 { maskRect.top, maskRect.bottom, blendMode.index, + oldLayer?._nativeLayer, ); final ShaderMaskEngineLayer layer = ShaderMaskEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); @@ -545,7 +554,8 @@ class SceneBuilder extends NativeFieldWrapperClass2 { double maskRectRight, double maskRectTop, double maskRectBottom, - int blendMode) native 'SceneBuilder_pushShaderMask'; + int blendMode, + EngineLayer? oldLayer) native 'SceneBuilder_pushShaderMask'; /// Pushes a physical layer operation for an arbitrary shape onto the /// operation stack. @@ -574,21 +584,21 @@ class SceneBuilder extends NativeFieldWrapperClass2 { }) { assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushPhysicalShape')); final EngineLayer engineLayer = EngineLayer._(); - _pushPhysicalShape( - engineLayer, - path, - elevation, - color.value, - shadowColor?.value ?? 0xFF000000, - clipBehavior.index, - ); + _pushPhysicalShape(engineLayer, path, elevation, color.value, shadowColor?.value ?? 0xFF000000, + clipBehavior.index, oldLayer?._nativeLayer); final PhysicalShapeEngineLayer layer = PhysicalShapeEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - void _pushPhysicalShape(EngineLayer outEngineLayer, Path path, double elevation, int color, int shadowColor, - int clipBehavior) native 'SceneBuilder_pushPhysicalShape'; + void _pushPhysicalShape( + EngineLayer outEngineLayer, + Path path, + double elevation, + int color, + int shadowColor, + int clipBehavior, + EngineLayer? oldLayer) native 'SceneBuilder_pushPhysicalShape'; /// Ends the effect of the most recently pushed operation. /// diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index b9d96ead946b2..1b38dc946515f 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -90,20 +90,32 @@ SceneBuilder::SceneBuilder() { SceneBuilder::~SceneBuilder() = default; void SceneBuilder::pushTransform(Dart_Handle layer_handle, - tonic::Float64List& matrix4) { + tonic::Float64List& matrix4, + fml::RefPtr oldLayer) { SkMatrix sk_matrix = ToSkMatrix(matrix4); auto layer = std::make_shared(sk_matrix); PushLayer(layer); // matrix4 has to be released before we can return another Dart object matrix4.Release(); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } -void SceneBuilder::pushOffset(Dart_Handle layer_handle, double dx, double dy) { +void SceneBuilder::pushOffset(Dart_Handle layer_handle, + double dx, + double dy, + fml::RefPtr oldLayer) { SkMatrix sk_matrix = SkMatrix::Translate(dx, dy); auto layer = std::make_shared(sk_matrix); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushClipRect(Dart_Handle layer_handle, @@ -111,67 +123,102 @@ void SceneBuilder::pushClipRect(Dart_Handle layer_handle, double right, double top, double bottom, - int clipBehavior) { + int clipBehavior, + fml::RefPtr oldLayer) { SkRect clipRect = SkRect::MakeLTRB(left, top, right, bottom); flutter::Clip clip_behavior = static_cast(clipBehavior); auto layer = std::make_shared(clipRect, clip_behavior); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushClipRRect(Dart_Handle layer_handle, const RRect& rrect, - int clipBehavior) { + int clipBehavior, + fml::RefPtr oldLayer) { flutter::Clip clip_behavior = static_cast(clipBehavior); auto layer = std::make_shared(rrect.sk_rrect, clip_behavior); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushClipPath(Dart_Handle layer_handle, const CanvasPath* path, - int clipBehavior) { + int clipBehavior, + fml::RefPtr oldLayer) { flutter::Clip clip_behavior = static_cast(clipBehavior); FML_DCHECK(clip_behavior != flutter::Clip::none); auto layer = std::make_shared(path->path(), clip_behavior); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushOpacity(Dart_Handle layer_handle, int alpha, double dx, - double dy) { + double dy, + fml::RefPtr oldLayer) { auto layer = std::make_shared(alpha, SkPoint::Make(dx, dy)); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushColorFilter(Dart_Handle layer_handle, - const ColorFilter* color_filter) { + const ColorFilter* color_filter, + fml::RefPtr oldLayer) { auto layer = std::make_shared(color_filter->filter()); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushImageFilter(Dart_Handle layer_handle, - const ImageFilter* image_filter) { + const ImageFilter* image_filter, + fml::RefPtr oldLayer) { auto layer = std::make_shared(image_filter->filter()); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushBackdropFilter(Dart_Handle layer_handle, - ImageFilter* filter) { + ImageFilter* filter, + fml::RefPtr oldLayer) { auto layer = std::make_shared(filter->filter()); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushShaderMask(Dart_Handle layer_handle, @@ -180,13 +227,18 @@ void SceneBuilder::pushShaderMask(Dart_Handle layer_handle, double maskRectRight, double maskRectTop, double maskRectBottom, - int blendMode) { + int blendMode, + fml::RefPtr oldLayer) { SkRect rect = SkRect::MakeLTRB(maskRectLeft, maskRectTop, maskRectRight, maskRectBottom); auto layer = std::make_shared( shader->shader(), rect, static_cast(blendMode)); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::pushPhysicalShape(Dart_Handle layer_handle, @@ -194,13 +246,18 @@ void SceneBuilder::pushPhysicalShape(Dart_Handle layer_handle, double elevation, int color, int shadow_color, - int clipBehavior) { + int clipBehavior, + fml::RefPtr oldLayer) { auto layer = std::make_shared( static_cast(color), static_cast(shadow_color), static_cast(elevation), path->path(), static_cast(clipBehavior)); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); + + if (oldLayer && oldLayer->Layer()) { + layer->AssignOldLayer(oldLayer->Layer().get()); + } } void SceneBuilder::addRetained(fml::RefPtr retainedLayer) { diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h index 37f229429e679..51ca025c584bf 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -37,42 +37,57 @@ class SceneBuilder : public RefCountedDartWrappable { } ~SceneBuilder() override; - void pushTransform(Dart_Handle layer_handle, tonic::Float64List& matrix4); - void pushOffset(Dart_Handle layer_handle, double dx, double dy); + void pushTransform(Dart_Handle layer_handle, + tonic::Float64List& matrix4, + fml::RefPtr oldLayer); + void pushOffset(Dart_Handle layer_handle, + double dx, + double dy, + fml::RefPtr oldLayer); void pushClipRect(Dart_Handle layer_handle, double left, double right, double top, double bottom, - int clipBehavior); + int clipBehavior, + fml::RefPtr oldLayer); void pushClipRRect(Dart_Handle layer_handle, const RRect& rrect, - int clipBehavior); + int clipBehavior, + fml::RefPtr oldLayer); void pushClipPath(Dart_Handle layer_handle, const CanvasPath* path, - int clipBehavior); + int clipBehavior, + fml::RefPtr oldLayer); void pushOpacity(Dart_Handle layer_handle, int alpha, - double dx = 0, - double dy = 0); + double dx, + double dy, + fml::RefPtr oldLayer); void pushColorFilter(Dart_Handle layer_handle, - const ColorFilter* color_filter); + const ColorFilter* color_filter, + fml::RefPtr oldLayer); void pushImageFilter(Dart_Handle layer_handle, - const ImageFilter* image_filter); - void pushBackdropFilter(Dart_Handle layer_handle, ImageFilter* filter); + const ImageFilter* image_filter, + fml::RefPtr oldLayer); + void pushBackdropFilter(Dart_Handle layer_handle, + ImageFilter* filter, + fml::RefPtr oldLayer); void pushShaderMask(Dart_Handle layer_handle, Shader* shader, double maskRectLeft, double maskRectRight, double maskRectTop, double maskRectBottom, - int blendMode); + int blendMode, + fml::RefPtr oldLayer); void pushPhysicalShape(Dart_Handle layer_handle, const CanvasPath* path, double elevation, int color, int shadowColor, - int clipBehavior); + int clipBehavior, + fml::RefPtr oldLayer); void addRetained(fml::RefPtr retainedLayer); From 92b478f748310b9bc99638de5d04f1495e1938d3 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 14 Oct 2020 01:23:56 +0200 Subject: [PATCH 02/43] Add basic unit tests --- flow/BUILD.gn | 3 + flow/diff_context_unittests.cc | 229 ++++++++++++++++++++++++++++++ flow/testing/diff_context_test.cc | 49 +++++++ flow/testing/diff_context_test.h | 60 ++++++++ 4 files changed, 341 insertions(+) create mode 100644 flow/diff_context_unittests.cc create mode 100644 flow/testing/diff_context_test.cc create mode 100644 flow/testing/diff_context_test.h diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 819eced5f8d65..c2d0058c19f2b 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -105,6 +105,8 @@ if (enable_unittests) { testonly = true sources = [ + "testing/diff_context_test.cc", + "testing/diff_context_test.h", "testing/gl_context_switch_test.cc", "testing/gl_context_switch_test.h", "testing/layer_test.h", @@ -133,6 +135,7 @@ if (enable_unittests) { testonly = true sources = [ + "diff_context_unittests.cc", "embedded_view_params_unittests.cc", "flow_run_all_unittests.cc", "flow_test_utils.cc", diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc new file mode 100644 index 0000000000000..621dd456d4fad --- /dev/null +++ b/flow/diff_context_unittests.cc @@ -0,0 +1,229 @@ +#include "diff_context.h" +#include "flutter/flow/layers/container_layer.h" +#include "flutter/flow/layers/picture_layer.h" +#include "flutter/flow/testing/diff_context_test.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +TEST_F(DiffContextTest, SimplePicture) { + auto picture = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + + LayerTree tree1; + tree1.root()->Add(CreatePictureLayer(picture)); + + auto damage = DiffLayerTree(tree1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); + + LayerTree tree2; + tree2.root()->Add(CreatePictureLayer(picture)); + + damage = DiffLayerTree(tree2, tree1); + EXPECT_TRUE(damage.surface_damage.isEmpty()); + + LayerTree tree3; + damage = DiffLayerTree(tree3, tree2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); +} + +TEST_F(DiffContextTest, PictureCompare) { + LayerTree tree1; + auto picture1 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + tree1.root()->Add(CreatePictureLayer(picture1)); + + auto damage = DiffLayerTree(tree1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); + + LayerTree tree2; + auto picture2 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + tree2.root()->Add(CreatePictureLayer(picture2)); + + damage = DiffLayerTree(tree2, tree1); + EXPECT_TRUE(damage.surface_damage.isEmpty()); + + LayerTree tree3; + auto picture3 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + // add offset + tree3.root()->Add(CreatePictureLayer(picture3, SkPoint::Make(10, 10))); + + damage = DiffLayerTree(tree3, tree2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 60, 60)); + + LayerTree tree4; + // different color + auto picture4 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 2); + tree4.root()->Add(CreatePictureLayer(picture4, SkPoint::Make(10, 10))); + + damage = DiffLayerTree(tree4, tree3); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(20, 20, 50, 50)); +} + +TEST_F(DiffContextTest, PictureLayerInsertion) { + auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + + LayerTree t1; + + auto t1_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + t1.root()->Add(t1_c1); + + auto t1_c2 = CreateContainerLayer(CreatePictureLayer(pic2)); + t1.root()->Add(t1_c2); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 150, 50)); + + // Add in the middle + + LayerTree t2; + auto t2_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + t2_c1->AssignOldLayer(t1_c1.get()); + t2.root()->Add(t2_c1); + + t2.root()->Add(CreatePictureLayer(pic3)); + + auto t2_c2 = CreateContainerLayer(CreatePictureLayer(pic2)); + t2_c2->AssignOldLayer(t1_c2.get()); + t2.root()->Add(t2_c2); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + + // Add in the beginning + + t2 = LayerTree(); + t2.root()->Add(CreatePictureLayer(pic3)); + t2.root()->Add(t2_c1); + t2.root()->Add(t2_c2); + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + + // Add at the end + + t2 = LayerTree(); + t2.root()->Add(t2_c1); + t2.root()->Add(t2_c2); + t2.root()->Add(CreatePictureLayer(pic3)); + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); +} + +TEST_F(DiffContextTest, LayerDeletion) { + auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + + auto c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + auto c2 = CreateContainerLayer(CreatePictureLayer(pic2)); + auto c3 = CreateContainerLayer(CreatePictureLayer(pic3)); + + LayerTree t1; + t1.root()->Add(c1); + t1.root()->Add(c2); + t1.root()->Add(c3); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 250, 50)); + + LayerTree t2; + t2.root()->Add(c2); + t2.root()->Add(c3); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 50, 50)); + + LayerTree t3; + t3.root()->Add(c1); + t3.root()->Add(c3); + + damage = DiffLayerTree(t3, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 50)); + + LayerTree t4; + t4.root()->Add(c1); + t4.root()->Add(c2); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + + LayerTree t5; + t5.root()->Add(c1); + + damage = DiffLayerTree(t5, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 150, 50)); + + LayerTree t6; + t6.root()->Add(c2); + + damage = DiffLayerTree(t6, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 250, 50)); + + LayerTree t7; + t7.root()->Add(c3); + + damage = DiffLayerTree(t7, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 150, 50)); +} + +TEST_F(DiffContextTest, ReplaceLayer) { + auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + + auto pic1a = CreatePicture(SkRect::MakeXYWH(0, 100, 50, 50), 1); + auto pic2a = CreatePicture(SkRect::MakeXYWH(100, 100, 50, 50), 1); + auto pic3a = CreatePicture(SkRect::MakeXYWH(200, 100, 50, 50), 1); + + auto c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + auto c2 = CreateContainerLayer(CreatePictureLayer(pic2)); + auto c3 = CreateContainerLayer(CreatePictureLayer(pic3)); + + LayerTree t1; + t1.root()->Add(c1); + t1.root()->Add(c2); + t1.root()->Add(c3); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 250, 50)); + + LayerTree t2; + t2.root()->Add(c1); + t2.root()->Add(c2); + t2.root()->Add(c3); + + damage = DiffLayerTree(t2, t1); + EXPECT_TRUE(damage.surface_damage.isEmpty()); + + LayerTree t3; + t3.root()->Add(CreateContainerLayer({CreatePictureLayer(pic1a)})); + t3.root()->Add(c2); + t3.root()->Add(c3); + + damage = DiffLayerTree(t3, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 50, 150)); + + LayerTree t4; + t4.root()->Add(c1); + t4.root()->Add(CreateContainerLayer(CreatePictureLayer(pic2a))); + t4.root()->Add(c3); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 150)); + + LayerTree t5; + t5.root()->Add(c1); + t5.root()->Add(c2); + t5.root()->Add(CreateContainerLayer(CreatePictureLayer(pic3a))); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 150)); +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + +} // namespace testing +} // namespace flutter diff --git a/flow/testing/diff_context_test.cc b/flow/testing/diff_context_test.cc new file mode 100644 index 0000000000000..43b82650ab2df --- /dev/null +++ b/flow/testing/diff_context_test.cc @@ -0,0 +1,49 @@ +#include "diff_context_test.h" + +namespace flutter { +namespace testing { + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +DiffContextTest::DiffContextTest() + : unref_queue_(fml::MakeRefCounted( + GetCurrentTaskRunner(), + fml::TimeDelta::FromSeconds(0))) {} + +Damage DiffContextTest::DiffLayerTree(LayerTree& layer_tree, + const LayerTree& old_layer_tree, + const SkIRect& additional_damage) { + DiffContext dc(1, layer_tree.paint_region_map(), + old_layer_tree.paint_region_map()); + layer_tree.root()->Diff(&dc, old_layer_tree.root()); + return dc.GetDamage(additional_damage); +} + +sk_sp DiffContextTest::CreatePicture(const SkRect& bounds, + uint32_t color) { + SkPictureRecorder recorder; + SkCanvas* recording_canvas = recorder.beginRecording(bounds); + recording_canvas->drawRect(bounds, SkPaint(SkColor4f::FromBytes_RGBA(color))); + return recorder.finishRecordingAsPicture(); +} + +std::shared_ptr DiffContextTest::CreatePictureLayer( + sk_sp picture, + const SkPoint& offset) { + return std::make_shared( + offset, SkiaGPUObject(picture, unref_queue()), false, false); +} + +std::shared_ptr DiffContextTest::CreateContainerLayer( + std::initializer_list> layers) { + auto res = std::make_shared(); + for (const auto& l : layers) { + res->Add(l); + } + return res; +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + +} // namespace testing +} // namespace flutter diff --git a/flow/testing/diff_context_test.h b/flow/testing/diff_context_test.h new file mode 100644 index 0000000000000..7116cbaebf4ae --- /dev/null +++ b/flow/testing/diff_context_test.h @@ -0,0 +1,60 @@ +#include "flutter/flow/layers/container_layer.h" +#include "flutter/flow/layers/picture_layer.h" +#include "flutter/flow/testing/skia_gpu_object_layer_test.h" +#include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" + +namespace flutter { +namespace testing { + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +class LayerTree { + public: + LayerTree() : root_(std::make_shared()) {} + + ContainerLayer* root() { return root_.get(); } + const ContainerLayer* root() const { return root_.get(); } + + PaintRegionMap& paint_region_map() { return paint_region_map_; } + const PaintRegionMap& paint_region_map() const { return paint_region_map_; } + + private: + std::shared_ptr root_; + PaintRegionMap paint_region_map_; +}; + +class DiffContextTest : public ThreadTest { + public: + DiffContextTest(); + + Damage DiffLayerTree(LayerTree& layer_tree, + const LayerTree& old_layer_tree, + const SkIRect& additional_damage = SkIRect::MakeEmpty()); + + // Create picture consisting of filled rect with given color; Being able + // to specify different color is useful to test deep comparison of pictures + sk_sp CreatePicture(const SkRect& bounds, uint32_t color); + + std::shared_ptr CreatePictureLayer( + sk_sp picture, + const SkPoint& offset = SkPoint::Make(0, 0)); + + std::shared_ptr CreateContainerLayer( + std::initializer_list> layers); + + std::shared_ptr CreateContainerLayer( + std::shared_ptr l) { + return CreateContainerLayer({l}); + } + + fml::RefPtr unref_queue() { return unref_queue_; } + + private: + fml::RefPtr unref_queue_; +}; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + +} // namespace testing +} // namespace flutter From d39a23e5e2a779eb5c071ec1911e51370f140ce1 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 14 Oct 2020 01:36:49 +0200 Subject: [PATCH 03/43] Add DiffContextTest.DieIfOldLayerWasNeverDiffed --- flow/diff_context_unittests.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index 621dd456d4fad..3190f33362869 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -223,6 +223,31 @@ TEST_F(DiffContextTest, ReplaceLayer) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 150)); } +TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { + auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); + auto c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + + LayerTree t1; + t1.root()->Add(c1); + + LayerTree t2; + t2.root()->Add(c1); + + // t1 is used as old_layer_tree, but it was never used used during diffing as + // current layer tree + // i.e. + // DiffLayerTree(t1, LayerTree()) + // That means it contains layers for which the paint regions are not known + EXPECT_DEATH_IF_SUPPORTED(DiffLayerTree(t2, t1), " region.is_valid\\(\\)"); + + // Diff t1 with empty layer tree to determine paint regions + DiffLayerTree(t1, LayerTree()); + + // Now we can diff t2 and t1 + auto damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); +} + #endif // FLUTTER_ENABLE_DIFF_CONTEXT } // namespace testing From 60964fc9f2518cfa74cf8847bcb6deb6fc995957 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 14 Oct 2020 01:48:42 +0200 Subject: [PATCH 04/43] Use FML_DCHECK instead of assert --- flow/diff_context.cc | 2 +- flow/diff_context.h | 5 +++-- flow/layers/backdrop_filter_layer.cc | 2 +- flow/layers/clip_path_layer.cc | 2 +- flow/layers/clip_rect_layer.cc | 2 +- flow/layers/clip_rrect_layer.cc | 2 +- flow/layers/color_filter_layer.cc | 2 +- flow/layers/container_layer.cc | 2 +- flow/layers/image_filter_layer.cc | 2 +- flow/layers/opacity_layer.cc | 2 +- flow/layers/performance_overlay_layer.cc | 2 +- flow/layers/physical_shape_layer.cc | 2 +- flow/layers/picture_layer.cc | 2 +- flow/layers/shader_mask_layer.cc | 2 +- flow/layers/texture_layer.cc | 2 +- flow/layers/transform_layer.cc | 2 +- 16 files changed, 18 insertions(+), 17 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index bf1a9d760eb4c..39c3cdaba7bfd 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -27,7 +27,7 @@ void DiffContext::BeginSubtree() { } void DiffContext::EndSubtree() { - assert(!state_stack_.empty()); + FML_DCHECK(!state_stack_.empty()); state_ = std::move(state_stack_.back()); state_stack_.pop_back(); } diff --git a/flow/diff_context.h b/flow/diff_context.h index 330dd36428e43..a1b4bd5fdb00b 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -3,6 +3,7 @@ #include #include +#include "flutter/fml/logging.h" #include "flutter/fml/macros.h" #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkRect.h" @@ -51,12 +52,12 @@ class PaintRegion { : rects_(rects), from_(from), to_(to), has_readback_(has_readback) {} std::vector::const_iterator begin() const { - assert(is_valid()); + FML_DCHECK(is_valid()); return rects_->begin() + from_; } std::vector::const_iterator end() const { - assert(is_valid()); + FML_DCHECK(is_valid()); return rects_->begin() + to_; } diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 59efa674f3c85..06d7bfeac6218 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -15,7 +15,7 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (filter_ != prev->filter_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 7e1a26a1d2d72..79488dbf34d5a 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -22,7 +22,7 @@ void ClipPathLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (clip_behavior_ != prev->clip_behavior_ || clip_path_ != prev->clip_path_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index 85d7d6ac02ae9..078a9d6a0d855 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -18,7 +18,7 @@ void ClipRectLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (clip_behavior_ != prev->clip_behavior_ || clip_rect_ != prev->clip_rect_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 4680ece931086..2fb346a78fbb9 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -18,7 +18,7 @@ void ClipRRectLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (clip_behavior_ != prev->clip_behavior_ || clip_rrect_ != prev->clip_rrect_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 1c4e9e220a6ef..7d662f07f4ab2 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -15,7 +15,7 @@ void ColorFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (filter_ != prev->filter_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 7e0fe1231b744..65a6a028abd89 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -34,7 +34,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, } return; } - assert(old_layer); + FML_DCHECK(old_layer); const auto& prev_layers = old_layer->layers_; diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index b1741cf6f23d9..33a790284edae 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -17,7 +17,7 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (filter_ != prev->filter_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index a4e1456638eba..5ab3f79cde220 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -18,7 +18,7 @@ void OpacityLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (alpha_ != prev->alpha_ || offset_ != prev->offset_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index fbfe71ef44803..9a59b5edaf13c 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -80,7 +80,7 @@ void PerformanceOverlayLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); if (!context->IsSubtreeDirty()) { - assert(old_layer); + FML_DCHECK(old_layer); auto prev = old_layer->as_performance_overlay_layer(); context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); } diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index 9e40838749fa0..124d50125d9a0 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -29,7 +29,7 @@ void PhysicalShapeLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (color_ != prev->color_ || shadow_color_ != prev->shadow_color_ || elevation_ != prev->elevation() || path_ != prev->path_ || clip_behavior_ != prev->clip_behavior_) { diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index c59322f6854b3..e875791e47a96 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -23,7 +23,7 @@ PictureLayer::PictureLayer(const SkPoint& offset, void PictureLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); if (!context->IsSubtreeDirty()) { - assert(old_layer); + FML_DCHECK(old_layer); auto prev = old_layer->as_picture_layer(); if (prev->offset_ != offset_ || !Compare(context, this, prev)) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index d878eaa292f06..190bf68e06f92 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -17,7 +17,7 @@ void ShaderMaskLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (shader_ != prev->shader_ || mask_rect_ != prev->mask_rect_ || blend_mode_ != prev->blend_mode_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index b9022fb053562..14a905fa4ac68 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -24,7 +24,7 @@ TextureLayer::TextureLayer(const SkPoint& offset, void TextureLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); if (!context->IsSubtreeDirty()) { - assert(old_layer); + FML_DCHECK(old_layer); auto prev = old_layer->as_texture_layer(); // TODO(knopp) It would be nice to be able to determine that a texture is // dirty diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index 300652c0c759c..8363a55ab3a91 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -32,7 +32,7 @@ void TransformLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { - assert(prev); + FML_DCHECK(prev); if (transform_ != prev->transform_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } From 54bffaef1080040e061fb7a6329e20033b5708f1 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 14 Oct 2020 01:49:04 +0200 Subject: [PATCH 05/43] Add missing space --- flow/layers/layer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 57c22cfa9a513..b2c89c519dadb 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -241,7 +241,7 @@ class Layer { return nullptr; } -#endif // FLUTTER_ENABLE_DIFF_CONTEXT +#endif // FLUTTER_ENABLE_DIFF_CONTEXT protected: #if defined(LEGACY_FUCHSIA_EMBEDDER) From 99e886c02d0d8026b147cf227e51b54570954fa1 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 14 Oct 2020 02:38:22 +0200 Subject: [PATCH 06/43] Compare pictures in PictureLayer::CanDiff Only consider picture layers that have same picture as diffable. This way ContainerLayer will properly detect inserted or deleted PictureLayer in case siblings are other PictureLayers. --- flow/diff_context_unittests.cc | 39 +++++++++++++++++++++++++ flow/layers/container_layer.cc | 4 +-- flow/layers/layer.h | 2 +- flow/layers/performance_overlay_layer.h | 2 +- flow/layers/picture_layer.cc | 32 +++++++++++++------- flow/layers/picture_layer.h | 6 ++-- flow/layers/texture_layer.h | 2 +- 7 files changed, 68 insertions(+), 19 deletions(-) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index 3190f33362869..323e0a34b1dca 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -61,6 +61,7 @@ TEST_F(DiffContextTest, PictureCompare) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(20, 20, 50, 50)); } +// Insert PictureLayer amongst container layers TEST_F(DiffContextTest, PictureLayerInsertion) { auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); @@ -112,6 +113,44 @@ TEST_F(DiffContextTest, PictureLayerInsertion) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); } +// Insert picture layer amongst other picture layers +TEST_F(DiffContextTest, PictureInsertion) { + auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + + LayerTree t1; + t1.root()->Add(CreatePictureLayer(pic1)); + t1.root()->Add(CreatePictureLayer(pic2)); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 150, 50)); + + LayerTree t2; + t2.root()->Add(CreatePictureLayer(pic3)); + t2.root()->Add(CreatePictureLayer(pic1)); + t2.root()->Add(CreatePictureLayer(pic2)); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + + LayerTree t3; + t3.root()->Add(CreatePictureLayer(pic1)); + t3.root()->Add(CreatePictureLayer(pic3)); + t3.root()->Add(CreatePictureLayer(pic2)); + + damage = DiffLayerTree(t3, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + + LayerTree t4; + t4.root()->Add(CreatePictureLayer(pic1)); + t4.root()->Add(CreatePictureLayer(pic2)); + t4.root()->Add(CreatePictureLayer(pic3)); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); +} + TEST_F(DiffContextTest, LayerDeletion) { auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 65a6a028abd89..9255f4d8cb3cb 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -49,7 +49,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, while ((old_children_top <= old_children_bottom) && (new_children_top <= new_children_bottom)) { if (!layers_[new_children_top]->CanDiff( - prev_layers[old_children_top].get())) { + context, prev_layers[old_children_top].get())) { break; } ++new_children_top; @@ -59,7 +59,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, while ((old_children_top <= old_children_bottom) && (new_children_top <= new_children_bottom)) { if (!layers_[new_children_bottom]->CanDiff( - prev_layers[old_children_bottom].get())) { + context, prev_layers[old_children_bottom].get())) { break; } --new_children_bottom; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index b2c89c519dadb..4361d2cfdef31 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -87,7 +87,7 @@ class Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - virtual bool CanDiff(const Layer* layer) const { + virtual bool CanDiff(DiffContext* context, const Layer* layer) const { return original_layer_id_ == layer->original_layer_id_; } diff --git a/flow/layers/performance_overlay_layer.h b/flow/layers/performance_overlay_layer.h index 75976cf16387f..d4a27c3270be8 100644 --- a/flow/layers/performance_overlay_layer.h +++ b/flow/layers/performance_overlay_layer.h @@ -28,7 +28,7 @@ class PerformanceOverlayLayer : public Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - bool CanDiff(const Layer* layer) const override { + bool CanDiff(DiffContext* context, const Layer* layer) const override { return layer->as_performance_overlay_layer() != nullptr; } diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index e875791e47a96..f02577f592e99 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -20,42 +20,54 @@ PictureLayer::PictureLayer(const SkPoint& offset, #ifdef FLUTTER_ENABLE_DIFF_CONTEXT +bool PictureLayer::CanDiff(DiffContext* context, const Layer* layer) const { + // Only return true for identical pictures; This way + // ContainerLayer::DiffChildren can detect when a picture layer got inserted + // between other picture layers + auto picture_layer = layer->as_picture_layer(); + return picture_layer != nullptr && offset_ == picture_layer->offset_ && + Compare(context->statistics(), this, picture_layer); +} + void PictureLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); if (!context->IsSubtreeDirty()) { +#ifndef NDEBUG FML_DCHECK(old_layer); auto prev = old_layer->as_picture_layer(); - if (prev->offset_ != offset_ || !Compare(context, this, prev)) { - context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); - } + DiffContext::Statistics dummy_statistics; + // CanDiff has already determined that the picture is same + FML_DCHECK(prev->offset_ == offset_ && + Compare(dummy_statistics, this, prev)); +#endif } context->PushTransform(SkMatrix::Translate(offset_.x(), offset_.y())); context->AddPaintRegion(picture()->cullRect()); context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); } -bool PictureLayer::Compare(DiffContext* context, +bool PictureLayer::Compare(DiffContext::Statistics& statistics, const PictureLayer* l1, const PictureLayer* l2) { const auto& pic1 = l1->picture_.get(); const auto& pic2 = l2->picture_.get(); if (pic1.get() == pic2.get()) { - context->statistics().AddSameInstancePicture(); + statistics.AddSameInstancePicture(); return true; } auto op_cnt_1 = pic1->approximateOpCount(); auto op_cnt_2 = pic2->approximateOpCount(); if (op_cnt_1 != op_cnt_2 || pic1->cullRect() != pic2->cullRect()) { - context->statistics().AddNewPicture(); + statistics.AddNewPicture(); return false; } if (op_cnt_1 > 10) { - context->statistics().AddPictureTooComplexToCompare(); + statistics.AddPictureTooComplexToCompare(); return false; } - context->statistics().AddDeepComparePicture(); + statistics.AddDeepComparePicture(); // TODO(knopp) we don't actually need the data; this could be done without // allocations by implementing stream that calculates SHA hash and @@ -64,9 +76,9 @@ bool PictureLayer::Compare(DiffContext* context, auto d2 = l2->SerializedPicture(); auto res = d1->equals(d2.get()); if (res) { - context->statistics().AddDifferentInstanceButEqualPicture(); + statistics.AddDifferentInstanceButEqualPicture(); } else { - context->statistics().AddNewPicture(); + statistics.AddNewPicture(); } return res; } diff --git a/flow/layers/picture_layer.h b/flow/layers/picture_layer.h index 22473ec6ebd8d..5a17618629f9f 100644 --- a/flow/layers/picture_layer.h +++ b/flow/layers/picture_layer.h @@ -24,9 +24,7 @@ class PictureLayer : public Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - bool CanDiff(const Layer* layer) const override { - return layer->as_picture_layer() != nullptr; - } + bool CanDiff(DiffContext* context, const Layer* layer) const override; void Diff(DiffContext* context, const Layer* old_layer) override; @@ -50,7 +48,7 @@ class PictureLayer : public Layer { sk_sp SerializedPicture() const; mutable sk_sp cached_serialized_picture_; - static bool Compare(DiffContext* context, + static bool Compare(DiffContext::Statistics& statistics, const PictureLayer* l1, const PictureLayer* l2); diff --git a/flow/layers/texture_layer.h b/flow/layers/texture_layer.h index 737b9bec2ef77..47a71d2a64332 100644 --- a/flow/layers/texture_layer.h +++ b/flow/layers/texture_layer.h @@ -22,7 +22,7 @@ class TextureLayer : public Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - bool CanDiff(const Layer* layer) const override { + bool CanDiff(DiffContext* context, const Layer* layer) const override { return layer->as_texture_layer() != nullptr; } From 74f63572cf235e46a55ac86def6bf0ac37a81a43 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 14 Oct 2020 03:05:14 +0200 Subject: [PATCH 07/43] =?UTF-8?q?Fail=20early=20if=20requesting=20paint=20?= =?UTF-8?q?region=20from=20layer=20that=20doesn=E2=80=99t=20have=20one?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flow/diff_context.cc | 1 + flow/diff_context_unittests.cc | 2 +- flow/layers/container_layer.cc | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 39c3cdaba7bfd..232f4d55c9a58 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -136,6 +136,7 @@ PaintRegion DiffContext::GetOldLayerPaintRegion(const Layer* layer) const { if (i != last_frame_paint_region_map_.end()) { return i->second; } else { + FML_CHECK(false) << "Old layer doesn't have paint region"; return PaintRegion(); } } diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index 323e0a34b1dca..c025a39dffe4a 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -277,7 +277,7 @@ TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { // i.e. // DiffLayerTree(t1, LayerTree()) // That means it contains layers for which the paint regions are not known - EXPECT_DEATH_IF_SUPPORTED(DiffLayerTree(t2, t1), " region.is_valid\\(\\)"); + EXPECT_DEATH_IF_SUPPORTED(DiffLayerTree(t2, t1), "Old layer doesn't have paint region"); // Diff t1 with empty layer tree to determine paint regions DiffLayerTree(t1, LayerTree()); diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 9255f4d8cb3cb..9164c07fa5807 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -78,7 +78,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, i < new_children_top ? i : prev_layers.size() - (layers_.size() - i); auto layer = layers_[i]; auto prev_layer = prev_layers[i_prev]; - auto paint_region = context->GetOldLayerPaintRegion(layer.get()); + auto paint_region = context->GetOldLayerPaintRegion(old_layer); if (layer == prev_layer && !paint_region.has_readback()) { // for retained layers, stop processing the subtree and add existing // region; We know current subtree is not dirty (every ancestor up to From e1341e382b047b66b4f32e2a8e8d612f4336b700 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 14 Oct 2020 03:06:53 +0200 Subject: [PATCH 08/43] Rename AddPaintRegion to AddExistingPaintRegion This overload is used when reusing paint region from retained layers and name should reflect it. --- flow/diff_context.cc | 5 ++++- flow/diff_context.h | 4 ++-- flow/layers/container_layer.cc | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 232f4d55c9a58..2a9ad37c5269f 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -92,7 +92,10 @@ void DiffContext::AddPaintRegion(const SkRect& rect) { } } -void DiffContext::AddPaintRegion(const PaintRegion& region) { +void DiffContext::AddExistingPaintRegion(const PaintRegion& region) { + // Adding paint region for retained layer implies that current subtree is not + // dirty + FML_DCHECK(!IsSubtreeDirty()); FML_DCHECK(region.is_valid()); rects_->insert(rects_->end(), region.begin(), region.end()); } diff --git a/flow/diff_context.h b/flow/diff_context.h index a1b4bd5fdb00b..2190536915481 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -134,8 +134,8 @@ class DiffContext { // Add paint region for layer; rect is in "local" (layer) coordinates void AddPaintRegion(const SkRect& rect); - // Add entire paint region for current subtree - void AddPaintRegion(const PaintRegion& region); + // Add entire paint region of retained layer for current subtree + void AddExistingPaintRegion(const PaintRegion& region); // The idea of readback region is that if any part of the readback region // needs to be repainted, then the whole readback region must be repainted; diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 9164c07fa5807..64763a985207a 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -86,7 +86,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, // previous frame; We can only do this if there is no readback in the // subtree. Layers that do readback must be able to register readback // inside Diff - context->AddPaintRegion(paint_region); + context->AddExistingPaintRegion(paint_region); // While we don't need to diff retained layers, we still need to // associate their paint region with current layer tree so that we can From 24be2f657fede752d648ed809d0139bd46a4f831 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 15 Oct 2020 00:34:50 +0200 Subject: [PATCH 09/43] Fix BackdropFilterLayer paint region --- flow/layers/backdrop_filter_layer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 06d7bfeac6218..bf98acfb1a306 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -22,9 +22,9 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { } // Backdrop filter paints everywhere in cull rect - auto paint_bounds = filter_->computeFastBounds(context->GetCullRect()); + auto paint_bounds = context->GetCullRect(); context->AddPaintRegion(paint_bounds); - context->AddReadbackRegion(paint_bounds); + context->AddReadbackRegion(filter_->computeFastBounds(paint_bounds)); DiffChildren(context, prev); From 71da136a1541bb04838ed8c2ba42d65a967ec1da Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 15 Oct 2020 21:41:56 +0200 Subject: [PATCH 10/43] Use filterBounds instead of computeFastBounds --- flow/diff_context.cc | 16 ++++++++++++++++ flow/diff_context.h | 8 ++++++++ flow/layers/backdrop_filter_layer.cc | 6 +++++- flow/layers/image_filter_layer.cc | 14 ++++++++++---- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 2a9ad37c5269f..4d05fef55fc33 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -71,6 +71,22 @@ bool DiffContext::PushCullRect(const SkRect& clip) { return state_.cull_rect.intersect(clip); } +SkRect DiffContext::MapToLayer(const SkIRect& screen_rect) { + SkMatrix inverse; + if (!state_.transform.invert(&inverse)) { + // Give up and pass the rect unmodified + return SkRect::Make(screen_rect); + } else { + return inverse.mapRect(SkRect::Make(screen_rect)); + } +} + +SkIRect DiffContext::MapToScreen(const SkRect& layer_rect) { + SkIRect res; + state_.transform.mapRect(layer_rect).roundOut(&res); + return res; +} + void DiffContext::MarkSubtreeDirty(const PaintRegion& previous_paint_region) { FML_DCHECK(!IsSubtreeDirty()); if (previous_paint_region.is_valid()) { diff --git a/flow/diff_context.h b/flow/diff_context.h index 2190536915481..aa6593aebfdb6 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -119,6 +119,14 @@ class DiffContext { // Return cull rect for current subtree (in local coordinates) SkRect GetCullRect() const { return state_.cull_rect; } + // Maps given rect from screen (global) coordinates to layer (local) + // coordinates + SkRect MapToLayer(const SkIRect& screen_rect); + + // Maps given rect from layer (local) coordinates to screen (global) + // coordinates + SkIRect MapToScreen(const SkRect& layer_rect); + // Sets the dirty flag on current subtree; // // previous_paint_region, which should represent region of previous subtree diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index bf98acfb1a306..a10d9bf07a870 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -24,7 +24,11 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { // Backdrop filter paints everywhere in cull rect auto paint_bounds = context->GetCullRect(); context->AddPaintRegion(paint_bounds); - context->AddReadbackRegion(filter_->computeFastBounds(paint_bounds)); + + auto filter_bounds = // in screen coordinates + filter_->filterBounds(context->MapToScreen(paint_bounds), SkMatrix::I(), + SkImageFilter::kReverse_MapDirection); + context->AddReadbackRegion(context->MapToLayer(filter_bounds)); DiffChildren(context, prev); diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 33a790284edae..d3fa037030e67 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -27,11 +27,17 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { SkMatrix inverse; if (context->GetTransform().invert(&inverse)) { - auto paint_bounds = context->CurrentSubtreeRegion().GetBounds(); - inverse.mapRect(&paint_bounds); - paint_bounds = filter_->computeFastBounds(paint_bounds); - + SkIRect screen_bounds; + context->CurrentSubtreeRegion().GetBounds().roundOut(&screen_bounds); + auto paint_bounds = context->MapToLayer(filter_->filterBounds( + screen_bounds, SkMatrix::I(), SkImageFilter::kForward_MapDirection)); context->AddPaintRegion(paint_bounds); + + // Technically, there is no readback with ImageFilterLayer, but we can't + // clip the filter (because it may sample out of clip rect) so if any part + // of layer is repainted the whole layer needs to be. + // TODO(knopp) There is a room for optimization here - this doesn't need to + // be done if we know for sure that we're using raster cache context->AddReadbackRegion(paint_bounds); } From c1fa535e1aef3687005dc69a9e143476211738b8 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 26 Oct 2020 17:23:24 +0100 Subject: [PATCH 11/43] Use MockLayer in diff unit test --- common/graphics/persistent_cache.h | 4 +-- flow/diff_context_unittests.cc | 44 ++++++++++++++++-------------- flow/layers/layer.h | 5 ++++ flow/testing/mock_layer.cc | 19 +++++++++++++ flow/testing/mock_layer.h | 8 ++++++ 5 files changed, 57 insertions(+), 23 deletions(-) diff --git a/common/graphics/persistent_cache.h b/common/graphics/persistent_cache.h index 8585b9d671c2e..efb3935c58ae6 100644 --- a/common/graphics/persistent_cache.h +++ b/common/graphics/persistent_cache.h @@ -15,12 +15,12 @@ #include "flutter/fml/unique_fd.h" #include "third_party/skia/include/gpu/GrContextOptions.h" +namespace flutter { + namespace testing { class ShellTest; } -namespace flutter { - /// A cache of SkData that gets stored to disk. /// /// This is mainly used for Shaders but is also written to by Dart. It is diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index c025a39dffe4a..409e1aadf867d 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -2,6 +2,7 @@ #include "flutter/flow/layers/container_layer.h" #include "flutter/flow/layers/picture_layer.h" #include "flutter/flow/testing/diff_context_test.h" +#include "flutter/flow/testing/mock_layer.h" #include "gtest/gtest.h" namespace flutter { @@ -152,13 +153,13 @@ TEST_F(DiffContextTest, PictureInsertion) { } TEST_F(DiffContextTest, LayerDeletion) { - auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); - auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); - auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto path2 = SkPath().addRect(SkRect::MakeXYWH(100, 0, 50, 50)); + auto path3 = SkPath().addRect(SkRect::MakeXYWH(200, 0, 50, 50)); - auto c1 = CreateContainerLayer(CreatePictureLayer(pic1)); - auto c2 = CreateContainerLayer(CreatePictureLayer(pic2)); - auto c3 = CreateContainerLayer(CreatePictureLayer(pic3)); + auto c1 = CreateContainerLayer(std::make_shared(path1)); + auto c2 = CreateContainerLayer(std::make_shared(path2)); + auto c3 = CreateContainerLayer(std::make_shared(path3)); LayerTree t1; t1.root()->Add(c1); @@ -209,17 +210,17 @@ TEST_F(DiffContextTest, LayerDeletion) { } TEST_F(DiffContextTest, ReplaceLayer) { - auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); - auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); - auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto path2 = SkPath().addRect(SkRect::MakeXYWH(100, 0, 50, 50)); + auto path3 = SkPath().addRect(SkRect::MakeXYWH(200, 0, 50, 50)); - auto pic1a = CreatePicture(SkRect::MakeXYWH(0, 100, 50, 50), 1); - auto pic2a = CreatePicture(SkRect::MakeXYWH(100, 100, 50, 50), 1); - auto pic3a = CreatePicture(SkRect::MakeXYWH(200, 100, 50, 50), 1); + auto path1a = SkPath().addRect(SkRect::MakeXYWH(0, 100, 50, 50)); + auto path2a = SkPath().addRect(SkRect::MakeXYWH(100, 100, 50, 50)); + auto path3a = SkPath().addRect(SkRect::MakeXYWH(200, 100, 50, 50)); - auto c1 = CreateContainerLayer(CreatePictureLayer(pic1)); - auto c2 = CreateContainerLayer(CreatePictureLayer(pic2)); - auto c3 = CreateContainerLayer(CreatePictureLayer(pic3)); + auto c1 = CreateContainerLayer(std::make_shared(path1)); + auto c2 = CreateContainerLayer(std::make_shared(path2)); + auto c3 = CreateContainerLayer(std::make_shared(path3)); LayerTree t1; t1.root()->Add(c1); @@ -238,7 +239,7 @@ TEST_F(DiffContextTest, ReplaceLayer) { EXPECT_TRUE(damage.surface_damage.isEmpty()); LayerTree t3; - t3.root()->Add(CreateContainerLayer({CreatePictureLayer(pic1a)})); + t3.root()->Add(CreateContainerLayer({std::make_shared(path1a)})); t3.root()->Add(c2); t3.root()->Add(c3); @@ -247,7 +248,7 @@ TEST_F(DiffContextTest, ReplaceLayer) { LayerTree t4; t4.root()->Add(c1); - t4.root()->Add(CreateContainerLayer(CreatePictureLayer(pic2a))); + t4.root()->Add(CreateContainerLayer(std::make_shared(path2a))); t4.root()->Add(c3); damage = DiffLayerTree(t4, t1); @@ -256,15 +257,15 @@ TEST_F(DiffContextTest, ReplaceLayer) { LayerTree t5; t5.root()->Add(c1); t5.root()->Add(c2); - t5.root()->Add(CreateContainerLayer(CreatePictureLayer(pic3a))); + t5.root()->Add(CreateContainerLayer(std::make_shared(path3a))); damage = DiffLayerTree(t4, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 150)); } TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { - auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); - auto c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto c1 = CreateContainerLayer(std::make_shared(path1)); LayerTree t1; t1.root()->Add(c1); @@ -277,7 +278,8 @@ TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { // i.e. // DiffLayerTree(t1, LayerTree()) // That means it contains layers for which the paint regions are not known - EXPECT_DEATH_IF_SUPPORTED(DiffLayerTree(t2, t1), "Old layer doesn't have paint region"); + EXPECT_DEATH_IF_SUPPORTED(DiffLayerTree(t2, t1), + "Old layer doesn't have paint region"); // Diff t1 with empty layer tree to determine paint regions DiffLayerTree(t1, LayerTree()); diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 4361d2cfdef31..a8210f224b02e 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -36,6 +36,10 @@ namespace flutter { +namespace testing { +class MockLayer; +} // namespace testing + static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); // This should be an exact copy of the Clip enum in painting.dart. @@ -240,6 +244,7 @@ class Layer { virtual const PerformanceOverlayLayer* as_performance_overlay_layer() const { return nullptr; } + virtual const testing::MockLayer* as_mock_layer() const { return nullptr; } #endif // FLUTTER_ENABLE_DIFF_CONTEXT diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 5fc9f60ee840e..66cf4a81662bb 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -18,6 +18,25 @@ MockLayer::MockLayer(SkPath path, fake_needs_system_composite_(fake_needs_system_composite), fake_reads_surface_(fake_reads_surface) {} +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +bool MockLayer::CanDiff(DiffContext* context, const Layer* layer) const { + // Similar to PictureLayer, only return true for identical mock layers; + // That way ContainerLayer::DiffChildren can properly detect mock layer + // insertion + auto mock_layer = layer->as_mock_layer(); + return mock_layer && mock_layer->fake_paint_ == fake_paint_ && + mock_layer->fake_paint_path_ == fake_paint_path_; +} + +void MockLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + context->AddPaintRegion(fake_paint_path_.getBounds()); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +#endif + void MockLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { parent_mutators_ = context->mutators_stack; parent_matrix_ = matrix; diff --git a/flow/testing/mock_layer.h b/flow/testing/mock_layer.h index b92583f581209..87e135fc7c0a0 100644 --- a/flow/testing/mock_layer.h +++ b/flow/testing/mock_layer.h @@ -30,6 +30,14 @@ class MockLayer : public Layer { const SkRect& parent_cull_rect() { return parent_cull_rect_; } bool parent_has_platform_view() { return parent_has_platform_view_; } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + bool CanDiff(DiffContext* context, const Layer* layer) const override; + void Diff(DiffContext* context, const Layer* old_layer) override; + const MockLayer* as_mock_layer() const override { return this; } + +#endif + private: MutatorsStack parent_mutators_; SkMatrix parent_matrix_; From c4099d9592828ea63dfd9b07840945fdc923afad Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sat, 31 Oct 2020 02:00:10 +0100 Subject: [PATCH 12/43] Clip damage to frame bounds --- flow/diff_context.cc | 8 +++++++- flow/diff_context.h | 4 +++- flow/testing/diff_context_test.cc | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 4d05fef55fc33..79ea64b6d15d5 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -13,10 +13,12 @@ SkRect PaintRegion::GetBounds() const { return res; } -DiffContext::DiffContext(double frame_device_pixel_ratio, +DiffContext::DiffContext(SkISize frame_size, + double frame_device_pixel_ratio, PaintRegionMap& this_frame_paint_region_map, const PaintRegionMap& last_frame_paint_region_map) : rects_(std::make_shared>()), + frame_size_(frame_size), frame_device_pixel_ratio_(frame_device_pixel_ratio), this_frame_paint_region_map_(this_frame_paint_region_map), last_frame_paint_region_map_(last_frame_paint_region_map) {} @@ -64,6 +66,10 @@ Damage DiffContext::GetDamage(const SkIRect& accumulated_buffer_damage) const { Damage res; framebuffer.roundOut(&res.buffer_damage); net.roundOut(&res.surface_damage); + + SkIRect frame_clip = SkIRect::MakeSize(frame_size_); + res.buffer_damage.intersect(frame_clip); + res.surface_damage.intersect(frame_clip); return res; } diff --git a/flow/diff_context.h b/flow/diff_context.h index aa6593aebfdb6..102601442a091 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -82,7 +82,8 @@ using PaintRegionMap = std::map; // Tracks state during tree diffing process and computes resulting damage class DiffContext { public: - explicit DiffContext(double device_pixel_aspect_ratio, + explicit DiffContext(SkISize frame_size, + double device_pixel_aspect_ratio, PaintRegionMap& this_frame_paint_region_map, const PaintRegionMap& last_frame_paint_region_map); @@ -215,6 +216,7 @@ class DiffContext { std::shared_ptr> rects_; State state_; + SkISize frame_size_; double frame_device_pixel_ratio_; std::vector state_stack_; diff --git a/flow/testing/diff_context_test.cc b/flow/testing/diff_context_test.cc index 43b82650ab2df..dbee6dc4ffc29 100644 --- a/flow/testing/diff_context_test.cc +++ b/flow/testing/diff_context_test.cc @@ -13,7 +13,9 @@ DiffContextTest::DiffContextTest() Damage DiffContextTest::DiffLayerTree(LayerTree& layer_tree, const LayerTree& old_layer_tree, const SkIRect& additional_damage) { - DiffContext dc(1, layer_tree.paint_region_map(), + FML_CHECK(layer_tree.size() == old_layer_tree.size()); + + DiffContext dc(layer_tree.size(), 1, layer_tree.paint_region_map(), old_layer_tree.paint_region_map()); layer_tree.root()->Diff(&dc, old_layer_tree.root()); return dc.GetDamage(additional_damage); From 8528d850483f2c9e42edf7f044d95e9032cb3ca3 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Fri, 30 Oct 2020 22:00:39 +0100 Subject: [PATCH 13/43] Add tests for TransformLayer and BackdropFilterLayer --- flow/diff_context_unittests.cc | 162 ++++++++++++++++++++++++++++++ flow/testing/diff_context_test.cc | 2 + flow/testing/diff_context_test.h | 6 +- 3 files changed, 169 insertions(+), 1 deletion(-) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index 409e1aadf867d..42e05ce716e22 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -1,9 +1,13 @@ #include "diff_context.h" +#include "flutter/flow/layers/backdrop_filter_layer.h" +#include "flutter/flow/layers/clip_rect_layer.h" #include "flutter/flow/layers/container_layer.h" #include "flutter/flow/layers/picture_layer.h" +#include "flutter/flow/layers/transform_layer.h" #include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/mock_layer.h" #include "gtest/gtest.h" +#include "third_party/skia/include/effects/SkBlurImageFilter.h" namespace flutter { namespace testing { @@ -289,6 +293,164 @@ TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); } +TEST_F(DiffContextTest, Transform) { + auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto m1 = std::make_shared(path1); + + auto transform1 = + std::make_shared(SkMatrix::MakeTrans(10, 10)); + transform1->Add(m1); + + LayerTree t1; + t1.root()->Add(transform1); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); + + auto transform2 = + std::make_shared(SkMatrix::MakeTrans(20, 20)); + transform2->Add(m1); + transform2->AssignOldLayer(transform1.get()); + + LayerTree t2; + t2.root()->Add(transform2); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 60, 60)); + + auto transform3 = + std::make_shared(SkMatrix::MakeTrans(20, 20)); + transform3->Add(m1); + transform3->AssignOldLayer(transform2.get()); + + LayerTree t3; + t3.root()->Add(transform3); + + damage = DiffLayerTree(t3, t2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); +} + +TEST_F(DiffContextTest, TransformNested) { + auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto m1 = CreateContainerLayer(std::make_shared(path1)); + + auto transform1 = + std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + + auto transform1_1 = + std::make_shared(SkMatrix::MakeTrans(10, 10)); + transform1_1->Add(m1); + transform1->Add(transform1_1); + + auto transform1_2 = + std::make_shared(SkMatrix::MakeTrans(100, 100)); + transform1_2->Add(m1); + transform1->Add(transform1_2); + + auto transform1_3 = + std::make_shared(SkMatrix::MakeTrans(200, 200)); + transform1_3->Add(m1); + transform1->Add(transform1_3); + + LayerTree l1; + l1.root()->Add(transform1); + + auto damage = DiffLayerTree(l1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(20, 20, 480, 480)); + + auto transform2 = + std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + + auto transform2_1 = + std::make_shared(SkMatrix::MakeTrans(10, 10)); + transform2_1->Add(m1); + transform2_1->AssignOldLayer(transform1_1.get()); + transform2->Add(transform2_1); + + auto transform2_2 = + std::make_shared(SkMatrix::MakeTrans(100, 101)); + transform2_2->Add(m1); + transform2_2->AssignOldLayer(transform1_2.get()); + transform2->Add(transform2_2); + + auto transform2_3 = + std::make_shared(SkMatrix::MakeTrans(200, 200)); + transform2_3->Add(m1); + transform2_3->AssignOldLayer(transform1_3.get()); + transform2->Add(transform2_3); + + LayerTree l2; + l2.root()->Add(transform2); + + damage = DiffLayerTree(l2, l1); + + // transform2 has not transform1 assigned as old layer, so it should be + // invalidated completely + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(20, 20, 480, 480)); + + // now diff the tree properly, the only difference being transform2_2 and + // transform_2_1 + transform2->AssignOldLayer(transform1.get()); + damage = DiffLayerTree(l2, l1); + + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 200, 100, 102)); +} + +TEST_F(DiffContextTest, BackdropLayer) { + auto filter = SkBlurImageFilter::Make(10, 10, nullptr, nullptr, + SkBlurImageFilter::kClamp_TileMode); + + { + // tests later assume 30px readback area, fail early if that's not the case + auto readback = filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), + SkImageFilter::kReverse_MapDirection); + EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); + } + + LayerTree l1(SkISize::Make(100, 100)); + l1.root()->Add(std::make_shared(filter)); + + // no clip, effect over entire surface + auto damage = DiffLayerTree(l1, LayerTree(SkISize::Make(100, 100))); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeWH(100, 100)); + + LayerTree l2(SkISize::Make(100, 100)); + + auto clip = std::make_shared(SkRect::MakeXYWH(20, 20, 40, 40), + Clip::hardEdge); + clip->Add(std::make_shared(filter)); + l2.root()->Add(clip); + damage = DiffLayerTree(l2, LayerTree(SkISize::Make(100, 100))); + + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 90, 90)); + + LayerTree l3; + auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + scale->Add(clip); + l3.root()->Add(scale); + + damage = DiffLayerTree(l3, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 140, 140)); + + LayerTree l4; + l4.root()->Add(scale); + + // path just outside of readback region, doesn't affect blur + auto path1 = SkPath().addRect(SkRect::MakeXYWH(150, 150, 10, 10)); + l4.root()->Add(std::make_shared(path1)); + damage = DiffLayerTree(l4, l3); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(150, 150, 10, 10)); + + LayerTree l5; + l5.root()->Add(scale); + + // path just inside of readback region, must trigger backdrop repaint + auto path2 = SkPath().addRect(SkRect::MakeXYWH(149, 149, 10, 10)); + l5.root()->Add(std::make_shared(path2)); + damage = DiffLayerTree(l5, l4); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 150, 150)); +} + #endif // FLUTTER_ENABLE_DIFF_CONTEXT } // namespace testing diff --git a/flow/testing/diff_context_test.cc b/flow/testing/diff_context_test.cc index dbee6dc4ffc29..3c0d7d7c87cc1 100644 --- a/flow/testing/diff_context_test.cc +++ b/flow/testing/diff_context_test.cc @@ -17,6 +17,8 @@ Damage DiffContextTest::DiffLayerTree(LayerTree& layer_tree, DiffContext dc(layer_tree.size(), 1, layer_tree.paint_region_map(), old_layer_tree.paint_region_map()); + dc.PushCullRect( + SkRect::MakeIWH(layer_tree.size().width(), layer_tree.size().height())); layer_tree.root()->Diff(&dc, old_layer_tree.root()); return dc.GetDamage(additional_damage); } diff --git a/flow/testing/diff_context_test.h b/flow/testing/diff_context_test.h index 7116cbaebf4ae..e7bedf89860db 100644 --- a/flow/testing/diff_context_test.h +++ b/flow/testing/diff_context_test.h @@ -11,7 +11,8 @@ namespace testing { class LayerTree { public: - LayerTree() : root_(std::make_shared()) {} + explicit LayerTree(SkISize size = SkISize::Make(1000, 1000)) + : root_(std::make_shared()), size_(size) {} ContainerLayer* root() { return root_.get(); } const ContainerLayer* root() const { return root_.get(); } @@ -19,9 +20,12 @@ class LayerTree { PaintRegionMap& paint_region_map() { return paint_region_map_; } const PaintRegionMap& paint_region_map() const { return paint_region_map_; } + const SkISize & size() const { return size_; } + private: std::shared_ptr root_; PaintRegionMap paint_region_map_; + SkISize size_; }; class DiffContextTest : public ThreadTest { From bd81dddb960f94f7f944a3784b5b4d64d56ccd54 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Fri, 30 Oct 2020 23:49:04 +0100 Subject: [PATCH 14/43] Add ImageFilterLayer test --- flow/diff_context_unittests.cc | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index 42e05ce716e22..fc9f568824981 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -2,6 +2,7 @@ #include "flutter/flow/layers/backdrop_filter_layer.h" #include "flutter/flow/layers/clip_rect_layer.h" #include "flutter/flow/layers/container_layer.h" +#include "flutter/flow/layers/image_filter_layer.h" #include "flutter/flow/layers/picture_layer.h" #include "flutter/flow/layers/transform_layer.h" #include "flutter/flow/testing/diff_context_test.h" @@ -451,6 +452,55 @@ TEST_F(DiffContextTest, BackdropLayer) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 150, 150)); } +TEST_F(DiffContextTest, ImageFilterLayer) { + auto filter = SkBlurImageFilter::Make(10, 10, nullptr, nullptr, + SkBlurImageFilter::kClamp_TileMode); + + { + // tests later assume 30px paint area, fail early if that's not the case + auto paint_rect = + filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), + SkImageFilter::kForward_MapDirection); + EXPECT_EQ(paint_rect, SkIRect::MakeLTRB(-30, -30, 40, 40)); + } + + LayerTree l1; + auto filter_layer = std::make_shared(filter); + auto path = SkPath().addRect(SkRect::MakeXYWH(100, 100, 10, 10)); + filter_layer->Add(std::make_shared(path)); + l1.root()->Add(filter_layer); + + auto damage = DiffLayerTree(l1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(70, 70, 70, 70)); + + // filter bounds are calculated in screen space, make sure scaling doesn't + // affect it + LayerTree l2; + auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + scale->Add(filter_layer); + l2.root()->Add(scale); + + damage = DiffLayerTree(l2, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(170, 170, 80, 80)); + + LayerTree l3; + l3.root()->Add(scale); + + // path outside of ImageFilterLayer + auto path1 = SkPath().addRect(SkRect::MakeXYWH(160, 160, 10, 10)); + l3.root()->Add(std::make_shared(path1)); + damage = DiffLayerTree(l3, l2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(160, 160, 10, 10)); + + // path intersecting ImageFilterLayer, should trigger ImageFilterLayer repaint + LayerTree l4; + l4.root()->Add(scale); + auto path2 = SkPath().addRect(SkRect::MakeXYWH(160, 160, 11, 11)); + l4.root()->Add(std::make_shared(path2)); + damage = DiffLayerTree(l4, l3); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(160, 160, 90, 90)); +} + #endif // FLUTTER_ENABLE_DIFF_CONTEXT } // namespace testing From b26987fc36c929ebe751fa90c3c1aa5866f65907 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sun, 1 Nov 2020 17:55:12 +0100 Subject: [PATCH 15/43] tweak comment --- flow/diff_context.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flow/diff_context.h b/flow/diff_context.h index 102601442a091..5baefd348aa0d 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -36,9 +36,9 @@ struct Damage { // // The area is used when adding damage of removed or dirty later. // -// Because there is PaintRegion for each layer, it must be able to represent +// Because there is a PaintRegion for each layer, it must be able to represent // the area with minimal overhead. This is accomplished by having one -// vector of SkRect shared between all paint regions, and each paint region +// vector shared between all paint regions, and each paint region // keeping begin and end index of rects relevant to particular subtree. // // All rects are in screen coordinates. From 68107c0f288e454cc0b0bd975278891a58ada7c3 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 9 Nov 2020 21:58:51 +0100 Subject: [PATCH 16/43] FilterBounds is in local coordinates --- flow/diff_context_unittests.cc | 22 ++++++++++------------ flow/layers/backdrop_filter_layer.cc | 5 +++-- flow/layers/image_filter_layer.cc | 14 ++++++++------ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index fc9f568824981..bd73709f80ed5 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -431,25 +431,25 @@ TEST_F(DiffContextTest, BackdropLayer) { l3.root()->Add(scale); damage = DiffLayerTree(l3, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 140, 140)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 180, 180)); LayerTree l4; l4.root()->Add(scale); // path just outside of readback region, doesn't affect blur - auto path1 = SkPath().addRect(SkRect::MakeXYWH(150, 150, 10, 10)); + auto path1 = SkPath().addRect(SkRect::MakeXYWH(180, 180, 10, 10)); l4.root()->Add(std::make_shared(path1)); damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(150, 150, 10, 10)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(180, 180, 10, 10)); LayerTree l5; l5.root()->Add(scale); // path just inside of readback region, must trigger backdrop repaint - auto path2 = SkPath().addRect(SkRect::MakeXYWH(149, 149, 10, 10)); + auto path2 = SkPath().addRect(SkRect::MakeXYWH(179, 179, 10, 10)); l5.root()->Add(std::make_shared(path2)); damage = DiffLayerTree(l5, l4); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 150, 150)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 190, 190)); } TEST_F(DiffContextTest, ImageFilterLayer) { @@ -473,32 +473,30 @@ TEST_F(DiffContextTest, ImageFilterLayer) { auto damage = DiffLayerTree(l1, LayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(70, 70, 70, 70)); - // filter bounds are calculated in screen space, make sure scaling doesn't - // affect it LayerTree l2; auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); scale->Add(filter_layer); l2.root()->Add(scale); damage = DiffLayerTree(l2, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(170, 170, 80, 80)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(140, 140, 140, 140)); LayerTree l3; l3.root()->Add(scale); // path outside of ImageFilterLayer - auto path1 = SkPath().addRect(SkRect::MakeXYWH(160, 160, 10, 10)); + auto path1 = SkPath().addRect(SkRect::MakeXYWH(130, 130, 10, 10)); l3.root()->Add(std::make_shared(path1)); damage = DiffLayerTree(l3, l2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(160, 160, 10, 10)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(130, 130, 10, 10)); // path intersecting ImageFilterLayer, should trigger ImageFilterLayer repaint LayerTree l4; l4.root()->Add(scale); - auto path2 = SkPath().addRect(SkRect::MakeXYWH(160, 160, 11, 11)); + auto path2 = SkPath().addRect(SkRect::MakeXYWH(130, 130, 11, 11)); l4.root()->Add(std::make_shared(path2)); damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(160, 160, 90, 90)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(130, 130, 150, 150)); } #endif // FLUTTER_ENABLE_DIFF_CONTEXT diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index a10d9bf07a870..56c5f8c15d4ed 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -25,10 +25,11 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { auto paint_bounds = context->GetCullRect(); context->AddPaintRegion(paint_bounds); + auto input_filter_bounds = paint_bounds.roundOut(); auto filter_bounds = // in screen coordinates - filter_->filterBounds(context->MapToScreen(paint_bounds), SkMatrix::I(), + filter_->filterBounds(input_filter_bounds, SkMatrix::I(), SkImageFilter::kReverse_MapDirection); - context->AddReadbackRegion(context->MapToLayer(filter_bounds)); + context->AddReadbackRegion(SkRect::Make(filter_bounds)); DiffChildren(context, prev); diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index d3fa037030e67..6060fdcb93e4d 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -27,18 +27,20 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { SkMatrix inverse; if (context->GetTransform().invert(&inverse)) { - SkIRect screen_bounds; - context->CurrentSubtreeRegion().GetBounds().roundOut(&screen_bounds); - auto paint_bounds = context->MapToLayer(filter_->filterBounds( - screen_bounds, SkMatrix::I(), SkImageFilter::kForward_MapDirection)); - context->AddPaintRegion(paint_bounds); + auto paint_bounds = + inverse.mapRect(context->CurrentSubtreeRegion().GetBounds()); + + auto filter_bounds = + filter_->filterBounds(paint_bounds.roundOut(), SkMatrix::I(), + SkImageFilter::kForward_MapDirection); + context->AddPaintRegion(SkRect::Make(filter_bounds)); // Technically, there is no readback with ImageFilterLayer, but we can't // clip the filter (because it may sample out of clip rect) so if any part // of layer is repainted the whole layer needs to be. // TODO(knopp) There is a room for optimization here - this doesn't need to // be done if we know for sure that we're using raster cache - context->AddReadbackRegion(paint_bounds); + context->AddReadbackRegion(SkRect::Make(filter_bounds)); } context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); From 89a545bcfb3195f0aa27f6876542938ff54b0826 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Tue, 10 Nov 2020 02:29:26 +0100 Subject: [PATCH 17/43] Reformat --- flow/testing/diff_context_test.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/testing/diff_context_test.h b/flow/testing/diff_context_test.h index e7bedf89860db..a8b69e95d42ae 100644 --- a/flow/testing/diff_context_test.h +++ b/flow/testing/diff_context_test.h @@ -20,7 +20,7 @@ class LayerTree { PaintRegionMap& paint_region_map() { return paint_region_map_; } const PaintRegionMap& paint_region_map() const { return paint_region_map_; } - const SkISize & size() const { return size_; } + const SkISize& size() const { return size_; } private: std::shared_ptr root_; From 020d2125f6d6d028297452dbc5197ff2352014d0 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Tue, 10 Nov 2020 02:37:36 +0100 Subject: [PATCH 18/43] Add entries to licenses_flutter --- ci/licenses_golden/licenses_flutter | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index a646d94e34f24..d0ba39b4bb08a 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -34,6 +34,9 @@ FILE: ../../../flutter/common/task_runners.cc FILE: ../../../flutter/common/task_runners.h FILE: ../../../flutter/flow/compositor_context.cc FILE: ../../../flutter/flow/compositor_context.h +FILE: ../../../flutter/flow/diff_context.cc +FILE: ../../../flutter/flow/diff_context.h +FILE: ../../../flutter/flow/diff_context_unittests.cc FILE: ../../../flutter/flow/embedded_view_params_unittests.cc FILE: ../../../flutter/flow/embedded_views.cc FILE: ../../../flutter/flow/embedded_views.h From 5dd72d0c363c11ce91efda2edfd6ae87acc631a4 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 11 Nov 2020 13:04:35 +0100 Subject: [PATCH 19/43] Remove map methods, no longer used --- flow/diff_context.cc | 16 ---------------- flow/diff_context.h | 8 -------- 2 files changed, 24 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 79ea64b6d15d5..a21b455610f8b 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -77,22 +77,6 @@ bool DiffContext::PushCullRect(const SkRect& clip) { return state_.cull_rect.intersect(clip); } -SkRect DiffContext::MapToLayer(const SkIRect& screen_rect) { - SkMatrix inverse; - if (!state_.transform.invert(&inverse)) { - // Give up and pass the rect unmodified - return SkRect::Make(screen_rect); - } else { - return inverse.mapRect(SkRect::Make(screen_rect)); - } -} - -SkIRect DiffContext::MapToScreen(const SkRect& layer_rect) { - SkIRect res; - state_.transform.mapRect(layer_rect).roundOut(&res); - return res; -} - void DiffContext::MarkSubtreeDirty(const PaintRegion& previous_paint_region) { FML_DCHECK(!IsSubtreeDirty()); if (previous_paint_region.is_valid()) { diff --git a/flow/diff_context.h b/flow/diff_context.h index 5baefd348aa0d..82d4f3f2f6c21 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -120,14 +120,6 @@ class DiffContext { // Return cull rect for current subtree (in local coordinates) SkRect GetCullRect() const { return state_.cull_rect; } - // Maps given rect from screen (global) coordinates to layer (local) - // coordinates - SkRect MapToLayer(const SkIRect& screen_rect); - - // Maps given rect from layer (local) coordinates to screen (global) - // coordinates - SkIRect MapToScreen(const SkRect& layer_rect); - // Sets the dirty flag on current subtree; // // previous_paint_region, which should represent region of previous subtree From 11af6afa15d4be5337420ec3a85ebc5a2b60b1de Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 11 Nov 2020 13:36:59 +0100 Subject: [PATCH 20/43] Replace SkRect::MakeXYWH with SkRect::MakeLTRB --- flow/diff_context_unittests.cc | 132 ++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index bd73709f80ed5..c1afbc5683e3d 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -16,13 +16,13 @@ namespace testing { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT TEST_F(DiffContextTest, SimplePicture) { - auto picture = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + auto picture = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); LayerTree tree1; tree1.root()->Add(CreatePictureLayer(picture)); auto damage = DiffLayerTree(tree1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); LayerTree tree2; tree2.root()->Add(CreatePictureLayer(picture)); @@ -32,46 +32,46 @@ TEST_F(DiffContextTest, SimplePicture) { LayerTree tree3; damage = DiffLayerTree(tree3, tree2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); } TEST_F(DiffContextTest, PictureCompare) { LayerTree tree1; - auto picture1 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + auto picture1 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree1.root()->Add(CreatePictureLayer(picture1)); auto damage = DiffLayerTree(tree1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); LayerTree tree2; - auto picture2 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + auto picture2 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree2.root()->Add(CreatePictureLayer(picture2)); damage = DiffLayerTree(tree2, tree1); EXPECT_TRUE(damage.surface_damage.isEmpty()); LayerTree tree3; - auto picture3 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 1); + auto picture3 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); // add offset tree3.root()->Add(CreatePictureLayer(picture3, SkPoint::Make(10, 10))); damage = DiffLayerTree(tree3, tree2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 60, 60)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); LayerTree tree4; // different color - auto picture4 = CreatePicture(SkRect::MakeXYWH(10, 10, 50, 50), 2); + auto picture4 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 2); tree4.root()->Add(CreatePictureLayer(picture4, SkPoint::Make(10, 10))); damage = DiffLayerTree(tree4, tree3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(20, 20, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 70, 70)); } // Insert PictureLayer amongst container layers TEST_F(DiffContextTest, PictureLayerInsertion) { - auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); - auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); - auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + auto pic1 = CreatePicture(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); LayerTree t1; @@ -82,7 +82,7 @@ TEST_F(DiffContextTest, PictureLayerInsertion) { t1.root()->Add(t1_c2); auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 150, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); // Add in the middle @@ -98,7 +98,7 @@ TEST_F(DiffContextTest, PictureLayerInsertion) { t2.root()->Add(t2_c2); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); // Add in the beginning @@ -107,7 +107,7 @@ TEST_F(DiffContextTest, PictureLayerInsertion) { t2.root()->Add(t2_c1); t2.root()->Add(t2_c2); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); // Add at the end @@ -116,21 +116,21 @@ TEST_F(DiffContextTest, PictureLayerInsertion) { t2.root()->Add(t2_c2); t2.root()->Add(CreatePictureLayer(pic3)); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); } // Insert picture layer amongst other picture layers TEST_F(DiffContextTest, PictureInsertion) { - auto pic1 = CreatePicture(SkRect::MakeXYWH(0, 0, 50, 50), 1); - auto pic2 = CreatePicture(SkRect::MakeXYWH(100, 0, 50, 50), 1); - auto pic3 = CreatePicture(SkRect::MakeXYWH(200, 0, 50, 50), 1); + auto pic1 = CreatePicture(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); LayerTree t1; t1.root()->Add(CreatePictureLayer(pic1)); t1.root()->Add(CreatePictureLayer(pic2)); auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 150, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); LayerTree t2; t2.root()->Add(CreatePictureLayer(pic3)); @@ -138,7 +138,7 @@ TEST_F(DiffContextTest, PictureInsertion) { t2.root()->Add(CreatePictureLayer(pic2)); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); LayerTree t3; t3.root()->Add(CreatePictureLayer(pic1)); @@ -146,7 +146,7 @@ TEST_F(DiffContextTest, PictureInsertion) { t3.root()->Add(CreatePictureLayer(pic2)); damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); LayerTree t4; t4.root()->Add(CreatePictureLayer(pic1)); @@ -154,13 +154,13 @@ TEST_F(DiffContextTest, PictureInsertion) { t4.root()->Add(CreatePictureLayer(pic3)); damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); } TEST_F(DiffContextTest, LayerDeletion) { - auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); - auto path2 = SkPath().addRect(SkRect::MakeXYWH(100, 0, 50, 50)); - auto path3 = SkPath().addRect(SkRect::MakeXYWH(200, 0, 50, 50)); + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); + auto path2 = SkPath().addRect(SkRect::MakeLTRB(100, 0, 150, 50)); + auto path3 = SkPath().addRect(SkRect::MakeLTRB(200, 0, 250, 50)); auto c1 = CreateContainerLayer(std::make_shared(path1)); auto c2 = CreateContainerLayer(std::make_shared(path2)); @@ -172,56 +172,56 @@ TEST_F(DiffContextTest, LayerDeletion) { t1.root()->Add(c3); auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 250, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); LayerTree t2; t2.root()->Add(c2); t2.root()->Add(c3); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 50)); LayerTree t3; t3.root()->Add(c1); t3.root()->Add(c3); damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 50)); LayerTree t4; t4.root()->Add(c1); t4.root()->Add(c2); damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 0, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); LayerTree t5; t5.root()->Add(c1); damage = DiffLayerTree(t5, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 150, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 250, 50)); LayerTree t6; t6.root()->Add(c2); damage = DiffLayerTree(t6, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 250, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); LayerTree t7; t7.root()->Add(c3); damage = DiffLayerTree(t7, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 150, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); } TEST_F(DiffContextTest, ReplaceLayer) { - auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); - auto path2 = SkPath().addRect(SkRect::MakeXYWH(100, 0, 50, 50)); - auto path3 = SkPath().addRect(SkRect::MakeXYWH(200, 0, 50, 50)); + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); + auto path2 = SkPath().addRect(SkRect::MakeLTRB(100, 0, 150, 50)); + auto path3 = SkPath().addRect(SkRect::MakeLTRB(200, 0, 250, 50)); - auto path1a = SkPath().addRect(SkRect::MakeXYWH(0, 100, 50, 50)); - auto path2a = SkPath().addRect(SkRect::MakeXYWH(100, 100, 50, 50)); - auto path3a = SkPath().addRect(SkRect::MakeXYWH(200, 100, 50, 50)); + auto path1a = SkPath().addRect(SkRect::MakeLTRB(0, 100, 50, 150)); + auto path2a = SkPath().addRect(SkRect::MakeLTRB(100, 100, 150, 150)); + auto path3a = SkPath().addRect(SkRect::MakeLTRB(200, 100, 250, 150)); auto c1 = CreateContainerLayer(std::make_shared(path1)); auto c2 = CreateContainerLayer(std::make_shared(path2)); @@ -233,7 +233,7 @@ TEST_F(DiffContextTest, ReplaceLayer) { t1.root()->Add(c3); auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 250, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); LayerTree t2; t2.root()->Add(c1); @@ -249,7 +249,7 @@ TEST_F(DiffContextTest, ReplaceLayer) { t3.root()->Add(c3); damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 50, 150)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 150)); LayerTree t4; t4.root()->Add(c1); @@ -257,7 +257,7 @@ TEST_F(DiffContextTest, ReplaceLayer) { t4.root()->Add(c3); damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 150)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); LayerTree t5; t5.root()->Add(c1); @@ -265,11 +265,11 @@ TEST_F(DiffContextTest, ReplaceLayer) { t5.root()->Add(CreateContainerLayer(std::make_shared(path3a))); damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(100, 0, 50, 150)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); } TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { - auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); auto c1 = CreateContainerLayer(std::make_shared(path1)); LayerTree t1; @@ -295,7 +295,7 @@ TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { } TEST_F(DiffContextTest, Transform) { - auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); auto m1 = std::make_shared(path1); auto transform1 = @@ -306,7 +306,7 @@ TEST_F(DiffContextTest, Transform) { t1.root()->Add(transform1); auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 50, 50)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); auto transform2 = std::make_shared(SkMatrix::MakeTrans(20, 20)); @@ -317,7 +317,7 @@ TEST_F(DiffContextTest, Transform) { t2.root()->Add(transform2); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(10, 10, 60, 60)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); auto transform3 = std::make_shared(SkMatrix::MakeTrans(20, 20)); @@ -332,7 +332,7 @@ TEST_F(DiffContextTest, Transform) { } TEST_F(DiffContextTest, TransformNested) { - auto path1 = SkPath().addRect(SkRect::MakeXYWH(0, 0, 50, 50)); + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); auto m1 = CreateContainerLayer(std::make_shared(path1)); auto transform1 = @@ -357,7 +357,7 @@ TEST_F(DiffContextTest, TransformNested) { l1.root()->Add(transform1); auto damage = DiffLayerTree(l1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(20, 20, 480, 480)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); auto transform2 = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); @@ -387,14 +387,14 @@ TEST_F(DiffContextTest, TransformNested) { // transform2 has not transform1 assigned as old layer, so it should be // invalidated completely - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(20, 20, 480, 480)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); // now diff the tree properly, the only difference being transform2_2 and // transform_2_1 transform2->AssignOldLayer(transform1.get()); damage = DiffLayerTree(l2, l1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(200, 200, 100, 102)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 200, 300, 302)); } TEST_F(DiffContextTest, BackdropLayer) { @@ -417,13 +417,13 @@ TEST_F(DiffContextTest, BackdropLayer) { LayerTree l2(SkISize::Make(100, 100)); - auto clip = std::make_shared(SkRect::MakeXYWH(20, 20, 40, 40), + auto clip = std::make_shared(SkRect::MakeLTRB(20, 20, 60, 60), Clip::hardEdge); clip->Add(std::make_shared(filter)); l2.root()->Add(clip); damage = DiffLayerTree(l2, LayerTree(SkISize::Make(100, 100))); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 90, 90)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); LayerTree l3; auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); @@ -431,25 +431,25 @@ TEST_F(DiffContextTest, BackdropLayer) { l3.root()->Add(scale); damage = DiffLayerTree(l3, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 180, 180)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 180, 180)); LayerTree l4; l4.root()->Add(scale); // path just outside of readback region, doesn't affect blur - auto path1 = SkPath().addRect(SkRect::MakeXYWH(180, 180, 10, 10)); + auto path1 = SkPath().addRect(SkRect::MakeLTRB(180, 180, 190, 190)); l4.root()->Add(std::make_shared(path1)); damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(180, 180, 10, 10)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(180, 180, 190, 190)); LayerTree l5; l5.root()->Add(scale); // path just inside of readback region, must trigger backdrop repaint - auto path2 = SkPath().addRect(SkRect::MakeXYWH(179, 179, 10, 10)); + auto path2 = SkPath().addRect(SkRect::MakeLTRB(179, 179, 189, 189)); l5.root()->Add(std::make_shared(path2)); damage = DiffLayerTree(l5, l4); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(0, 0, 190, 190)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 190, 190)); } TEST_F(DiffContextTest, ImageFilterLayer) { @@ -466,12 +466,12 @@ TEST_F(DiffContextTest, ImageFilterLayer) { LayerTree l1; auto filter_layer = std::make_shared(filter); - auto path = SkPath().addRect(SkRect::MakeXYWH(100, 100, 10, 10)); + auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110)); filter_layer->Add(std::make_shared(path)); l1.root()->Add(filter_layer); auto damage = DiffLayerTree(l1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(70, 70, 70, 70)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(70, 70, 140, 140)); LayerTree l2; auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); @@ -479,24 +479,24 @@ TEST_F(DiffContextTest, ImageFilterLayer) { l2.root()->Add(scale); damage = DiffLayerTree(l2, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(140, 140, 140, 140)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(140, 140, 280, 280)); LayerTree l3; l3.root()->Add(scale); // path outside of ImageFilterLayer - auto path1 = SkPath().addRect(SkRect::MakeXYWH(130, 130, 10, 10)); + auto path1 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 140, 140)); l3.root()->Add(std::make_shared(path1)); damage = DiffLayerTree(l3, l2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(130, 130, 10, 10)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 140, 140)); // path intersecting ImageFilterLayer, should trigger ImageFilterLayer repaint LayerTree l4; l4.root()->Add(scale); - auto path2 = SkPath().addRect(SkRect::MakeXYWH(130, 130, 11, 11)); + auto path2 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 141, 141)); l4.root()->Add(std::make_shared(path2)); damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeXYWH(130, 130, 150, 150)); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 280, 280)); } #endif // FLUTTER_ENABLE_DIFF_CONTEXT From ee505ca4d02efb97b4707729f1906e9b800635ae Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 23 Nov 2020 14:53:31 +0100 Subject: [PATCH 21/43] Move diff tests to respective layer unit tests --- flow/diff_context_unittests.cc | 467 +----------------- .../layers/backdrop_filter_layer_unittests.cc | 65 +++ flow/layers/container_layer_unittests.cc | 208 ++++++++ flow/layers/image_filter_layer_unittests.cc | 54 ++ flow/layers/picture_layer_unittests.cc | 59 +++ flow/layers/transform_layer_unittests.cc | 110 +++++ 6 files changed, 497 insertions(+), 466 deletions(-) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index c1afbc5683e3d..e0a5f9fa6ee3f 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -1,274 +1,14 @@ #include "diff_context.h" -#include "flutter/flow/layers/backdrop_filter_layer.h" -#include "flutter/flow/layers/clip_rect_layer.h" -#include "flutter/flow/layers/container_layer.h" -#include "flutter/flow/layers/image_filter_layer.h" -#include "flutter/flow/layers/picture_layer.h" -#include "flutter/flow/layers/transform_layer.h" #include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/mock_layer.h" #include "gtest/gtest.h" -#include "third_party/skia/include/effects/SkBlurImageFilter.h" namespace flutter { namespace testing { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT -TEST_F(DiffContextTest, SimplePicture) { - auto picture = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); - - LayerTree tree1; - tree1.root()->Add(CreatePictureLayer(picture)); - - auto damage = DiffLayerTree(tree1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); - - LayerTree tree2; - tree2.root()->Add(CreatePictureLayer(picture)); - - damage = DiffLayerTree(tree2, tree1); - EXPECT_TRUE(damage.surface_damage.isEmpty()); - - LayerTree tree3; - damage = DiffLayerTree(tree3, tree2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); -} - -TEST_F(DiffContextTest, PictureCompare) { - LayerTree tree1; - auto picture1 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); - tree1.root()->Add(CreatePictureLayer(picture1)); - - auto damage = DiffLayerTree(tree1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); - - LayerTree tree2; - auto picture2 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); - tree2.root()->Add(CreatePictureLayer(picture2)); - - damage = DiffLayerTree(tree2, tree1); - EXPECT_TRUE(damage.surface_damage.isEmpty()); - - LayerTree tree3; - auto picture3 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); - // add offset - tree3.root()->Add(CreatePictureLayer(picture3, SkPoint::Make(10, 10))); - - damage = DiffLayerTree(tree3, tree2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); - - LayerTree tree4; - // different color - auto picture4 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 2); - tree4.root()->Add(CreatePictureLayer(picture4, SkPoint::Make(10, 10))); - - damage = DiffLayerTree(tree4, tree3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 70, 70)); -} - -// Insert PictureLayer amongst container layers -TEST_F(DiffContextTest, PictureLayerInsertion) { - auto pic1 = CreatePicture(SkRect::MakeLTRB(0, 0, 50, 50), 1); - auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); - auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); - - LayerTree t1; - - auto t1_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); - t1.root()->Add(t1_c1); - - auto t1_c2 = CreateContainerLayer(CreatePictureLayer(pic2)); - t1.root()->Add(t1_c2); - - auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); - - // Add in the middle - - LayerTree t2; - auto t2_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); - t2_c1->AssignOldLayer(t1_c1.get()); - t2.root()->Add(t2_c1); - - t2.root()->Add(CreatePictureLayer(pic3)); - - auto t2_c2 = CreateContainerLayer(CreatePictureLayer(pic2)); - t2_c2->AssignOldLayer(t1_c2.get()); - t2.root()->Add(t2_c2); - - damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - - // Add in the beginning - - t2 = LayerTree(); - t2.root()->Add(CreatePictureLayer(pic3)); - t2.root()->Add(t2_c1); - t2.root()->Add(t2_c2); - damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - - // Add at the end - - t2 = LayerTree(); - t2.root()->Add(t2_c1); - t2.root()->Add(t2_c2); - t2.root()->Add(CreatePictureLayer(pic3)); - damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); -} - -// Insert picture layer amongst other picture layers -TEST_F(DiffContextTest, PictureInsertion) { - auto pic1 = CreatePicture(SkRect::MakeLTRB(0, 0, 50, 50), 1); - auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); - auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); - - LayerTree t1; - t1.root()->Add(CreatePictureLayer(pic1)); - t1.root()->Add(CreatePictureLayer(pic2)); - - auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); - - LayerTree t2; - t2.root()->Add(CreatePictureLayer(pic3)); - t2.root()->Add(CreatePictureLayer(pic1)); - t2.root()->Add(CreatePictureLayer(pic2)); - - damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - - LayerTree t3; - t3.root()->Add(CreatePictureLayer(pic1)); - t3.root()->Add(CreatePictureLayer(pic3)); - t3.root()->Add(CreatePictureLayer(pic2)); - - damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - - LayerTree t4; - t4.root()->Add(CreatePictureLayer(pic1)); - t4.root()->Add(CreatePictureLayer(pic2)); - t4.root()->Add(CreatePictureLayer(pic3)); - - damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); -} - -TEST_F(DiffContextTest, LayerDeletion) { - auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); - auto path2 = SkPath().addRect(SkRect::MakeLTRB(100, 0, 150, 50)); - auto path3 = SkPath().addRect(SkRect::MakeLTRB(200, 0, 250, 50)); - - auto c1 = CreateContainerLayer(std::make_shared(path1)); - auto c2 = CreateContainerLayer(std::make_shared(path2)); - auto c3 = CreateContainerLayer(std::make_shared(path3)); - - LayerTree t1; - t1.root()->Add(c1); - t1.root()->Add(c2); - t1.root()->Add(c3); - - auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); - - LayerTree t2; - t2.root()->Add(c2); - t2.root()->Add(c3); - - damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 50)); - - LayerTree t3; - t3.root()->Add(c1); - t3.root()->Add(c3); - - damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 50)); - - LayerTree t4; - t4.root()->Add(c1); - t4.root()->Add(c2); - - damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - - LayerTree t5; - t5.root()->Add(c1); - - damage = DiffLayerTree(t5, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 250, 50)); - - LayerTree t6; - t6.root()->Add(c2); - - damage = DiffLayerTree(t6, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); - - LayerTree t7; - t7.root()->Add(c3); - - damage = DiffLayerTree(t7, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); -} - -TEST_F(DiffContextTest, ReplaceLayer) { - auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); - auto path2 = SkPath().addRect(SkRect::MakeLTRB(100, 0, 150, 50)); - auto path3 = SkPath().addRect(SkRect::MakeLTRB(200, 0, 250, 50)); - - auto path1a = SkPath().addRect(SkRect::MakeLTRB(0, 100, 50, 150)); - auto path2a = SkPath().addRect(SkRect::MakeLTRB(100, 100, 150, 150)); - auto path3a = SkPath().addRect(SkRect::MakeLTRB(200, 100, 250, 150)); - - auto c1 = CreateContainerLayer(std::make_shared(path1)); - auto c2 = CreateContainerLayer(std::make_shared(path2)); - auto c3 = CreateContainerLayer(std::make_shared(path3)); - - LayerTree t1; - t1.root()->Add(c1); - t1.root()->Add(c2); - t1.root()->Add(c3); - - auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); - - LayerTree t2; - t2.root()->Add(c1); - t2.root()->Add(c2); - t2.root()->Add(c3); - - damage = DiffLayerTree(t2, t1); - EXPECT_TRUE(damage.surface_damage.isEmpty()); - - LayerTree t3; - t3.root()->Add(CreateContainerLayer({std::make_shared(path1a)})); - t3.root()->Add(c2); - t3.root()->Add(c3); - - damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 150)); - - LayerTree t4; - t4.root()->Add(c1); - t4.root()->Add(CreateContainerLayer(std::make_shared(path2a))); - t4.root()->Add(c3); - - damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); - - LayerTree t5; - t5.root()->Add(c1); - t5.root()->Add(c2); - t5.root()->Add(CreateContainerLayer(std::make_shared(path3a))); - - damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); -} - -TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { +TEST_F(DiffContextTest, DieIfOldLayerTreeWasNeverDiffed) { auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); auto c1 = CreateContainerLayer(std::make_shared(path1)); @@ -294,211 +34,6 @@ TEST_F(DiffContextTest, DieIfOldLayerWasNeverDiffed) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); } -TEST_F(DiffContextTest, Transform) { - auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); - auto m1 = std::make_shared(path1); - - auto transform1 = - std::make_shared(SkMatrix::MakeTrans(10, 10)); - transform1->Add(m1); - - LayerTree t1; - t1.root()->Add(transform1); - - auto damage = DiffLayerTree(t1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); - - auto transform2 = - std::make_shared(SkMatrix::MakeTrans(20, 20)); - transform2->Add(m1); - transform2->AssignOldLayer(transform1.get()); - - LayerTree t2; - t2.root()->Add(transform2); - - damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); - - auto transform3 = - std::make_shared(SkMatrix::MakeTrans(20, 20)); - transform3->Add(m1); - transform3->AssignOldLayer(transform2.get()); - - LayerTree t3; - t3.root()->Add(transform3); - - damage = DiffLayerTree(t3, t2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); -} - -TEST_F(DiffContextTest, TransformNested) { - auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); - auto m1 = CreateContainerLayer(std::make_shared(path1)); - - auto transform1 = - std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); - - auto transform1_1 = - std::make_shared(SkMatrix::MakeTrans(10, 10)); - transform1_1->Add(m1); - transform1->Add(transform1_1); - - auto transform1_2 = - std::make_shared(SkMatrix::MakeTrans(100, 100)); - transform1_2->Add(m1); - transform1->Add(transform1_2); - - auto transform1_3 = - std::make_shared(SkMatrix::MakeTrans(200, 200)); - transform1_3->Add(m1); - transform1->Add(transform1_3); - - LayerTree l1; - l1.root()->Add(transform1); - - auto damage = DiffLayerTree(l1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); - - auto transform2 = - std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); - - auto transform2_1 = - std::make_shared(SkMatrix::MakeTrans(10, 10)); - transform2_1->Add(m1); - transform2_1->AssignOldLayer(transform1_1.get()); - transform2->Add(transform2_1); - - auto transform2_2 = - std::make_shared(SkMatrix::MakeTrans(100, 101)); - transform2_2->Add(m1); - transform2_2->AssignOldLayer(transform1_2.get()); - transform2->Add(transform2_2); - - auto transform2_3 = - std::make_shared(SkMatrix::MakeTrans(200, 200)); - transform2_3->Add(m1); - transform2_3->AssignOldLayer(transform1_3.get()); - transform2->Add(transform2_3); - - LayerTree l2; - l2.root()->Add(transform2); - - damage = DiffLayerTree(l2, l1); - - // transform2 has not transform1 assigned as old layer, so it should be - // invalidated completely - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); - - // now diff the tree properly, the only difference being transform2_2 and - // transform_2_1 - transform2->AssignOldLayer(transform1.get()); - damage = DiffLayerTree(l2, l1); - - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 200, 300, 302)); -} - -TEST_F(DiffContextTest, BackdropLayer) { - auto filter = SkBlurImageFilter::Make(10, 10, nullptr, nullptr, - SkBlurImageFilter::kClamp_TileMode); - - { - // tests later assume 30px readback area, fail early if that's not the case - auto readback = filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), - SkImageFilter::kReverse_MapDirection); - EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); - } - - LayerTree l1(SkISize::Make(100, 100)); - l1.root()->Add(std::make_shared(filter)); - - // no clip, effect over entire surface - auto damage = DiffLayerTree(l1, LayerTree(SkISize::Make(100, 100))); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeWH(100, 100)); - - LayerTree l2(SkISize::Make(100, 100)); - - auto clip = std::make_shared(SkRect::MakeLTRB(20, 20, 60, 60), - Clip::hardEdge); - clip->Add(std::make_shared(filter)); - l2.root()->Add(clip); - damage = DiffLayerTree(l2, LayerTree(SkISize::Make(100, 100))); - - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); - - LayerTree l3; - auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); - scale->Add(clip); - l3.root()->Add(scale); - - damage = DiffLayerTree(l3, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 180, 180)); - - LayerTree l4; - l4.root()->Add(scale); - - // path just outside of readback region, doesn't affect blur - auto path1 = SkPath().addRect(SkRect::MakeLTRB(180, 180, 190, 190)); - l4.root()->Add(std::make_shared(path1)); - damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(180, 180, 190, 190)); - - LayerTree l5; - l5.root()->Add(scale); - - // path just inside of readback region, must trigger backdrop repaint - auto path2 = SkPath().addRect(SkRect::MakeLTRB(179, 179, 189, 189)); - l5.root()->Add(std::make_shared(path2)); - damage = DiffLayerTree(l5, l4); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 190, 190)); -} - -TEST_F(DiffContextTest, ImageFilterLayer) { - auto filter = SkBlurImageFilter::Make(10, 10, nullptr, nullptr, - SkBlurImageFilter::kClamp_TileMode); - - { - // tests later assume 30px paint area, fail early if that's not the case - auto paint_rect = - filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), - SkImageFilter::kForward_MapDirection); - EXPECT_EQ(paint_rect, SkIRect::MakeLTRB(-30, -30, 40, 40)); - } - - LayerTree l1; - auto filter_layer = std::make_shared(filter); - auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110)); - filter_layer->Add(std::make_shared(path)); - l1.root()->Add(filter_layer); - - auto damage = DiffLayerTree(l1, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(70, 70, 140, 140)); - - LayerTree l2; - auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); - scale->Add(filter_layer); - l2.root()->Add(scale); - - damage = DiffLayerTree(l2, LayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(140, 140, 280, 280)); - - LayerTree l3; - l3.root()->Add(scale); - - // path outside of ImageFilterLayer - auto path1 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 140, 140)); - l3.root()->Add(std::make_shared(path1)); - damage = DiffLayerTree(l3, l2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 140, 140)); - - // path intersecting ImageFilterLayer, should trigger ImageFilterLayer repaint - LayerTree l4; - l4.root()->Add(scale); - auto path2 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 141, 141)); - l4.root()->Add(std::make_shared(path2)); - damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 280, 280)); -} - #endif // FLUTTER_ENABLE_DIFF_CONTEXT } // namespace testing diff --git a/flow/layers/backdrop_filter_layer_unittests.cc b/flow/layers/backdrop_filter_layer_unittests.cc index 5fff33ecc17ef..91bbcdc2dd5c1 100644 --- a/flow/layers/backdrop_filter_layer_unittests.cc +++ b/flow/layers/backdrop_filter_layer_unittests.cc @@ -4,11 +4,15 @@ #include "flutter/flow/layers/backdrop_filter_layer.h" +#include "flutter/flow/layers/clip_rect_layer.h" +#include "flutter/flow/layers/transform_layer.h" +#include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" #include "flutter/testing/mock_canvas.h" #include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/effects/SkBlurImageFilter.h" #include "third_party/skia/include/effects/SkImageFilters.h" namespace flutter { @@ -213,5 +217,66 @@ TEST_F(BackdropFilterLayerTest, Readback) { EXPECT_FALSE(preroll_context()->surface_needs_readback); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +using BackdropLayerDiffTest = DiffContextTest; + +TEST_F(BackdropLayerDiffTest, BackdropLayer) { + auto filter = SkBlurImageFilter::Make(10, 10, nullptr, nullptr, + SkBlurImageFilter::kClamp_TileMode); + + { + // tests later assume 30px readback area, fail early if that's not the case + auto readback = filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), + SkImageFilter::kReverse_MapDirection); + EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); + } + + LayerTree l1(SkISize::Make(100, 100)); + l1.root()->Add(std::make_shared(filter)); + + // no clip, effect over entire surface + auto damage = DiffLayerTree(l1, LayerTree(SkISize::Make(100, 100))); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeWH(100, 100)); + + LayerTree l2(SkISize::Make(100, 100)); + + auto clip = std::make_shared(SkRect::MakeLTRB(20, 20, 60, 60), + Clip::hardEdge); + clip->Add(std::make_shared(filter)); + l2.root()->Add(clip); + damage = DiffLayerTree(l2, LayerTree(SkISize::Make(100, 100))); + + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); + + LayerTree l3; + auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + scale->Add(clip); + l3.root()->Add(scale); + + damage = DiffLayerTree(l3, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 180, 180)); + + LayerTree l4; + l4.root()->Add(scale); + + // path just outside of readback region, doesn't affect blur + auto path1 = SkPath().addRect(SkRect::MakeLTRB(180, 180, 190, 190)); + l4.root()->Add(std::make_shared(path1)); + damage = DiffLayerTree(l4, l3); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(180, 180, 190, 190)); + + LayerTree l5; + l5.root()->Add(scale); + + // path just inside of readback region, must trigger backdrop repaint + auto path2 = SkPath().addRect(SkRect::MakeLTRB(179, 179, 189, 189)); + l5.root()->Add(std::make_shared(path2)); + damage = DiffLayerTree(l5, l4); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 190, 190)); +} + +#endif + } // namespace testing } // namespace flutter diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index a8111c2920450..74dc7d3f95537 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -4,6 +4,7 @@ #include "flutter/flow/layers/container_layer.h" +#include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" @@ -268,5 +269,212 @@ TEST_F(ContainerLayerTest, MergedMultipleChildren) { child_path2, child_paint2}}})); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +using ContainerLayerDiffTest = DiffContextTest; + +// Insert PictureLayer amongst container layers +TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { + auto pic1 = CreatePicture(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); + + LayerTree t1; + + auto t1_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + t1.root()->Add(t1_c1); + + auto t1_c2 = CreateContainerLayer(CreatePictureLayer(pic2)); + t1.root()->Add(t1_c2); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); + + // Add in the middle + + LayerTree t2; + auto t2_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); + t2_c1->AssignOldLayer(t1_c1.get()); + t2.root()->Add(t2_c1); + + t2.root()->Add(CreatePictureLayer(pic3)); + + auto t2_c2 = CreateContainerLayer(CreatePictureLayer(pic2)); + t2_c2->AssignOldLayer(t1_c2.get()); + t2.root()->Add(t2_c2); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + + // Add in the beginning + + t2 = LayerTree(); + t2.root()->Add(CreatePictureLayer(pic3)); + t2.root()->Add(t2_c1); + t2.root()->Add(t2_c2); + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + + // Add at the end + + t2 = LayerTree(); + t2.root()->Add(t2_c1); + t2.root()->Add(t2_c2); + t2.root()->Add(CreatePictureLayer(pic3)); + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); +} + +// Insert picture layer amongst other picture layers +TEST_F(ContainerLayerDiffTest, PictureInsertion) { + auto pic1 = CreatePicture(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); + + LayerTree t1; + t1.root()->Add(CreatePictureLayer(pic1)); + t1.root()->Add(CreatePictureLayer(pic2)); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); + + LayerTree t2; + t2.root()->Add(CreatePictureLayer(pic3)); + t2.root()->Add(CreatePictureLayer(pic1)); + t2.root()->Add(CreatePictureLayer(pic2)); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + + LayerTree t3; + t3.root()->Add(CreatePictureLayer(pic1)); + t3.root()->Add(CreatePictureLayer(pic3)); + t3.root()->Add(CreatePictureLayer(pic2)); + + damage = DiffLayerTree(t3, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + + LayerTree t4; + t4.root()->Add(CreatePictureLayer(pic1)); + t4.root()->Add(CreatePictureLayer(pic2)); + t4.root()->Add(CreatePictureLayer(pic3)); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); +} + +TEST_F(ContainerLayerDiffTest, LayerDeletion) { + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); + auto path2 = SkPath().addRect(SkRect::MakeLTRB(100, 0, 150, 50)); + auto path3 = SkPath().addRect(SkRect::MakeLTRB(200, 0, 250, 50)); + + auto c1 = CreateContainerLayer(std::make_shared(path1)); + auto c2 = CreateContainerLayer(std::make_shared(path2)); + auto c3 = CreateContainerLayer(std::make_shared(path3)); + + LayerTree t1; + t1.root()->Add(c1); + t1.root()->Add(c2); + t1.root()->Add(c3); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); + + LayerTree t2; + t2.root()->Add(c2); + t2.root()->Add(c3); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 50)); + + LayerTree t3; + t3.root()->Add(c1); + t3.root()->Add(c3); + + damage = DiffLayerTree(t3, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 50)); + + LayerTree t4; + t4.root()->Add(c1); + t4.root()->Add(c2); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + + LayerTree t5; + t5.root()->Add(c1); + + damage = DiffLayerTree(t5, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 250, 50)); + + LayerTree t6; + t6.root()->Add(c2); + + damage = DiffLayerTree(t6, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); + + LayerTree t7; + t7.root()->Add(c3); + + damage = DiffLayerTree(t7, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); +} + +TEST_F(ContainerLayerDiffTest, ReplaceLayer) { + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); + auto path2 = SkPath().addRect(SkRect::MakeLTRB(100, 0, 150, 50)); + auto path3 = SkPath().addRect(SkRect::MakeLTRB(200, 0, 250, 50)); + + auto path1a = SkPath().addRect(SkRect::MakeLTRB(0, 100, 50, 150)); + auto path2a = SkPath().addRect(SkRect::MakeLTRB(100, 100, 150, 150)); + auto path3a = SkPath().addRect(SkRect::MakeLTRB(200, 100, 250, 150)); + + auto c1 = CreateContainerLayer(std::make_shared(path1)); + auto c2 = CreateContainerLayer(std::make_shared(path2)); + auto c3 = CreateContainerLayer(std::make_shared(path3)); + + LayerTree t1; + t1.root()->Add(c1); + t1.root()->Add(c2); + t1.root()->Add(c3); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); + + LayerTree t2; + t2.root()->Add(c1); + t2.root()->Add(c2); + t2.root()->Add(c3); + + damage = DiffLayerTree(t2, t1); + EXPECT_TRUE(damage.surface_damage.isEmpty()); + + LayerTree t3; + t3.root()->Add(CreateContainerLayer({std::make_shared(path1a)})); + t3.root()->Add(c2); + t3.root()->Add(c3); + + damage = DiffLayerTree(t3, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 150)); + + LayerTree t4; + t4.root()->Add(c1); + t4.root()->Add(CreateContainerLayer(std::make_shared(path2a))); + t4.root()->Add(c3); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); + + LayerTree t5; + t5.root()->Add(c1); + t5.root()->Add(c2); + t5.root()->Add(CreateContainerLayer(std::make_shared(path3a))); + + damage = DiffLayerTree(t4, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); +} + +#endif + } // namespace testing } // namespace flutter diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index c2cab8d3f6237..7f5d25e23611c 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -4,6 +4,8 @@ #include "flutter/flow/layers/image_filter_layer.h" +#include "flutter/flow/layers/transform_layer.h" +#include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" @@ -333,5 +335,57 @@ TEST_F(ImageFilterLayerTest, ChildrenNotCached) { EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas)); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +using ImageFilterLayerDiffTest = DiffContextTest; + +TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { + auto filter = SkImageFilters::Blur(10, 10, SkTileMode::kClamp, nullptr); + + { + // tests later assume 30px paint area, fail early if that's not the case + auto paint_rect = + filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), + SkImageFilter::kForward_MapDirection); + EXPECT_EQ(paint_rect, SkIRect::MakeLTRB(-30, -30, 40, 40)); + } + + LayerTree l1; + auto filter_layer = std::make_shared(filter); + auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110)); + filter_layer->Add(std::make_shared(path)); + l1.root()->Add(filter_layer); + + auto damage = DiffLayerTree(l1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(70, 70, 140, 140)); + + LayerTree l2; + auto scale = std::make_shared(SkMatrix::Scale(2.0, 2.0)); + scale->Add(filter_layer); + l2.root()->Add(scale); + + damage = DiffLayerTree(l2, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(140, 140, 280, 280)); + + LayerTree l3; + l3.root()->Add(scale); + + // path outside of ImageFilterLayer + auto path1 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 140, 140)); + l3.root()->Add(std::make_shared(path1)); + damage = DiffLayerTree(l3, l2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 140, 140)); + + // path intersecting ImageFilterLayer, should trigger ImageFilterLayer repaint + LayerTree l4; + l4.root()->Add(scale); + auto path2 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 141, 141)); + l4.root()->Add(std::make_shared(path2)); + damage = DiffLayerTree(l4, l3); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 280, 280)); +} + +#endif + } // namespace testing } // namespace flutter diff --git a/flow/layers/picture_layer_unittests.cc b/flow/layers/picture_layer_unittests.cc index 861921e1328ef..0fea7c5c87aac 100644 --- a/flow/layers/picture_layer_unittests.cc +++ b/flow/layers/picture_layer_unittests.cc @@ -6,6 +6,7 @@ #include "flutter/flow/layers/picture_layer.h" +#include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/skia_gpu_object_layer_test.h" #include "flutter/fml/macros.h" #include "flutter/testing/mock_canvas.h" @@ -98,5 +99,63 @@ TEST_F(PictureLayerTest, SimplePicture) { EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +using PictureLayerDiffTest = DiffContextTest; + +TEST_F(PictureLayerDiffTest, SimplePicture) { + auto picture = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); + + LayerTree tree1; + tree1.root()->Add(CreatePictureLayer(picture)); + + auto damage = DiffLayerTree(tree1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); + + LayerTree tree2; + tree2.root()->Add(CreatePictureLayer(picture)); + + damage = DiffLayerTree(tree2, tree1); + EXPECT_TRUE(damage.surface_damage.isEmpty()); + + LayerTree tree3; + damage = DiffLayerTree(tree3, tree2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); +} + +TEST_F(PictureLayerDiffTest, PictureCompare) { + LayerTree tree1; + auto picture1 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); + tree1.root()->Add(CreatePictureLayer(picture1)); + + auto damage = DiffLayerTree(tree1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); + + LayerTree tree2; + auto picture2 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); + tree2.root()->Add(CreatePictureLayer(picture2)); + + damage = DiffLayerTree(tree2, tree1); + EXPECT_TRUE(damage.surface_damage.isEmpty()); + + LayerTree tree3; + auto picture3 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); + // add offset + tree3.root()->Add(CreatePictureLayer(picture3, SkPoint::Make(10, 10))); + + damage = DiffLayerTree(tree3, tree2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); + + LayerTree tree4; + // different color + auto picture4 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 2); + tree4.root()->Add(CreatePictureLayer(picture4, SkPoint::Make(10, 10))); + + damage = DiffLayerTree(tree4, tree3); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 70, 70)); +} + +#endif + } // namespace testing } // namespace flutter diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index 5a393319071c4..4732d31d0f261 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -4,6 +4,7 @@ #include "flutter/flow/layers/transform_layer.h" +#include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" @@ -224,5 +225,114 @@ TEST_F(TransformLayerTest, NestedSeparated) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +using TransformLayerLayerDiffTest = DiffContextTest; + +TEST_F(TransformLayerLayerDiffTest, Transform) { + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); + auto m1 = std::make_shared(path1); + + auto transform1 = + std::make_shared(SkMatrix::MakeTrans(10, 10)); + transform1->Add(m1); + + LayerTree t1; + t1.root()->Add(transform1); + + auto damage = DiffLayerTree(t1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); + + auto transform2 = + std::make_shared(SkMatrix::MakeTrans(20, 20)); + transform2->Add(m1); + transform2->AssignOldLayer(transform1.get()); + + LayerTree t2; + t2.root()->Add(transform2); + + damage = DiffLayerTree(t2, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); + + auto transform3 = + std::make_shared(SkMatrix::MakeTrans(20, 20)); + transform3->Add(m1); + transform3->AssignOldLayer(transform2.get()); + + LayerTree t3; + t3.root()->Add(transform3); + + damage = DiffLayerTree(t3, t2); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); +} + +TEST_F(TransformLayerLayerDiffTest, TransformNested) { + auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); + auto m1 = CreateContainerLayer(std::make_shared(path1)); + + auto transform1 = + std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + + auto transform1_1 = + std::make_shared(SkMatrix::MakeTrans(10, 10)); + transform1_1->Add(m1); + transform1->Add(transform1_1); + + auto transform1_2 = + std::make_shared(SkMatrix::MakeTrans(100, 100)); + transform1_2->Add(m1); + transform1->Add(transform1_2); + + auto transform1_3 = + std::make_shared(SkMatrix::MakeTrans(200, 200)); + transform1_3->Add(m1); + transform1->Add(transform1_3); + + LayerTree l1; + l1.root()->Add(transform1); + + auto damage = DiffLayerTree(l1, LayerTree()); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); + + auto transform2 = + std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + + auto transform2_1 = + std::make_shared(SkMatrix::MakeTrans(10, 10)); + transform2_1->Add(m1); + transform2_1->AssignOldLayer(transform1_1.get()); + transform2->Add(transform2_1); + + auto transform2_2 = + std::make_shared(SkMatrix::MakeTrans(100, 101)); + transform2_2->Add(m1); + transform2_2->AssignOldLayer(transform1_2.get()); + transform2->Add(transform2_2); + + auto transform2_3 = + std::make_shared(SkMatrix::MakeTrans(200, 200)); + transform2_3->Add(m1); + transform2_3->AssignOldLayer(transform1_3.get()); + transform2->Add(transform2_3); + + LayerTree l2; + l2.root()->Add(transform2); + + damage = DiffLayerTree(l2, l1); + + // transform2 has not transform1 assigned as old layer, so it should be + // invalidated completely + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); + + // now diff the tree properly, the only difference being transform2_2 and + // transform_2_1 + transform2->AssignOldLayer(transform1.get()); + damage = DiffLayerTree(l2, l1); + + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 200, 300, 302)); +} + +#endif + } // namespace testing } // namespace flutter From dd6bc8b722681d872eaef5913a6bef7946bc5a8b Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 14:29:47 +0100 Subject: [PATCH 22/43] Skia factories rename --- .../layers/backdrop_filter_layer_unittests.cc | 2 +- flow/layers/transform_layer_unittests.cc | 24 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/flow/layers/backdrop_filter_layer_unittests.cc b/flow/layers/backdrop_filter_layer_unittests.cc index 91bbcdc2dd5c1..2609bcc460246 100644 --- a/flow/layers/backdrop_filter_layer_unittests.cc +++ b/flow/layers/backdrop_filter_layer_unittests.cc @@ -250,7 +250,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); LayerTree l3; - auto scale = std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + auto scale = std::make_shared(SkMatrix::Scale(2.0, 2.0)); scale->Add(clip); l3.root()->Add(scale); diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index 4732d31d0f261..de23686019dcf 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -234,7 +234,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { auto m1 = std::make_shared(path1); auto transform1 = - std::make_shared(SkMatrix::MakeTrans(10, 10)); + std::make_shared(SkMatrix::Translate(10, 10)); transform1->Add(m1); LayerTree t1; @@ -244,7 +244,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); auto transform2 = - std::make_shared(SkMatrix::MakeTrans(20, 20)); + std::make_shared(SkMatrix::Translate(20, 20)); transform2->Add(m1); transform2->AssignOldLayer(transform1.get()); @@ -255,7 +255,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); auto transform3 = - std::make_shared(SkMatrix::MakeTrans(20, 20)); + std::make_shared(SkMatrix::Translate(20, 20)); transform3->Add(m1); transform3->AssignOldLayer(transform2.get()); @@ -270,21 +270,20 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); auto m1 = CreateContainerLayer(std::make_shared(path1)); - auto transform1 = - std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + auto transform1 = std::make_shared(SkMatrix::Scale(2.0, 2.0)); auto transform1_1 = - std::make_shared(SkMatrix::MakeTrans(10, 10)); + std::make_shared(SkMatrix::Translate(10, 10)); transform1_1->Add(m1); transform1->Add(transform1_1); auto transform1_2 = - std::make_shared(SkMatrix::MakeTrans(100, 100)); + std::make_shared(SkMatrix::Translate(100, 100)); transform1_2->Add(m1); transform1->Add(transform1_2); auto transform1_3 = - std::make_shared(SkMatrix::MakeTrans(200, 200)); + std::make_shared(SkMatrix::Translate(200, 200)); transform1_3->Add(m1); transform1->Add(transform1_3); @@ -294,23 +293,22 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { auto damage = DiffLayerTree(l1, LayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); - auto transform2 = - std::make_shared(SkMatrix::MakeScale(2.0, 2.0)); + auto transform2 = std::make_shared(SkMatrix::Scale(2.0, 2.0)); auto transform2_1 = - std::make_shared(SkMatrix::MakeTrans(10, 10)); + std::make_shared(SkMatrix::Translate(10, 10)); transform2_1->Add(m1); transform2_1->AssignOldLayer(transform1_1.get()); transform2->Add(transform2_1); auto transform2_2 = - std::make_shared(SkMatrix::MakeTrans(100, 101)); + std::make_shared(SkMatrix::Translate(100, 101)); transform2_2->Add(m1); transform2_2->AssignOldLayer(transform1_2.get()); transform2->Add(transform2_2); auto transform2_3 = - std::make_shared(SkMatrix::MakeTrans(200, 200)); + std::make_shared(SkMatrix::Translate(200, 200)); transform2_3->Add(m1); transform2_3->AssignOldLayer(transform1_3.get()); transform2->Add(transform2_3); From 7a29cc06ba38b0e60e5db89e0bd1dc9a7056810e Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 15:49:49 +0100 Subject: [PATCH 23/43] Move PaintRegion to separate file --- ci/licenses_golden/licenses_flutter | 2 + flow/BUILD.gn | 19 ++++++++++ flow/diff_context.cc | 10 +---- flow/diff_context.h | 50 +------------------------ flow/paint_region.cc | 17 +++++++++ flow/paint_region.h | 57 +++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 58 deletions(-) create mode 100644 flow/paint_region.cc create mode 100644 flow/paint_region.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d0ba39b4bb08a..5a0566ba6aeb6 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -104,6 +104,8 @@ FILE: ../../../flutter/flow/matrix_decomposition.cc FILE: ../../../flutter/flow/matrix_decomposition.h FILE: ../../../flutter/flow/matrix_decomposition_unittests.cc FILE: ../../../flutter/flow/mutators_stack_unittests.cc +FILE: ../../../flutter/flow/paint_region.cc +FILE: ../../../flutter/flow/paint_region.h FILE: ../../../flutter/flow/paint_utils.cc FILE: ../../../flutter/flow/paint_utils.h FILE: ../../../flutter/flow/raster_cache.cc diff --git a/flow/BUILD.gn b/flow/BUILD.gn index c2d0058c19f2b..f9c47439f3aeb 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -52,6 +52,8 @@ source_set("flow") { "layers/transform_layer.h", "matrix_decomposition.cc", "matrix_decomposition.h", + "paint_region.cc", + "paint_region.h", "paint_utils.cc", "paint_utils.h", "raster_cache.cc", @@ -94,6 +96,13 @@ source_set("flow") { "$fuchsia_sdk_root/pkg:scenic_cpp", ] } + + if (!defined(defines)) { + defines = [] + } + if (is_debug) { + defines += [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] + } } if (enable_unittests) { @@ -129,6 +138,13 @@ if (enable_unittests) { ":flow", "//flutter/common/graphics", ] + + if (!defined(defines)) { + defines = [] + } + if (is_debug) { + defines += [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] + } } executable("flow_unittests") { @@ -188,6 +204,9 @@ if (enable_unittests) { # Required for M_PI and others. defines += [ "_USE_MATH_DEFINES" ] } + if (is_debug) { + defines += [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] + } if (is_fuchsia && flutter_enable_legacy_fuchsia_embedder) { sources += [ "layers/fuchsia_layer_unittests.cc" ] diff --git a/flow/diff_context.cc b/flow/diff_context.cc index a21b455610f8b..ce5108d27ae5c 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -1,18 +1,10 @@ -#include "diff_context.h" +#include "flutter/flow/diff_context.h" #include "flutter/flow/layers/layer.h" namespace flutter { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT -SkRect PaintRegion::GetBounds() const { - SkRect res = SkRect::MakeEmpty(); - for (const auto& r : *this) { - res.join(r); - } - return res; -} - DiffContext::DiffContext(SkISize frame_size, double frame_device_pixel_ratio, PaintRegionMap& this_frame_paint_region_map, diff --git a/flow/diff_context.h b/flow/diff_context.h index 82d4f3f2f6c21..734eb6eb03efa 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -5,15 +5,12 @@ #include #include "flutter/fml/logging.h" #include "flutter/fml/macros.h" +#include "flutter/flow/paint_region.h" #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkRect.h" namespace flutter { -#ifndef NDEBUG -#define FLUTTER_ENABLE_DIFF_CONTEXT -#endif - #ifdef FLUTTER_ENABLE_DIFF_CONTEXT class Layer; @@ -31,51 +28,6 @@ struct Damage { SkIRect buffer_damage; }; -// Every layer has a PaintRegion that covers screen area where the layer subtree -// painted anything. -// -// The area is used when adding damage of removed or dirty later. -// -// Because there is a PaintRegion for each layer, it must be able to represent -// the area with minimal overhead. This is accomplished by having one -// vector shared between all paint regions, and each paint region -// keeping begin and end index of rects relevant to particular subtree. -// -// All rects are in screen coordinates. -class PaintRegion { - public: - PaintRegion() {} - PaintRegion(std::shared_ptr> rects, - size_t from, - size_t to, - bool has_readback) - : rects_(rects), from_(from), to_(to), has_readback_(has_readback) {} - - std::vector::const_iterator begin() const { - FML_DCHECK(is_valid()); - return rects_->begin() + from_; - } - - std::vector::const_iterator end() const { - FML_DCHECK(is_valid()); - return rects_->begin() + to_; - } - - // Compute bounds for this region - SkRect GetBounds() const; - - bool is_valid() const { return rects_ != nullptr; } - - // Returns true if there is a layer in subtree represented by this region - // that performs readback - bool has_readback() const { return has_readback_; } - - private: - std::shared_ptr> rects_; - size_t from_ = 0; - size_t to_ = 0; - bool has_readback_ = false; -}; using PaintRegionMap = std::map; diff --git a/flow/paint_region.cc b/flow/paint_region.cc new file mode 100644 index 0000000000000..f131bf38a9214 --- /dev/null +++ b/flow/paint_region.cc @@ -0,0 +1,17 @@ +#include "flutter/flow/paint_region.h" + +namespace flutter { + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +SkRect PaintRegion::GetBounds() const { + SkRect res = SkRect::MakeEmpty(); + for (const auto& r : *this) { + res.join(r); + } + return res; +} + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + +} // namespace flutter diff --git a/flow/paint_region.h b/flow/paint_region.h new file mode 100644 index 0000000000000..9f1d9d9f58d19 --- /dev/null +++ b/flow/paint_region.h @@ -0,0 +1,57 @@ +#include +#include "flutter/fml/logging.h" +#include "third_party/skia/include/core/SkRect.h" + +namespace flutter { + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +// Every layer has a PaintRegion that covers screen area where the layer subtree +// painted anything. +// +// The area is used when adding damage of removed or dirty later. +// +// Because there is a PaintRegion for each layer, it must be able to represent +// the area with minimal overhead. This is accomplished by having one +// vector shared between all paint regions, and each paint region +// keeping begin and end index of rects relevant to particular subtree. +// +// All rects are in screen coordinates. +class PaintRegion { + public: + PaintRegion() {} + PaintRegion(std::shared_ptr> rects, + size_t from, + size_t to, + bool has_readback) + : rects_(rects), from_(from), to_(to), has_readback_(has_readback) {} + + std::vector::const_iterator begin() const { + FML_DCHECK(is_valid()); + return rects_->begin() + from_; + } + + std::vector::const_iterator end() const { + FML_DCHECK(is_valid()); + return rects_->begin() + to_; + } + + // Compute bounds for this region + SkRect GetBounds() const; + + bool is_valid() const { return rects_ != nullptr; } + + // Returns true if there is a layer in subtree represented by this region + // that performs readback + bool has_readback() const { return has_readback_; } + + private: + std::shared_ptr> rects_; + size_t from_ = 0; + size_t to_ = 0; + bool has_readback_ = false; +}; + +#endif + +} // namespace flutter From 57552a9a7391bb5cb26f616decf9335713c7d12f Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 15:57:14 +0100 Subject: [PATCH 24/43] GetBounds -> ComputeBounds --- flow/layers/image_filter_layer.cc | 2 +- flow/paint_region.cc | 2 +- flow/paint_region.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 6060fdcb93e4d..7f6b9b324c466 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -28,7 +28,7 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { SkMatrix inverse; if (context->GetTransform().invert(&inverse)) { auto paint_bounds = - inverse.mapRect(context->CurrentSubtreeRegion().GetBounds()); + inverse.mapRect(context->CurrentSubtreeRegion().ComputeBounds()); auto filter_bounds = filter_->filterBounds(paint_bounds.roundOut(), SkMatrix::I(), diff --git a/flow/paint_region.cc b/flow/paint_region.cc index f131bf38a9214..76c71195a89dd 100644 --- a/flow/paint_region.cc +++ b/flow/paint_region.cc @@ -4,7 +4,7 @@ namespace flutter { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT -SkRect PaintRegion::GetBounds() const { +SkRect PaintRegion::ComputeBounds() const { SkRect res = SkRect::MakeEmpty(); for (const auto& r : *this) { res.join(r); diff --git a/flow/paint_region.h b/flow/paint_region.h index 9f1d9d9f58d19..12f250d77ecab 100644 --- a/flow/paint_region.h +++ b/flow/paint_region.h @@ -37,7 +37,7 @@ class PaintRegion { } // Compute bounds for this region - SkRect GetBounds() const; + SkRect ComputeBounds() const; bool is_valid() const { return rects_ != nullptr; } From 4fb5d821f9aac933bb51e0b9fbb387517b8d7b1f Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 15:58:36 +0100 Subject: [PATCH 25/43] GetDamage -> ComputeDamage --- flow/diff_context.cc | 3 ++- flow/diff_context.h | 5 ++--- flow/testing/diff_context_test.cc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index ce5108d27ae5c..9b5f785e19d0a 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -41,7 +41,8 @@ void DiffContext::PushTransform(const SkMatrix& transform) { } } -Damage DiffContext::GetDamage(const SkIRect& accumulated_buffer_damage) const { +Damage DiffContext::ComputeDamage( + const SkIRect& accumulated_buffer_damage) const { SkRect framebuffer = SkRect::Make(accumulated_buffer_damage); framebuffer.join(damage_); SkRect net(damage_); diff --git a/flow/diff_context.h b/flow/diff_context.h index 734eb6eb03efa..89c6c1bb9b195 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -3,9 +3,9 @@ #include #include +#include "flutter/flow/paint_region.h" #include "flutter/fml/logging.h" #include "flutter/fml/macros.h" -#include "flutter/flow/paint_region.h" #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkRect.h" @@ -28,7 +28,6 @@ struct Damage { SkIRect buffer_damage; }; - using PaintRegionMap = std::map; // Tracks state during tree diffing process and computes resulting damage @@ -103,7 +102,7 @@ class DiffContext { // // additional_damage is the previously accumulated surface_damage for // current framebuffer - Damage GetDamage(const SkIRect& additional_damage) const; + Damage ComputeDamage(const SkIRect& additional_damage) const; double frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }; diff --git a/flow/testing/diff_context_test.cc b/flow/testing/diff_context_test.cc index 3c0d7d7c87cc1..8e08b7de0743e 100644 --- a/flow/testing/diff_context_test.cc +++ b/flow/testing/diff_context_test.cc @@ -20,7 +20,7 @@ Damage DiffContextTest::DiffLayerTree(LayerTree& layer_tree, dc.PushCullRect( SkRect::MakeIWH(layer_tree.size().width(), layer_tree.size().height())); layer_tree.root()->Diff(&dc, old_layer_tree.root()); - return dc.GetDamage(additional_damage); + return dc.ComputeDamage(additional_damage); } sk_sp DiffContextTest::CreatePicture(const SkRect& bounds, From b70a3b4d9c2a39165762a0d9e7dafe537eeb3c62 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 16:16:55 +0100 Subject: [PATCH 26/43] Fix coments --- flow/diff_context.cc | 2 +- flow/diff_context.h | 18 ++++++++++++++---- flow/layers/layer.h | 2 ++ flow/paint_region.h | 8 ++++---- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 9b5f785e19d0a..5e94f0cb1f92c 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -93,7 +93,7 @@ void DiffContext::AddPaintRegion(const SkRect& rect) { void DiffContext::AddExistingPaintRegion(const PaintRegion& region) { // Adding paint region for retained layer implies that current subtree is not - // dirty + // dirty, so we know, for example, that the inherited transforms must match FML_DCHECK(!IsSubtreeDirty()); FML_DCHECK(region.is_valid()); rects_->insert(rects_->end(), region.begin(), region.end()); diff --git a/flow/diff_context.h b/flow/diff_context.h index 89c6c1bb9b195..303769f9d257f 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -86,7 +86,9 @@ class DiffContext { // Add paint region for layer; rect is in "local" (layer) coordinates void AddPaintRegion(const SkRect& rect); - // Add entire paint region of retained layer for current subtree + // Add entire paint region of retained layer for current subtree. This can + // only be used in subtrees that are not dirty, otherwise ancestor transforms + // or clips may result in different paint region. void AddExistingPaintRegion(const PaintRegion& region); // The idea of readback region is that if any part of the readback region @@ -94,8 +96,9 @@ class DiffContext { void AddReadbackRegion(const SkRect& rect); // Returns the paint region for current subtree; Each rect in paint region is - // in screen coordinates; The result should be set to layer's paint_region - // before closing the subtree + // in screen coordinates; Once a layer accumulates the paint regions of its + // children, this PaintRegion value can be associated with the current layer + // using DiffContext::SetLayerPaintRegion. PaintRegion CurrentSubtreeRegion() const; // Computes final damage @@ -106,11 +109,18 @@ class DiffContext { double frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }; - // Adds the region to current damage + // Adds the region to current damage. Used for removed layers, where instead + // of diffing the layer its paint region is direcly added to damage. void AddDamage(const PaintRegion& damage); + // Associates the paint region with specified layer and current layer tree. + // The paint region can not be stored directly in layer itself, because same + // retained layer instance can possibly paint in different locations depending + // on ancestor layers. void SetLayerPaintRegion(const Layer* layer, const PaintRegion& region); + // Retrieves the paint region associated with specified layer and previous + // frame layer tree. PaintRegion GetOldLayerPaintRegion(const Layer* layer) const; class Statistics { diff --git a/flow/layers/layer.h b/flow/layers/layer.h index a8210f224b02e..d22a4901b8afd 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -101,6 +101,8 @@ class Layer { // doesn't need to be diffed, but the paint region needs to be stored in diff // context so that it can be used in next frame virtual void PreservePaintRegion(DiffContext* context) { + // retained layer means same instance so 'this' is used to index into both + // current and old region context->SetLayerPaintRegion(this, context->GetOldLayerPaintRegion(this)); } diff --git a/flow/paint_region.h b/flow/paint_region.h index 12f250d77ecab..e4ad3b3b35a2c 100644 --- a/flow/paint_region.h +++ b/flow/paint_region.h @@ -6,10 +6,10 @@ namespace flutter { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT -// Every layer has a PaintRegion that covers screen area where the layer subtree -// painted anything. +// Corresponds to area on the screen where the layer subtree has painted to. // -// The area is used when adding damage of removed or dirty later. +// The area is used when adding damage of removed or dirty layer to overall +// damage. // // Because there is a PaintRegion for each layer, it must be able to represent // the area with minimal overhead. This is accomplished by having one @@ -19,7 +19,7 @@ namespace flutter { // All rects are in screen coordinates. class PaintRegion { public: - PaintRegion() {} + PaintRegion() = default; PaintRegion(std::shared_ptr> rects, size_t from, size_t to, From b696f8c8b5e6645f1b8dfa8d5947be368e8b7e8c Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 17:03:31 +0100 Subject: [PATCH 27/43] Consistency --- flow/diff_context.cc | 4 ++-- flow/diff_context.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 5e94f0cb1f92c..6b5502e917c6b 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -147,11 +147,11 @@ void DiffContext::Statistics::LogStatistics() { #if !FLUTTER_RELEASE FML_TRACE_COUNTER("flutter", "DiffContext", reinterpret_cast(this), "NewPictures", new_pictures_, "PicturesTooComplexToCompare", - picture_too_complex_to_compare_, "DeepComparePictures", + pictures_too_complex_to_compare_, "DeepComparePictures", deep_compare_pictures_, "SameInstancePictures", same_instance_pictures_, "DifferentInstanceButEqualPictures", - difference_instance_but_equal_pictures_); + different_instance_but_equal_pictures_); #endif // !FLUTTER_RELEASE } diff --git a/flow/diff_context.h b/flow/diff_context.h index 303769f9d257f..af4096b67e864 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -130,18 +130,18 @@ class DiffContext { // Picture that would require deep comparison but was considered too complex // to serialize and thus was treated as new picture - void AddPictureTooComplexToCompare() { ++picture_too_complex_to_compare_; } + void AddPictureTooComplexToCompare() { ++pictures_too_complex_to_compare_; } // Picture that has identical instance between frames void AddSameInstancePicture() { ++same_instance_pictures_; }; - // Pictures that had to be serialized to compare for equality + // Picture that had to be serialized to compare for equality void AddDeepComparePicture() { ++deep_compare_pictures_; } - // Pictures that had to be serialized to compare (different instances), + // Picture that had to be serialized to compare (different instances), // but were equal void AddDifferentInstanceButEqualPicture() { - ++difference_instance_but_equal_pictures_; + ++different_instance_but_equal_pictures_; }; // Logs the statistics to trace counter @@ -149,10 +149,10 @@ class DiffContext { private: int new_pictures_ = 0; - int picture_too_complex_to_compare_ = 0; + int pictures_too_complex_to_compare_ = 0; int same_instance_pictures_ = 0; int deep_compare_pictures_ = 0; - int difference_instance_but_equal_pictures_ = 0; + int different_instance_but_equal_pictures_ = 0; }; Statistics& statistics() { return statistics_; } From b9c16b5fc8749e68c0e4a9e67574d1d216c4f900 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 17:47:28 +0100 Subject: [PATCH 28/43] AddPaintRegion -> AddLayerBounds --- flow/diff_context.cc | 2 +- flow/diff_context.h | 5 +++-- flow/layers/backdrop_filter_layer.cc | 2 +- flow/layers/image_filter_layer.cc | 2 +- flow/layers/performance_overlay_layer.cc | 2 +- flow/layers/physical_shape_layer.cc | 2 +- flow/layers/picture_layer.cc | 2 +- flow/layers/texture_layer.cc | 2 +- flow/testing/mock_layer.cc | 2 +- 9 files changed, 11 insertions(+), 10 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 6b5502e917c6b..a7ed44b691484 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -78,7 +78,7 @@ void DiffContext::MarkSubtreeDirty(const PaintRegion& previous_paint_region) { state_.dirty = true; } -void DiffContext::AddPaintRegion(const SkRect& rect) { +void DiffContext::AddLayerBounds(const SkRect& rect) { SkRect r(rect); if (r.intersect(state_.cull_rect)) { state_.transform.mapRect(&r); diff --git a/flow/diff_context.h b/flow/diff_context.h index af4096b67e864..f8c7fb8626869 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -83,8 +83,9 @@ class DiffContext { bool IsSubtreeDirty() const { return state_.dirty; } - // Add paint region for layer; rect is in "local" (layer) coordinates - void AddPaintRegion(const SkRect& rect); + // Add layer bounds to current paint region; rect is in "local" (layer) + // coordinates + void AddLayerBounds(const SkRect& rect); // Add entire paint region of retained layer for current subtree. This can // only be used in subtrees that are not dirty, otherwise ancestor transforms diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 56c5f8c15d4ed..0ac49b5c958cc 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -23,7 +23,7 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { // Backdrop filter paints everywhere in cull rect auto paint_bounds = context->GetCullRect(); - context->AddPaintRegion(paint_bounds); + context->AddLayerBounds(paint_bounds); auto input_filter_bounds = paint_bounds.roundOut(); auto filter_bounds = // in screen coordinates diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 7f6b9b324c466..72808e9591f34 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -33,7 +33,7 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { auto filter_bounds = filter_->filterBounds(paint_bounds.roundOut(), SkMatrix::I(), SkImageFilter::kForward_MapDirection); - context->AddPaintRegion(SkRect::Make(filter_bounds)); + context->AddLayerBounds(SkRect::Make(filter_bounds)); // Technically, there is no readback with ImageFilterLayer, but we can't // clip the filter (because it may sample out of clip rect) so if any part diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index 9a59b5edaf13c..b9ccee84c7a79 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -84,7 +84,7 @@ void PerformanceOverlayLayer::Diff(DiffContext* context, auto prev = old_layer->as_performance_overlay_layer(); context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); } - context->AddPaintRegion(paint_bounds()); + context->AddLayerBounds(paint_bounds()); context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); } diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index 124d50125d9a0..7a08c12004ae3 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -45,7 +45,7 @@ void PhysicalShapeLayer::Diff(DiffContext* context, const Layer* old_layer) { context->frame_device_pixel_ratio()); } - context->AddPaintRegion(bounds); + context->AddLayerBounds(bounds); if (context->PushCullRect(bounds)) { DiffChildren(context, prev); diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index f02577f592e99..c00cf868687c3 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -42,7 +42,7 @@ void PictureLayer::Diff(DiffContext* context, const Layer* old_layer) { #endif } context->PushTransform(SkMatrix::Translate(offset_.x(), offset_.y())); - context->AddPaintRegion(picture()->cullRect()); + context->AddLayerBounds(picture()->cullRect()); context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); } diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index 14a905fa4ac68..0608bf2034ed0 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -30,7 +30,7 @@ void TextureLayer::Diff(DiffContext* context, const Layer* old_layer) { // dirty context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); } - context->AddPaintRegion(SkRect::MakeXYWH(offset_.x(), offset_.y(), + context->AddLayerBounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(), size_.height())); context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); } diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 66cf4a81662bb..2d710236f83c8 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -31,7 +31,7 @@ bool MockLayer::CanDiff(DiffContext* context, const Layer* layer) const { void MockLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); - context->AddPaintRegion(fake_paint_path_.getBounds()); + context->AddLayerBounds(fake_paint_path_.getBounds()); context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); } From d4b2497c03447dceb2be638e61efe886611301c3 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 17:48:59 +0100 Subject: [PATCH 29/43] Cleanup --- flow/layers/picture_layer.cc | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index c00cf868687c3..55110d0a024d1 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -84,24 +84,22 @@ bool PictureLayer::Compare(DiffContext::Statistics& statistics, } sk_sp PictureLayer::SerializedPicture() const { - SkSerialProcs procs = { - nullptr, - nullptr, - [](SkImage* i, void* ctx) { - auto id = i->uniqueID(); - return SkData::MakeWithCopy(&id, sizeof(id)); - }, - nullptr, - [](SkTypeface* tf, void* ctx) { - auto id = tf->uniqueID(); - return SkData::MakeWithCopy(&id, sizeof(id)); - }, - nullptr, - }; - if (!cached_serialized_picture_) { + SkSerialProcs procs = { + nullptr, + nullptr, + [](SkImage* i, void* ctx) { + auto id = i->uniqueID(); + return SkData::MakeWithCopy(&id, sizeof(id)); + }, + nullptr, + [](SkTypeface* tf, void* ctx) { + auto id = tf->uniqueID(); + return SkData::MakeWithCopy(&id, sizeof(id)); + }, + nullptr, + }; cached_serialized_picture_ = picture_.get()->serialize(&procs); - } else { } return cached_serialized_picture_; } From c525795e538f3e183237f36d614e5ad66a1cc056 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 18:19:52 +0100 Subject: [PATCH 30/43] Use different layer instances --- flow/layers/transform_layer_unittests.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index de23686019dcf..5ad50dd8ea0ac 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -269,6 +269,8 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { TEST_F(TransformLayerLayerDiffTest, TransformNested) { auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); auto m1 = CreateContainerLayer(std::make_shared(path1)); + auto m2 = CreateContainerLayer(std::make_shared(path1)); + auto m3 = CreateContainerLayer(std::make_shared(path1)); auto transform1 = std::make_shared(SkMatrix::Scale(2.0, 2.0)); @@ -279,12 +281,12 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { auto transform1_2 = std::make_shared(SkMatrix::Translate(100, 100)); - transform1_2->Add(m1); + transform1_2->Add(m2); transform1->Add(transform1_2); auto transform1_3 = std::make_shared(SkMatrix::Translate(200, 200)); - transform1_3->Add(m1); + transform1_3->Add(m3); transform1->Add(transform1_3); LayerTree l1; @@ -301,15 +303,16 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { transform2_1->AssignOldLayer(transform1_1.get()); transform2->Add(transform2_1); + // Offset 1px from transform1_2 so that they're not the same auto transform2_2 = std::make_shared(SkMatrix::Translate(100, 101)); - transform2_2->Add(m1); + transform2_2->Add(m2); transform2_2->AssignOldLayer(transform1_2.get()); transform2->Add(transform2_2); auto transform2_3 = std::make_shared(SkMatrix::Translate(200, 200)); - transform2_3->Add(m1); + transform2_3->Add(m3); transform2_3->AssignOldLayer(transform1_3.get()); transform2->Add(transform2_3); From 756a3e5f99f7000c0ee68b8f40c78772cba1454b Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 18:20:35 +0100 Subject: [PATCH 31/43] Diff proper subtrees --- flow/layers/container_layer_unittests.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index 74dc7d3f95537..907f43d1de590 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -470,8 +470,8 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { t5.root()->Add(c2); t5.root()->Add(CreateContainerLayer(std::make_shared(path3a))); - damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); + damage = DiffLayerTree(t5, t1); + EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 150)); } #endif From 9d3453eec725e52d5bb3db0095fc065440cf4835 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 10 Dec 2020 18:21:47 +0100 Subject: [PATCH 32/43] LayerTree -> MockLayerTree --- flow/diff_context_unittests.cc | 6 +-- .../layers/backdrop_filter_layer_unittests.cc | 16 +++---- flow/layers/container_layer_unittests.cc | 48 +++++++++---------- flow/layers/image_filter_layer_unittests.cc | 12 ++--- flow/layers/picture_layer_unittests.cc | 18 +++---- flow/layers/transform_layer_unittests.cc | 14 +++--- flow/testing/diff_context_test.cc | 4 +- flow/testing/diff_context_test.h | 8 ++-- 8 files changed, 63 insertions(+), 63 deletions(-) diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index e0a5f9fa6ee3f..3ecf5beb875f8 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -12,10 +12,10 @@ TEST_F(DiffContextTest, DieIfOldLayerTreeWasNeverDiffed) { auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); auto c1 = CreateContainerLayer(std::make_shared(path1)); - LayerTree t1; + MockLayerTree t1; t1.root()->Add(c1); - LayerTree t2; + MockLayerTree t2; t2.root()->Add(c1); // t1 is used as old_layer_tree, but it was never used used during diffing as @@ -27,7 +27,7 @@ TEST_F(DiffContextTest, DieIfOldLayerTreeWasNeverDiffed) { "Old layer doesn't have paint region"); // Diff t1 with empty layer tree to determine paint regions - DiffLayerTree(t1, LayerTree()); + DiffLayerTree(t1, MockLayerTree()); // Now we can diff t2 and t1 auto damage = DiffLayerTree(t2, t1); diff --git a/flow/layers/backdrop_filter_layer_unittests.cc b/flow/layers/backdrop_filter_layer_unittests.cc index 2609bcc460246..f788be1dd2501 100644 --- a/flow/layers/backdrop_filter_layer_unittests.cc +++ b/flow/layers/backdrop_filter_layer_unittests.cc @@ -232,32 +232,32 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); } - LayerTree l1(SkISize::Make(100, 100)); + MockLayerTree l1(SkISize::Make(100, 100)); l1.root()->Add(std::make_shared(filter)); // no clip, effect over entire surface - auto damage = DiffLayerTree(l1, LayerTree(SkISize::Make(100, 100))); + auto damage = DiffLayerTree(l1, MockLayerTree(SkISize::Make(100, 100))); EXPECT_EQ(damage.surface_damage, SkIRect::MakeWH(100, 100)); - LayerTree l2(SkISize::Make(100, 100)); + MockLayerTree l2(SkISize::Make(100, 100)); auto clip = std::make_shared(SkRect::MakeLTRB(20, 20, 60, 60), Clip::hardEdge); clip->Add(std::make_shared(filter)); l2.root()->Add(clip); - damage = DiffLayerTree(l2, LayerTree(SkISize::Make(100, 100))); + damage = DiffLayerTree(l2, MockLayerTree(SkISize::Make(100, 100))); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); - LayerTree l3; + MockLayerTree l3; auto scale = std::make_shared(SkMatrix::Scale(2.0, 2.0)); scale->Add(clip); l3.root()->Add(scale); - damage = DiffLayerTree(l3, LayerTree()); + damage = DiffLayerTree(l3, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 180, 180)); - LayerTree l4; + MockLayerTree l4; l4.root()->Add(scale); // path just outside of readback region, doesn't affect blur @@ -266,7 +266,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { damage = DiffLayerTree(l4, l3); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(180, 180, 190, 190)); - LayerTree l5; + MockLayerTree l5; l5.root()->Add(scale); // path just inside of readback region, must trigger backdrop repaint diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index 907f43d1de590..c554b47c9aef4 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -279,7 +279,7 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); - LayerTree t1; + MockLayerTree t1; auto t1_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); t1.root()->Add(t1_c1); @@ -287,12 +287,12 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { auto t1_c2 = CreateContainerLayer(CreatePictureLayer(pic2)); t1.root()->Add(t1_c2); - auto damage = DiffLayerTree(t1, LayerTree()); + auto damage = DiffLayerTree(t1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); // Add in the middle - LayerTree t2; + MockLayerTree t2; auto t2_c1 = CreateContainerLayer(CreatePictureLayer(pic1)); t2_c1->AssignOldLayer(t1_c1.get()); t2.root()->Add(t2_c1); @@ -308,7 +308,7 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { // Add in the beginning - t2 = LayerTree(); + t2 = MockLayerTree(); t2.root()->Add(CreatePictureLayer(pic3)); t2.root()->Add(t2_c1); t2.root()->Add(t2_c2); @@ -317,7 +317,7 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { // Add at the end - t2 = LayerTree(); + t2 = MockLayerTree(); t2.root()->Add(t2_c1); t2.root()->Add(t2_c2); t2.root()->Add(CreatePictureLayer(pic3)); @@ -331,14 +331,14 @@ TEST_F(ContainerLayerDiffTest, PictureInsertion) { auto pic2 = CreatePicture(SkRect::MakeLTRB(100, 0, 150, 50), 1); auto pic3 = CreatePicture(SkRect::MakeLTRB(200, 0, 250, 50), 1); - LayerTree t1; + MockLayerTree t1; t1.root()->Add(CreatePictureLayer(pic1)); t1.root()->Add(CreatePictureLayer(pic2)); - auto damage = DiffLayerTree(t1, LayerTree()); + auto damage = DiffLayerTree(t1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); - LayerTree t2; + MockLayerTree t2; t2.root()->Add(CreatePictureLayer(pic3)); t2.root()->Add(CreatePictureLayer(pic1)); t2.root()->Add(CreatePictureLayer(pic2)); @@ -346,7 +346,7 @@ TEST_F(ContainerLayerDiffTest, PictureInsertion) { damage = DiffLayerTree(t2, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - LayerTree t3; + MockLayerTree t3; t3.root()->Add(CreatePictureLayer(pic1)); t3.root()->Add(CreatePictureLayer(pic3)); t3.root()->Add(CreatePictureLayer(pic2)); @@ -354,7 +354,7 @@ TEST_F(ContainerLayerDiffTest, PictureInsertion) { damage = DiffLayerTree(t3, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - LayerTree t4; + MockLayerTree t4; t4.root()->Add(CreatePictureLayer(pic1)); t4.root()->Add(CreatePictureLayer(pic2)); t4.root()->Add(CreatePictureLayer(pic3)); @@ -372,48 +372,48 @@ TEST_F(ContainerLayerDiffTest, LayerDeletion) { auto c2 = CreateContainerLayer(std::make_shared(path2)); auto c3 = CreateContainerLayer(std::make_shared(path3)); - LayerTree t1; + MockLayerTree t1; t1.root()->Add(c1); t1.root()->Add(c2); t1.root()->Add(c3); - auto damage = DiffLayerTree(t1, LayerTree()); + auto damage = DiffLayerTree(t1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); - LayerTree t2; + MockLayerTree t2; t2.root()->Add(c2); t2.root()->Add(c3); damage = DiffLayerTree(t2, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 50)); - LayerTree t3; + MockLayerTree t3; t3.root()->Add(c1); t3.root()->Add(c3); damage = DiffLayerTree(t3, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 50)); - LayerTree t4; + MockLayerTree t4; t4.root()->Add(c1); t4.root()->Add(c2); damage = DiffLayerTree(t4, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); - LayerTree t5; + MockLayerTree t5; t5.root()->Add(c1); damage = DiffLayerTree(t5, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 250, 50)); - LayerTree t6; + MockLayerTree t6; t6.root()->Add(c2); damage = DiffLayerTree(t6, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); - LayerTree t7; + MockLayerTree t7; t7.root()->Add(c3); damage = DiffLayerTree(t7, t1); @@ -433,15 +433,15 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { auto c2 = CreateContainerLayer(std::make_shared(path2)); auto c3 = CreateContainerLayer(std::make_shared(path3)); - LayerTree t1; + MockLayerTree t1; t1.root()->Add(c1); t1.root()->Add(c2); t1.root()->Add(c3); - auto damage = DiffLayerTree(t1, LayerTree()); + auto damage = DiffLayerTree(t1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); - LayerTree t2; + MockLayerTree t2; t2.root()->Add(c1); t2.root()->Add(c2); t2.root()->Add(c3); @@ -449,7 +449,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { damage = DiffLayerTree(t2, t1); EXPECT_TRUE(damage.surface_damage.isEmpty()); - LayerTree t3; + MockLayerTree t3; t3.root()->Add(CreateContainerLayer({std::make_shared(path1a)})); t3.root()->Add(c2); t3.root()->Add(c3); @@ -457,7 +457,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { damage = DiffLayerTree(t3, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 150)); - LayerTree t4; + MockLayerTree t4; t4.root()->Add(c1); t4.root()->Add(CreateContainerLayer(std::make_shared(path2a))); t4.root()->Add(c3); @@ -465,7 +465,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { damage = DiffLayerTree(t4, t1); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); - LayerTree t5; + MockLayerTree t5; t5.root()->Add(c1); t5.root()->Add(c2); t5.root()->Add(CreateContainerLayer(std::make_shared(path3a))); diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 7f5d25e23611c..b15f08254880d 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -350,24 +350,24 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { EXPECT_EQ(paint_rect, SkIRect::MakeLTRB(-30, -30, 40, 40)); } - LayerTree l1; + MockLayerTree l1; auto filter_layer = std::make_shared(filter); auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110)); filter_layer->Add(std::make_shared(path)); l1.root()->Add(filter_layer); - auto damage = DiffLayerTree(l1, LayerTree()); + auto damage = DiffLayerTree(l1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(70, 70, 140, 140)); - LayerTree l2; + MockLayerTree l2; auto scale = std::make_shared(SkMatrix::Scale(2.0, 2.0)); scale->Add(filter_layer); l2.root()->Add(scale); - damage = DiffLayerTree(l2, LayerTree()); + damage = DiffLayerTree(l2, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(140, 140, 280, 280)); - LayerTree l3; + MockLayerTree l3; l3.root()->Add(scale); // path outside of ImageFilterLayer @@ -377,7 +377,7 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 140, 140)); // path intersecting ImageFilterLayer, should trigger ImageFilterLayer repaint - LayerTree l4; + MockLayerTree l4; l4.root()->Add(scale); auto path2 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 141, 141)); l4.root()->Add(std::make_shared(path2)); diff --git a/flow/layers/picture_layer_unittests.cc b/flow/layers/picture_layer_unittests.cc index 0fea7c5c87aac..1dc6eb4ac63c8 100644 --- a/flow/layers/picture_layer_unittests.cc +++ b/flow/layers/picture_layer_unittests.cc @@ -106,39 +106,39 @@ using PictureLayerDiffTest = DiffContextTest; TEST_F(PictureLayerDiffTest, SimplePicture) { auto picture = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); - LayerTree tree1; + MockLayerTree tree1; tree1.root()->Add(CreatePictureLayer(picture)); - auto damage = DiffLayerTree(tree1, LayerTree()); + auto damage = DiffLayerTree(tree1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); - LayerTree tree2; + MockLayerTree tree2; tree2.root()->Add(CreatePictureLayer(picture)); damage = DiffLayerTree(tree2, tree1); EXPECT_TRUE(damage.surface_damage.isEmpty()); - LayerTree tree3; + MockLayerTree tree3; damage = DiffLayerTree(tree3, tree2); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); } TEST_F(PictureLayerDiffTest, PictureCompare) { - LayerTree tree1; + MockLayerTree tree1; auto picture1 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree1.root()->Add(CreatePictureLayer(picture1)); - auto damage = DiffLayerTree(tree1, LayerTree()); + auto damage = DiffLayerTree(tree1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); - LayerTree tree2; + MockLayerTree tree2; auto picture2 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree2.root()->Add(CreatePictureLayer(picture2)); damage = DiffLayerTree(tree2, tree1); EXPECT_TRUE(damage.surface_damage.isEmpty()); - LayerTree tree3; + MockLayerTree tree3; auto picture3 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); // add offset tree3.root()->Add(CreatePictureLayer(picture3, SkPoint::Make(10, 10))); @@ -146,7 +146,7 @@ TEST_F(PictureLayerDiffTest, PictureCompare) { damage = DiffLayerTree(tree3, tree2); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); - LayerTree tree4; + MockLayerTree tree4; // different color auto picture4 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 2); tree4.root()->Add(CreatePictureLayer(picture4, SkPoint::Make(10, 10))); diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index 5ad50dd8ea0ac..8f45f48c1500f 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -237,10 +237,10 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { std::make_shared(SkMatrix::Translate(10, 10)); transform1->Add(m1); - LayerTree t1; + MockLayerTree t1; t1.root()->Add(transform1); - auto damage = DiffLayerTree(t1, LayerTree()); + auto damage = DiffLayerTree(t1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); auto transform2 = @@ -248,7 +248,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { transform2->Add(m1); transform2->AssignOldLayer(transform1.get()); - LayerTree t2; + MockLayerTree t2; t2.root()->Add(transform2); damage = DiffLayerTree(t2, t1); @@ -259,7 +259,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { transform3->Add(m1); transform3->AssignOldLayer(transform2.get()); - LayerTree t3; + MockLayerTree t3; t3.root()->Add(transform3); damage = DiffLayerTree(t3, t2); @@ -289,10 +289,10 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { transform1_3->Add(m3); transform1->Add(transform1_3); - LayerTree l1; + MockLayerTree l1; l1.root()->Add(transform1); - auto damage = DiffLayerTree(l1, LayerTree()); + auto damage = DiffLayerTree(l1, MockLayerTree()); EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); auto transform2 = std::make_shared(SkMatrix::Scale(2.0, 2.0)); @@ -316,7 +316,7 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { transform2_3->AssignOldLayer(transform1_3.get()); transform2->Add(transform2_3); - LayerTree l2; + MockLayerTree l2; l2.root()->Add(transform2); damage = DiffLayerTree(l2, l1); diff --git a/flow/testing/diff_context_test.cc b/flow/testing/diff_context_test.cc index 8e08b7de0743e..f167d95480b6c 100644 --- a/flow/testing/diff_context_test.cc +++ b/flow/testing/diff_context_test.cc @@ -10,8 +10,8 @@ DiffContextTest::DiffContextTest() GetCurrentTaskRunner(), fml::TimeDelta::FromSeconds(0))) {} -Damage DiffContextTest::DiffLayerTree(LayerTree& layer_tree, - const LayerTree& old_layer_tree, +Damage DiffContextTest::DiffLayerTree(MockLayerTree& layer_tree, + const MockLayerTree& old_layer_tree, const SkIRect& additional_damage) { FML_CHECK(layer_tree.size() == old_layer_tree.size()); diff --git a/flow/testing/diff_context_test.h b/flow/testing/diff_context_test.h index a8b69e95d42ae..3d1cbab1d31c9 100644 --- a/flow/testing/diff_context_test.h +++ b/flow/testing/diff_context_test.h @@ -9,9 +9,9 @@ namespace testing { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT -class LayerTree { +class MockLayerTree { public: - explicit LayerTree(SkISize size = SkISize::Make(1000, 1000)) + explicit MockLayerTree(SkISize size = SkISize::Make(1000, 1000)) : root_(std::make_shared()), size_(size) {} ContainerLayer* root() { return root_.get(); } @@ -32,8 +32,8 @@ class DiffContextTest : public ThreadTest { public: DiffContextTest(); - Damage DiffLayerTree(LayerTree& layer_tree, - const LayerTree& old_layer_tree, + Damage DiffLayerTree(MockLayerTree& layer_tree, + const MockLayerTree& old_layer_tree, const SkIRect& additional_damage = SkIRect::MakeEmpty()); // Create picture consisting of filled rect with given color; Being able From edae4578fb55547836d78726445327a1e474193e Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Fri, 11 Dec 2020 02:29:21 +0100 Subject: [PATCH 33/43] Put FLUTTER_ENABLE_DIFF_CONTEXT in separate config so that flow dependencies can properly inherit it. --- flow/BUILD.gn | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/flow/BUILD.gn b/flow/BUILD.gn index f9c47439f3aeb..8bf1c6eb4cadd 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -6,6 +6,12 @@ import("//build/fuchsia/sdk.gni") import("//flutter/common/config.gni") import("//flutter/testing/testing.gni") +config("config") { + if (is_debug) { + defines = [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] + } +} + source_set("flow") { sources = [ "compositor_context.cc", @@ -70,7 +76,10 @@ source_set("flow") { "surface_frame.h", ] - public_configs = [ "//flutter:config" ] + public_configs = [ + "//flutter:config", + ":config", + ] deps = [ "//flutter/common", @@ -96,13 +105,6 @@ source_set("flow") { "$fuchsia_sdk_root/pkg:scenic_cpp", ] } - - if (!defined(defines)) { - defines = [] - } - if (is_debug) { - defines += [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] - } } if (enable_unittests) { @@ -138,13 +140,6 @@ if (enable_unittests) { ":flow", "//flutter/common/graphics", ] - - if (!defined(defines)) { - defines = [] - } - if (is_debug) { - defines += [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] - } } executable("flow_unittests") { @@ -204,9 +199,6 @@ if (enable_unittests) { # Required for M_PI and others. defines += [ "_USE_MATH_DEFINES" ] } - if (is_debug) { - defines += [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] - } if (is_fuchsia && flutter_enable_legacy_fuchsia_embedder) { sources += [ "layers/fuchsia_layer_unittests.cc" ] From 67ab7ce593cb5ae8f46c4c5543415bfab986558a Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 14 Dec 2020 16:12:00 +0100 Subject: [PATCH 34/43] surface_damage -> frame_damage also mention equivalent terms from EGL_KHR_partial_update. --- flow/diff_context.cc | 4 +- flow/diff_context.h | 10 +++-- flow/diff_context_unittests.cc | 2 +- .../layers/backdrop_filter_layer_unittests.cc | 10 ++--- flow/layers/container_layer_unittests.cc | 40 +++++++++---------- flow/layers/image_filter_layer_unittests.cc | 8 ++-- flow/layers/picture_layer_unittests.cc | 14 +++---- flow/layers/transform_layer_unittests.cc | 12 +++--- 8 files changed, 51 insertions(+), 49 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index a7ed44b691484..9cdab6d7eec3c 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -58,11 +58,11 @@ Damage DiffContext::ComputeDamage( Damage res; framebuffer.roundOut(&res.buffer_damage); - net.roundOut(&res.surface_damage); + net.roundOut(&res.frame_damage); SkIRect frame_clip = SkIRect::MakeSize(frame_size_); res.buffer_damage.intersect(frame_clip); - res.surface_damage.intersect(frame_clip); + res.frame_damage.intersect(frame_clip); return res; } diff --git a/flow/diff_context.h b/flow/diff_context.h index f8c7fb8626869..53425b7b24306 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -18,13 +18,15 @@ class Layer; struct Damage { // This is the damage between current and previous frame; // If embedder supports partial update, this is the region that needs to be - // swapped. - SkIRect surface_damage; + // repainted. + // Corresponds to "surface damage" from EGL_KHR_partial_update. + SkIRect frame_damage; - // Reflects actual change to target framebuffer; This is surface_damage + + // Reflects actual change to target framebuffer; This is frame_damage + // damage previously acumulated for target framebuffer. // All drawing will be clipped to this region. Knowing the affected area // upfront may be useful for tile based GPUs. + // Corresponds to "buffer damage" from EGL_KHR_partial_update. SkIRect buffer_damage; }; @@ -104,7 +106,7 @@ class DiffContext { // Computes final damage // - // additional_damage is the previously accumulated surface_damage for + // additional_damage is the previously accumulated frame_damage for // current framebuffer Damage ComputeDamage(const SkIRect& additional_damage) const; diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index 3ecf5beb875f8..e3b4f5cd9cf38 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -31,7 +31,7 @@ TEST_F(DiffContextTest, DieIfOldLayerTreeWasNeverDiffed) { // Now we can diff t2 and t1 auto damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeEmpty()); } #endif // FLUTTER_ENABLE_DIFF_CONTEXT diff --git a/flow/layers/backdrop_filter_layer_unittests.cc b/flow/layers/backdrop_filter_layer_unittests.cc index f788be1dd2501..2538b7c8d82e9 100644 --- a/flow/layers/backdrop_filter_layer_unittests.cc +++ b/flow/layers/backdrop_filter_layer_unittests.cc @@ -237,7 +237,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { // no clip, effect over entire surface auto damage = DiffLayerTree(l1, MockLayerTree(SkISize::Make(100, 100))); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeWH(100, 100)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeWH(100, 100)); MockLayerTree l2(SkISize::Make(100, 100)); @@ -247,7 +247,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { l2.root()->Add(clip); damage = DiffLayerTree(l2, MockLayerTree(SkISize::Make(100, 100))); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); MockLayerTree l3; auto scale = std::make_shared(SkMatrix::Scale(2.0, 2.0)); @@ -255,7 +255,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { l3.root()->Add(scale); damage = DiffLayerTree(l3, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 180, 180)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 180, 180)); MockLayerTree l4; l4.root()->Add(scale); @@ -264,7 +264,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { auto path1 = SkPath().addRect(SkRect::MakeLTRB(180, 180, 190, 190)); l4.root()->Add(std::make_shared(path1)); damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(180, 180, 190, 190)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(180, 180, 190, 190)); MockLayerTree l5; l5.root()->Add(scale); @@ -273,7 +273,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { auto path2 = SkPath().addRect(SkRect::MakeLTRB(179, 179, 189, 189)); l5.root()->Add(std::make_shared(path2)); damage = DiffLayerTree(l5, l4); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 190, 190)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 190, 190)); } #endif diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index c554b47c9aef4..53af6275d17ae 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -288,7 +288,7 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { t1.root()->Add(t1_c2); auto damage = DiffLayerTree(t1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); // Add in the middle @@ -304,7 +304,7 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { t2.root()->Add(t2_c2); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); // Add in the beginning @@ -313,7 +313,7 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { t2.root()->Add(t2_c1); t2.root()->Add(t2_c2); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); // Add at the end @@ -322,7 +322,7 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { t2.root()->Add(t2_c2); t2.root()->Add(CreatePictureLayer(pic3)); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); } // Insert picture layer amongst other picture layers @@ -336,7 +336,7 @@ TEST_F(ContainerLayerDiffTest, PictureInsertion) { t1.root()->Add(CreatePictureLayer(pic2)); auto damage = DiffLayerTree(t1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); MockLayerTree t2; t2.root()->Add(CreatePictureLayer(pic3)); @@ -344,7 +344,7 @@ TEST_F(ContainerLayerDiffTest, PictureInsertion) { t2.root()->Add(CreatePictureLayer(pic2)); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); MockLayerTree t3; t3.root()->Add(CreatePictureLayer(pic1)); @@ -352,7 +352,7 @@ TEST_F(ContainerLayerDiffTest, PictureInsertion) { t3.root()->Add(CreatePictureLayer(pic2)); damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); MockLayerTree t4; t4.root()->Add(CreatePictureLayer(pic1)); @@ -360,7 +360,7 @@ TEST_F(ContainerLayerDiffTest, PictureInsertion) { t4.root()->Add(CreatePictureLayer(pic3)); damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); } TEST_F(ContainerLayerDiffTest, LayerDeletion) { @@ -378,46 +378,46 @@ TEST_F(ContainerLayerDiffTest, LayerDeletion) { t1.root()->Add(c3); auto damage = DiffLayerTree(t1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); MockLayerTree t2; t2.root()->Add(c2); t2.root()->Add(c3); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 50, 50)); MockLayerTree t3; t3.root()->Add(c1); t3.root()->Add(c3); damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(100, 0, 150, 50)); MockLayerTree t4; t4.root()->Add(c1); t4.root()->Add(c2); damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 50)); MockLayerTree t5; t5.root()->Add(c1); damage = DiffLayerTree(t5, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(100, 0, 250, 50)); MockLayerTree t6; t6.root()->Add(c2); damage = DiffLayerTree(t6, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); MockLayerTree t7; t7.root()->Add(c3); damage = DiffLayerTree(t7, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 150, 50)); } TEST_F(ContainerLayerDiffTest, ReplaceLayer) { @@ -439,7 +439,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { t1.root()->Add(c3); auto damage = DiffLayerTree(t1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 250, 50)); MockLayerTree t2; t2.root()->Add(c1); @@ -447,7 +447,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { t2.root()->Add(c3); damage = DiffLayerTree(t2, t1); - EXPECT_TRUE(damage.surface_damage.isEmpty()); + EXPECT_TRUE(damage.frame_damage.isEmpty()); MockLayerTree t3; t3.root()->Add(CreateContainerLayer({std::make_shared(path1a)})); @@ -455,7 +455,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { t3.root()->Add(c3); damage = DiffLayerTree(t3, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(0, 0, 50, 150)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 50, 150)); MockLayerTree t4; t4.root()->Add(c1); @@ -463,7 +463,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { t4.root()->Add(c3); damage = DiffLayerTree(t4, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(100, 0, 150, 150)); MockLayerTree t5; t5.root()->Add(c1); @@ -471,7 +471,7 @@ TEST_F(ContainerLayerDiffTest, ReplaceLayer) { t5.root()->Add(CreateContainerLayer(std::make_shared(path3a))); damage = DiffLayerTree(t5, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 0, 250, 150)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 0, 250, 150)); } #endif diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index b15f08254880d..9fd48b851eff4 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -357,7 +357,7 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { l1.root()->Add(filter_layer); auto damage = DiffLayerTree(l1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(70, 70, 140, 140)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(70, 70, 140, 140)); MockLayerTree l2; auto scale = std::make_shared(SkMatrix::Scale(2.0, 2.0)); @@ -365,7 +365,7 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { l2.root()->Add(scale); damage = DiffLayerTree(l2, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(140, 140, 280, 280)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(140, 140, 280, 280)); MockLayerTree l3; l3.root()->Add(scale); @@ -374,7 +374,7 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { auto path1 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 140, 140)); l3.root()->Add(std::make_shared(path1)); damage = DiffLayerTree(l3, l2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 140, 140)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(130, 130, 140, 140)); // path intersecting ImageFilterLayer, should trigger ImageFilterLayer repaint MockLayerTree l4; @@ -382,7 +382,7 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { auto path2 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 141, 141)); l4.root()->Add(std::make_shared(path2)); damage = DiffLayerTree(l4, l3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(130, 130, 280, 280)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(130, 130, 280, 280)); } #endif diff --git a/flow/layers/picture_layer_unittests.cc b/flow/layers/picture_layer_unittests.cc index 1dc6eb4ac63c8..f3d9ceddba198 100644 --- a/flow/layers/picture_layer_unittests.cc +++ b/flow/layers/picture_layer_unittests.cc @@ -110,17 +110,17 @@ TEST_F(PictureLayerDiffTest, SimplePicture) { tree1.root()->Add(CreatePictureLayer(picture)); auto damage = DiffLayerTree(tree1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); MockLayerTree tree2; tree2.root()->Add(CreatePictureLayer(picture)); damage = DiffLayerTree(tree2, tree1); - EXPECT_TRUE(damage.surface_damage.isEmpty()); + EXPECT_TRUE(damage.frame_damage.isEmpty()); MockLayerTree tree3; damage = DiffLayerTree(tree3, tree2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); } TEST_F(PictureLayerDiffTest, PictureCompare) { @@ -129,14 +129,14 @@ TEST_F(PictureLayerDiffTest, PictureCompare) { tree1.root()->Add(CreatePictureLayer(picture1)); auto damage = DiffLayerTree(tree1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); MockLayerTree tree2; auto picture2 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree2.root()->Add(CreatePictureLayer(picture2)); damage = DiffLayerTree(tree2, tree1); - EXPECT_TRUE(damage.surface_damage.isEmpty()); + EXPECT_TRUE(damage.frame_damage.isEmpty()); MockLayerTree tree3; auto picture3 = CreatePicture(SkRect::MakeLTRB(10, 10, 60, 60), 1); @@ -144,7 +144,7 @@ TEST_F(PictureLayerDiffTest, PictureCompare) { tree3.root()->Add(CreatePictureLayer(picture3, SkPoint::Make(10, 10))); damage = DiffLayerTree(tree3, tree2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); MockLayerTree tree4; // different color @@ -152,7 +152,7 @@ TEST_F(PictureLayerDiffTest, PictureCompare) { tree4.root()->Add(CreatePictureLayer(picture4, SkPoint::Make(10, 10))); damage = DiffLayerTree(tree4, tree3); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 70, 70)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(20, 20, 70, 70)); } #endif diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index 8f45f48c1500f..969fa117eb994 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -241,7 +241,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { t1.root()->Add(transform1); auto damage = DiffLayerTree(t1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); auto transform2 = std::make_shared(SkMatrix::Translate(20, 20)); @@ -252,7 +252,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { t2.root()->Add(transform2); damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 70, 70)); auto transform3 = std::make_shared(SkMatrix::Translate(20, 20)); @@ -263,7 +263,7 @@ TEST_F(TransformLayerLayerDiffTest, Transform) { t3.root()->Add(transform3); damage = DiffLayerTree(t3, t2); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeEmpty()); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeEmpty()); } TEST_F(TransformLayerLayerDiffTest, TransformNested) { @@ -293,7 +293,7 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { l1.root()->Add(transform1); auto damage = DiffLayerTree(l1, MockLayerTree()); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); auto transform2 = std::make_shared(SkMatrix::Scale(2.0, 2.0)); @@ -323,14 +323,14 @@ TEST_F(TransformLayerLayerDiffTest, TransformNested) { // transform2 has not transform1 assigned as old layer, so it should be // invalidated completely - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(20, 20, 500, 500)); // now diff the tree properly, the only difference being transform2_2 and // transform_2_1 transform2->AssignOldLayer(transform1.get()); damage = DiffLayerTree(l2, l1); - EXPECT_EQ(damage.surface_damage, SkIRect::MakeLTRB(200, 200, 300, 302)); + EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 200, 300, 302)); } #endif From 33064adcfa884fb23836e159a1b02b1a603bf048 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 14 Dec 2020 16:38:52 +0100 Subject: [PATCH 35/43] Rename variables --- flow/diff_context.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 9cdab6d7eec3c..d3a037d8136f5 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -43,22 +43,22 @@ void DiffContext::PushTransform(const SkMatrix& transform) { Damage DiffContext::ComputeDamage( const SkIRect& accumulated_buffer_damage) const { - SkRect framebuffer = SkRect::Make(accumulated_buffer_damage); - framebuffer.join(damage_); - SkRect net(damage_); + SkRect buffer_damage = SkRect::Make(accumulated_buffer_damage); + buffer_damage.join(damage_); + SkRect frame_damage(damage_); for (const auto& r : readbacks_) { - if (r.rect.intersects(net)) { - net.join(r.rect); + if (r.rect.intersects(frame_damage)) { + frame_damage.join(r.rect); } - if (r.rect.intersects(framebuffer)) { - framebuffer.join(r.rect); + if (r.rect.intersects(buffer_damage)) { + buffer_damage.join(r.rect); } } Damage res; - framebuffer.roundOut(&res.buffer_damage); - net.roundOut(&res.frame_damage); + buffer_damage.roundOut(&res.buffer_damage); + frame_damage.roundOut(&res.frame_damage); SkIRect frame_clip = SkIRect::MakeSize(frame_size_); res.buffer_damage.intersect(frame_clip); From 48e345075ec16e6859e9a643ff91ebb6f43310f1 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 14 Dec 2020 23:42:31 +0100 Subject: [PATCH 36/43] Get old paint region of correct layer --- flow/layers/container_layer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 64763a985207a..1be8b47627dbc 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -78,7 +78,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, i < new_children_top ? i : prev_layers.size() - (layers_.size() - i); auto layer = layers_[i]; auto prev_layer = prev_layers[i_prev]; - auto paint_region = context->GetOldLayerPaintRegion(old_layer); + auto paint_region = context->GetOldLayerPaintRegion(prev_layer.get()); if (layer == prev_layer && !paint_region.has_readback()) { // for retained layers, stop processing the subtree and add existing // region; We know current subtree is not dirty (every ancestor up to From aaf0b754f8aa4d4ff012c85db284af2cfef992d2 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 14 Dec 2020 23:48:19 +0100 Subject: [PATCH 37/43] Missing paint region of retained layer is a valid state If this layer was within zero sized clip rect, the Diff was never called on it. --- flow/diff_context.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index d3a037d8136f5..d510d0c13790a 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -95,8 +95,9 @@ void DiffContext::AddExistingPaintRegion(const PaintRegion& region) { // Adding paint region for retained layer implies that current subtree is not // dirty, so we know, for example, that the inherited transforms must match FML_DCHECK(!IsSubtreeDirty()); - FML_DCHECK(region.is_valid()); - rects_->insert(rects_->end(), region.begin(), region.end()); + if (region.is_valid()) { + rects_->insert(rects_->end(), region.begin(), region.end()); + } } void DiffContext::AddReadbackRegion(const SkRect& rect) { @@ -138,7 +139,8 @@ PaintRegion DiffContext::GetOldLayerPaintRegion(const Layer* layer) const { if (i != last_frame_paint_region_map_.end()) { return i->second; } else { - FML_CHECK(false) << "Old layer doesn't have paint region"; + // This is valid when Layer::PreservePaintRegion is called for retained + // layer with zero sized parent clip (these layers are not diffed) return PaintRegion(); } } From b1d259331e90c994f114d21b0bbb6f0565eabb71 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 14 Dec 2020 20:52:59 +0100 Subject: [PATCH 38/43] Move FLUTTER_ENABLE_DIFF_CONTEXT to //flutter:config --- BUILD.gn | 4 ++++ flow/BUILD.gn | 11 +---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index c174f50169e59..2f2cd3826efa8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -28,6 +28,10 @@ config("config") { if (is_fuchsia && flutter_enable_legacy_fuchsia_embedder) { defines = [ "LEGACY_FUCHSIA_EMBEDDER" ] } + + if (is_debug) { + defines = [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] + } } config("export_dynamic_symbols") { diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 8bf1c6eb4cadd..f81955c3d9809 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -6,12 +6,6 @@ import("//build/fuchsia/sdk.gni") import("//flutter/common/config.gni") import("//flutter/testing/testing.gni") -config("config") { - if (is_debug) { - defines = [ "FLUTTER_ENABLE_DIFF_CONTEXT" ] - } -} - source_set("flow") { sources = [ "compositor_context.cc", @@ -76,10 +70,7 @@ source_set("flow") { "surface_frame.h", ] - public_configs = [ - "//flutter:config", - ":config", - ] + public_configs = [ "//flutter:config" ] deps = [ "//flutter/common", From 22f35ff8f0499c5b9ef2f031789035b49ae2f2b1 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 13 Jan 2021 23:53:53 +0100 Subject: [PATCH 39/43] Remove DieIfOldLayerTreeWasNeverDiffed test --- ci/licenses_golden/licenses_flutter | 1 - flow/BUILD.gn | 1 - flow/diff_context_unittests.cc | 40 ----------------------------- 3 files changed, 42 deletions(-) delete mode 100644 flow/diff_context_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 5a0566ba6aeb6..05718642b88d4 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -36,7 +36,6 @@ FILE: ../../../flutter/flow/compositor_context.cc FILE: ../../../flutter/flow/compositor_context.h FILE: ../../../flutter/flow/diff_context.cc FILE: ../../../flutter/flow/diff_context.h -FILE: ../../../flutter/flow/diff_context_unittests.cc FILE: ../../../flutter/flow/embedded_view_params_unittests.cc FILE: ../../../flutter/flow/embedded_views.cc FILE: ../../../flutter/flow/embedded_views.h diff --git a/flow/BUILD.gn b/flow/BUILD.gn index f81955c3d9809..ebb8873d26e45 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -137,7 +137,6 @@ if (enable_unittests) { testonly = true sources = [ - "diff_context_unittests.cc", "embedded_view_params_unittests.cc", "flow_run_all_unittests.cc", "flow_test_utils.cc", diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc deleted file mode 100644 index e3b4f5cd9cf38..0000000000000 --- a/flow/diff_context_unittests.cc +++ /dev/null @@ -1,40 +0,0 @@ -#include "diff_context.h" -#include "flutter/flow/testing/diff_context_test.h" -#include "flutter/flow/testing/mock_layer.h" -#include "gtest/gtest.h" - -namespace flutter { -namespace testing { - -#ifdef FLUTTER_ENABLE_DIFF_CONTEXT - -TEST_F(DiffContextTest, DieIfOldLayerTreeWasNeverDiffed) { - auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50)); - auto c1 = CreateContainerLayer(std::make_shared(path1)); - - MockLayerTree t1; - t1.root()->Add(c1); - - MockLayerTree t2; - t2.root()->Add(c1); - - // t1 is used as old_layer_tree, but it was never used used during diffing as - // current layer tree - // i.e. - // DiffLayerTree(t1, LayerTree()) - // That means it contains layers for which the paint regions are not known - EXPECT_DEATH_IF_SUPPORTED(DiffLayerTree(t2, t1), - "Old layer doesn't have paint region"); - - // Diff t1 with empty layer tree to determine paint regions - DiffLayerTree(t1, MockLayerTree()); - - // Now we can diff t2 and t1 - auto damage = DiffLayerTree(t2, t1); - EXPECT_EQ(damage.frame_damage, SkIRect::MakeEmpty()); -} - -#endif // FLUTTER_ENABLE_DIFF_CONTEXT - -} // namespace testing -} // namespace flutter From 86a5e4d90b696541bcbe357869c5a8c4e8529ccd Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sun, 14 Feb 2021 16:21:55 +0100 Subject: [PATCH 40/43] Fix include and blur constructor --- flow/layers/backdrop_filter_layer_unittests.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flow/layers/backdrop_filter_layer_unittests.cc b/flow/layers/backdrop_filter_layer_unittests.cc index 2538b7c8d82e9..53cb5d151c809 100644 --- a/flow/layers/backdrop_filter_layer_unittests.cc +++ b/flow/layers/backdrop_filter_layer_unittests.cc @@ -12,7 +12,6 @@ #include "flutter/fml/macros.h" #include "flutter/testing/mock_canvas.h" #include "third_party/skia/include/core/SkImageFilter.h" -#include "third_party/skia/include/effects/SkBlurImageFilter.h" #include "third_party/skia/include/effects/SkImageFilters.h" namespace flutter { @@ -222,8 +221,7 @@ TEST_F(BackdropFilterLayerTest, Readback) { using BackdropLayerDiffTest = DiffContextTest; TEST_F(BackdropLayerDiffTest, BackdropLayer) { - auto filter = SkBlurImageFilter::Make(10, 10, nullptr, nullptr, - SkBlurImageFilter::kClamp_TileMode); + auto filter = SkImageFilters::Blur(10, 10, SkTileMode::kClamp, nullptr); { // tests later assume 30px readback area, fail early if that's not the case From b69e1c4b998a4ba6b2f3eebf5b8aad284d2b4fd6 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sun, 14 Feb 2021 16:52:11 +0100 Subject: [PATCH 41/43] Comment fixes --- flow/diff_context.h | 13 ++++++++----- flow/layers/layer.h | 8 ++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/flow/diff_context.h b/flow/diff_context.h index 53425b7b24306..5bbc667a4dbc3 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -15,6 +15,8 @@ namespace flutter { class Layer; +// Represents area that needs to be updated in front buffer (frame_damage) and +// area that is going to be painted to in back buffer (buffer_damage). struct Damage { // This is the damage between current and previous frame; // If embedder supports partial update, this is the region that needs to be @@ -30,6 +32,7 @@ struct Damage { SkIRect buffer_damage; }; +// Layer Unique Id to PaintRegion using PaintRegionMap = std::map; // Tracks state during tree diffing process and computes resulting damage @@ -68,25 +71,25 @@ class DiffContext { bool PushCullRect(const SkRect& clip); // Returns transform matrix for current subtree - SkMatrix GetTransform() const { return state_.transform; } + const SkMatrix& GetTransform() const { return state_.transform; } // Return cull rect for current subtree (in local coordinates) - SkRect GetCullRect() const { return state_.cull_rect; } + const SkRect& GetCullRect() const { return state_.cull_rect; } // Sets the dirty flag on current subtree; // // previous_paint_region, which should represent region of previous subtree - // at this level will be added to damage area + // at this level will be added to damage area. // // Each paint region added to dirty subtree (through AddPaintRegion) is also - // added to damage + // added to damage. void MarkSubtreeDirty( const PaintRegion& previous_paint_region = PaintRegion()); bool IsSubtreeDirty() const { return state_.dirty; } // Add layer bounds to current paint region; rect is in "local" (layer) - // coordinates + // coordinates. void AddLayerBounds(const SkRect& rect); // Add entire paint region of retained layer for current subtree. This can diff --git a/flow/layers/layer.h b/flow/layers/layer.h index d22a4901b8afd..7cdf06d5c17fa 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -91,10 +91,14 @@ class Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - virtual bool CanDiff(DiffContext* context, const Layer* layer) const { - return original_layer_id_ == layer->original_layer_id_; + // Used to establish link between old layer and new layer that replaces it. + // If this method returns true, it is assumed that this layer replaces the old + // layer in tree and is able to diff with it. + virtual bool CanDiff(DiffContext* context, const Layer* old_layer) const { + return original_layer_id_ == old_layer->original_layer_id_; } + // Performs diff with given layer virtual void Diff(DiffContext* context, const Layer* old_layer) {} // Used when diffing retained layer; In case the layer is identical, it From 23b7318e0832843a07881c23e980d838c99916a4 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sun, 14 Feb 2021 17:00:50 +0100 Subject: [PATCH 42/43] Rename CanDiff to IsReplacing --- flow/layers/container_layer.cc | 4 ++-- flow/layers/layer.h | 2 +- flow/layers/performance_overlay_layer.h | 2 +- flow/layers/picture_layer.cc | 4 ++-- flow/layers/picture_layer.h | 2 +- flow/layers/texture_layer.h | 2 +- flow/testing/mock_layer.cc | 2 +- flow/testing/mock_layer.h | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 1be8b47627dbc..35aef14590140 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -48,7 +48,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, while ((old_children_top <= old_children_bottom) && (new_children_top <= new_children_bottom)) { - if (!layers_[new_children_top]->CanDiff( + if (!layers_[new_children_top]->IsReplacing( context, prev_layers[old_children_top].get())) { break; } @@ -58,7 +58,7 @@ void ContainerLayer::DiffChildren(DiffContext* context, while ((old_children_top <= old_children_bottom) && (new_children_top <= new_children_bottom)) { - if (!layers_[new_children_bottom]->CanDiff( + if (!layers_[new_children_bottom]->IsReplacing( context, prev_layers[old_children_bottom].get())) { break; } diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 7cdf06d5c17fa..fa2674105cb8f 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -94,7 +94,7 @@ class Layer { // Used to establish link between old layer and new layer that replaces it. // If this method returns true, it is assumed that this layer replaces the old // layer in tree and is able to diff with it. - virtual bool CanDiff(DiffContext* context, const Layer* old_layer) const { + virtual bool IsReplacing(DiffContext* context, const Layer* old_layer) const { return original_layer_id_ == old_layer->original_layer_id_; } diff --git a/flow/layers/performance_overlay_layer.h b/flow/layers/performance_overlay_layer.h index d4a27c3270be8..91b90244e3f61 100644 --- a/flow/layers/performance_overlay_layer.h +++ b/flow/layers/performance_overlay_layer.h @@ -28,7 +28,7 @@ class PerformanceOverlayLayer : public Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - bool CanDiff(DiffContext* context, const Layer* layer) const override { + bool IsReplacing(DiffContext* context, const Layer* layer) const override { return layer->as_performance_overlay_layer() != nullptr; } diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 55110d0a024d1..fcb95933a8b0a 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -20,7 +20,7 @@ PictureLayer::PictureLayer(const SkPoint& offset, #ifdef FLUTTER_ENABLE_DIFF_CONTEXT -bool PictureLayer::CanDiff(DiffContext* context, const Layer* layer) const { +bool PictureLayer::IsReplacing(DiffContext* context, const Layer* layer) const { // Only return true for identical pictures; This way // ContainerLayer::DiffChildren can detect when a picture layer got inserted // between other picture layers @@ -36,7 +36,7 @@ void PictureLayer::Diff(DiffContext* context, const Layer* old_layer) { FML_DCHECK(old_layer); auto prev = old_layer->as_picture_layer(); DiffContext::Statistics dummy_statistics; - // CanDiff has already determined that the picture is same + // IsReplacing has already determined that the picture is same FML_DCHECK(prev->offset_ == offset_ && Compare(dummy_statistics, this, prev)); #endif diff --git a/flow/layers/picture_layer.h b/flow/layers/picture_layer.h index 5a17618629f9f..53fed5706bb0e 100644 --- a/flow/layers/picture_layer.h +++ b/flow/layers/picture_layer.h @@ -24,7 +24,7 @@ class PictureLayer : public Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - bool CanDiff(DiffContext* context, const Layer* layer) const override; + bool IsReplacing(DiffContext* context, const Layer* layer) const override; void Diff(DiffContext* context, const Layer* old_layer) override; diff --git a/flow/layers/texture_layer.h b/flow/layers/texture_layer.h index 47a71d2a64332..d784ecd79ed48 100644 --- a/flow/layers/texture_layer.h +++ b/flow/layers/texture_layer.h @@ -22,7 +22,7 @@ class TextureLayer : public Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - bool CanDiff(DiffContext* context, const Layer* layer) const override { + bool IsReplacing(DiffContext* context, const Layer* layer) const override { return layer->as_texture_layer() != nullptr; } diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 2d710236f83c8..c70b86ee4a6c6 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -20,7 +20,7 @@ MockLayer::MockLayer(SkPath path, #ifdef FLUTTER_ENABLE_DIFF_CONTEXT -bool MockLayer::CanDiff(DiffContext* context, const Layer* layer) const { +bool MockLayer::IsReplacing(DiffContext* context, const Layer* layer) const { // Similar to PictureLayer, only return true for identical mock layers; // That way ContainerLayer::DiffChildren can properly detect mock layer // insertion diff --git a/flow/testing/mock_layer.h b/flow/testing/mock_layer.h index 87e135fc7c0a0..ed123f9640e3f 100644 --- a/flow/testing/mock_layer.h +++ b/flow/testing/mock_layer.h @@ -32,7 +32,7 @@ class MockLayer : public Layer { #ifdef FLUTTER_ENABLE_DIFF_CONTEXT - bool CanDiff(DiffContext* context, const Layer* layer) const override; + bool IsReplacing(DiffContext* context, const Layer* layer) const override; void Diff(DiffContext* context, const Layer* old_layer) override; const MockLayer* as_mock_layer() const override { return this; } From 72d0b75167f771af74eeb8f70cdf563a581cbb4a Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sun, 14 Feb 2021 18:19:12 +0100 Subject: [PATCH 43/43] Apply filter in screen space Use SkImageFilter::makeWithLocalMatrix to convert the filter to screen space and then apply the filter in screen space. --- flow/diff_context.cc | 15 +++++++-------- flow/diff_context.h | 10 ++++++++-- flow/layers/backdrop_filter_layer.cc | 11 ++++++++--- flow/layers/image_filter_layer.cc | 13 +++++++------ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/flow/diff_context.cc b/flow/diff_context.cc index d510d0c13790a..b0e9892ce6e0d 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -48,11 +48,12 @@ Damage DiffContext::ComputeDamage( SkRect frame_damage(damage_); for (const auto& r : readbacks_) { - if (r.rect.intersects(frame_damage)) { - frame_damage.join(r.rect); + SkRect rect = SkRect::Make(r.rect); + if (rect.intersects(frame_damage)) { + frame_damage.join(rect); } - if (r.rect.intersects(buffer_damage)) { - buffer_damage.join(r.rect); + if (rect.intersects(buffer_damage)) { + buffer_damage.join(rect); } } @@ -100,11 +101,9 @@ void DiffContext::AddExistingPaintRegion(const PaintRegion& region) { } } -void DiffContext::AddReadbackRegion(const SkRect& rect) { - SkRect r(rect); - state_.transform.mapRect(&r); +void DiffContext::AddReadbackRegion(const SkIRect& rect) { Readback readback; - readback.rect = r; + readback.rect = rect; readback.position = rects_->size(); // Push empty rect as a placeholder for position in current subtree rects_->push_back(SkRect::MakeEmpty()); diff --git a/flow/diff_context.h b/flow/diff_context.h index 5bbc667a4dbc3..14a5b72092f05 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -99,7 +99,9 @@ class DiffContext { // The idea of readback region is that if any part of the readback region // needs to be repainted, then the whole readback region must be repainted; - void AddReadbackRegion(const SkRect& rect); + // + // Readback rect is in screen coordinates. + void AddReadbackRegion(const SkIRect& rect); // Returns the paint region for current subtree; Each rect in paint region is // in screen coordinates; Once a layer accumulates the paint regions of its @@ -187,8 +189,12 @@ class DiffContext { void AddDamage(const SkRect& rect); struct Readback { + // Index of rects_ entry that this readback belongs to. Used to + // determine if subtree has any readback size_t position; - SkRect rect; + + // readback area, in screen coordinates + SkIRect rect; }; std::vector readbacks_; diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 0ac49b5c958cc..9dfd84105b69e 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -25,11 +25,16 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { auto paint_bounds = context->GetCullRect(); context->AddLayerBounds(paint_bounds); + // convert paint bounds and filter to screen coordinates + context->GetTransform().mapRect(&paint_bounds); auto input_filter_bounds = paint_bounds.roundOut(); + auto filter = filter_->makeWithLocalMatrix(context->GetTransform()); + auto filter_bounds = // in screen coordinates - filter_->filterBounds(input_filter_bounds, SkMatrix::I(), - SkImageFilter::kReverse_MapDirection); - context->AddReadbackRegion(SkRect::Make(filter_bounds)); + filter->filterBounds(input_filter_bounds, SkMatrix::I(), + SkImageFilter::kReverse_MapDirection); + + context->AddReadbackRegion(filter_bounds); DiffChildren(context, prev); diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 72808e9591f34..a252d457cbf80 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -27,20 +27,21 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { SkMatrix inverse; if (context->GetTransform().invert(&inverse)) { - auto paint_bounds = - inverse.mapRect(context->CurrentSubtreeRegion().ComputeBounds()); + auto screen_bounds = context->CurrentSubtreeRegion().ComputeBounds(); + + auto filter = filter_->makeWithLocalMatrix(context->GetTransform()); auto filter_bounds = - filter_->filterBounds(paint_bounds.roundOut(), SkMatrix::I(), - SkImageFilter::kForward_MapDirection); - context->AddLayerBounds(SkRect::Make(filter_bounds)); + filter->filterBounds(screen_bounds.roundOut(), SkMatrix::I(), + SkImageFilter::kForward_MapDirection); + context->AddLayerBounds(inverse.mapRect(SkRect::Make(filter_bounds))); // Technically, there is no readback with ImageFilterLayer, but we can't // clip the filter (because it may sample out of clip rect) so if any part // of layer is repainted the whole layer needs to be. // TODO(knopp) There is a room for optimization here - this doesn't need to // be done if we know for sure that we're using raster cache - context->AddReadbackRegion(SkRect::Make(filter_bounds)); + context->AddReadbackRegion(filter_bounds); } context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());