Allow raster caching any layer subtree (flutter/engine#6442)

We first test this with OpacityLayer. This test alone (without retained rendering) should have ~30% speedup as we'll have fewer render target switches by snapshoting in the Preroll instead of saveLayer in the Paint.

In my local flutter_gallery transition perf tests, the average frame time drops from ~16ms to ~12ms.

https://github.com/flutter/flutter/issues/21756
This commit is contained in:
liyuqian
2018-10-11 13:24:33 -07:00
committed by GitHub
parent c1330d94f5
commit 397c02b215
15 changed files with 248 additions and 119 deletions

View File

@@ -63,7 +63,7 @@ CompositorContext::ScopedFrame::~ScopedFrame() {
bool CompositorContext::ScopedFrame::Raster(flow::LayerTree& layer_tree,
bool ignore_raster_cache) {
layer_tree.Preroll(*this, ignore_raster_cache);
layer_tree.Paint(*this);
layer_tree.Paint(*this, ignore_raster_cache);
return true;
}

View File

@@ -25,9 +25,8 @@ std::ostream& operator<<(std::ostream& os, const flow::MatrixDecomposition& m) {
std::ostream& operator<<(std::ostream& os, const SkMatrix& m) {
SkString string;
string.printf(
"[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
string.printf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
os << string.c_str();
return os;
}
@@ -72,8 +71,9 @@ std::ostream& operator<<(std::ostream& os, const SkPoint& r) {
return os;
}
std::ostream& operator<<(std::ostream& os, const flow::RasterCacheKey& k) {
os << "Picture: " << k.picture_id() << " matrix: " << k.matrix();
std::ostream& operator<<(std::ostream& os,
const flow::PictureRasterCacheKey& k) {
os << "Picture: " << k.id() << " matrix: " << k.matrix();
return os;
}

View File

@@ -16,7 +16,7 @@
#define DEF_PRINTER(x) std::ostream& operator<<(std::ostream&, const x&);
DEF_PRINTER(flow::MatrixDecomposition);
DEF_PRINTER(flow::RasterCacheKey);
DEF_PRINTER(flow::PictureRasterCacheKey);
DEF_PRINTER(SkISize);
DEF_PRINTER(SkMatrix);
DEF_PRINTER(SkMatrix44);

View File

@@ -40,6 +40,19 @@ enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer };
class ContainerLayer;
struct PrerollContext {
RasterCache* raster_cache;
GrContext* gr_context;
SkColorSpace* dst_color_space;
SkRect child_paint_bounds;
// The following allows us to paint in the end of subtree preroll
const Stopwatch& frame_time;
const Stopwatch& engine_time;
TextureRegistry& texture_registry;
const bool checkerboard_offscreen_layers;
};
// Represents a single composited layer. Created on the UI thread but then
// subquently used on the Rasterizer thread.
class Layer {
@@ -47,13 +60,6 @@ class Layer {
Layer();
virtual ~Layer();
struct PrerollContext {
RasterCache* raster_cache;
GrContext* gr_context;
SkColorSpace* dst_color_space;
SkRect child_paint_bounds;
};
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);
struct PaintContext {
@@ -61,6 +67,7 @@ class Layer {
const Stopwatch& frame_time;
const Stopwatch& engine_time;
TextureRegistry& texture_registry;
const RasterCache* raster_cache;
const bool checkerboard_offscreen_layers;
};

View File

@@ -25,12 +25,15 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
frame.canvas() ? frame.canvas()->imageInfo().colorSpace() : nullptr;
frame.context().raster_cache().SetCheckboardCacheImages(
checkerboard_raster_cache_images_);
Layer::PrerollContext context = {
PrerollContext context = {
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
frame.gr_context(),
color_space,
SkRect::MakeEmpty(),
};
frame.context().frame_time(),
frame.context().engine_time(),
frame.context().texture_registry(),
checkerboard_offscreen_layers_};
root_layer_->Preroll(&context, frame.root_surface_transformation());
}
@@ -60,15 +63,16 @@ void LayerTree::UpdateScene(SceneUpdateContext& context,
}
#endif
void LayerTree::Paint(CompositorContext::ScopedFrame& frame) const {
void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache) const {
TRACE_EVENT0("flutter", "LayerTree::Paint");
Layer::PaintContext context = {
*frame.canvas(), //
frame.context().frame_time(), //
frame.context().engine_time(), //
frame.context().texture_registry(), //
checkerboard_offscreen_layers_ //
};
*frame.canvas(),
frame.context().frame_time(),
frame.context().engine_time(),
frame.context().texture_registry(),
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
checkerboard_offscreen_layers_};
if (root_layer_->needs_painting())
root_layer_->Paint(context);
@@ -84,24 +88,29 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
return nullptr;
}
Layer::PrerollContext preroll_context{
nullptr, // raster_cache (don't consult the cache)
nullptr, // gr_context (used for the raster cache)
nullptr, // SkColorSpace* dst_color_space
SkRect::MakeEmpty(), // SkRect child_paint_bounds
};
const Stopwatch unused_stopwatch;
TextureRegistry unused_texture_registry;
SkMatrix root_surface_transformation;
// No root surface transformation. So assume identity.
root_surface_transformation.reset();
PrerollContext preroll_context{
nullptr, // raster_cache (don't consult the cache)
nullptr, // gr_context (used for the raster cache)
nullptr, // SkColorSpace* dst_color_space
SkRect::MakeEmpty(), // SkRect child_paint_bounds
unused_stopwatch, // frame time (dont care)
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
false, // checkerboard_offscreen_layers
};
Layer::PaintContext paint_context = {
*canvas, // canvas
unused_stopwatch, // frame time (dont care)
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
nullptr, // raster cache
false // checkerboard offscreen layers
};

View File

@@ -32,7 +32,8 @@ class LayerTree {
scenic::ContainerNode& container);
#endif
void Paint(CompositorContext::ScopedFrame& frame) const;
void Paint(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache = false) const;
sk_sp<SkPicture> Flatten(const SkRect& bounds);

View File

@@ -10,6 +10,18 @@ OpacityLayer::OpacityLayer() = default;
OpacityLayer::~OpacityLayer() = default;
void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
ContainerLayer::Preroll(context, matrix);
if (context->raster_cache && layers().size() == 1) {
std::shared_ptr<Layer> child = layers()[0];
SkMatrix ctm = matrix;
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
ctm = RasterCache::GetIntegralTransCTM(ctm);
#endif
context->raster_cache->Prepare(context, child, ctm);
}
}
void OpacityLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
FML_DCHECK(needs_painting());
@@ -17,7 +29,23 @@ void OpacityLayer::Paint(PaintContext& context) const {
SkPaint paint;
paint.setAlpha(alpha_);
Layer::AutoSaveLayer save =
SkAutoCanvasRestore save(&context.canvas, true);
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
context.canvas.setMatrix(
RasterCache::GetIntegralTransCTM(context.canvas.getTotalMatrix()));
#endif
if (layers().size() == 1 && context.raster_cache) {
const SkMatrix& ctm = context.canvas.getTotalMatrix();
RasterCacheResult child_cache = context.raster_cache->Get(layers()[0], ctm);
if (child_cache.is_valid()) {
child_cache.draw(context.canvas, &paint);
return;
}
}
Layer::AutoSaveLayer save_layer =
Layer::AutoSaveLayer::Create(context, paint_bounds(), &paint);
PaintChildren(context);
}

View File

@@ -16,6 +16,8 @@ class OpacityLayer : public ContainerLayer {
void set_alpha(int alpha) { alpha_ = alpha; }
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
// TODO(chinmaygarde): Once MZ-139 is addressed, introduce a new node in the

View File

@@ -21,11 +21,8 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
ctm = RasterCache::GetIntegralTransCTM(ctm);
#endif
raster_cache_result_ = cache->GetPrerolledImage(
context->gr_context, sk_picture, ctm, context->dst_color_space,
is_complex_, will_change_);
} else {
raster_cache_result_ = RasterCacheResult();
cache->Prepare(context->gr_context, sk_picture, ctm,
context->dst_color_space, is_complex_, will_change_);
}
SkRect bounds = sk_picture->cullRect().makeOffset(offset_.x(), offset_.y());
@@ -44,11 +41,15 @@ void PictureLayer::Paint(PaintContext& context) const {
RasterCache::GetIntegralTransCTM(context.canvas.getTotalMatrix()));
#endif
if (raster_cache_result_.is_valid()) {
raster_cache_result_.draw(context.canvas);
} else {
context.canvas.drawPicture(picture());
if (context.raster_cache) {
const SkMatrix& ctm = context.canvas.getTotalMatrix();
RasterCacheResult result = context.raster_cache->Get(*picture(), ctm);
if (result.is_valid()) {
result.draw(context.canvas);
return;
}
}
context.canvas.drawPicture(picture());
}
} // namespace flow

View File

@@ -39,7 +39,6 @@ class PictureLayer : public Layer {
SkiaGPUObject<SkPicture> picture_;
bool is_complex_ = false;
bool will_change_ = false;
RasterCacheResult raster_cache_result_;
FML_DISALLOW_COPY_AND_ASSIGN(PictureLayer);
};

View File

@@ -6,6 +6,7 @@
#include <vector>
#include "flutter/flow/layers/layer.h"
#include "flutter/flow/paint_utils.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
@@ -17,13 +18,13 @@
namespace flow {
void RasterCacheResult::draw(SkCanvas& canvas) const {
void RasterCacheResult::draw(SkCanvas& canvas, const SkPaint* paint) const {
SkAutoCanvasRestore auto_restore(&canvas, true);
SkIRect bounds =
RasterCache::GetDeviceBounds(logical_rect_, canvas.getTotalMatrix());
FML_DCHECK(bounds.size() == image_->dimensions());
canvas.resetMatrix();
canvas.drawImage(image_, bounds.fLeft, bounds.fTop);
canvas.drawImage(image_, bounds.fLeft, bounds.fTop, paint);
}
RasterCache::RasterCache(size_t threshold)
@@ -77,14 +78,13 @@ static bool IsPictureWorthRasterizing(SkPicture* picture,
return picture->approximateOpCount() > 10;
}
RasterCacheResult RasterizePicture(SkPicture* picture,
GrContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard) {
TRACE_EVENT0("flutter", "RasterCachePopulate");
const SkRect logical_rect = picture->cullRect();
static RasterCacheResult Rasterize(
GrContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard,
const SkRect& logical_rect,
std::function<void(SkCanvas*)> draw_function) {
SkIRect cache_rect = RasterCache::GetDeviceBounds(logical_rect, ctm);
const SkImageInfo image_info =
@@ -112,7 +112,7 @@ RasterCacheResult RasterizePicture(SkPicture* picture,
canvas->clear(SK_ColorTRANSPARENT);
canvas->translate(-cache_rect.left(), -cache_rect.top());
canvas->concat(ctm);
canvas->drawPicture(picture);
draw_function(canvas);
if (checkerboard) {
DrawCheckerboard(canvas, logical_rect);
@@ -121,6 +121,18 @@ RasterCacheResult RasterizePicture(SkPicture* picture,
return {surface->makeImageSnapshot(), logical_rect};
}
RasterCacheResult RasterizePicture(SkPicture* picture,
GrContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard) {
TRACE_EVENT0("flutter", "RasterCachePopulate");
return Rasterize(context, ctm, dst_color_space, checkerboard,
picture->cullRect(),
[=](SkCanvas* canvas) { canvas->drawPicture(picture); });
}
static inline size_t ClampSize(size_t value, size_t min, size_t max) {
if (value > max) {
return max;
@@ -133,16 +145,38 @@ static inline size_t ClampSize(size_t value, size_t min, size_t max) {
return value;
}
RasterCacheResult RasterCache::GetPrerolledImage(
GrContext* context,
SkPicture* picture,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change) {
void RasterCache::Prepare(PrerollContext* context,
std::shared_ptr<Layer> layer,
const SkMatrix& ctm) {
LayerRasterCacheKey cache_key(layer, ctm);
Entry& entry = layer_cache_[cache_key];
entry.access_count = ClampSize(entry.access_count + 1, 0, threshold_);
entry.used_this_frame = true;
if (!entry.image.is_valid()) {
entry.image = Rasterize(context->gr_context, ctm, context->dst_color_space,
checkerboard_images_, layer->paint_bounds(),
[layer, context](SkCanvas* canvas) {
Layer::PaintContext paintContext = {
*canvas,
context->frame_time,
context->engine_time,
context->texture_registry,
context->raster_cache,
context->checkerboard_offscreen_layers};
layer->Paint(paintContext);
});
}
}
bool RasterCache::Prepare(GrContext* context,
SkPicture* picture,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change) {
if (!IsPictureWorthRasterizing(picture, will_change, is_complex)) {
// We only deal with pictures that are worthy of rasterization.
return {};
return false;
}
// Decompose the matrix (once) for all subsequent operations. We want to make
@@ -151,46 +185,50 @@ RasterCacheResult RasterCache::GetPrerolledImage(
if (!matrix.IsValid()) {
// The matrix was singular. No point in going further.
return {};
return false;
}
RasterCacheKey cache_key(*picture, transformation_matrix);
PictureRasterCacheKey cache_key(picture->uniqueID(), transformation_matrix);
Entry& entry = cache_[cache_key];
Entry& entry = picture_cache_[cache_key];
entry.access_count = ClampSize(entry.access_count + 1, 0, threshold_);
entry.used_this_frame = true;
if (entry.access_count < threshold_ || threshold_ == 0) {
// Frame threshold has not yet been reached.
return {};
return false;
}
if (!entry.image.is_valid()) {
entry.image = RasterizePicture(picture, context, transformation_matrix,
dst_color_space, checkerboard_images_);
}
return true;
}
return entry.image;
RasterCacheResult RasterCache::Get(const SkPicture& picture,
const SkMatrix& ctm) const {
PictureRasterCacheKey cache_key(picture.uniqueID(), ctm);
auto it = picture_cache_.find(cache_key);
return it == picture_cache_.end() ? RasterCacheResult() : it->second.image;
}
RasterCacheResult RasterCache::Get(std::shared_ptr<Layer> layer,
const SkMatrix& ctm) const {
LayerRasterCacheKey cache_key(layer, ctm);
auto it = layer_cache_.find(cache_key);
return it == layer_cache_.end() ? RasterCacheResult() : it->second.image;
}
void RasterCache::SweepAfterFrame() {
std::vector<RasterCacheKey::Map<Entry>::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);
}
using PictureCache = PictureRasterCacheKey::Map<Entry>;
using LayerCache = LayerRasterCacheKey::Map<Entry>;
SweepOneCacheAfterFrame<PictureCache, PictureCache::iterator>(picture_cache_);
SweepOneCacheAfterFrame<LayerCache, LayerCache::iterator>(layer_cache_);
}
void RasterCache::Clear() {
cache_.clear();
picture_cache_.clear();
}
void RasterCache::SetCheckboardCacheImages(bool checkerboard) {

View File

@@ -28,13 +28,15 @@ class RasterCacheResult {
bool is_valid() const { return static_cast<bool>(image_); };
void draw(SkCanvas& canvas) const;
void draw(SkCanvas& canvas, const SkPaint* paint = nullptr) const;
private:
sk_sp<SkImage> image_;
SkRect logical_rect_;
};
struct PrerollContext;
class RasterCache {
public:
explicit RasterCache(size_t threshold = 3);
@@ -56,12 +58,26 @@ class RasterCache {
return result;
}
RasterCacheResult GetPrerolledImage(GrContext* context,
SkPicture* picture,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change);
// Return true if the cache is generated.
//
// We may return false and not generate the cache if
// 1. The picture is not worth rasterizing
// 2. The matrix is singular
// 3. The picture is accessed too few times
bool Prepare(GrContext* context,
SkPicture* picture,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change);
void Prepare(PrerollContext* context,
std::shared_ptr<Layer> layer,
const SkMatrix& ctm);
RasterCacheResult Get(const SkPicture& picture, const SkMatrix& ctm) const;
RasterCacheResult Get(std::shared_ptr<Layer> layer,
const SkMatrix& ctm) const;
void SweepAfterFrame();
@@ -76,8 +92,26 @@ class RasterCache {
RasterCacheResult image;
};
template <class Cache, class Iterator>
static void SweepOneCacheAfterFrame(Cache& cache) {
std::vector<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);
}
}
const size_t threshold_;
RasterCacheKey::Map<Entry> cache_;
PictureRasterCacheKey::Map<Entry> picture_cache_;
LayerRasterCacheKey::Map<Entry> layer_cache_;
bool checkerboard_images_;
fml::WeakPtrFactory<RasterCache> weak_factory_;

View File

@@ -14,10 +14,10 @@
namespace flow {
template <typename ID>
class RasterCacheKey {
public:
RasterCacheKey(const SkPicture& picture, const SkMatrix& ctm)
: picture_id_(picture.uniqueID()), matrix_(ctm) {
RasterCacheKey(ID id, const SkMatrix& ctm) : id_(id), matrix_(ctm) {
matrix_[SkMatrix::kMTransX] = SkScalarFraction(ctm.getTranslateX());
matrix_[SkMatrix::kMTransY] = SkScalarFraction(ctm.getTranslateY());
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
@@ -25,19 +25,19 @@ class RasterCacheKey {
#endif
}
uint32_t picture_id() const { return picture_id_; }
ID id() const { return id_; }
const SkMatrix& matrix() const { return matrix_; }
struct Hash {
std::size_t operator()(RasterCacheKey const& key) const {
return key.picture_id_;
uint32_t operator()(RasterCacheKey const& key) const {
return std::hash<ID>()(key.id_);
}
};
struct Equal {
constexpr bool operator()(const RasterCacheKey& lhs,
const RasterCacheKey& rhs) const {
return lhs.picture_id_ == rhs.picture_id_ && lhs.matrix_ == rhs.matrix_;
return lhs.id_ == rhs.id_ && lhs.matrix_ == rhs.matrix_;
}
};
@@ -45,7 +45,7 @@ class RasterCacheKey {
using Map = std::unordered_map<RasterCacheKey, Value, Hash, Equal>;
private:
uint32_t picture_id_;
ID id_;
// ctm where only fractional (0-1) translations are preserved:
// matrix_ = ctm;
@@ -54,6 +54,13 @@ class RasterCacheKey {
SkMatrix matrix_;
};
// The ID is the uint32_t picture uniqueID
using PictureRasterCacheKey = RasterCacheKey<uint32_t>;
class Layer;
using LayerRasterCacheKey = RasterCacheKey<std::shared_ptr<Layer>>;
} // namespace flow
#endif // FLUTTER_FLOW_RASTER_CACHE_KEY_H_

View File

@@ -33,14 +33,14 @@ TEST(RasterCache, ThresholdIsRespected) {
sk_sp<SkImage> image;
sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 1
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 1
cache.SweepAfterFrame();
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 2
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 2
cache.SweepAfterFrame();
ASSERT_TRUE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 3
ASSERT_TRUE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 3
cache.SweepAfterFrame();
}
@@ -55,14 +55,14 @@ TEST(RasterCache, ThresholdIsRespectedWhenZero) {
sk_sp<SkImage> image;
sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 1
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 1
cache.SweepAfterFrame();
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 2
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 2
cache.SweepAfterFrame();
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 3
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 3
cache.SweepAfterFrame();
}
@@ -77,19 +77,19 @@ TEST(RasterCache, SweepsRemoveUnusedFrames) {
sk_sp<SkImage> image;
sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 1
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 1
cache.SweepAfterFrame();
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 2
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 2
cache.SweepAfterFrame();
ASSERT_TRUE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 3
ASSERT_TRUE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 3
cache.SweepAfterFrame();
ASSERT_TRUE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 4
ASSERT_TRUE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 4
cache.SweepAfterFrame();
cache.SweepAfterFrame(); // Extra frame without a preroll image access.
ASSERT_FALSE(cache.GetPrerolledImage(NULL, picture.get(), matrix, srgb.get(),
true, false)); // 5
ASSERT_FALSE(cache.Prepare(NULL, picture.get(), matrix, srgb.get(), true,
false)); // 5
}

View File

@@ -187,9 +187,12 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
for (auto& task : paint_tasks_) {
FML_DCHECK(task.surface);
SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
Layer::PaintContext context = {*canvas, frame.context().frame_time(),
Layer::PaintContext context = {*canvas,
frame.context().frame_time(),
frame.context().engine_time(),
frame.context().texture_registry(), false};
frame.context().texture_registry(),
&frame.context().raster_cache(),
false};
canvas->restoreToCount(1);
canvas->save();
canvas->clear(task.background_color);