Merge pull request #2225 from abarth/cache_layers

Experiment with caching rasterized layers
This commit is contained in:
Adam Barth 2016-01-08 11:03:33 -08:00
commit f4fc4e24a0
8 changed files with 176 additions and 8 deletions

View File

@ -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",

View File

@ -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;

View File

@ -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

View File

@ -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();
}

View File

@ -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_;

View File

@ -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<SkImage> image = cache.GetImage(picture_.get(), size);
#else
RefPtr<SkImage> 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

View File

@ -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<SkImage> 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<Cache::iterator> 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

View File

@ -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 <memory>
#include <unordered_map>
#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<SkImage> 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<SkImage> image;
};
using Cache = std::unordered_map<uint32_t, Entry>;
Cache cache_;
DISALLOW_COPY_AND_ASSIGN(RasterCache);
};
} // namespace compositor
} // namespace sky
#endif // SKY_COMPOSITOR_RASTER_CACHE_H_