[DisplayList] benchmark DisplayList dispatch method (#54324)
We will be updating the DisplayList dispatching to support random access iteration through the records so we need a benchmark to set a baseline to track any impact on the default way to dispatch a DisplayList.
diff --git a/display_list/benchmarking/dl_builder_benchmarks.cc b/display_list/benchmarking/dl_builder_benchmarks.cc
index 2b17ce0..8f9f05e 100644
--- a/display_list/benchmarking/dl_builder_benchmarks.cc
+++ b/display_list/benchmarking/dl_builder_benchmarks.cc
@@ -4,6 +4,7 @@
#include "flutter/benchmarking/benchmarking.h"
#include "flutter/display_list/testing/dl_test_snippets.h"
+#include "flutter/display_list/utils/dl_receiver_utils.h"
namespace flutter {
@@ -16,6 +17,9 @@
static std::vector<testing::DisplayListInvocationGroup> allRenderingOps =
testing::CreateAllRenderingOps();
+static std::vector<testing::DisplayListInvocationGroup> allOps =
+ testing::CreateAllGroups();
+
enum class DisplayListBuilderBenchmarkType {
kDefault,
kBounds,
@@ -23,6 +27,12 @@
kBoundsAndRtree,
};
+enum class DisplayListDispatchBenchmarkType {
+ kDefaultNoRtree,
+ kDefaultWithRtree,
+ kCulledWithRtree,
+};
+
static void InvokeAllRenderingOps(DisplayListBuilder& builder) {
DlOpReceiver& receiver = DisplayListBuilderBenchmarkAccessor(builder);
for (auto& group : allRenderingOps) {
@@ -33,6 +43,21 @@
}
}
+static void InvokeAllOps(DisplayListBuilder& builder) {
+ DlOpReceiver& receiver = DisplayListBuilderBenchmarkAccessor(builder);
+ for (auto& group : allOps) {
+ // Save/restore around each group so that the clip and transform
+ // test ops do not walk us out to infinity or prevent any future
+ // rendering ops.
+ receiver.save();
+ for (size_t i = 0; i < group.variants.size(); i++) {
+ auto& invocation = group.variants[i];
+ invocation.Invoke(receiver);
+ }
+ receiver.restore();
+ }
+}
+
static void Complete(DisplayListBuilder& builder,
DisplayListBuilderBenchmarkType type) {
auto display_list = builder.Build();
@@ -57,6 +82,10 @@
type == DisplayListBuilderBenchmarkType::kBoundsAndRtree;
}
+bool NeedPrepareRTree(DisplayListDispatchBenchmarkType type) {
+ return type != DisplayListDispatchBenchmarkType::kDefaultNoRtree;
+}
+
} // namespace
static void BM_DisplayListBuilderDefault(benchmark::State& state,
@@ -171,6 +200,42 @@
}
}
+class DlOpReceiverIgnore : public IgnoreAttributeDispatchHelper,
+ public IgnoreTransformDispatchHelper,
+ public IgnoreClipDispatchHelper,
+ public IgnoreDrawDispatchHelper {};
+
+static void BM_DisplayListDispatchDefault(
+ benchmark::State& state,
+ DisplayListDispatchBenchmarkType type) {
+ bool prepare_rtree = NeedPrepareRTree(type);
+ DisplayListBuilder builder(prepare_rtree);
+ for (int i = 0; i < 5; i++) {
+ InvokeAllOps(builder);
+ }
+ auto display_list = builder.Build();
+ DlOpReceiverIgnore receiver;
+ while (state.KeepRunning()) {
+ display_list->Dispatch(receiver);
+ }
+}
+
+static void BM_DisplayListDispatchCull(benchmark::State& state,
+ DisplayListDispatchBenchmarkType type) {
+ bool prepare_rtree = NeedPrepareRTree(type);
+ DisplayListBuilder builder(prepare_rtree);
+ for (int i = 0; i < 5; i++) {
+ InvokeAllOps(builder);
+ }
+ auto display_list = builder.Build();
+ SkRect rect = SkRect::MakeLTRB(0, 0, 100, 100);
+ EXPECT_FALSE(rect.contains(display_list->bounds()));
+ DlOpReceiverIgnore receiver;
+ while (state.KeepRunning()) {
+ display_list->Dispatch(receiver, rect);
+ }
+}
+
BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault,
kDefault,
DisplayListBuilderBenchmarkType::kDefault)
@@ -290,4 +355,19 @@
DisplayListBuilderBenchmarkType::kBoundsAndRtree)
->Unit(benchmark::kMicrosecond);
+BENCHMARK_CAPTURE(BM_DisplayListDispatchDefault,
+ kDefaultNoRtree,
+ DisplayListDispatchBenchmarkType::kDefaultNoRtree)
+ ->Unit(benchmark::kMicrosecond);
+
+BENCHMARK_CAPTURE(BM_DisplayListDispatchDefault,
+ kDefaultWithRtree,
+ DisplayListDispatchBenchmarkType::kDefaultWithRtree)
+ ->Unit(benchmark::kMicrosecond);
+
+BENCHMARK_CAPTURE(BM_DisplayListDispatchCull,
+ kCulledWithRtree,
+ DisplayListDispatchBenchmarkType::kCulledWithRtree)
+ ->Unit(benchmark::kMicrosecond);
+
} // namespace flutter
diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc
index 25d9330..5dc341c 100644
--- a/display_list/testing/dl_test_snippets.cc
+++ b/display_list/testing/dl_test_snippets.cc
@@ -50,11 +50,15 @@
{"SetAntiAlias",
{
{0, 8, 0, [](DlOpReceiver& r) { r.setAntiAlias(true); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0, [](DlOpReceiver& r) { r.setAntiAlias(false); }},
}},
{"SetInvertColors",
{
{0, 8, 0, [](DlOpReceiver& r) { r.setInvertColors(true); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0, [](DlOpReceiver& r) { r.setInvertColors(false); }},
}},
{"SetStrokeCap",
@@ -63,6 +67,8 @@
[](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kRound); }},
{0, 8, 0,
[](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kSquare); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0,
[](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kButt); }},
}},
@@ -72,6 +78,8 @@
[](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kBevel); }},
{0, 8, 0,
[](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kRound); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0,
[](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kMiter); }},
}},
@@ -83,6 +91,8 @@
[](DlOpReceiver& r) {
r.setDrawStyle(DlDrawStyle::kStrokeAndFill);
}},
+
+ // Reset attribute to default as last entry
{0, 0, 0,
[](DlOpReceiver& r) { r.setDrawStyle(DlDrawStyle::kFill); }},
}},
@@ -90,12 +100,16 @@
{
{0, 8, 0, [](DlOpReceiver& r) { r.setStrokeWidth(1.0); }},
{0, 8, 0, [](DlOpReceiver& r) { r.setStrokeWidth(5.0); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(0.0); }},
}},
{"SetStrokeMiter",
{
{0, 8, 0, [](DlOpReceiver& r) { r.setStrokeMiter(0.0); }},
{0, 8, 0, [](DlOpReceiver& r) { r.setStrokeMiter(5.0); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(4.0); }},
}},
{"SetColor",
@@ -104,6 +118,8 @@
[](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorGREEN)); }},
{0, 8, 0,
[](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorBLUE)); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0,
[](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorBLACK)); }},
}},
@@ -113,6 +129,8 @@
[](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kSrcIn); }},
{0, 8, 0,
[](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kDstIn); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0,
[](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kSrcOver); }},
}},
@@ -128,6 +146,8 @@
[](DlOpReceiver& r) { r.setColorSource(kTestSource4.get()); }},
{0, 80 + 6 * 4, 0,
[](DlOpReceiver& r) { r.setColorSource(kTestSource5.get()); }},
+
+ // Reset attribute to default as last entry
{0, 0, 0, [](DlOpReceiver& r) { r.setColorSource(nullptr); }},
}},
{"SetImageFilter",
@@ -186,7 +206,6 @@
[](DlOpReceiver& r) { r.setImageFilter(&kTestCFImageFilter1); }},
{0, 24, 0,
[](DlOpReceiver& r) { r.setImageFilter(&kTestCFImageFilter2); }},
- {0, 0, 0, [](DlOpReceiver& r) { r.setImageFilter(nullptr); }},
{0, 24, 0,
[](DlOpReceiver& r) {
r.setImageFilter(
@@ -194,6 +213,9 @@
.makeWithLocalMatrix(SkMatrix::Translate(2, 2))
.get());
}},
+
+ // Reset attribute to default as last entry
+ {0, 0, 0, [](DlOpReceiver& r) { r.setImageFilter(nullptr); }},
}},
{"SetColorFilter",
{
@@ -219,6 +241,8 @@
[](DlOpReceiver& r) {
r.setColorFilter(DlLinearToSrgbGammaColorFilter::kInstance.get());
}},
+
+ // Reset attribute to default as last entry
{0, 0, 0, [](DlOpReceiver& r) { r.setColorFilter(nullptr); }},
}},
{"SetMaskFilter",
@@ -238,6 +262,8 @@
{0, 32, 0,
[](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter5); }, 0u,
2u},
+
+ // Reset attribute to default as last entry
{0, 0, 0, [](DlOpReceiver& r) { r.setMaskFilter(nullptr); }, 0u, 1u},
}},
};