未验证 提交 efe3f456 编写于 作者: J Jim Graham 提交者: GitHub

Fix child caching in opacity_layer (#17914)

Choose a child more likely to remain stable from frame to frame as the target to cache in the OpacityLayer.
上级 17737e6f
...@@ -55,7 +55,7 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { ...@@ -55,7 +55,7 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
#ifndef SUPPORT_FRACTIONAL_TRANSLATION #ifndef SUPPORT_FRACTIONAL_TRANSLATION
child_matrix = RasterCache::GetIntegralTransCTM(child_matrix); child_matrix = RasterCache::GetIntegralTransCTM(child_matrix);
#endif #endif
TryToPrepareRasterCache(context, container, child_matrix); TryToPrepareRasterCache(context, GetCacheableChild(), child_matrix);
} }
// Restore cull_rect // Restore cull_rect
...@@ -78,7 +78,7 @@ void OpacityLayer::Paint(PaintContext& context) const { ...@@ -78,7 +78,7 @@ void OpacityLayer::Paint(PaintContext& context) const {
#endif #endif
if (context.raster_cache && if (context.raster_cache &&
context.raster_cache->Draw(GetChildContainer(), context.raster_cache->Draw(GetCacheableChild(),
*context.leaf_nodes_canvas, &paint)) { *context.leaf_nodes_canvas, &paint)) {
return; return;
} }
...@@ -118,4 +118,13 @@ ContainerLayer* OpacityLayer::GetChildContainer() const { ...@@ -118,4 +118,13 @@ ContainerLayer* OpacityLayer::GetChildContainer() const {
return static_cast<ContainerLayer*>(layers()[0].get()); return static_cast<ContainerLayer*>(layers()[0].get());
} }
Layer* OpacityLayer::GetCacheableChild() const {
ContainerLayer* child_container = GetChildContainer();
if (child_container->layers().size() == 1) {
return child_container->layers()[0].get();
}
return child_container;
}
} // namespace flutter } // namespace flutter
...@@ -38,8 +38,58 @@ class OpacityLayer : public ContainerLayer { ...@@ -38,8 +38,58 @@ class OpacityLayer : public ContainerLayer {
#endif // defined(OS_FUCHSIA) #endif // defined(OS_FUCHSIA)
private: private:
/**
* @brief Returns the ContainerLayer used to hold all of the children
* of the OpacityLayer.
*
* Often opacity layers will only have a single child since the associated
* Flutter widget is specified with only a single child widget pointer.
* But depending on the structure of the child tree that single widget at
* the framework level can turn into multiple children at the engine
* API level since there is no guarantee of a 1:1 correspondence of widgets
* to engine layers. This synthetic child container layer is established to
* hold all of the children in a single layer so that we can cache their
* output, but this synthetic layer will typically not be the best choice
* for the layer cache since the synthetic container is created fresh with
* each new OpacityLayer, and so may not be stable from frame to frame.
*
* @see GetCacheableChild()
* @return the ContainerLayer child used to hold the children
*/
ContainerLayer* GetChildContainer() const; ContainerLayer* GetChildContainer() const;
/**
* @brief Returns the best choice for a Layer object that can be used
* in RasterCache operations to cache the children of the OpacityLayer.
*
* The returned Layer must represent all children and try to remain stable
* if the OpacityLayer is reconstructed in subsequent frames of the scene.
*
* Note that since the synthetic child container returned from the
* GetChildContainer() method is created fresh with each new OpacityLayer,
* its return value will not be a good candidate for caching. But if the
* standard recommendations for animations are followed and the child widget
* is wrapped with a RepaintBoundary widget at the framework level, then
* the synthetic child container should contain the same single child layer
* on each frame. Under those conditions, that single child of the child
* container will be the best candidate for caching in the RasterCache
* and this method will return that single child if possible to improve
* the performance of caching the children.
*
* Note that if GetCacheableChild() does not find a single stable child of
* the child container it will return the child container as a fallback.
* Even though that child is new in each frame of an animation and thus we
* cannot reuse the cached layer raster between animation frames, the single
* container child will allow us to paint the child onto an offscreen buffer
* during Preroll() which reduces one render target switch compared to
* painting the child on the fly via an AutoSaveLayer in Paint() and thus
* still improves our performance.
*
* @see GetChildContainer()
* @return the best candidate Layer for caching the children
*/
Layer* GetCacheableChild() const;
SkAlpha alpha_; SkAlpha alpha_;
SkPoint offset_; SkPoint offset_;
SkRRect frameRRect_; SkRRect frameRRect_;
......
...@@ -53,6 +53,71 @@ TEST_F(OpacityLayerTest, PaintBeforePreollDies) { ...@@ -53,6 +53,71 @@ TEST_F(OpacityLayerTest, PaintBeforePreollDies) {
} }
#endif #endif
TEST_F(OpacityLayerTest, ChildIsCached) {
const SkAlpha alpha_half = 255 / 2;
auto initial_transform = SkMatrix::MakeTrans(50.0, 25.5);
auto other_transform = SkMatrix::MakeScale(1.0, 2.0);
const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
auto mock_layer = std::make_shared<MockLayer>(child_path);
auto layer =
std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f));
layer->Add(mock_layer);
SkMatrix cache_ctm = initial_transform;
SkCanvas cache_canvas;
cache_canvas.setMatrix(cache_ctm);
SkCanvas other_canvas;
other_canvas.setMatrix(other_transform);
use_mock_raster_cache();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas));
EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), cache_canvas));
layer->Preroll(preroll_context(), initial_transform);
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas));
EXPECT_TRUE(raster_cache()->Draw(mock_layer.get(), cache_canvas));
}
TEST_F(OpacityLayerTest, ChildrenNotCached) {
const SkAlpha alpha_half = 255 / 2;
auto initial_transform = SkMatrix::MakeTrans(50.0, 25.5);
auto other_transform = SkMatrix::MakeScale(1.0, 2.0);
const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
auto mock_layer1 = std::make_shared<MockLayer>(child_path1);
auto mock_layer2 = std::make_shared<MockLayer>(child_path2);
auto layer =
std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f));
layer->Add(mock_layer1);
layer->Add(mock_layer2);
SkMatrix cache_ctm = initial_transform;
SkCanvas cache_canvas;
cache_canvas.setMatrix(cache_ctm);
SkCanvas other_canvas;
other_canvas.setMatrix(other_transform);
use_mock_raster_cache();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas));
EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas));
EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas));
EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas));
layer->Preroll(preroll_context(), initial_transform);
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas));
EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas));
EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas));
EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas));
}
TEST_F(OpacityLayerTest, FullyOpaque) { TEST_F(OpacityLayerTest, FullyOpaque) {
const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f); const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
......
...@@ -86,7 +86,7 @@ static bool IsPictureWorthRasterizing(SkPicture* picture, ...@@ -86,7 +86,7 @@ static bool IsPictureWorthRasterizing(SkPicture* picture,
} }
/// @note Procedure doesn't copy all closures. /// @note Procedure doesn't copy all closures.
static RasterCacheResult Rasterize( static std::unique_ptr<RasterCacheResult> Rasterize(
GrContext* context, GrContext* context,
const SkMatrix& ctm, const SkMatrix& ctm,
SkColorSpace* dst_color_space, SkColorSpace* dst_color_space,
...@@ -105,7 +105,7 @@ static RasterCacheResult Rasterize( ...@@ -105,7 +105,7 @@ static RasterCacheResult Rasterize(
: SkSurface::MakeRaster(image_info); : SkSurface::MakeRaster(image_info);
if (!surface) { if (!surface) {
return {}; return nullptr;
} }
SkCanvas* canvas = surface->getCanvas(); SkCanvas* canvas = surface->getCanvas();
...@@ -118,14 +118,16 @@ static RasterCacheResult Rasterize( ...@@ -118,14 +118,16 @@ static RasterCacheResult Rasterize(
DrawCheckerboard(canvas, logical_rect); DrawCheckerboard(canvas, logical_rect);
} }
return {surface->makeImageSnapshot(), logical_rect}; return std::make_unique<RasterCacheResult>(surface->makeImageSnapshot(),
logical_rect);
} }
RasterCacheResult RasterizePicture(SkPicture* picture, std::unique_ptr<RasterCacheResult> RasterCache::RasterizePicture(
GrContext* context, SkPicture* picture,
const SkMatrix& ctm, GrContext* context,
SkColorSpace* dst_color_space, const SkMatrix& ctm,
bool checkerboard) { SkColorSpace* dst_color_space,
bool checkerboard) const {
return Rasterize(context, ctm, dst_color_space, checkerboard, return Rasterize(context, ctm, dst_color_space, checkerboard,
picture->cullRect(), picture->cullRect(),
[=](SkCanvas* canvas) { canvas->drawPicture(picture); }); [=](SkCanvas* canvas) { canvas->drawPicture(picture); });
...@@ -138,34 +140,41 @@ void RasterCache::Prepare(PrerollContext* context, ...@@ -138,34 +140,41 @@ void RasterCache::Prepare(PrerollContext* context,
Entry& entry = layer_cache_[cache_key]; Entry& entry = layer_cache_[cache_key];
entry.access_count++; entry.access_count++;
entry.used_this_frame = true; entry.used_this_frame = true;
if (!entry.image.is_valid()) { if (!entry.image) {
entry.image = Rasterize( entry.image = RasterizeLayer(context, layer, ctm, checkerboard_images_);
context->gr_context, ctm, context->dst_color_space,
checkerboard_images_, layer->paint_bounds(),
[layer, context](SkCanvas* canvas) {
SkISize canvas_size = canvas->getBaseLayerSize();
SkNWayCanvas internal_nodes_canvas(canvas_size.width(),
canvas_size.height());
internal_nodes_canvas.addCanvas(canvas);
Layer::PaintContext paintContext = {
(SkCanvas*)&internal_nodes_canvas,
canvas,
context->gr_context,
nullptr,
context->raster_time,
context->ui_time,
context->texture_registry,
context->has_platform_view ? nullptr : context->raster_cache,
context->checkerboard_offscreen_layers,
context->frame_physical_depth,
context->frame_device_pixel_ratio};
if (layer->needs_painting()) {
layer->Paint(paintContext);
}
});
} }
} }
std::unique_ptr<RasterCacheResult> RasterCache::RasterizeLayer(
PrerollContext* context,
Layer* layer,
const SkMatrix& ctm,
bool checkerboard) const {
return Rasterize(
context->gr_context, ctm, context->dst_color_space, checkerboard,
layer->paint_bounds(), [layer, context](SkCanvas* canvas) {
SkISize canvas_size = canvas->getBaseLayerSize();
SkNWayCanvas internal_nodes_canvas(canvas_size.width(),
canvas_size.height());
internal_nodes_canvas.addCanvas(canvas);
Layer::PaintContext paintContext = {
(SkCanvas*)&internal_nodes_canvas, // internal_nodes_canvas
canvas, // leaf_nodes_canvas
context->gr_context, // gr_context
nullptr, // view_embedder
context->raster_time,
context->ui_time,
context->texture_registry,
context->has_platform_view ? nullptr : context->raster_cache,
context->checkerboard_offscreen_layers,
context->frame_physical_depth,
context->frame_device_pixel_ratio};
if (layer->needs_painting()) {
layer->Paint(paintContext);
}
});
}
bool RasterCache::Prepare(GrContext* context, bool RasterCache::Prepare(GrContext* context,
SkPicture* picture, SkPicture* picture,
const SkMatrix& transformation_matrix, const SkMatrix& transformation_matrix,
...@@ -202,7 +211,7 @@ bool RasterCache::Prepare(GrContext* context, ...@@ -202,7 +211,7 @@ bool RasterCache::Prepare(GrContext* context,
return false; return false;
} }
if (!entry.image.is_valid()) { if (!entry.image) {
entry.image = RasterizePicture(picture, context, transformation_matrix, entry.image = RasterizePicture(picture, context, transformation_matrix,
dst_color_space, checkerboard_images_); dst_color_space, checkerboard_images_);
picture_cached_this_frame_++; picture_cached_this_frame_++;
...@@ -221,8 +230,8 @@ bool RasterCache::Draw(const SkPicture& picture, SkCanvas& canvas) const { ...@@ -221,8 +230,8 @@ bool RasterCache::Draw(const SkPicture& picture, SkCanvas& canvas) const {
entry.access_count++; entry.access_count++;
entry.used_this_frame = true; entry.used_this_frame = true;
if (entry.image.is_valid()) { if (entry.image) {
entry.image.draw(canvas); entry.image->draw(canvas);
return true; return true;
} }
...@@ -242,8 +251,8 @@ bool RasterCache::Draw(const Layer* layer, ...@@ -242,8 +251,8 @@ bool RasterCache::Draw(const Layer* layer,
entry.access_count++; entry.access_count++;
entry.used_this_frame = true; entry.used_this_frame = true;
if (entry.image.is_valid()) { if (entry.image) {
entry.image.draw(canvas, paint); entry.image->draw(canvas, paint);
return true; return true;
} }
...@@ -266,6 +275,14 @@ size_t RasterCache::GetCachedEntriesCount() const { ...@@ -266,6 +275,14 @@ size_t RasterCache::GetCachedEntriesCount() const {
return layer_cache_.size() + picture_cache_.size(); return layer_cache_.size() + picture_cache_.size();
} }
size_t RasterCache::GetLayerCachedEntriesCount() const {
return layer_cache_.size();
}
size_t RasterCache::GetPictureCachedEntriesCount() const {
return picture_cache_.size();
}
void RasterCache::SetCheckboardCacheImages(bool checkerboard) { void RasterCache::SetCheckboardCacheImages(bool checkerboard) {
if (checkerboard_images_ == checkerboard) { if (checkerboard_images_ == checkerboard) {
return; return;
...@@ -287,15 +304,17 @@ void RasterCache::TraceStatsToTimeline() const { ...@@ -287,15 +304,17 @@ void RasterCache::TraceStatsToTimeline() const {
size_t picture_cache_bytes = 0; size_t picture_cache_bytes = 0;
for (const auto& item : layer_cache_) { for (const auto& item : layer_cache_) {
const auto dimensions = item.second.image.image_dimensions();
layer_cache_count++; layer_cache_count++;
layer_cache_bytes += dimensions.width() * dimensions.height() * 4; if (item.second.image) {
layer_cache_bytes += item.second.image->image_bytes();
}
} }
for (const auto& item : picture_cache_) { for (const auto& item : picture_cache_) {
const auto dimensions = item.second.image.image_dimensions();
picture_cache_count++; picture_cache_count++;
picture_cache_bytes += dimensions.width() * dimensions.height() * 4; if (item.second.image) {
picture_cache_bytes += item.second.image->image_bytes();
}
} }
FML_TRACE_COUNTER("flutter", "RasterCache", FML_TRACE_COUNTER("flutter", "RasterCache",
......
...@@ -19,22 +19,22 @@ namespace flutter { ...@@ -19,22 +19,22 @@ namespace flutter {
class RasterCacheResult { class RasterCacheResult {
public: public:
RasterCacheResult() = default;
RasterCacheResult(const RasterCacheResult& other) = default;
RasterCacheResult(sk_sp<SkImage> image, const SkRect& logical_rect); RasterCacheResult(sk_sp<SkImage> image, const SkRect& logical_rect);
operator bool() const { return static_cast<bool>(image_); } virtual ~RasterCacheResult() = default;
bool is_valid() const { return static_cast<bool>(image_); }; virtual void draw(SkCanvas& canvas, const SkPaint* paint = nullptr) const;
void draw(SkCanvas& canvas, const SkPaint* paint = nullptr) const; virtual SkISize image_dimensions() const {
SkISize image_dimensions() const {
return image_ ? image_->dimensions() : SkISize::Make(0, 0); return image_ ? image_->dimensions() : SkISize::Make(0, 0);
}; };
virtual int64_t image_bytes() const {
return image_ ? image_->dimensions().area() *
image_->imageInfo().bytesPerPixel()
: 0;
};
private: private:
sk_sp<SkImage> image_; sk_sp<SkImage> image_;
SkRect logical_rect_; SkRect logical_rect_;
...@@ -54,6 +54,50 @@ class RasterCache { ...@@ -54,6 +54,50 @@ class RasterCache {
size_t access_threshold = 3, size_t access_threshold = 3,
size_t picture_cache_limit_per_frame = kDefaultPictureCacheLimitPerFrame); size_t picture_cache_limit_per_frame = kDefaultPictureCacheLimitPerFrame);
virtual ~RasterCache() = default;
/**
* @brief Rasterize a picture object and produce a RasterCacheResult
* to be stored in the cache.
*
* @param picture the SkPicture object to be cached.
* @param context the GrContext used for rendering.
* @param ctm the transformation matrix used for rendering.
* @param dst_color_space the destination color space that the cached
* rendering will be drawn into
* @param checkerboard a flag indicating whether or not a checkerboard
* pattern should be rendered into the cached image for debug
* analysis
* @return a RasterCacheResult that can draw the rendered picture into
* the destination using a simple image blit
*/
virtual std::unique_ptr<RasterCacheResult> RasterizePicture(
SkPicture* picture,
GrContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard) const;
/**
* @brief Rasterize an engine Layer and produce a RasterCacheResult
* to be stored in the cache.
*
* @param context the PrerollContext containing important information
* needed for rendering a layer.
* @param layer the Layer object to be cached.
* @param ctm the transformation matrix used for rendering.
* @param checkerboard a flag indicating whether or not a checkerboard
* pattern should be rendered into the cached image for debug
* analysis
* @return a RasterCacheResult that can draw the rendered layer into
* the destination using a simple image blit
*/
virtual std::unique_ptr<RasterCacheResult> RasterizeLayer(
PrerollContext* context,
Layer* layer,
const SkMatrix& ctm,
bool checkerboard) const;
static SkIRect GetDeviceBounds(const SkRect& rect, const SkMatrix& ctm) { static SkIRect GetDeviceBounds(const SkRect& rect, const SkMatrix& ctm) {
SkRect device_rect; SkRect device_rect;
ctm.mapRect(&device_rect, rect); ctm.mapRect(&device_rect, rect);
...@@ -123,11 +167,15 @@ class RasterCache { ...@@ -123,11 +167,15 @@ class RasterCache {
size_t GetCachedEntriesCount() const; size_t GetCachedEntriesCount() const;
size_t GetLayerCachedEntriesCount() const;
size_t GetPictureCachedEntriesCount() const;
private: private:
struct Entry { struct Entry {
bool used_this_frame = false; bool used_this_frame = false;
size_t access_count = 0; size_t access_count = 0;
RasterCacheResult image; std::unique_ptr<RasterCacheResult> image;
}; };
template <class Cache> template <class Cache>
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "flutter/fml/macros.h" #include "flutter/fml/macros.h"
#include "flutter/testing/canvas_test.h" #include "flutter/testing/canvas_test.h"
#include "flutter/testing/mock_canvas.h" #include "flutter/testing/mock_canvas.h"
#include "flutter/testing/mock_raster_cache.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h" #include "third_party/skia/include/utils/SkNWayCanvas.h"
...@@ -24,6 +25,13 @@ namespace testing { ...@@ -24,6 +25,13 @@ namespace testing {
// |Layer|'s. // |Layer|'s.
// |LayerTest| is a default implementation based on |::testing::Test|. // |LayerTest| is a default implementation based on |::testing::Test|.
// //
// By default the preroll and paint contexts will not use a raster cache.
// If a test needs to verify the proper operation of a layer in the presence
// of a raster cache then a number of options can be enabled by using the
// methods |LayerTestBase::use_null_raster_cache()|,
// |LayerTestBase::use_mock_raster_cache()| or
// |LayerTestBase::use_skia_raster_cache()|
//
// |BaseT| should be the base test type, such as |::testing::Test| below. // |BaseT| should be the base test type, such as |::testing::Test| below.
template <typename BaseT> template <typename BaseT>
class LayerTestBase : public CanvasTestBase<BaseT> { class LayerTestBase : public CanvasTestBase<BaseT> {
...@@ -55,18 +63,77 @@ class LayerTestBase : public CanvasTestBase<BaseT> { ...@@ -55,18 +63,77 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
false, /* checkerboard_offscreen_layers */ false, /* checkerboard_offscreen_layers */
100.0f, /* frame_physical_depth */ 100.0f, /* frame_physical_depth */
1.0f, /* frame_device_pixel_ratio */ 1.0f, /* frame_device_pixel_ratio */
}) {} }) {
use_null_raster_cache();
}
/**
* @brief Use no raster cache in the preroll_context() and
* paint_context() structures.
*
* This method must be called before using the preroll_context() and
* paint_context() structures in calls to the Layer::Preroll() and
* Layer::Paint() methods. This is the default mode of operation.
*
* @see use_mock_raster_cache()
* @see use_skia_raster_cache()
*/
void use_null_raster_cache() { set_raster_cache_(nullptr); }
/**
* @brief Use a mock raster cache in the preroll_context() and
* paint_context() structures.
*
* This method must be called before using the preroll_context() and
* paint_context() structures in calls to the Layer::Preroll() and
* Layer::Paint() methods. The mock raster cache behaves like a normal
* raster cache with respect to decisions about when layers and pictures
* should be cached, but it does not incur the overhead of rendering the
* layers or caching the resulting pixels.
*
* @see use_null_raster_cache()
* @see use_skia_raster_cache()
*/
void use_mock_raster_cache() {
set_raster_cache_(std::make_unique<MockRasterCache>());
}
/**
* @brief Use a normal raster cache in the preroll_context() and
* paint_context() structures.
*
* This method must be called before using the preroll_context() and
* paint_context() structures in calls to the Layer::Preroll() and
* Layer::Paint() methods. The Skia raster cache will behave identically
* to the raster cache typically used when handling a frame on a device
* including rendering the contents of pictures and layers to an
* SkImage, but using a software rather than a hardware renderer.
*
* @see use_null_raster_cache()
* @see use_mock_raster_cache()
*/
void use_skia_raster_cache() {
set_raster_cache_(std::make_unique<RasterCache>());
}
TextureRegistry& texture_regitry() { return texture_registry_; } TextureRegistry& texture_regitry() { return texture_registry_; }
RasterCache* raster_cache() { return raster_cache_.get(); }
PrerollContext* preroll_context() { return &preroll_context_; } PrerollContext* preroll_context() { return &preroll_context_; }
Layer::PaintContext& paint_context() { return paint_context_; } Layer::PaintContext& paint_context() { return paint_context_; }
private: private:
void set_raster_cache_(std::unique_ptr<RasterCache> raster_cache) {
raster_cache_ = std::move(raster_cache);
preroll_context_.raster_cache = raster_cache_.get();
paint_context_.raster_cache = raster_cache_.get();
}
Stopwatch raster_time_; Stopwatch raster_time_;
Stopwatch ui_time_; Stopwatch ui_time_;
MutatorsStack mutators_stack_; MutatorsStack mutators_stack_;
TextureRegistry texture_registry_; TextureRegistry texture_registry_;
std::unique_ptr<RasterCache> raster_cache_;
PrerollContext preroll_context_; PrerollContext preroll_context_;
Layer::PaintContext paint_context_; Layer::PaintContext paint_context_;
......
...@@ -71,10 +71,13 @@ source_set("skia") { ...@@ -71,10 +71,13 @@ source_set("skia") {
"canvas_test.h", "canvas_test.h",
"mock_canvas.cc", "mock_canvas.cc",
"mock_canvas.h", "mock_canvas.h",
"mock_raster_cache.cc",
"mock_raster_cache.h",
] ]
public_deps = [ public_deps = [
":testing_lib", ":testing_lib",
"//flutter/flow",
"//third_party/skia", "//third_party/skia",
] ]
} }
......
// Copyright 2013 The Flutter 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 "flutter/testing/mock_raster_cache.h"
#include "flutter/flow/layers/layer.h"
namespace flutter {
namespace testing {
MockRasterCacheResult::MockRasterCacheResult(SkIRect device_rect)
: RasterCacheResult(nullptr, SkRect::MakeEmpty()),
device_rect_(device_rect) {}
std::unique_ptr<RasterCacheResult> MockRasterCache::RasterizePicture(
SkPicture* picture,
GrContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard) const {
SkRect logical_rect = picture->cullRect();
SkIRect cache_rect = RasterCache::GetDeviceBounds(logical_rect, ctm);
return std::make_unique<MockRasterCacheResult>(cache_rect);
}
std::unique_ptr<RasterCacheResult> MockRasterCache::RasterizeLayer(
PrerollContext* context,
Layer* layer,
const SkMatrix& ctm,
bool checkerboard) const {
SkRect logical_rect = layer->paint_bounds();
SkIRect cache_rect = RasterCache::GetDeviceBounds(logical_rect, ctm);
return std::make_unique<MockRasterCacheResult>(cache_rect);
}
} // namespace testing
} // namespace flutter
// Copyright 2013 The Flutter 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 TESTING_MOCK_RASTER_CACHE_H_
#define TESTING_MOCK_RASTER_CACHE_H_
#include "flutter/flow/raster_cache.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPicture.h"
namespace flutter {
namespace testing {
/**
* @brief A RasterCacheResult implementation that represents a cached Layer or
* SkPicture without the overhead of storage.
*
* This implementation is used by MockRasterCache only for testing proper usage
* of the RasterCache in layer unit tests.
*/
class MockRasterCacheResult : public RasterCacheResult {
public:
MockRasterCacheResult(SkIRect device_rect);
void draw(SkCanvas& canvas, const SkPaint* paint = nullptr) const override{};
SkISize image_dimensions() const override { return device_rect_.size(); };
int64_t image_bytes() const override {
return image_dimensions().area() *
SkColorTypeBytesPerPixel(kBGRA_8888_SkColorType);
}
private:
SkIRect device_rect_;
};
/**
* @brief A RasterCache implementation that simulates the act of rendering a
* Layer or SkPicture without the overhead of rasterization or pixel storage.
* This implementation is used only for testing proper usage of the RasterCache
* in layer unit tests.
*/
class MockRasterCache : public RasterCache {
public:
std::unique_ptr<RasterCacheResult> RasterizePicture(
SkPicture* picture,
GrContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard) const override;
std::unique_ptr<RasterCacheResult> RasterizeLayer(
PrerollContext* context,
Layer* layer,
const SkMatrix& ctm,
bool checkerboard) const override;
};
} // namespace testing
} // namespace flutter
#endif // TESTING_MOCK_RASTER_CACHE_H_
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册