Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions display_list/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ if (enable_unittests) {
"//flutter/common/graphics",
"//flutter/display_list/testing:display_list_surface_provider",
"//flutter/display_list/testing:display_list_testing",
"//flutter/impeller/typographer/backends/skia:typographer_skia_backend",
"//flutter/testing",
]

Expand Down
94 changes: 72 additions & 22 deletions display_list/testing/dl_rendering_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include "flutter/fml/math.h"
#include "flutter/testing/display_list_testing.h"
#include "flutter/testing/testing.h"
#ifdef IMPELLER_SUPPORTS_RENDERING
#include "flutter/impeller/typographer/backends/skia/text_frame_skia.h"
#endif // IMPELLER_SUPPORTS_RENDERING

#include "third_party/skia/include/core/SkBBHFactory.h"
#include "third_party/skia/include/core/SkColorFilter.h"
Expand Down Expand Up @@ -592,16 +595,11 @@ class RenderEnvironment {
return RenderEnvironment(provider, PixelFormat::kN32PremulPixelFormat);
}

void init_ref(SkRenderer& sk_renderer,
DlRenderer& dl_renderer,
DlColor bg = DlColor::kTransparent()) {
init_ref(kEmptySkSetup, sk_renderer, kEmptyDlSetup, dl_renderer, bg);
}

void init_ref(SkSetup& sk_setup,
SkRenderer& sk_renderer,
DlSetup& dl_setup,
DlRenderer& dl_renderer,
DlRenderer& imp_renderer,
DlColor bg = DlColor::kTransparent()) {
SkJobRenderer sk_job(sk_setup, sk_renderer, kEmptySkRenderer, kTestSkImage);
RenderJobInfo info = {
Expand All @@ -617,7 +615,7 @@ class RenderEnvironment {
ASSERT_EQ(sk_job.setup_clip_bounds(), ref_clip_bounds_);
if (provider_->supports_impeller()) {
test_impeller_image_ = makeTestImpellerImage(provider_);
DlJobRenderer imp_job(dl_setup, dl_renderer, kEmptyDlRenderer,
DlJobRenderer imp_job(dl_setup, imp_renderer, kEmptyDlRenderer,
test_impeller_image_);
ref_impeller_result_ = getImpellerResult(info, imp_job);
}
Expand Down Expand Up @@ -818,11 +816,34 @@ class TestParameters {
TestParameters(const SkRenderer& sk_renderer,
const DlRenderer& dl_renderer,
const DisplayListAttributeFlags& flags)
: sk_renderer_(sk_renderer), dl_renderer_(dl_renderer), flags_(flags) {}
: TestParameters(sk_renderer, dl_renderer, dl_renderer, flags) {}

TestParameters(const SkRenderer& sk_renderer,
const DlRenderer& dl_renderer,
const DlRenderer& imp_renderer,
const DisplayListAttributeFlags& flags)
: sk_renderer_(sk_renderer),
dl_renderer_(dl_renderer),
imp_renderer_(imp_renderer),
flags_(flags) {}

bool uses_paint() const { return !flags_.ignores_paint(); }
bool uses_gradient() const { return flags_.applies_shader(); }

bool impeller_compatible(const DlPaint& paint) const {
if (is_draw_text_blob()) {
// Non-color text is rendered as paths
if (paint.getColorSourcePtr() && !paint.getColorSourcePtr()->asColor()) {
return false;
}
// Non-filled text (stroke or stroke and fill) is rendered as paths
if (paint.getDrawStyle() != DlDrawStyle::kFill) {
return false;
}
}
return true;
}

bool should_match(const RenderEnvironment& env,
const CaseParameters& caseP,
const DlPaint& attr,
Expand Down Expand Up @@ -1015,6 +1036,7 @@ class TestParameters {

const SkRenderer& sk_renderer() const { return sk_renderer_; }
const DlRenderer& dl_renderer() const { return dl_renderer_; }
const DlRenderer& imp_renderer() const { return imp_renderer_; }

// Tests that call drawTextBlob with an sk_ref paint attribute will cause
// those attributes to be stored in an internal Skia cache so we need
Expand Down Expand Up @@ -1065,6 +1087,7 @@ class TestParameters {
private:
const SkRenderer sk_renderer_;
const DlRenderer dl_renderer_;
const DlRenderer imp_renderer_;
const DisplayListAttributeFlags flags_;

bool is_draw_text_blob_ = false;
Expand Down Expand Up @@ -1110,7 +1133,8 @@ class CanvasCompareTester {
for (auto& back_end : kTestBackends) {
auto provider = GetProvider(back_end);
RenderEnvironment env = RenderEnvironment::MakeN32(provider.get());
env.init_ref(params.sk_renderer(), params.dl_renderer());
env.init_ref(kEmptySkSetup, params.sk_renderer(), //
kEmptyDlSetup, params.dl_renderer(), params.imp_renderer());
quickCompareToReference(env, "default");
if (env.supports_impeller()) {
auto impeller_result = env.ref_impeller_result();
Expand Down Expand Up @@ -1279,7 +1303,8 @@ class CanvasCompareTester {
ctx.paint.setAlpha(ctx.paint.getAlpha() / 2);
};
backdrop_env.init_ref(sk_backdrop_setup, testP.sk_renderer(),
dl_backdrop_setup, testP.dl_renderer());
dl_backdrop_setup, testP.dl_renderer(),
testP.imp_renderer());
quickCompareToReference(backdrop_env, "backdrop");

DlBlurImageFilter dl_backdrop(5, 5, DlTileMode::kDecal);
Expand Down Expand Up @@ -1463,7 +1488,7 @@ class CanvasCompareTester {
[=](const SkSetupContext& ctx) { sk_aa_setup(ctx, false); },
testP.sk_renderer(),
[=](const DlSetupContext& ctx) { dl_aa_setup(ctx, false); },
testP.dl_renderer());
testP.dl_renderer(), testP.imp_renderer());
quickCompareToReference(aa_env, "AntiAlias");
RenderWith(
testP, aa_env, aa_tolerance,
Expand Down Expand Up @@ -1547,7 +1572,8 @@ class CanvasCompareTester {
ctx.paint.setStrokeWidth(5.0);
};
blur_env.init_ref(sk_blur_setup, testP.sk_renderer(), //
dl_blur_setup, testP.dl_renderer());
dl_blur_setup, testP.dl_renderer(),
testP.imp_renderer());
quickCompareToReference(blur_env, "blur");
DlBlurImageFilter dl_filter_decal_5(5.0, 5.0, DlTileMode::kDecal);
auto sk_filter_decal_5 =
Expand Down Expand Up @@ -1598,7 +1624,8 @@ class CanvasCompareTester {
ctx.paint.setStrokeWidth(5.0);
};
dilate_env.init_ref(sk_dilate_setup, testP.sk_renderer(), //
dl_dilate_setup, testP.dl_renderer());
dl_dilate_setup, testP.dl_renderer(),
testP.imp_renderer());
quickCompareToReference(dilate_env, "dilate");
DlDilateImageFilter dl_dilate_filter_5(5.0, 5.0);
auto sk_dilate_filter_5 = SkImageFilters::Dilate(5.0, 5.0, nullptr);
Expand Down Expand Up @@ -1629,7 +1656,8 @@ class CanvasCompareTester {
ctx.paint.setStrokeWidth(6.0);
};
erode_env.init_ref(sk_erode_setup, testP.sk_renderer(), //
dl_erode_setup, testP.dl_renderer());
dl_erode_setup, testP.dl_renderer(),
testP.imp_renderer());
quickCompareToReference(erode_env, "erode");
// do not erode too much, because some tests assert there are enough
// pixels that are changed.
Expand Down Expand Up @@ -1779,7 +1807,8 @@ class CanvasCompareTester {
ctx.paint.setStrokeWidth(5.0);
};
dither_env.init_ref(sk_dither_setup, testP.sk_renderer(),
dl_dither_setup, testP.dl_renderer(), dither_bg);
dl_dither_setup, testP.dl_renderer(),
testP.imp_renderer(), dither_bg);
quickCompareToReference(dither_env, "dither");
RenderWith(testP, dither_env, tolerance,
CaseParameters(
Expand Down Expand Up @@ -1875,7 +1904,8 @@ class CanvasCompareTester {
ctx.paint.setStrokeWidth(5.0);
};
stroke_base_env.init_ref(sk_stroke_setup, testP.sk_renderer(),
dl_stroke_setup, testP.dl_renderer());
dl_stroke_setup, testP.dl_renderer(),
testP.imp_renderer());
quickCompareToReference(stroke_base_env, "stroke");

RenderWith(testP, stroke_base_env, tolerance,
Expand Down Expand Up @@ -2296,10 +2326,16 @@ class CanvasCompareTester {
info + " (attribute should affect rendering)");
}

if (env.supports_impeller()) {
DlJobRenderer imp_job(caseP.dl_setup(), //
testP.dl_renderer(), //
caseP.dl_restore(), //
// If either the reference setup or the test setup contain attributes
// that Impeller doesn't support, we skip the Impeller testing. This
// is mostly stroked or patterned text which is vectored through drawPath
// for Impeller.
if (env.supports_impeller() &&
testP.impeller_compatible(dl_job.setup_paint()) &&
testP.impeller_compatible(env.ref_dl_paint())) {
DlJobRenderer imp_job(caseP.dl_setup(), //
testP.imp_renderer(), //
caseP.dl_restore(), //
env.impeller_image());
auto imp_result = env.getImpellerResult(base_info, imp_job);
std::string imp_info = info + " (Impeller)";
Expand All @@ -2317,7 +2353,8 @@ class CanvasCompareTester {
imp_info + " (attribute should affect rendering)");
}
if (!success) {
FML_LOG(ERROR) << "Impeller issue encountered for: " << *display_list;
FML_LOG(ERROR) << "Impeller issue encountered for: "
<< *imp_job.MakeDisplayList(base_info);
std::string filename = to_png_filename(info + " (Impeller Output)");
imp_result->write(filename);
FML_LOG(ERROR) << "output saved in: " << filename;
Expand Down Expand Up @@ -3621,6 +3658,9 @@ TEST_F(DisplayListRendering, DrawTextBlob) {
#else
sk_sp<SkTextBlob> blob =
CanvasCompareTester::MakeTextBlob("Testing", kRenderHeight * 0.33f);
#ifdef IMPELLER_SUPPORTS_RENDERING
auto frame = impeller::MakeTextFrameFromTextBlobSkia(blob);
#endif // IMPELLER_SUPPORTS_RENDERING
SkScalar render_y_1_3 = kRenderTop + kRenderHeight * 0.3;
SkScalar render_y_2_3 = kRenderTop + kRenderHeight * 0.6;
CanvasCompareTester::RenderAll( //
Expand All @@ -3637,6 +3677,14 @@ TEST_F(DisplayListRendering, DrawTextBlob) {
ctx.canvas->DrawTextBlob(blob, kRenderLeft, render_y_2_3, paint);
ctx.canvas->DrawTextBlob(blob, kRenderLeft, kRenderBottom, paint);
},
#ifdef IMPELLER_SUPPORTS_RENDERING
[=](const DlRenderContext& ctx) {
auto paint = ctx.paint;
ctx.canvas->DrawTextFrame(frame, kRenderLeft, render_y_1_3, paint);
ctx.canvas->DrawTextFrame(frame, kRenderLeft, render_y_2_3, paint);
ctx.canvas->DrawTextFrame(frame, kRenderLeft, kRenderBottom, paint);
},
#endif // IMPELLER_SUPPORTS_RENDERING
kDrawTextBlobFlags)
.set_draw_text_blob(),
// From examining the bounds differential for the "Default" case, the
Expand Down Expand Up @@ -3766,7 +3814,9 @@ TEST_F(DisplayListRendering, SaveLayerClippedContentStillFilters) {
for (auto& back_end : CanvasCompareTester::kTestBackends) {
auto provider = CanvasCompareTester::GetProvider(back_end);
RenderEnvironment env = RenderEnvironment::MakeN32(provider.get());
env.init_ref(test_params.sk_renderer(), test_params.dl_renderer());
env.init_ref(kEmptySkSetup, test_params.sk_renderer(), //
kEmptyDlSetup, test_params.dl_renderer(),
test_params.imp_renderer());
CanvasCompareTester::quickCompareToReference(env, "default");
CanvasCompareTester::RenderWith(test_params, env, tolerance, case_params);
}
Expand Down
24 changes: 18 additions & 6 deletions testing/display_list_testing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,17 @@ static std::ostream& operator<<(std::ostream& os, const SkTextBlob* blob) {
return os << "&SkTextBlob(ID: " << blob->uniqueID() << ", " << blob->bounds() << ")";
}

static std::ostream& operator<<(std::ostream& os,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be a utility in text_frame.cc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextFrame might want to have a more fully featured streamer. This one just needs enough to hold it's place in the debugging output. The Text objects and Path just dump out some useful info here like bounds.

const impeller::TextFrame* frame) {
if (frame == nullptr) {
return os << "no text";
}
auto bounds = frame->GetBounds();
return os << "&TextFrame("
<< bounds.GetLeft() << ", " << bounds.GetTop() << " => "
<< bounds.GetRight() << ", " << bounds.GetBottom() << ")";
}

std::ostream& operator<<(std::ostream& os, const DlVertexMode& mode) {
switch (mode) {
case DlVertexMode::kTriangles: return os << "VertexMode::kTriangles";
Expand Down Expand Up @@ -860,12 +871,13 @@ void DisplayListStreamDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
<< x << ", " << y << ");" << std::endl;
}

void DisplayListStreamDispatcher::drawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
SkScalar x,
SkScalar y) {
startl() << "drawTextFrame("
<< text_frame.get() << ", "
<< x << ", " << y << ");" << std::endl;
void DisplayListStreamDispatcher::drawTextFrame(
const std::shared_ptr<impeller::TextFrame>& text_frame,
SkScalar x,
SkScalar y) {
startl() << "drawTextFrame("
<< text_frame.get() << ", "
<< x << ", " << y << ");" << std::endl;
}

void DisplayListStreamDispatcher::drawShadow(const SkPath& path,
Expand Down
2 changes: 1 addition & 1 deletion third_party/txt/src/skia/paragraph_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter {
// filters rely on having the glyph coverage, whereas regular text is
// drawn as rectangular texture samples.
return ((paint.getColorSource() && !paint.getColorSource()->asColor()) ||
paint.getDrawStyle() == DlDrawStyle::kStroke);
paint.getDrawStyle() != DlDrawStyle::kFill);
}

DlPaint toDlPaint(const DecorationStyle& decor_style,
Expand Down