From be3cf593d96c8c3159b56d05159b029909a49e9c Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 23 Sep 2024 18:24:29 -0700 Subject: [PATCH] [DisplayList] Optimize draws of simple shapes expressed as paths --- display_list/display_list_unittests.cc | 173 +++++++++++++++++++++-- display_list/dl_builder.cc | 18 +++ display_list/testing/dl_test_snippets.cc | 5 +- 3 files changed, 180 insertions(+), 16 deletions(-) diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index 56c560540bce4..76899955675c1 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -5094,11 +5094,164 @@ TEST_F(DisplayListTest, DrawRectPathPromoteToDrawRect) { expected.DrawRect(rect, DlPaint()); auto expect_dl = expected.Build(); - // Support for this will be re-added soon, until then verify that we - // do not promote. + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); +} + +TEST_F(DisplayListTest, FillCompleteUnclosedRectPathPromoteToDrawRect) { + DlPaint paint = DlPaint().setDrawStyle(DlDrawStyle::kFill); + + SkPath path; + path.moveTo(10.0f, 10.0f); + path.lineTo(20.0f, 10.0f); + path.lineTo(20.0f, 20.0f); + path.lineTo(10.0f, 20.0f); + path.lineTo(10.0f, 10.0f); + // No explicit close + // path.close(); + + DisplayListBuilder builder; + builder.DrawPath(path, paint); + auto dl = builder.Build(); + + DisplayListBuilder expected; + expected.DrawRect(path.getBounds(), paint); + auto expect_dl = expected.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); +} + +TEST_F(DisplayListTest, FillIncompleteUnclosedRectPathPromoteToDrawRect) { + DlPaint paint = DlPaint().setDrawStyle(DlDrawStyle::kFill); + + SkPath path; + path.moveTo(10.0f, 10.0f); + path.lineTo(20.0f, 10.0f); + path.lineTo(20.0f, 20.0f); + path.lineTo(10.0f, 20.0f); + // Leave last segment for fill operation to infer + // path.lineTo(10.0f, 10.0f); + // No explicit close + // path.close(); + + DisplayListBuilder builder; + builder.DrawPath(path, paint); + auto dl = builder.Build(); + + DisplayListBuilder expected; + expected.DrawRect(path.getBounds(), paint); + auto expect_dl = expected.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); +} + +TEST_F(DisplayListTest, FillBarelyUnclosedRectPathPromoteToDrawPath) { + DlPaint paint = DlPaint().setDrawStyle(DlDrawStyle::kFill); + + SkPath path; + path.moveTo(10.0f, 10.0f); + path.lineTo(20.0f, 10.0f); + path.lineTo(20.0f, 20.0f); + path.lineTo(10.0f, 20.0f); + path.lineTo(10.0f, 11.0f); // One pixel short of closed + + DisplayListBuilder builder; + builder.DrawPath(path, paint); + auto dl = builder.Build(); + + DisplayListBuilder expected; + expected.DrawRect(path.getBounds(), paint); + auto expect_dl = expected.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); +} + +TEST_F(DisplayListTest, StrokeBarelyUnclosedRectPathPromoteToDrawPath) { + DlPaint paint = DlPaint().setDrawStyle(DlDrawStyle::kStroke); + + SkPath path; + path.moveTo(10.0f, 10.0f); + path.lineTo(20.0f, 10.0f); + path.lineTo(20.0f, 20.0f); + path.lineTo(10.0f, 20.0f); + path.lineTo(10.0f, 11.0f); // One pixel short of closed + + DisplayListBuilder builder; + builder.DrawPath(path, paint); + auto dl = builder.Build(); + + DisplayListBuilder expected; + expected.DrawRect(path.getBounds(), paint); + auto expect_dl = expected.Build(); + + ASSERT_TRUE(DisplayListsNE_Verbose(dl, expect_dl)); +} + +TEST_F(DisplayListTest, StrokeCompleteUnclosedRectPathNotPromoteToDrawPath) { + DlPaint paint = DlPaint().setDrawStyle(DlDrawStyle::kStroke); + + SkPath path; + path.moveTo(10.0f, 10.0f); + path.lineTo(20.0f, 10.0f); + path.lineTo(20.0f, 20.0f); + path.lineTo(10.0f, 20.0f); + path.lineTo(10.0f, 10.0f); + + DisplayListBuilder builder; + builder.DrawPath(path, paint); + auto dl = builder.Build(); + + DisplayListBuilder expected; + expected.DrawRect(path.getBounds(), paint); + auto expect_dl = expected.Build(); + ASSERT_TRUE(DisplayListsNE_Verbose(dl, expect_dl)); } +TEST_F(DisplayListTest, StrokeIncompleteClosedRectPathPromoteToDrawRect) { + DlPaint paint = DlPaint().setDrawStyle(DlDrawStyle::kStroke); + + SkPath path; + path.moveTo(10.0f, 10.0f); + path.lineTo(20.0f, 10.0f); + path.lineTo(20.0f, 20.0f); + path.lineTo(10.0f, 20.0f); + // Leave last segment for close to fill in + // path.lineTo(10.0f, 10.0f); + path.close(); + + DisplayListBuilder builder; + builder.DrawPath(path, paint); + auto dl = builder.Build(); + + DisplayListBuilder expected; + expected.DrawRect(path.getBounds(), paint); + auto expect_dl = expected.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); +} + +TEST_F(DisplayListTest, StrokeCompleteClosedRectPathPromoteToDrawRect) { + DlPaint paint = DlPaint().setDrawStyle(DlDrawStyle::kStroke); + + SkPath path; + path.moveTo(10.0f, 10.0f); + path.lineTo(20.0f, 10.0f); + path.lineTo(20.0f, 20.0f); + path.lineTo(10.0f, 20.0f); + path.lineTo(10.0f, 10.0f); + path.close(); + + DisplayListBuilder builder; + builder.DrawPath(path, paint); + auto dl = builder.Build(); + + DisplayListBuilder expected; + expected.DrawRect(path.getBounds(), paint); + auto expect_dl = expected.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); +} + TEST_F(DisplayListTest, DrawOvalPathPromoteToDrawOval) { SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f); @@ -5110,9 +5263,7 @@ TEST_F(DisplayListTest, DrawOvalPathPromoteToDrawOval) { expected.DrawOval(rect, DlPaint()); auto expect_dl = expected.Build(); - // Support for this will be re-added soon, until then verify that we - // do not promote. - ASSERT_TRUE(DisplayListsNE_Verbose(dl, expect_dl)); + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); } TEST_F(DisplayListTest, DrawRRectPathPromoteToDrawRRect) { @@ -5127,9 +5278,7 @@ TEST_F(DisplayListTest, DrawRRectPathPromoteToDrawRRect) { expected.DrawRRect(rrect, DlPaint()); auto expect_dl = expected.Build(); - // Support for this will be re-added soon, until then verify that we - // do not promote. - ASSERT_TRUE(DisplayListsNE_Verbose(dl, expect_dl)); + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); } TEST_F(DisplayListTest, DrawRectRRectPathPromoteToDrawRect) { @@ -5144,9 +5293,7 @@ TEST_F(DisplayListTest, DrawRectRRectPathPromoteToDrawRect) { expected.DrawRect(rect, DlPaint()); auto expect_dl = expected.Build(); - // Support for this will be re-added soon, until then verify that we - // do not promote. - ASSERT_TRUE(DisplayListsNE_Verbose(dl, expect_dl)); + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); } TEST_F(DisplayListTest, DrawOvalRRectPathPromoteToDrawOval) { @@ -5161,9 +5308,7 @@ TEST_F(DisplayListTest, DrawOvalRRectPathPromoteToDrawOval) { expected.DrawOval(rect, DlPaint()); auto expect_dl = expected.Build(); - // Support for this will be re-added soon, until then verify that we - // do not promote. - ASSERT_TRUE(DisplayListsNE_Verbose(dl, expect_dl)); + ASSERT_TRUE(DisplayListsEQ_Verbose(dl, expect_dl)); } TEST_F(DisplayListTest, ClipRectRRectPromoteToClipRect) { diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index 86b6def705e12..637cfbfab7798 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -1227,6 +1227,24 @@ void DisplayListBuilder::DrawDRRect(const SkRRect& outer, drawDRRect(outer, inner); } void DisplayListBuilder::drawPath(const DlPath& path) { + if (!path.IsInverseFillType()) { + SkRect rect; + bool is_closed; + if (path.IsSkRect(&rect, &is_closed) && + (is_closed || current_.getDrawStyle() == DlDrawStyle::kFill)) { + drawRect(ToDlRect(rect)); + return; + } + if (path.IsSkOval(&rect)) { + drawOval(ToDlRect(rect)); + return; + } + SkRRect rrect; + if (path.IsSkRRect(&rrect)) { + drawRRect(rrect); + return; + } + } DisplayListAttributeFlags flags = kDrawPathFlags; OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect) { diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc index 05ca54dbd38ae..e3ea4b30ebc5f 100644 --- a/display_list/testing/dl_test_snippets.cc +++ b/display_list/testing/dl_test_snippets.cc @@ -700,10 +700,11 @@ std::vector CreateAllRenderingOps() { {1, 24, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath1); }}, {1, 24, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath2); }}, {1, 24, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath3); }}, - // oval, rect and rrect paths are left as drawPath + // oval and rect paths are redirected to drawRect and drawOval {1, 24, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathRect); }}, {1, 24, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathOval); }}, - {1, 24, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathRRect); }}, + // rrect path is redirected to drawRRect + {1, 56, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathRRect); }}, }}, {"DrawArc", {