diff --git a/sky/compositor/BUILD.gn b/sky/compositor/BUILD.gn index 715fd759c73fadcb12f756971f51513fdcf25e0d..998f1b8b8c7d196df0016bda57bbc0e75e2ed389 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 42b3a245d490d7a50717a26c4394003c5133b827..d9e49eb914a5dead49a41df4c6ce7faf5f8bf6d0 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 b52e69eb87467492347ebbf0e6e1674986d16d22..a10f11f7f2127210a45a75215383d7832d6f3c90 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 1d14bbd7628d1e8fdf1603967b0cc497b290509a..5dbbb0e7db2acc10e704e4b6af2caf424a348774 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 89cc85a1c9ea91baabe9919556ca7e5c72a12056..fe6d198564f8cb8f3f148097af64e1f59c450e98 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 1ce43d1580de758a3e304dc6778b38d8442f9da8..d2c9e317b6d292cd9a81f03f8e9ed2ed369e80a1 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 0000000000000000000000000000000000000000..c73863a1ff82c921761fea54d0d24e40820d8296 --- /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 0000000000000000000000000000000000000000..fadc71a138f3642e5da373f833f12ed78a564dd8 --- /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_