From 3de2e1cf030548dd566082c695fb184c5c07643e Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Fri, 8 Jan 2016 01:53:36 -0800 Subject: [PATCH] Experiment with caching rasterized layers This patch adds back (and tweaks) some code that we previously removed for caching rasterized layers. Now that our layerization code in the framework is more sophisticated, we should be able to get more value out of this mechanism. --- sky/compositor/BUILD.gn | 2 + sky/compositor/checkerboard.cc | 6 +-- sky/compositor/checkerboard.h | 2 +- sky/compositor/paint_context.cc | 1 + sky/compositor/paint_context.h | 5 ++ sky/compositor/picture_layer.cc | 36 ++++++++++++-- sky/compositor/raster_cache.cc | 83 +++++++++++++++++++++++++++++++++ sky/compositor/raster_cache.h | 49 +++++++++++++++++++ 8 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 sky/compositor/raster_cache.cc create mode 100644 sky/compositor/raster_cache.h diff --git a/sky/compositor/BUILD.gn b/sky/compositor/BUILD.gn index 715fd759c73..998f1b8b8c7 100644 --- a/sky/compositor/BUILD.gn +++ b/sky/compositor/BUILD.gn @@ -32,6 +32,8 @@ source_set("compositor") { "picture_layer.h", "picture_serializer.cc", "picture_serializer.h", + "raster_cache.cc", + "raster_cache.h", "statistics_layer.cc", "statistics_layer.h", "transform_layer.cc", diff --git a/sky/compositor/checkerboard.cc b/sky/compositor/checkerboard.cc index 42b3a245d49..d9e49eb914a 100644 --- a/sky/compositor/checkerboard.cc +++ b/sky/compositor/checkerboard.cc @@ -27,12 +27,12 @@ static void DrawCheckerboard(SkCanvas* canvas, canvas->drawPaint(paint); } -void DrawCheckerboard(SkCanvas* canvas, int width, int height) { - SkRect rect = SkRect::MakeIWH(width, height); - +void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect) { // Draw a checkerboard + canvas->save(); canvas->clipRect(rect); DrawCheckerboard(canvas, 0x4400FF00, 0x00000000, 12); + canvas->restore(); // Stroke the drawn area SkPaint debugPaint; diff --git a/sky/compositor/checkerboard.h b/sky/compositor/checkerboard.h index b52e69eb874..a10f11f7f21 100644 --- a/sky/compositor/checkerboard.h +++ b/sky/compositor/checkerboard.h @@ -10,7 +10,7 @@ namespace sky { namespace compositor { -void DrawCheckerboard(SkCanvas* canvas, int width, int height); +void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect); } // namespace compositor } // namespace sky diff --git a/sky/compositor/paint_context.cc b/sky/compositor/paint_context.cc index 1d14bbd7628..5dbbb0e7db2 100644 --- a/sky/compositor/paint_context.cc +++ b/sky/compositor/paint_context.cc @@ -22,6 +22,7 @@ void PaintContext::beginFrame(ScopedFrame& frame, bool enableInstrumentation) { } void PaintContext::endFrame(ScopedFrame& frame, bool enableInstrumentation) { + raster_cache_.SweepAfterFrame(); if (enableInstrumentation) { frame_time_.stop(); } diff --git a/sky/compositor/paint_context.h b/sky/compositor/paint_context.h index 89cc85a1c9e..fe6d198564f 100644 --- a/sky/compositor/paint_context.h +++ b/sky/compositor/paint_context.h @@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/logging.h" #include "sky/compositor/instrumentation.h" +#include "sky/compositor/raster_cache.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" #include "ui/gfx/geometry/size.h" @@ -56,6 +57,8 @@ class PaintContext { ScopedFrame AcquireFrame(const std::string& trace_file_name, gfx::Size frame_size); + RasterCache& raster_cache() { return raster_cache_; } + const instrumentation::Counter& frame_count() const { return frame_count_; } const instrumentation::Stopwatch& frame_time() const { return frame_time_; } @@ -63,6 +66,8 @@ class PaintContext { instrumentation::Stopwatch& engine_time() { return engine_time_; }; private: + RasterCache raster_cache_; + instrumentation::Counter frame_count_; instrumentation::Stopwatch frame_time_; instrumentation::Stopwatch engine_time_; diff --git a/sky/compositor/picture_layer.cc b/sky/compositor/picture_layer.cc index 1ce43d1580d..d2c9e317b6d 100644 --- a/sky/compositor/picture_layer.cc +++ b/sky/compositor/picture_layer.cc @@ -3,11 +3,19 @@ // found in the LICENSE file. #include "sky/compositor/picture_layer.h" + #include "base/logging.h" +#include "sky/compositor/checkerboard.h" +#include "sky/compositor/raster_cache.h" + +#define ENABLE_RASTER_CACHE 0 namespace sky { namespace compositor { +// TODO(abarth): Make this configurable by developers. +const bool kDebugCheckerboardRasterizedLayers = false; + PictureLayer::PictureLayer() { } @@ -18,10 +26,30 @@ void PictureLayer::Paint(PaintContext::ScopedFrame& frame) { DCHECK(picture_); SkCanvas& canvas = frame.canvas(); - canvas.save(); - canvas.translate(offset_.x(), offset_.y()); - canvas.drawPicture(picture_.get()); - canvas.restore(); + +#if ENABLE_RASTER_CACHE + const SkMatrix& ctm = canvas.getTotalMatrix(); + SkISize size = SkISize::Make(paint_bounds().width() * ctm.getScaleX(), + paint_bounds().height() * ctm.getScaleY()); + + RasterCache& cache = frame.context().raster_cache(); + RefPtr image = cache.GetImage(picture_.get(), size); +#else + RefPtr image; +#endif + + if (image) { + canvas.drawImage(image.get(), offset_.x(), offset_.y()); + if (kDebugCheckerboardRasterizedLayers) { + SkRect rect = paint_bounds().makeOffset(offset_.x(), offset_.y()); + DrawCheckerboard(&canvas, rect); + } + } else { + canvas.save(); + canvas.translate(offset_.x(), offset_.y()); + canvas.drawPicture(picture_.get()); + canvas.restore(); + } } } // namespace compositor diff --git a/sky/compositor/raster_cache.cc b/sky/compositor/raster_cache.cc new file mode 100644 index 00000000000..c73863a1ff8 --- /dev/null +++ b/sky/compositor/raster_cache.cc @@ -0,0 +1,83 @@ +// Copyright 2016 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 "sky/compositor/raster_cache.h" + +#include "sky/compositor/paint_context.h" +#include "base/logging.h" +#include "third_party/skia/include/core/SkImage.h" + +namespace sky { +namespace compositor { + +static const int kRasterThreshold = 3; + +static bool isWorthRasterizing(SkPicture* picture) { + // TODO(abarth): We should find a better heuristic here that lets us avoid + // wasting memory on trivial layers that are easy to re-rasterize every frame. + return picture->approximateOpCount() > 10 || picture->hasText(); +} + +RasterCache::RasterCache() { +} + +RasterCache::~RasterCache() { +} + +RasterCache::Entry::Entry() { + physical_size.setEmpty(); +} + +RasterCache::Entry::~Entry() { +} + +RefPtr RasterCache::GetImage( + SkPicture* picture, const SkISize& physical_size) { + if (physical_size.isEmpty()) + return nullptr; + + Entry& entry = cache_[picture->uniqueID()]; + + const bool size_matched = entry.physical_size == physical_size; + + entry.used_this_frame = true; + entry.physical_size = physical_size; + + if (!size_matched) { + entry.access_count = 1; + entry.image = nullptr; + return nullptr; + } + + entry.access_count++; + + if (entry.access_count >= kRasterThreshold) { + // Saturate at the threshhold. + entry.access_count = kRasterThreshold; + + if (!entry.image && isWorthRasterizing(picture)) { + entry.image = adoptRef(SkImage::NewFromPicture(picture, physical_size, + nullptr, nullptr)); + } + } + + return entry.image; +} + +void RasterCache::SweepAfterFrame() { + std::vector dead; + + for (auto it = cache_.begin(); it != cache_.end(); ++it) { + Entry& entry = it->second; + if (!entry.used_this_frame) + dead.push_back(it); + entry.used_this_frame = false; + } + + for (auto it : dead) + cache_.erase(it); +} + +} // namespace compositor +} // namespace sky diff --git a/sky/compositor/raster_cache.h b/sky/compositor/raster_cache.h new file mode 100644 index 00000000000..fadc71a138f --- /dev/null +++ b/sky/compositor/raster_cache.h @@ -0,0 +1,49 @@ +// Copyright 2016 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 SKY_COMPOSITOR_RASTER_CACHE_H_ +#define SKY_COMPOSITOR_RASTER_CACHE_H_ + +#include +#include + +#include "base/macros.h" +#include "third_party/skia/include/core/SkSize.h" +#include "third_party/skia/include/core/SkImage.h" +#include "sky/compositor/instrumentation.h" +#include "sky/engine/wtf/PassRefPtr.h" +#include "sky/engine/wtf/RefPtr.h" + +namespace sky { +namespace compositor { + +class RasterCache { + public: + RasterCache(); + ~RasterCache(); + + RefPtr GetImage(SkPicture* picture, const SkISize& physical_size); + void SweepAfterFrame(); + + private: + struct Entry { + Entry(); + ~Entry(); + + bool used_this_frame = false; + int access_count = 0; + SkISize physical_size; + RefPtr image; + }; + + using Cache = std::unordered_map; + Cache cache_; + + DISALLOW_COPY_AND_ASSIGN(RasterCache); +}; + +} // namespace compositor +} // namespace sky + +#endif // SKY_COMPOSITOR_RASTER_CACHE_H_