summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordanakj <danakj@chromium.org>2015-04-25 10:53:17 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-25 17:53:12 +0000
commit93f5730af51af283713ad19dd5e08c3b3ea34eaa (patch)
tree38e1eb1974410d8503476bb9d0d25218f3ec17c9
parentba5b67e27dc64c3c6793be8f9c991066c956c33f (diff)
downloadchromium_src-93f5730af51af283713ad19dd5e08c3b3ea34eaa.zip
chromium_src-93f5730af51af283713ad19dd5e08c3b3ea34eaa.tar.gz
chromium_src-93f5730af51af283713ad19dd5e08c3b3ea34eaa.tar.bz2
ui: Cache the output of View::OnPaint when the View isn't invalid.
Store the output of View::OnPaint as a PaintCache object, and when the view has not been invalidated, use that cache output instead of doing work to build a recording. Performance data as follows when the loading spinner is going: Before impl-side (TOT): 0.13ms / paint With impl-side (no slimming paint): 0.22ms / paint With impl-side and slimming paint (this patch): 0.17ms / paint So this gets us some of the way there. I need to investigate why it's not doing more. R=piman@chromium.org, sky BUG=466426 Committed: https://crrev.com/7f686cdcff81d6779b962e98e529a7360be2809c Cr-Commit-Position: refs/heads/master@{#326592} Review URL: https://codereview.chromium.org/1101783002 Cr-Commit-Position: refs/heads/master@{#326976}
-rw-r--r--cc/resources/drawing_display_item.cc4
-rw-r--r--cc/resources/drawing_display_item.h2
-rw-r--r--ui/compositor/BUILD.gn2
-rw-r--r--ui/compositor/compositor.gyp2
-rw-r--r--ui/compositor/layer.cc9
-rw-r--r--ui/compositor/paint_cache.cc31
-rw-r--r--ui/compositor/paint_cache.h45
-rw-r--r--ui/compositor/paint_context.h16
-rw-r--r--ui/compositor/paint_recorder.cc21
-rw-r--r--ui/compositor/paint_recorder.h5
-rw-r--r--ui/views/view.cc13
-rw-r--r--ui/views/view.h4
12 files changed, 134 insertions, 20 deletions
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc
index 91ab3fb..a37729f 100644
--- a/cc/resources/drawing_display_item.cc
+++ b/cc/resources/drawing_display_item.cc
@@ -62,4 +62,8 @@ void DrawingDisplayItem::AsValueInto(
array->EndDictionary();
}
+scoped_ptr<DrawingDisplayItem> DrawingDisplayItem::Clone() {
+ return Create(picture_);
+}
+
} // namespace cc
diff --git a/cc/resources/drawing_display_item.h b/cc/resources/drawing_display_item.h
index a3eef77..da302d8 100644
--- a/cc/resources/drawing_display_item.h
+++ b/cc/resources/drawing_display_item.h
@@ -33,6 +33,8 @@ class CC_EXPORT DrawingDisplayItem : public DisplayItem {
size_t PictureMemoryUsage() const override;
void AsValueInto(base::trace_event::TracedValue* array) const override;
+ scoped_ptr<DrawingDisplayItem> Clone();
+
protected:
explicit DrawingDisplayItem(skia::RefPtr<SkPicture> picture);
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index 590cb73..a0944fe 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -47,6 +47,8 @@ component("compositor") {
"layer_tree_owner.cc",
"layer_tree_owner.h",
"layer_type.h",
+ "paint_cache.cc",
+ "paint_cache.h",
"paint_context.cc",
"paint_context.h",
"paint_recorder.cc",
diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp
index 11d6723..92f5ef4 100644
--- a/ui/compositor/compositor.gyp
+++ b/ui/compositor/compositor.gyp
@@ -65,6 +65,8 @@
'layer_tree_owner.cc',
'layer_tree_owner.h',
'layer_type.h',
+ 'paint_cache.cc',
+ 'paint_cache.h',
'paint_context.cc',
'paint_context.h',
'paint_recorder.cc',
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 914e000..2b6f921 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -750,14 +750,13 @@ void Layer::PaintContentsToDisplayList(
const gfx::Rect& clip,
ContentLayerClient::PaintingControlSetting painting_control) {
TRACE_EVENT1("ui", "Layer::PaintContentsToDisplayList", "name", name_);
+ gfx::Rect local_bounds(bounds().size());
+ gfx::Rect invalidation(
+ gfx::IntersectRects(damaged_region_.bounds(), local_bounds));
+ DCHECK(clip.Contains(invalidation));
ClearDamagedRects();
if (!delegate_)
return;
- // TODO(danakj): Save the invalidation on the layer and pass that down
- // instead of the |clip| here. That will break everything until View
- // early-outs emit cached display items instead of nothing.
- gfx::Rect invalidation = clip;
- DCHECK(clip.Contains(invalidation));
delegate_->OnPaintLayer(
PaintContext(display_list, device_scale_factor_, clip, invalidation));
}
diff --git a/ui/compositor/paint_cache.cc b/ui/compositor/paint_cache.cc
new file mode 100644
index 0000000..ef0e5a7
--- /dev/null
+++ b/ui/compositor/paint_cache.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/paint_cache.h"
+
+#include "cc/resources/display_item_list.h"
+#include "cc/resources/drawing_display_item.h"
+#include "ui/compositor/paint_context.h"
+
+namespace ui {
+
+PaintCache::PaintCache() {
+}
+
+PaintCache::~PaintCache() {
+}
+
+bool PaintCache::UseCache(const PaintContext& context) {
+ if (!display_item_)
+ return false;
+ DCHECK(context.list_);
+ context.list_->AppendItem(display_item_->Clone());
+ return true;
+}
+
+void PaintCache::SetCache(scoped_ptr<cc::DrawingDisplayItem> item) {
+ display_item_ = item.Pass();
+}
+
+} // namespace ui
diff --git a/ui/compositor/paint_cache.h b/ui/compositor/paint_cache.h
new file mode 100644
index 0000000..599a8ac
--- /dev/null
+++ b/ui/compositor/paint_cache.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_COMPOSITOR_PAINT_CACHE_H_
+#define UI_COMPOSITOR_PAINT_CACHE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/compositor/compositor_export.h"
+
+namespace cc {
+class DrawingDisplayItem;
+}
+
+namespace ui {
+class PaintContext;
+class PaintRecorder;
+
+// A class that holds the output of a PaintRecorder to be reused when the
+// object that created the PaintRecorder has not been changed/invalidated.
+class COMPOSITOR_EXPORT PaintCache {
+ public:
+ PaintCache();
+ ~PaintCache();
+
+ // Returns true if the PaintCache was able to insert a previously-saved
+ // painting output into the PaintContext. If it returns false, the caller
+ // needs to do the work of painting, which can be stored into the PaintCache
+ // to be used next time.
+ bool UseCache(const PaintContext& context);
+
+ private:
+ // Only PaintRecorder can modify these.
+ friend PaintRecorder;
+
+ void SetCache(scoped_ptr<cc::DrawingDisplayItem> item);
+
+ scoped_ptr<cc::DrawingDisplayItem> display_item_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaintCache);
+};
+
+} // namespace ui
+
+#endif // UI_COMPOSITOR_PAINT_CACHE_H_
diff --git a/ui/compositor/paint_context.h b/ui/compositor/paint_context.h
index d63f11f..a754ee4 100644
--- a/ui/compositor/paint_context.h
+++ b/ui/compositor/paint_context.h
@@ -56,15 +56,20 @@ class COMPOSITOR_EXPORT PaintContext {
return PaintContext(canvas_);
}
- // When true, IsRectInvalidated() can be called, otherwise its result would be
+ // When true, IsRectInvalid() can be called, otherwise its result would be
// invalid.
- bool CanCheckInvalidated() const { return !invalidation_.IsEmpty(); }
+ bool CanCheckInvalid() const { return !invalidation_.IsEmpty(); }
+
+ // When true, if a thing is not invalidated it does not need to paint itself.
+ // When false, everything should provide an output when painting regardless of
+ // being invalidated in order to remain visible.
+ bool ShouldEarlyOutOfPaintingWhenValid() const { return !!canvas_; }
// When true, the |bounds| touches an invalidated area, so should be
// re-painted. When false, re-painting can be skipped. Bounds should be in
// the local space with offsets up to the painting root in the PaintContext.
- bool IsRectInvalidated(const gfx::Rect& bounds) const {
- DCHECK(CanCheckInvalidated());
+ bool IsRectInvalid(const gfx::Rect& bounds) const {
+ DCHECK(CanCheckInvalid());
return invalidation_.Intersects(bounds + offset_);
}
@@ -86,6 +91,9 @@ class COMPOSITOR_EXPORT PaintContext {
friend class ClipTransformRecorder;
friend class CompositingRecorder;
friend class PaintRecorder;
+ // The Cache class also needs to access the DisplayItemList to append its
+ // cache contents.
+ friend class PaintCache;
PaintContext& operator=(const PaintContext& other) = delete;
diff --git a/ui/compositor/paint_recorder.cc b/ui/compositor/paint_recorder.cc
index 15aa0fb..80fb616 100644
--- a/ui/compositor/paint_recorder.cc
+++ b/ui/compositor/paint_recorder.cc
@@ -7,14 +7,15 @@
#include "cc/resources/display_item_list.h"
#include "cc/resources/drawing_display_item.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/compositor/paint_cache.h"
#include "ui/compositor/paint_context.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skia_util.h"
namespace ui {
-PaintRecorder::PaintRecorder(const PaintContext& context)
- : context_(context), canvas_(context.canvas_) {
+PaintRecorder::PaintRecorder(const PaintContext& context, PaintCache* cache)
+ : context_(context), canvas_(context.canvas_), cache_(cache) {
#if DCHECK_IS_ON()
DCHECK(!context.inside_paint_recorder_);
context.inside_paint_recorder_ = true;
@@ -34,15 +35,23 @@ PaintRecorder::PaintRecorder(const PaintContext& context)
}
}
+PaintRecorder::PaintRecorder(const PaintContext& context)
+ : PaintRecorder(context, nullptr) {
+}
+
PaintRecorder::~PaintRecorder() {
#if DCHECK_IS_ON()
context_.inside_paint_recorder_ = false;
#endif
- if (context_.list_) {
- context_.list_->AppendItem(cc::DrawingDisplayItem::Create(
- skia::AdoptRef(context_.recorder_->endRecordingAsPicture())));
- }
+ if (!context_.list_)
+ return;
+
+ scoped_ptr<cc::DrawingDisplayItem> item = cc::DrawingDisplayItem::Create(
+ skia::AdoptRef(context_.recorder_->endRecordingAsPicture()));
+ if (cache_)
+ cache_->SetCache(item->Clone());
+ context_.list_->AppendItem(item.Pass());
}
} // namespace ui
diff --git a/ui/compositor/paint_recorder.h b/ui/compositor/paint_recorder.h
index 7c3df82..9cac7a8 100644
--- a/ui/compositor/paint_recorder.h
+++ b/ui/compositor/paint_recorder.h
@@ -22,6 +22,7 @@ class SkCanvas;
class SkPictureRecorder;
namespace ui {
+class PaintCache;
class PaintContext;
// A class to hide the complexity behind setting up a recording into a
@@ -30,6 +31,9 @@ class PaintContext;
// recording is complete and can be cached.
class COMPOSITOR_EXPORT PaintRecorder {
public:
+ // The |cache| is owned by the caller and must be kept alive while
+ // PaintRecorder is in use.
+ PaintRecorder(const PaintContext& context, PaintCache* cache);
explicit PaintRecorder(const PaintContext& context);
~PaintRecorder();
@@ -40,6 +44,7 @@ class COMPOSITOR_EXPORT PaintRecorder {
const PaintContext& context_;
gfx::Canvas* canvas_;
scoped_ptr<gfx::Canvas> owned_canvas_;
+ PaintCache* cache_;
DISALLOW_COPY_AND_ASSIGN(PaintRecorder);
};
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 78659ca..c79cc6c 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -748,7 +748,8 @@ void View::Paint(const ui::PaintContext& parent_context) {
ui::PaintContext context =
parent_context.CloneWithPaintOffset(offset_to_parent);
- if (context.CanCheckInvalidated()) {
+ bool is_invalidated = true;
+ if (context.CanCheckInvalid()) {
#if DCHECK_IS_ON()
gfx::Vector2d offset;
context.Visited(this);
@@ -770,10 +771,12 @@ void View::Paint(const ui::PaintContext& parent_context) {
// If the View wasn't invalidated, don't waste time painting it, the output
// would be culled.
- if (!context.IsRectInvalidated(GetLocalBounds()))
- return;
+ is_invalidated = context.IsRectInvalid(GetLocalBounds());
}
+ if (!is_invalidated && context.ShouldEarlyOutOfPaintingWhenValid())
+ return;
+
TRACE_EVENT1("views", "View::Paint", "class", GetClassName());
// If the view is backed by a layer, it should paint with itself as the origin
@@ -803,8 +806,8 @@ void View::Paint(const ui::PaintContext& parent_context) {
clip_transform_recorder->Transform(transform_from_parent);
}
- {
- ui::PaintRecorder recorder(context);
+ if (is_invalidated || !paint_cache_.UseCache(context)) {
+ ui::PaintRecorder recorder(context, &paint_cache_);
gfx::Canvas* canvas = recorder.canvas();
gfx::ScopedCanvas scoped_canvas(canvas);
diff --git a/ui/views/view.h b/ui/views/view.h
index 00813e0..1a56db5 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -24,6 +24,7 @@
#include "ui/base/ui_base_types.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/compositor/layer_owner.h"
+#include "ui/compositor/paint_cache.h"
#include "ui/events/event.h"
#include "ui/events/event_target.h"
#include "ui/gfx/geometry/insets.h"
@@ -1509,6 +1510,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Border.
scoped_ptr<Border> border_;
+ // Cached output of painting to be reused in future frames until invalidated.
+ ui::PaintCache paint_cache_;
+
// RTL painting --------------------------------------------------------------
// Indicates whether or not the gfx::Canvas object passed to View::Paint()