add pixel snapping conditional on presence of raster cache (flutter/engine#35981)

This commit is contained in:
Jonah Williams 2022-09-08 18:10:01 -07:00 committed by GitHub
parent ca593fb04c
commit c4d3db0133
17 changed files with 181 additions and 118 deletions

View File

@ -11,14 +11,16 @@
namespace flutter {
std::optional<SkRect> FrameDamage::ComputeClipRect(
flutter::LayerTree& layer_tree) {
flutter::LayerTree& layer_tree,
bool has_raster_cache) {
if (layer_tree.root_layer()) {
PaintRegionMap empty_paint_region_map;
DiffContext context(layer_tree.frame_size(),
layer_tree.device_pixel_ratio(),
layer_tree.paint_region_map(),
prev_layer_tree_ ? prev_layer_tree_->paint_region_map()
: empty_paint_region_map);
: empty_paint_region_map,
has_raster_cache);
context.PushCullRect(SkRect::MakeIWH(layer_tree.frame_size().width(),
layer_tree.frame_size().height()));
{
@ -119,7 +121,9 @@ RasterStatus CompositorContext::ScopedFrame::Raster(
TRACE_EVENT0("flutter", "CompositorContext::ScopedFrame::Raster");
std::optional<SkRect> clip_rect =
frame_damage ? frame_damage->ComputeClipRect(layer_tree) : std::nullopt;
frame_damage
? frame_damage->ComputeClipRect(layer_tree, !ignore_raster_cache)
: std::nullopt;
bool root_needs_readback = layer_tree.Preroll(
*this, ignore_raster_cache, clip_rect ? *clip_rect : kGiantRect);

View File

@ -81,7 +81,8 @@ class FrameDamage {
// If previous layer tree is not specified, clip rect will be nullopt,
// but the paint region of layer_tree will be calculated so that it can be
// used for diffing of subsequent frames.
std::optional<SkRect> ComputeClipRect(flutter::LayerTree& layer_tree);
std::optional<SkRect> ComputeClipRect(flutter::LayerTree& layer_tree,
bool has_raster_cache);
// See Damage::frame_damage.
std::optional<SkIRect> GetFrameDamage() const {

View File

@ -10,12 +10,14 @@ namespace flutter {
DiffContext::DiffContext(SkISize frame_size,
double frame_device_pixel_ratio,
PaintRegionMap& this_frame_paint_region_map,
const PaintRegionMap& last_frame_paint_region_map)
const PaintRegionMap& last_frame_paint_region_map,
bool has_raster_cache)
: rects_(std::make_shared<std::vector<SkRect>>()),
frame_size_(frame_size),
frame_device_pixel_ratio_(frame_device_pixel_ratio),
this_frame_paint_region_map_(this_frame_paint_region_map),
last_frame_paint_region_map_(last_frame_paint_region_map) {}
last_frame_paint_region_map_(last_frame_paint_region_map),
has_raster_cache_(has_raster_cache) {}
void DiffContext::BeginSubtree() {
state_stack_.push_back(state_);

View File

@ -45,7 +45,8 @@ class DiffContext {
explicit DiffContext(SkISize frame_size,
double device_pixel_aspect_ratio,
PaintRegionMap& this_frame_paint_region_map,
const PaintRegionMap& last_frame_paint_region_map);
const PaintRegionMap& last_frame_paint_region_map,
bool has_raster_cache);
// Starts a new subtree.
void BeginSubtree();
@ -156,6 +157,11 @@ class DiffContext {
// frame layer tree.
PaintRegion GetOldLayerPaintRegion(const Layer* layer) const;
// Whether or not a raster cache is being used. If so, we must snap
// all transformations to physical pixels if the layer may be raster
// cached.
bool has_raster_cache() const { return has_raster_cache_; }
class Statistics {
public:
// Picture replaced by different picture
@ -223,6 +229,7 @@ class DiffContext {
PaintRegionMap& this_frame_paint_region_map_;
const PaintRegionMap& last_frame_paint_region_map_;
bool has_raster_cache_;
void AddDamage(const SkRect& rect);

View File

@ -8,6 +8,7 @@
#include "flutter/flow/layers/cacheable_layer.h"
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/paint_utils.h"
#include "flutter/flow/raster_cache_util.h"
namespace flutter {
@ -32,6 +33,10 @@ class ClipShapeLayer : public CacheableContainerLayer {
context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
}
}
if (UsesSaveLayer() && context->has_raster_cache()) {
context->SetTransform(
RasterCacheUtil::GetIntegralTransCTM(context->GetTransform()));
}
if (context->PushCullRect(clip_shape_bounds())) {
DiffChildren(context, prev);
}
@ -45,12 +50,16 @@ class ClipShapeLayer : public CacheableContainerLayer {
if (!context->cull_rect.intersect(clip_shape_bounds())) {
context->cull_rect.setEmpty();
}
SkMatrix child_matrix = matrix;
if (context->raster_cache && uses_save_layer) {
child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix);
}
// We can use the raster_cache for children only when the use_save_layer is
// true so if use_save_layer is false we pass the layer_raster_item is
// nullptr which mean we don't do raster cache logic.
AutoCache cache =
AutoCache(uses_save_layer ? layer_raster_cache_item_.get() : nullptr,
context, matrix);
context, child_matrix);
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer());
@ -89,6 +98,9 @@ class ClipShapeLayer : public CacheableContainerLayer {
AutoCachePaint cache_paint(context);
if (context.raster_cache) {
context.internal_nodes_canvas->setMatrix(
RasterCacheUtil::GetIntegralTransCTM(
context.leaf_nodes_canvas->getTotalMatrix()));
if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) {
return;
}

View File

@ -27,6 +27,11 @@ void ColorFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
}
}
if (context->has_raster_cache()) {
context->SetTransform(
RasterCacheUtil::GetIntegralTransCTM(context->GetTransform()));
}
DiffChildren(context, prev);
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
@ -38,7 +43,12 @@ void ColorFilterLayer::Preroll(PrerollContext* context,
Layer::AutoPrerollSaveLayerState::Create(context);
AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context, matrix);
ContainerLayer::Preroll(context, matrix);
SkMatrix child_matrix = matrix;
if (context->raster_cache) {
child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix);
}
ContainerLayer::Preroll(context, child_matrix);
// We always use a saveLayer (or a cached rendering), so we
// can always apply opacity in those cases.
context->subtree_can_inherit_opacity = true;
@ -49,6 +59,9 @@ void ColorFilterLayer::Paint(PaintContext& context) const {
FML_DCHECK(needs_painting(context));
if (context.raster_cache) {
context.internal_nodes_canvas->setMatrix(
RasterCacheUtil::GetIntegralTransCTM(
context.leaf_nodes_canvas->getTotalMatrix()));
AutoCachePaint cache_paint(context);
if (layer_raster_cache_item_->IsCacheChildren()) {
cache_paint.setColorFilter(filter_.get());

View File

@ -52,6 +52,10 @@ void DisplayListLayer::Diff(DiffContext* context, const Layer* old_layer) {
#endif
}
context->PushTransform(SkMatrix::Translate(offset_.x(), offset_.y()));
if (context->has_raster_cache()) {
context->SetTransform(
RasterCacheUtil::GetIntegralTransCTM(context->GetTransform()));
}
context->AddLayerBounds(display_list()->bounds());
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}
@ -95,9 +99,13 @@ void DisplayListLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "DisplayListLayer::Preroll");
DisplayList* disp_list = display_list();
SkMatrix child_matrix = matrix;
if (context->raster_cache) {
child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix);
}
AutoCache cache =
AutoCache(display_list_raster_cache_item_.get(), context, matrix);
AutoCache(display_list_raster_cache_item_.get(), context, child_matrix);
if (disp_list->can_apply_group_opacity()) {
context->subtree_can_inherit_opacity = true;
}
@ -111,6 +119,10 @@ void DisplayListLayer::Paint(PaintContext& context) const {
SkAutoCanvasRestore save(context.leaf_nodes_canvas, true);
context.leaf_nodes_canvas->translate(offset_.x(), offset_.y());
if (context.raster_cache) {
context.leaf_nodes_canvas->setMatrix(RasterCacheUtil::GetIntegralTransCTM(
context.leaf_nodes_canvas->getTotalMatrix()));
}
if (context.raster_cache && display_list_raster_cache_item_) {
AutoCachePaint cache_paint(context);

View File

@ -325,10 +325,25 @@ TEST_F(DisplayListLayerDiffTest, FractionalTranslation) {
tree1.root()->Add(
CreateDisplayListLayer(display_list, SkPoint::Make(0.5, 0.5)));
auto damage = DiffLayerTree(tree1, MockLayerTree());
auto damage =
DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0, 0,
/*use_raster_cache=*/false);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 61, 61));
}
TEST_F(DisplayListLayerDiffTest, FractionalTranslationWithRasterCache) {
auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1);
MockLayerTree tree1;
tree1.root()->Add(
CreateDisplayListLayer(display_list, SkPoint::Make(0.5, 0.5)));
auto damage =
DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0, 0,
/*use_raster_cache=*/true);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(11, 11, 61, 61));
}
TEST_F(DisplayListLayerDiffTest, DisplayListCompare) {
MockLayerTree tree1;
auto display_list1 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1);

View File

@ -25,6 +25,11 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
}
}
if (context->has_raster_cache()) {
context->SetTransform(
RasterCacheUtil::GetIntegralTransCTM(context->GetTransform()));
}
if (filter_) {
auto filter = filter_->makeWithLocalMatrix(context->GetTransform());
if (filter) {
@ -51,7 +56,11 @@ void ImageFilterLayer::Preroll(PrerollContext* context,
AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context, matrix);
SkRect child_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_bounds);
SkMatrix child_matrix = matrix;
if (context->raster_cache) {
child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix);
}
PrerollChildren(context, child_matrix, &child_bounds);
// We always paint with a saveLayer (or a cached rendering),
// so we can always apply opacity in any of those cases.
@ -74,7 +83,7 @@ void ImageFilterLayer::Preroll(PrerollContext* context,
// So in here we reset the LayerRasterCacheItem cache state.
layer_raster_cache_item_->MarkNotCacheChildren();
transformed_filter_ = filter_->makeWithLocalMatrix(matrix);
transformed_filter_ = filter_->makeWithLocalMatrix(child_matrix);
if (transformed_filter_) {
layer_raster_cache_item_->MarkCacheChildren();
}
@ -86,6 +95,9 @@ void ImageFilterLayer::Paint(PaintContext& context) const {
AutoCachePaint cache_paint(context);
if (context.raster_cache) {
context.internal_nodes_canvas->setMatrix(
RasterCacheUtil::GetIntegralTransCTM(
context.leaf_nodes_canvas->getTotalMatrix()));
if (layer_raster_cache_item_->IsCacheChildren()) {
cache_paint.setImageFilter(transformed_filter_.get());
}

View File

@ -5,6 +5,7 @@
#include "flutter/flow/layers/opacity_layer.h"
#include "flutter/flow/layers/cacheable_layer.h"
#include "flutter/flow/raster_cache_util.h"
#include "third_party/skia/include/core/SkPaint.h"
namespace flutter {
@ -27,6 +28,10 @@ void OpacityLayer::Diff(DiffContext* context, const Layer* old_layer) {
}
}
context->PushTransform(SkMatrix::Translate(offset_.fX, offset_.fY));
if (context->has_raster_cache()) {
context->SetTransform(
RasterCacheUtil::GetIntegralTransCTM(context->GetTransform()));
}
DiffChildren(context, prev);
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}
@ -85,6 +90,11 @@ void OpacityLayer::Paint(PaintContext& context) const {
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->translate(offset_.fX, offset_.fY);
if (context.raster_cache) {
context.internal_nodes_canvas->setMatrix(
RasterCacheUtil::GetIntegralTransCTM(
context.leaf_nodes_canvas->getTotalMatrix()));
}
SkScalar inherited_opacity = context.inherited_opacity;
SkScalar subtree_opacity = opacity() * inherited_opacity;

View File

@ -644,9 +644,23 @@ TEST_F(OpacityLayerDiffTest, FractionalTranslation) {
MockLayerTree tree1;
tree1.root()->Add(layer);
auto damage = DiffLayerTree(tree1, MockLayerTree());
auto damage = DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0,
0, /*use_raster_cache=*/false);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 61, 61));
}
TEST_F(OpacityLayerDiffTest, FractionalTranslationWithRasterCache) {
auto picture = CreateDisplayListLayer(
CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1));
auto layer = CreateOpacityLater({picture}, 128, SkPoint::Make(0.5, 0.5));
MockLayerTree tree1;
tree1.root()->Add(layer);
auto damage = DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0,
0, /*use_raster_cache=*/true);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(11, 11, 61, 61));
}
} // namespace testing
} // namespace flutter

View File

@ -26,6 +26,10 @@ void ShaderMaskLayer::Diff(DiffContext* context, const Layer* old_layer) {
context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
}
}
if (context->has_raster_cache()) {
context->SetTransform(
RasterCacheUtil::GetIntegralTransCTM(context->GetTransform()));
}
DiffChildren(context, prev);
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
@ -49,6 +53,12 @@ void ShaderMaskLayer::Paint(PaintContext& context) const {
AutoCachePaint cache_paint(context);
if (context.raster_cache) {
context.internal_nodes_canvas->setMatrix(
RasterCacheUtil::GetIntegralTransCTM(
context.leaf_nodes_canvas->getTotalMatrix()));
}
if (context.raster_cache) {
if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) {
return;

View File

@ -32,38 +32,14 @@ void RasterCacheResult::draw(SkCanvas& canvas, const SkPaint* paint) const {
TRACE_EVENT0("flutter", "RasterCacheResult::draw");
SkAutoCanvasRestore auto_restore(&canvas, true);
SkRect bounds =
RasterCacheUtil::GetDeviceBounds(logical_rect_, canvas.getTotalMatrix());
#ifndef NDEBUG
// The image dimensions should always be larger than the device bounds and
// smaller than the device bounds plus one pixel, at the same time, we must
// introduce epsilon to solve the round-off error. The value of epsilon is
// 1/512, which represents half of an AA sample.
float epsilon = 1 / 512.0;
FML_DCHECK(image_->dimensions().width() - bounds.width() > -epsilon &&
image_->dimensions().height() - bounds.height() > -epsilon &&
image_->dimensions().width() - bounds.width() < 1 + epsilon &&
image_->dimensions().height() - bounds.height() < 1 + epsilon);
#endif
SkRect bounds = RasterCacheUtil::GetRoundedOutDeviceBounds(
logical_rect_, canvas.getTotalMatrix());
FML_DCHECK(std::abs(bounds.width() - image_->dimensions().width()) <= 1 &&
std::abs(bounds.height() - image_->dimensions().height()) <= 1);
canvas.resetMatrix();
flow_.Step();
bool exceeds_bounds = bounds.fLeft + image_->dimensions().width() >
SkScalarCeilToScalar(bounds.fRight) ||
bounds.fTop + image_->dimensions().height() >
SkScalarCeilToScalar(bounds.fBottom);
// Make sure raster cache doesn't bleed to physical pixels outside of
// original bounds. https://github.com/flutter/flutter/issues/110002
if (exceeds_bounds) {
canvas.save();
canvas.clipRect(SkRect::Make(bounds.roundOut()));
}
canvas.drawImage(image_, bounds.fLeft, bounds.fTop, SkSamplingOptions(),
paint);
if (exceeds_bounds) {
canvas.restore();
}
}
RasterCache::RasterCache(size_t access_threshold,
@ -80,14 +56,12 @@ std::unique_ptr<RasterCacheResult> RasterCache::Rasterize(
const {
TRACE_EVENT0("flutter", "RasterCachePopulate");
SkRect dest_rect =
RasterCacheUtil::GetDeviceBounds(context.logical_rect, context.matrix);
// we always round out here so that the texture is integer sized.
int width = SkScalarCeilToInt(dest_rect.width());
int height = SkScalarCeilToInt(dest_rect.height());
SkRect dest_rect = RasterCacheUtil::GetRoundedOutDeviceBounds(
context.logical_rect, context.matrix);
const SkImageInfo image_info = SkImageInfo::MakeN32Premul(
width, height, sk_ref_sp(context.dst_color_space));
const SkImageInfo image_info =
SkImageInfo::MakeN32Premul(dest_rect.width(), dest_rect.height(),
sk_ref_sp(context.dst_color_space));
sk_sp<SkSurface> surface =
context.gr_context ? SkSurface::MakeRenderTarget(
@ -139,7 +113,8 @@ bool RasterCache::UpdateCacheEntry(
int RasterCache::MarkSeen(const RasterCacheKeyID& id,
const SkMatrix& matrix,
bool visible) const {
RasterCacheKey key = RasterCacheKey(id, matrix);
RasterCacheKey key =
RasterCacheKey(id, RasterCacheUtil::GetIntegralTransCTM(matrix));
Entry& entry = cache_[key];
entry.encountered_this_frame = true;
entry.visible_this_frame = visible;
@ -151,7 +126,8 @@ int RasterCache::MarkSeen(const RasterCacheKeyID& id,
int RasterCache::GetAccessCount(const RasterCacheKeyID& id,
const SkMatrix& matrix) const {
RasterCacheKey key = RasterCacheKey(id, matrix);
RasterCacheKey key =
RasterCacheKey(id, RasterCacheUtil::GetIntegralTransCTM(matrix));
auto entry = cache_.find(key);
if (entry != cache_.cend()) {
return entry->second.accesses_since_visible;
@ -161,7 +137,8 @@ int RasterCache::GetAccessCount(const RasterCacheKeyID& id,
bool RasterCache::HasEntry(const RasterCacheKeyID& id,
const SkMatrix& matrix) const {
RasterCacheKey key = RasterCacheKey(id, matrix);
RasterCacheKey key =
RasterCacheKey(id, RasterCacheUtil::GetIntegralTransCTM(matrix));
if (cache_.find(key) != cache_.cend()) {
return true;
}
@ -171,7 +148,8 @@ bool RasterCache::HasEntry(const RasterCacheKeyID& id,
bool RasterCache::Draw(const RasterCacheKeyID& id,
SkCanvas& canvas,
const SkPaint* paint) const {
auto it = cache_.find(RasterCacheKey(id, canvas.getTotalMatrix()));
auto it = cache_.find(RasterCacheKey(
id, RasterCacheUtil::GetIntegralTransCTM(canvas.getTotalMatrix())));
if (it == cache_.end()) {
return false;
}

View File

@ -787,67 +787,5 @@ TEST_F(RasterCacheTest, RasterCacheKeyID_LayerChildrenIds) {
ASSERT_EQ(ids, expected_ids);
}
TEST_F(RasterCacheTest, RasterCacheBleedingNoClipNeeded) {
SkImageInfo info =
SkImageInfo::MakeN32(40, 40, SkAlphaType::kOpaque_SkAlphaType);
auto image = SkImage::MakeRasterData(
info, SkData::MakeUninitialized(40 * 40 * 4), 40 * 4);
auto canvas = MockCanvas();
canvas.setMatrix(SkMatrix::Scale(2, 2));
// Drawing cached image does not exceeds physical pixels of the original
// bounds and does not need to be clipped.
auto cache_result =
RasterCacheResult(image, SkRect::MakeXYWH(100.3, 100.3, 20, 20), "");
auto paint = SkPaint();
cache_result.draw(canvas, &paint);
EXPECT_EQ(canvas.draw_calls(),
std::vector({
MockCanvas::DrawCall{
0, MockCanvas::SetMatrixData{SkM44::Scale(2, 2)}},
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkM44()}},
MockCanvas::DrawCall{
1, MockCanvas::DrawImageData{image, 200.6, 200.6,
SkSamplingOptions(), paint}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}},
}));
}
TEST_F(RasterCacheTest, RasterCacheBleedingClipNeeded) {
SkImageInfo info =
SkImageInfo::MakeN32(40, 40, SkAlphaType::kOpaque_SkAlphaType);
auto image = SkImage::MakeRasterData(
info, SkData::MakeUninitialized(40 * 40 * 4), 40 * 4);
auto canvas = MockCanvas();
canvas.setMatrix(SkMatrix::Scale(2, 2));
auto cache_result =
RasterCacheResult(image, SkRect::MakeXYWH(100.3, 100.3, 19.6, 19.6), "");
auto paint = SkPaint();
cache_result.draw(canvas, &paint);
EXPECT_EQ(
canvas.draw_calls(),
std::vector({
MockCanvas::DrawCall{0,
MockCanvas::SetMatrixData{SkM44::Scale(2, 2)}},
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkM44()}},
MockCanvas::DrawCall{1, MockCanvas::SaveData{2}},
MockCanvas::DrawCall{
2, MockCanvas::ClipRectData{SkRect::MakeLTRB(200, 200, 240, 240),
SkClipOp::kIntersect,
MockCanvas::kHard_ClipEdgeStyle}},
MockCanvas::DrawCall{
2, MockCanvas::DrawImageData{image, 200.6, 200.6,
SkSamplingOptions(), paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}},
}));
}
} // namespace testing
} // namespace flutter

View File

@ -54,6 +54,39 @@ struct RasterCacheUtil {
ctm.mapRect(&device_rect, rect);
return device_rect;
}
static SkRect GetRoundedOutDeviceBounds(const SkRect& rect,
const SkMatrix& ctm) {
SkRect device_rect;
ctm.mapRect(&device_rect, rect);
device_rect.roundOut(&device_rect);
return device_rect;
}
/**
* @brief Snap the translation components of the matrix to integers.
*
* The snapping will only happen if the matrix only has scale and translation
* transformations. This is used, along with GetRoundedOutDeviceBounds, to
* ensure that the textures drawn by the raster cache are exactly aligned to
* physical pixels. Any layers that participate in raster caching must align
* themselves to physical pixels even when not cached to prevent a change in
* apparent location if caching is later applied.
*
* @param ctm the current transformation matrix.
* @return SkMatrix the snapped transformation matrix.
*/
static SkMatrix GetIntegralTransCTM(const SkMatrix& ctm) {
// Avoid integral snapping if the matrix has complex transformation to avoid
// the artifact observed in https://github.com/flutter/flutter/issues/41654.
if (!ctm.isScaleTranslate()) {
return ctm;
}
SkMatrix result = ctm;
result[SkMatrix::kMTransX] = SkScalarRoundToScalar(ctm.getTranslateX());
result[SkMatrix::kMTransY] = SkScalarRoundToScalar(ctm.getTranslateY());
return result;
}
};
} // namespace flutter

View File

@ -17,11 +17,12 @@ Damage DiffContextTest::DiffLayerTree(MockLayerTree& layer_tree,
const MockLayerTree& old_layer_tree,
const SkIRect& additional_damage,
int horizontal_clip_alignment,
int vertical_clip_alignment) {
int vertical_clip_alignment,
bool use_raster_cache) {
FML_CHECK(layer_tree.size() == old_layer_tree.size());
DiffContext dc(layer_tree.size(), 1, layer_tree.paint_region_map(),
old_layer_tree.paint_region_map());
old_layer_tree.paint_region_map(), use_raster_cache);
dc.PushCullRect(
SkRect::MakeIWH(layer_tree.size().width(), layer_tree.size().height()));
layer_tree.root()->Diff(&dc, old_layer_tree.root());

View File

@ -39,7 +39,8 @@ class DiffContextTest : public ThreadTest {
const MockLayerTree& old_layer_tree,
const SkIRect& additional_damage = SkIRect::MakeEmpty(),
int horizontal_clip_alignment = 0,
int vertical_alignment = 0);
int vertical_alignment = 0,
bool use_raster_cache = true);
// Create display list consisting of filled rect with given color; Being able
// to specify different color is useful to test deep comparison of pictures