Skip to content

Commit

Permalink
switch MockTexture off of MockCanvas calls (flutter#41906)
Browse files Browse the repository at this point in the history
Part of an ongoing set of efforts to address flutter/flutter#106448

MockTexture now executes a call on the supplied DlCanvas object rather than creating its own list of MockCanvas-style draw calls. The TextureLayer tests now no longer use MockCanvas.
  • Loading branch information
flar authored May 11, 2023
1 parent eb88d37 commit cea8d94
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 68 deletions.
1 change: 1 addition & 0 deletions display_list/dl_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ class DisplayListBuilder final : public virtual DlCanvas,
DlImageSampling sampling,
const DlPaint* paint = nullptr,
SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
using DlCanvas::DrawImageRect;
// |DlCanvas|
void DrawImageNine(const sk_sp<DlImage>& image,
const SkIRect& center,
Expand Down
70 changes: 49 additions & 21 deletions flow/layers/texture_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "flutter/flow/testing/mock_layer.h"
#include "flutter/flow/testing/mock_texture.h"
#include "flutter/fml/macros.h"
#include "flutter/testing/mock_canvas.h"
#include "flutter/testing/display_list_testing.h"

namespace flutter {
namespace testing {
Expand All @@ -28,8 +28,8 @@ TEST_F(TextureLayerTest, InvalidTexture) {
.makeOffset(layer_offset.fX, layer_offset.fY)));
EXPECT_TRUE(layer->needs_painting(paint_context()));

layer->Paint(paint_context());
EXPECT_EQ(mock_canvas().draw_calls(), std::vector<MockCanvas::DrawCall>());
layer->Paint(display_list_paint_context());
EXPECT_TRUE(display_list()->Equals(DisplayList()));
}

#ifndef NDEBUG
Expand Down Expand Up @@ -72,26 +72,28 @@ TEST_F(TextureLayerTest, PaintBeforePrerollDies) {
TEST_F(TextureLayerTest, PaintingWithLinearSampling) {
const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
const SkSize layer_size = SkSize::Make(8.0f, 8.0f);
const SkRect layer_bounds =
SkRect::MakeSize(layer_size).makeOffset(layer_offset.fX, layer_offset.fY);
const int64_t texture_id = 0;
auto mock_texture = std::make_shared<MockTexture>(texture_id);
const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5);
auto mock_texture = std::make_shared<MockTexture>(texture_id, texture_image);
auto layer = std::make_shared<TextureLayer>(
layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear);

// Ensure the texture is located by the Layer.
preroll_context()->texture_registry->RegisterTexture(mock_texture);

layer->Preroll(preroll_context());
EXPECT_EQ(layer->paint_bounds(),
(SkRect::MakeSize(layer_size)
.makeOffset(layer_offset.fX, layer_offset.fY)));
EXPECT_EQ(layer->paint_bounds(), layer_bounds);
EXPECT_TRUE(layer->needs_painting(paint_context()));

layer->Paint(paint_context());
EXPECT_EQ(mock_texture->paint_calls(),
std::vector({MockTexture::PaintCall{
mock_canvas(), layer->paint_bounds(), false, nullptr,
DlImageSampling::kLinear}}));
EXPECT_EQ(mock_canvas().draw_calls(), std::vector<MockCanvas::DrawCall>());
layer->Paint(display_list_paint_context());
DisplayListBuilder expected_builder;
/* (Texture)layer::Paint */ {
expected_builder.DrawImageRect(texture_image, layer_bounds,
DlImageSampling::kLinear);
}
EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
}

using TextureLayerDiffTest = DiffContextTest;
Expand All @@ -118,24 +120,50 @@ TEST_F(TextureLayerDiffTest, TextureInRetainedLayer) {
TEST_F(TextureLayerTest, OpacityInheritance) {
const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
const SkSize layer_size = SkSize::Make(8.0f, 8.0f);
const SkRect layer_bounds =
SkRect::MakeSize(layer_size).makeOffset(layer_offset.fX, layer_offset.fY);
const int64_t texture_id = 0;
auto mock_texture = std::make_shared<MockTexture>(texture_id);
auto layer = std::make_shared<TextureLayer>(
const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5);
auto mock_texture = std::make_shared<MockTexture>(texture_id, texture_image);
SkAlpha alpha = 0x7f;
auto texture_layer = std::make_shared<TextureLayer>(
layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear);
auto layer = std::make_shared<OpacityLayer>(alpha, SkPoint::Make(0.0f, 0.0f));
layer->Add(texture_layer);

// Ensure the texture is located by the Layer.
preroll_context()->texture_registry->RegisterTexture(mock_texture);

// The texture layer always reports opacity compatibility.
PrerollContext* context = preroll_context();
context->texture_registry->RegisterTexture(mock_texture);

// The texture layer always reports opacity compatibility.
texture_layer->Preroll(context);
EXPECT_EQ(context->renderable_state_flags,
LayerStateStack::kCallerCanApplyOpacity);

// Reset has_texture_layer since it is not supposed to be sent as we
// descend a tree in Preroll, but it was set by the previous test.
context->has_texture_layer = false;
layer->Preroll(context);
EXPECT_EQ(context->renderable_state_flags,
LayerStateStack::kCallerCanApplyOpacity);

// MockTexture has no actual textur to render into the
// PaintContext canvas so we have no way to verify its
// rendering.
DlPaint texture_paint;
texture_paint.setAlpha(alpha);

layer->Paint(display_list_paint_context());
DisplayListBuilder expected_builder;
/* (Opacity)layer::Paint */ {
expected_builder.Save();
{
/* texture_layer::Paint */ {
expected_builder.DrawImageRect(texture_image, layer_bounds,
DlImageSampling::kLinear,
&texture_paint);
}
}
expected_builder.Restore();
}
EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
}

} // namespace testing
Expand Down
46 changes: 30 additions & 16 deletions flow/testing/mock_texture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,41 @@
namespace flutter {
namespace testing {

MockTexture::MockTexture(int64_t textureId) : Texture(textureId) {}
sk_sp<DlImage> MockTexture::MakeTestTexture(int w, int h, int checker_size) {
sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(w, h);
SkCanvas* canvas = surface->getCanvas();
SkPaint p0, p1;
p0.setStyle(SkPaint::kFill_Style);
p0.setColor(SK_ColorGREEN);
p1.setStyle(SkPaint::kFill_Style);
p1.setColor(SK_ColorBLUE);
p1.setAlpha(128);
for (int y = 0; y < w; y += checker_size) {
for (int x = 0; x < h; x += checker_size) {
SkPaint& cellp = ((x + y) & 1) == 0 ? p0 : p1;
canvas->drawRect(SkRect::MakeXYWH(x, y, checker_size, checker_size),
cellp);
}
}
return DlImage::Make(surface->makeImageSnapshot());
}

MockTexture::MockTexture(int64_t textureId, const sk_sp<DlImage>& texture)
: Texture(textureId), texture_(texture) {}

void MockTexture::Paint(PaintContext& context,
const SkRect& bounds,
bool freeze,
const DlImageSampling sampling) {
paint_calls_.emplace_back(PaintCall{*(context.canvas), bounds, freeze,
context.gr_context, sampling,
context.paint});
}

bool operator==(const MockTexture::PaintCall& a,
const MockTexture::PaintCall& b) {
return &a.canvas == &b.canvas && a.bounds == b.bounds &&
a.context == b.context && a.freeze == b.freeze &&
a.sampling == b.sampling && a.paint == b.paint;
}

std::ostream& operator<<(std::ostream& os, const MockTexture::PaintCall& data) {
return os << &data.canvas << " " << data.bounds << " " << data.context << " "
<< data.freeze << " " << data.sampling << " " << data.paint;
// MockTexture objects that are not painted are allowed to have a null
// texture, but when we get to this method we must have a non-null texture.
FML_DCHECK(texture_ != nullptr);
SkRect src = SkRect::Make(texture_->bounds());
if (freeze) {
FML_DCHECK(src.width() > 2.0f && src.height() > 2.0f);
src = src.makeInset(1.0f, 1.0f);
}
context.canvas->DrawImageRect(texture_, src, bounds, sampling, context.paint);
}

} // namespace testing
Expand Down
20 changes: 4 additions & 16 deletions flow/testing/mock_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,10 @@ namespace testing {
// later verify them against expected data.
class MockTexture : public Texture {
public:
struct PaintCall {
DlCanvas& canvas;
SkRect bounds;
bool freeze;
GrDirectContext* context;
DlImageSampling sampling;
const DlPaint* paint;
};
static sk_sp<DlImage> MakeTestTexture(int w, int h, int checker_size);

explicit MockTexture(int64_t textureId);
explicit MockTexture(int64_t textureId,
const sk_sp<DlImage>& texture = nullptr);

// Called from raster thread.
void Paint(PaintContext& context,
Expand All @@ -41,23 +35,17 @@ class MockTexture : public Texture {
void MarkNewFrameAvailable() override {}
void OnTextureUnregistered() override { unregistered_ = true; }

const std::vector<PaintCall>& paint_calls() { return paint_calls_; }
bool gr_context_created() { return gr_context_created_; }
bool gr_context_destroyed() { return gr_context_destroyed_; }
bool unregistered() { return unregistered_; }

private:
std::vector<PaintCall> paint_calls_;
sk_sp<DlImage> texture_;
bool gr_context_created_ = false;
bool gr_context_destroyed_ = false;
bool unregistered_ = false;
};

extern bool operator==(const MockTexture::PaintCall& a,
const MockTexture::PaintCall& b);
extern std::ostream& operator<<(std::ostream& os,
const MockTexture::PaintCall& data);

} // namespace testing
} // namespace flutter

Expand Down
45 changes: 30 additions & 15 deletions flow/testing/mock_texture_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

#include "flutter/flow/testing/mock_texture.h"

#include "flutter/testing/mock_canvas.h"
#include "flutter/display_list/dl_builder.h"
#include "flutter/testing/display_list_testing.h"
#include "gtest/gtest.h"

namespace flutter {
Expand All @@ -27,37 +28,51 @@ TEST(MockTextureTest, Callbacks) {
}

TEST(MockTextureTest, PaintCalls) {
MockCanvas canvas;
DisplayListBuilder builder;
const SkRect paint_bounds1 = SkRect::MakeWH(1.0f, 1.0f);
const SkRect paint_bounds2 = SkRect::MakeWH(2.0f, 2.0f);
const DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
const auto expected_paint_calls = std::vector{
MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr, sampling},
MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr, sampling}};
auto texture = std::make_shared<MockTexture>(0);
const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5);
auto texture = std::make_shared<MockTexture>(0, texture_image);

Texture::PaintContext context{
.canvas = &canvas,
.canvas = &builder,
};
texture->Paint(context, paint_bounds1, false, sampling);
texture->Paint(context, paint_bounds2, true, sampling);
EXPECT_EQ(texture->paint_calls(), expected_paint_calls);

SkRect src1 = SkRect::Make(texture_image->bounds());
SkRect src2 = src1.makeInset(1.0, 1.0f);

DisplayListBuilder expected_builder;
expected_builder.DrawImageRect(texture_image, src1, paint_bounds1, sampling);
expected_builder.DrawImageRect(texture_image, src2, paint_bounds2, sampling);
EXPECT_TRUE(
DisplayListsEQ_Verbose(builder.Build(), expected_builder.Build()));
}

TEST(MockTextureTest, PaintCallsWithLinearSampling) {
MockCanvas canvas;
DisplayListBuilder builder;
const SkRect paint_bounds1 = SkRect::MakeWH(1.0f, 1.0f);
const SkRect paint_bounds2 = SkRect::MakeWH(2.0f, 2.0f);
const auto sampling = DlImageSampling::kLinear;
const auto expected_paint_calls = std::vector{
MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr, sampling},
MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr, sampling}};
auto texture = std::make_shared<MockTexture>(0);
const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5);
auto texture = std::make_shared<MockTexture>(0, texture_image);

Texture::PaintContext context{
.canvas = &canvas,
.canvas = &builder,
};
texture->Paint(context, paint_bounds1, false, sampling);
texture->Paint(context, paint_bounds2, true, sampling);
EXPECT_EQ(texture->paint_calls(), expected_paint_calls);

SkRect src1 = SkRect::Make(texture_image->bounds());
SkRect src2 = src1.makeInset(1.0, 1.0f);

DisplayListBuilder expected_builder;
expected_builder.DrawImageRect(texture_image, src1, paint_bounds1, sampling);
expected_builder.DrawImageRect(texture_image, src2, paint_bounds2, sampling);
EXPECT_TRUE(
DisplayListsEQ_Verbose(builder.Build(), expected_builder.Build()));
}

} // namespace testing
Expand Down

0 comments on commit cea8d94

Please sign in to comment.