Create benchmarks for DisplayListBuilder (flutter/engine#34910)

This commit is contained in:
ColdPaleLight 2022-07-30 02:56:02 +08:00 committed by GitHub
parent 9c88c82e33
commit cbda16b4b4
9 changed files with 1652 additions and 869 deletions

View File

@ -126,6 +126,7 @@ group("flutter") {
if (enable_unittests && !is_win && !is_fuchsia) {
public_deps += [
"//flutter/display_list:display_list_benchmarks",
"//flutter/display_list:display_list_builder_benchmarks",
"//flutter/fml:fml_benchmarks",
"//flutter/lib/ui:ui_benchmarks",
"//flutter/shell/common:shell_benchmarks",

View File

@ -55,6 +55,7 @@ FILE: ../../../flutter/display_list/display_list_blend_mode.cc
FILE: ../../../flutter/display_list/display_list_blend_mode.h
FILE: ../../../flutter/display_list/display_list_builder.cc
FILE: ../../../flutter/display_list/display_list_builder.h
FILE: ../../../flutter/display_list/display_list_builder_benchmarks.cc
FILE: ../../../flutter/display_list/display_list_canvas_dispatcher.cc
FILE: ../../../flutter/display_list/display_list_canvas_dispatcher.h
FILE: ../../../flutter/display_list/display_list_canvas_recorder.cc

View File

@ -154,6 +154,20 @@ if (enable_unittests) {
[ "${fuchsia_sdk_path}/arch/${target_cpu}/sysroot/lib/libzircon.so" ]
}
}
executable("display_list_builder_benchmarks") {
testonly = true
sources = [ "display_list_builder_benchmarks.cc" ]
deps = [
":display_list",
":display_list_fixtures",
":display_list_testing",
"//flutter/benchmarking",
"//flutter/testing:testing_lib",
]
}
}
fixtures_location("display_list_benchmarks_fixtures") {

View File

@ -0,0 +1,235 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/benchmarking/benchmarking.h"
#include "flutter/display_list/display_list_test_utils.h"
namespace flutter {
namespace {
static std::vector<testing::DisplayListInvocationGroup> allRenderingOps =
testing::CreateAllRenderingOps();
enum class DisplayListBuilderBenchmarkType {
kDefault,
kBounds,
kRtree,
kBoundsAndRtree,
};
static void InvokeAllRenderingOps(DisplayListBuilder& builder) {
for (auto& group : allRenderingOps) {
for (size_t i = 0; i < group.variants.size(); i++) {
auto& invocation = group.variants[i];
invocation.Invoke(builder);
}
}
}
static void Complete(DisplayListBuilder& builder,
DisplayListBuilderBenchmarkType type) {
auto display_list = builder.Build();
switch (type) {
case DisplayListBuilderBenchmarkType::kBounds:
display_list->bounds();
break;
case DisplayListBuilderBenchmarkType::kRtree:
display_list->rtree();
break;
case DisplayListBuilderBenchmarkType::kBoundsAndRtree:
display_list->bounds();
display_list->rtree();
break;
case DisplayListBuilderBenchmarkType::kDefault:
break;
}
}
} // namespace
static void BM_DisplayListBuiderDefault(benchmark::State& state,
DisplayListBuilderBenchmarkType type) {
while (state.KeepRunning()) {
DisplayListBuilder builder;
InvokeAllRenderingOps(builder);
Complete(builder, type);
}
}
static void BM_DisplayListBuiderWithScaleAndTranslate(
benchmark::State& state,
DisplayListBuilderBenchmarkType type) {
while (state.KeepRunning()) {
DisplayListBuilder builder;
builder.scale(3.5, 3.5);
builder.translate(10.3, 6.9);
InvokeAllRenderingOps(builder);
Complete(builder, type);
}
}
static void BM_DisplayListBuiderWithPerspective(
benchmark::State& state,
DisplayListBuilderBenchmarkType type) {
while (state.KeepRunning()) {
DisplayListBuilder builder;
builder.transformFullPerspective(0, 1, 0, 12, 1, 0, 0, 33, 3, 2, 5, 29, 0,
0, 0, 12);
InvokeAllRenderingOps(builder);
Complete(builder, type);
}
}
static void BM_DisplayListBuiderWithClipRect(
benchmark::State& state,
DisplayListBuilderBenchmarkType type) {
SkRect clip_bounds = SkRect::MakeLTRB(6.5, 7.3, 90.2, 85.7);
while (state.KeepRunning()) {
DisplayListBuilder builder;
builder.clipRect(clip_bounds, SkClipOp::kIntersect, true);
InvokeAllRenderingOps(builder);
Complete(builder, type);
}
}
static void BM_DisplayListBuiderWithSaveLayer(
benchmark::State& state,
DisplayListBuilderBenchmarkType type) {
while (state.KeepRunning()) {
DisplayListBuilder builder;
for (auto& group : allRenderingOps) {
for (size_t i = 0; i < group.variants.size(); i++) {
auto& invocation = group.variants[i];
builder.saveLayer(nullptr, false);
invocation.Invoke(builder);
builder.restore();
}
}
Complete(builder, type);
}
}
static void BM_DisplayListBuiderWithSaveLayerAndImageFilter(
benchmark::State& state,
DisplayListBuilderBenchmarkType type) {
DlPaint layer_paint;
layer_paint.setImageFilter(&testing::kTestBlurImageFilter1);
SkRect layer_bounds = SkRect::MakeLTRB(6.5, 7.3, 35.2, 42.7);
while (state.KeepRunning()) {
DisplayListBuilder builder;
for (auto& group : allRenderingOps) {
for (size_t i = 0; i < group.variants.size(); i++) {
auto& invocation = group.variants[i];
builder.saveLayer(&layer_bounds, &layer_paint);
invocation.Invoke(builder);
builder.restore();
}
}
Complete(builder, type);
}
}
BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault,
kDefault,
DisplayListBuilderBenchmarkType::kDefault)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault,
kBounds,
DisplayListBuilderBenchmarkType::kBounds)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault,
kRtree,
DisplayListBuilderBenchmarkType::kRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault,
kBoundsAndRtree,
DisplayListBuilderBenchmarkType::kBoundsAndRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate,
kDefault,
DisplayListBuilderBenchmarkType::kDefault)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate,
kBounds,
DisplayListBuilderBenchmarkType::kBounds)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate,
kRtree,
DisplayListBuilderBenchmarkType::kRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate,
kBoundsAndRtree,
DisplayListBuilderBenchmarkType::kBoundsAndRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective,
kDefault,
DisplayListBuilderBenchmarkType::kDefault)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective,
kBounds,
DisplayListBuilderBenchmarkType::kBounds)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective,
kRtree,
DisplayListBuilderBenchmarkType::kRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective,
kBoundsAndRtree,
DisplayListBuilderBenchmarkType::kBoundsAndRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect,
kDefault,
DisplayListBuilderBenchmarkType::kDefault)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect,
kBounds,
DisplayListBuilderBenchmarkType::kBounds)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect,
kRtree,
DisplayListBuilderBenchmarkType::kRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect,
kBoundsAndRtree,
DisplayListBuilderBenchmarkType::kBoundsAndRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer,
kDefault,
DisplayListBuilderBenchmarkType::kDefault)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer,
kBounds,
DisplayListBuilderBenchmarkType::kBounds)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer,
kRtree,
DisplayListBuilderBenchmarkType::kRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer,
kBoundsAndRtree,
DisplayListBuilderBenchmarkType::kBoundsAndRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter,
kDefault,
DisplayListBuilderBenchmarkType::kDefault)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter,
kBounds,
DisplayListBuilderBenchmarkType::kBounds)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter,
kRtree,
DisplayListBuilderBenchmarkType::kRtree)
->Unit(benchmark::kMillisecond);
BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter,
kBoundsAndRtree,
DisplayListBuilderBenchmarkType::kBoundsAndRtree)
->Unit(benchmark::kMillisecond);
} // namespace flutter

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,12 @@
#include "flutter/display_list/display_list_builder.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/effects/SkBlenders.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "third_party/skia/include/effects/SkImageFilters.h"
namespace flutter {
namespace testing {
@ -17,6 +23,313 @@ sk_sp<DisplayList> GetSampleDisplayList();
sk_sp<DisplayList> GetSampleDisplayList(int ops);
sk_sp<DisplayList> GetSampleNestedDisplayList();
typedef const std::function<void(DisplayListBuilder&)> DlInvoker;
constexpr SkPoint kEndPoints[] = {
{0, 0},
{100, 100},
};
const DlColor kColors[] = {
DlColor::kGreen(),
DlColor::kYellow(),
DlColor::kBlue(),
};
constexpr float kStops[] = {
0.0,
0.5,
1.0,
};
static std::vector<uint32_t> color_vector(kColors, kColors + 3);
static std::vector<float> stops_vector(kStops, kStops + 3);
// clang-format off
constexpr float kRotateColorMatrix[20] = {
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
1, 0, 0, 0, 0,
0, 0, 0, 1, 0,
};
constexpr float kInvertColorMatrix[20] = {
-1.0, 0, 0, 1.0, 0,
0, -1.0, 0, 1.0, 0,
0, 0, -1.0, 1.0, 0,
1.0, 1.0, 1.0, 1.0, 0,
};
// clang-format on
const SkScalar kTestDashes1[] = {4.0, 2.0};
const SkScalar kTestDashes2[] = {1.0, 1.5};
constexpr SkPoint TestPoints[] = {
{10, 10},
{20, 20},
{10, 20},
{20, 10},
};
#define TestPointCount sizeof(TestPoints) / (sizeof(TestPoints[0]))
static DlImageSampling kNearestSampling = DlImageSampling::kNearestNeighbor;
static DlImageSampling kLinearSampling = DlImageSampling::kLinear;
static sk_sp<DlImage> MakeTestImage(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());
}
static auto TestImage1 = MakeTestImage(40, 40, 5);
static auto TestImage2 = MakeTestImage(50, 50, 5);
static const sk_sp<SkBlender> kTestBlender1 =
SkBlenders::Arithmetic(0.2, 0.2, 0.2, 0.2, false);
static const sk_sp<SkBlender> kTestBlender2 =
SkBlenders::Arithmetic(0.2, 0.2, 0.2, 0.2, true);
static const sk_sp<SkBlender> kTestBlender3 =
SkBlenders::Arithmetic(0.3, 0.3, 0.3, 0.3, true);
static const DlImageColorSource kTestSource1(TestImage1->skia_image(),
DlTileMode::kClamp,
DlTileMode::kMirror,
kLinearSampling);
static const std::shared_ptr<DlColorSource> kTestSource2 =
DlColorSource::MakeLinear(kEndPoints[0],
kEndPoints[1],
3,
kColors,
kStops,
DlTileMode::kMirror);
static const std::shared_ptr<DlColorSource> kTestSource3 =
DlColorSource::MakeRadial(kEndPoints[0],
10.0,
3,
kColors,
kStops,
DlTileMode::kMirror);
static const std::shared_ptr<DlColorSource> kTestSource4 =
DlColorSource::MakeConical(kEndPoints[0],
10.0,
kEndPoints[1],
200.0,
3,
kColors,
kStops,
DlTileMode::kDecal);
static const std::shared_ptr<DlColorSource> kTestSource5 =
DlColorSource::MakeSweep(kEndPoints[0],
0.0,
360.0,
3,
kColors,
kStops,
DlTileMode::kDecal);
static const DlBlendColorFilter kTestBlendColorFilter1(DlColor::kRed(),
DlBlendMode::kDstATop);
static const DlBlendColorFilter kTestBlendColorFilter2(DlColor::kBlue(),
DlBlendMode::kDstATop);
static const DlBlendColorFilter kTestBlendColorFilter3(DlColor::kRed(),
DlBlendMode::kDstIn);
static const DlMatrixColorFilter kTestMatrixColorFilter1(kRotateColorMatrix);
static const DlMatrixColorFilter kTestMatrixColorFilter2(kInvertColorMatrix);
static const DlBlurImageFilter kTestBlurImageFilter1(5.0,
5.0,
DlTileMode::kClamp);
static const DlBlurImageFilter kTestBlurImageFilter2(6.0,
5.0,
DlTileMode::kClamp);
static const DlBlurImageFilter kTestBlurImageFilter3(5.0,
6.0,
DlTileMode::kClamp);
static const DlBlurImageFilter kTestBlurImageFilter4(5.0,
5.0,
DlTileMode::kDecal);
static const DlDilateImageFilter kTestDilateImageFilter1(5.0, 5.0);
static const DlDilateImageFilter kTestDilateImageFilter2(6.0, 5.0);
static const DlDilateImageFilter kTestDilateImageFilter3(5.0, 6.0);
static const DlErodeImageFilter kTestErodeImageFilter1(5.0, 5.0);
static const DlErodeImageFilter kTestErodeImageFilter2(6.0, 5.0);
static const DlErodeImageFilter kTestErodeImageFilter3(5.0, 6.0);
static const DlMatrixImageFilter kTestMatrixImageFilter1(
SkMatrix::RotateDeg(45),
kNearestSampling);
static const DlMatrixImageFilter kTestMatrixImageFilter2(
SkMatrix::RotateDeg(85),
kNearestSampling);
static const DlMatrixImageFilter kTestMatrixImageFilter3(
SkMatrix::RotateDeg(45),
kLinearSampling);
static const DlComposeImageFilter kTestComposeImageFilter1(
kTestBlurImageFilter1,
kTestMatrixImageFilter1);
static const DlComposeImageFilter kTestComposeImageFilter2(
kTestBlurImageFilter2,
kTestMatrixImageFilter1);
static const DlComposeImageFilter kTestComposeImageFilter3(
kTestBlurImageFilter1,
kTestMatrixImageFilter2);
static const DlColorFilterImageFilter kTestCFImageFilter1(
kTestBlendColorFilter1);
static const DlColorFilterImageFilter kTestCFImageFilter2(
kTestBlendColorFilter2);
static const std::shared_ptr<DlPathEffect> kTestPathEffect1 =
DlDashPathEffect::Make(kTestDashes1, 2, 0.0f);
static const std::shared_ptr<DlPathEffect> kTestPathEffect2 =
DlDashPathEffect::Make(kTestDashes2, 2, 0.0f);
static const DlBlurMaskFilter kTestMaskFilter1(kNormal_SkBlurStyle, 3.0);
static const DlBlurMaskFilter kTestMaskFilter2(kNormal_SkBlurStyle, 5.0);
static const DlBlurMaskFilter kTestMaskFilter3(kSolid_SkBlurStyle, 3.0);
static const DlBlurMaskFilter kTestMaskFilter4(kInner_SkBlurStyle, 3.0);
static const DlBlurMaskFilter kTestMaskFilter5(kOuter_SkBlurStyle, 3.0);
constexpr SkRect kTestBounds = SkRect::MakeLTRB(10, 10, 50, 60);
static const SkRRect kTestRRect = SkRRect::MakeRectXY(kTestBounds, 5, 5);
static const SkRRect kTestRRectRect = SkRRect::MakeRect(kTestBounds);
static const SkRRect kTestInnerRRect =
SkRRect::MakeRectXY(kTestBounds.makeInset(5, 5), 2, 2);
static const SkPath kTestPathRect = SkPath::Rect(kTestBounds);
static const SkPath kTestPathOval = SkPath::Oval(kTestBounds);
static const SkPath kTestPath1 =
SkPath::Polygon({{0, 0}, {10, 10}, {10, 0}, {0, 10}}, true);
static const SkPath kTestPath2 =
SkPath::Polygon({{0, 0}, {10, 10}, {0, 10}, {10, 0}}, true);
static const SkPath kTestPath3 =
SkPath::Polygon({{0, 0}, {10, 10}, {10, 0}, {0, 10}}, false);
static const SkMatrix kTestMatrix1 = SkMatrix::Scale(2, 2);
static const SkMatrix kTestMatrix2 = SkMatrix::RotateDeg(45);
static std::shared_ptr<const DlVertices> TestVertices1 =
DlVertices::Make(DlVertexMode::kTriangles, //
3,
TestPoints,
nullptr,
kColors);
static std::shared_ptr<const DlVertices> TestVertices2 =
DlVertices::Make(DlVertexMode::kTriangleFan, //
3,
TestPoints,
nullptr,
kColors);
static constexpr int kTestDivs1[] = {10, 20, 30};
static constexpr int kTestDivs2[] = {15, 20, 25};
static constexpr int kTestDivs3[] = {15, 25};
static constexpr SkCanvas::Lattice::RectType kTestRTypes[] = {
SkCanvas::Lattice::RectType::kDefault,
SkCanvas::Lattice::RectType::kTransparent,
SkCanvas::Lattice::RectType::kFixedColor,
SkCanvas::Lattice::RectType::kDefault,
SkCanvas::Lattice::RectType::kTransparent,
SkCanvas::Lattice::RectType::kFixedColor,
SkCanvas::Lattice::RectType::kDefault,
SkCanvas::Lattice::RectType::kTransparent,
SkCanvas::Lattice::RectType::kFixedColor,
};
static constexpr SkColor kTestLatticeColors[] = {
SK_ColorBLUE, SK_ColorGREEN, SK_ColorYELLOW,
SK_ColorBLUE, SK_ColorGREEN, SK_ColorYELLOW,
SK_ColorBLUE, SK_ColorGREEN, SK_ColorYELLOW,
};
static constexpr SkIRect kTestLatticeSrcRect = {1, 1, 39, 39};
static sk_sp<SkPicture> MakeTestPicture(int w, int h, SkColor color) {
SkPictureRecorder recorder;
SkRTreeFactory rtree_factory;
SkCanvas* cv = recorder.beginRecording(kTestBounds, &rtree_factory);
SkPaint paint;
paint.setColor(color);
paint.setStyle(SkPaint::kFill_Style);
cv->drawRect(SkRect::MakeWH(w, h), paint);
return recorder.finishRecordingAsPicture();
}
static sk_sp<SkPicture> TestPicture1 = MakeTestPicture(20, 20, SK_ColorGREEN);
static sk_sp<SkPicture> TestPicture2 = MakeTestPicture(25, 25, SK_ColorBLUE);
static sk_sp<DisplayList> MakeTestDisplayList(int w, int h, SkColor color) {
DisplayListBuilder builder;
builder.setColor(color);
builder.drawRect(SkRect::MakeWH(w, h));
return builder.Build();
}
static sk_sp<DisplayList> TestDisplayList1 =
MakeTestDisplayList(20, 20, SK_ColorGREEN);
static sk_sp<DisplayList> TestDisplayList2 =
MakeTestDisplayList(25, 25, SK_ColorBLUE);
static sk_sp<SkTextBlob> MakeTextBlob(std::string string) {
return SkTextBlob::MakeFromText(string.c_str(), string.size(), SkFont(),
SkTextEncoding::kUTF8);
}
static sk_sp<SkTextBlob> TestBlob1 = MakeTextBlob("TestBlob1");
static sk_sp<SkTextBlob> TestBlob2 = MakeTextBlob("TestBlob2");
struct DisplayListInvocation {
unsigned int op_count_;
size_t byte_count_;
// in some cases, running the sequence through an SkCanvas will result
// in fewer ops/bytes. Attribute invocations are recorded in an SkPaint
// and not forwarded on, and SkCanvas culls unused save/restore/transforms.
int sk_op_count_;
size_t sk_byte_count_;
DlInvoker invoker;
bool supports_group_opacity_ = false;
bool sk_version_matches() {
return (static_cast<int>(op_count_) == sk_op_count_ &&
byte_count_ == sk_byte_count_);
}
// A negative sk_op_count means "do not test this op".
// Used mainly for these cases:
// - we cannot encode a DrawShadowRec (Skia private header)
// - SkCanvas cannot receive a DisplayList
// - SkCanvas may or may not inline an SkPicture
bool sk_testing_invalid() { return sk_op_count_ < 0; }
bool is_empty() { return byte_count_ == 0; }
bool supports_group_opacity() { return supports_group_opacity_; }
unsigned int op_count() { return op_count_; }
// byte count for the individual ops, no DisplayList overhead
size_t raw_byte_count() { return byte_count_; }
// byte count for the ops with DisplayList overhead, comparable
// to |DisplayList.byte_count().
size_t byte_count() { return sizeof(DisplayList) + byte_count_; }
int sk_op_count() { return sk_op_count_; }
// byte count for the ops with DisplayList overhead as translated
// through an SkCanvas interface, comparable to |DisplayList.byte_count().
size_t sk_byte_count() { return sizeof(DisplayList) + sk_byte_count_; }
void Invoke(DisplayListBuilder& builder) { invoker(builder); }
sk_sp<DisplayList> Build() {
DisplayListBuilder builder;
invoker(builder);
return builder.Build();
}
};
struct DisplayListInvocationGroup {
std::string op_name;
std::vector<DisplayListInvocation> variants;
};
std::vector<DisplayListInvocationGroup> CreateAllRenderingOps();
std::vector<DisplayListInvocationGroup> CreateAllGroups();
} // namespace testing
} // namespace flutter

View File

@ -9,883 +9,17 @@
#include "flutter/display_list/display_list_builder.h"
#include "flutter/display_list/display_list_canvas_recorder.h"
#include "flutter/display_list/display_list_rtree.h"
#include "flutter/display_list/display_list_test_utils.h"
#include "flutter/display_list/display_list_utils.h"
#include "flutter/fml/math.h"
#include "flutter/testing/display_list_testing.h"
#include "flutter/testing/testing.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/effects/SkBlenders.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "third_party/skia/include/effects/SkImageFilters.h"
namespace flutter {
namespace testing {
constexpr SkPoint kEndPoints[] = {
{0, 0},
{100, 100},
};
const DlColor kColors[] = {
DlColor::kGreen(),
DlColor::kYellow(),
DlColor::kBlue(),
};
constexpr float kStops[] = {
0.0,
0.5,
1.0,
};
std::vector<uint32_t> color_vector(kColors, kColors + 3);
std::vector<float> stops_vector(kStops, kStops + 3);
// clang-format off
constexpr float kRotateColorMatrix[20] = {
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
1, 0, 0, 0, 0,
0, 0, 0, 1, 0,
};
constexpr float kInvertColorMatrix[20] = {
-1.0, 0, 0, 1.0, 0,
0, -1.0, 0, 1.0, 0,
0, 0, -1.0, 1.0, 0,
1.0, 1.0, 1.0, 1.0, 0,
};
// clang-format on
const SkScalar kTestDashes1[] = {4.0, 2.0};
const SkScalar kTestDashes2[] = {1.0, 1.5};
constexpr SkPoint TestPoints[] = {
{10, 10},
{20, 20},
{10, 20},
{20, 10},
};
#define TestPointCount sizeof(TestPoints) / (sizeof(TestPoints[0]))
static DlImageSampling kNearestSampling = DlImageSampling::kNearestNeighbor;
static DlImageSampling kLinearSampling = DlImageSampling::kLinear;
static sk_sp<DlImage> MakeTestImage(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());
}
static auto TestImage1 = MakeTestImage(40, 40, 5);
static auto TestImage2 = MakeTestImage(50, 50, 5);
static const sk_sp<SkBlender> kTestBlender1 =
SkBlenders::Arithmetic(0.2, 0.2, 0.2, 0.2, false);
static const sk_sp<SkBlender> kTestBlender2 =
SkBlenders::Arithmetic(0.2, 0.2, 0.2, 0.2, true);
static const sk_sp<SkBlender> kTestBlender3 =
SkBlenders::Arithmetic(0.3, 0.3, 0.3, 0.3, true);
static const DlImageColorSource kTestSource1(TestImage1->skia_image(),
DlTileMode::kClamp,
DlTileMode::kMirror,
kLinearSampling);
static const std::shared_ptr<DlColorSource> kTestSource2 =
DlColorSource::MakeLinear(kEndPoints[0],
kEndPoints[1],
3,
kColors,
kStops,
DlTileMode::kMirror);
static const std::shared_ptr<DlColorSource> kTestSource3 =
DlColorSource::MakeRadial(kEndPoints[0],
10.0,
3,
kColors,
kStops,
DlTileMode::kMirror);
static const std::shared_ptr<DlColorSource> kTestSource4 =
DlColorSource::MakeConical(kEndPoints[0],
10.0,
kEndPoints[1],
200.0,
3,
kColors,
kStops,
DlTileMode::kDecal);
static const std::shared_ptr<DlColorSource> kTestSource5 =
DlColorSource::MakeSweep(kEndPoints[0],
0.0,
360.0,
3,
kColors,
kStops,
DlTileMode::kDecal);
static const DlBlendColorFilter kTestBlendColorFilter1(DlColor::kRed(),
DlBlendMode::kDstATop);
static const DlBlendColorFilter kTestBlendColorFilter2(DlColor::kBlue(),
DlBlendMode::kDstATop);
static const DlBlendColorFilter kTestBlendColorFilter3(DlColor::kRed(),
DlBlendMode::kDstIn);
static const DlMatrixColorFilter kTestMatrixColorFilter1(kRotateColorMatrix);
static const DlMatrixColorFilter kTestMatrixColorFilter2(kInvertColorMatrix);
static const DlBlurImageFilter kTestBlurImageFilter1(5.0,
5.0,
DlTileMode::kClamp);
static const DlBlurImageFilter kTestBlurImageFilter2(6.0,
5.0,
DlTileMode::kClamp);
static const DlBlurImageFilter kTestBlurImageFilter3(5.0,
6.0,
DlTileMode::kClamp);
static const DlBlurImageFilter kTestBlurImageFilter4(5.0,
5.0,
DlTileMode::kDecal);
static const DlDilateImageFilter kTestDilateImageFilter1(5.0, 5.0);
static const DlDilateImageFilter kTestDilateImageFilter2(6.0, 5.0);
static const DlDilateImageFilter kTestDilateImageFilter3(5.0, 6.0);
static const DlErodeImageFilter kTestErodeImageFilter1(5.0, 5.0);
static const DlErodeImageFilter kTestErodeImageFilter2(6.0, 5.0);
static const DlErodeImageFilter kTestErodeImageFilter3(5.0, 6.0);
static const DlMatrixImageFilter kTestMatrixImageFilter1(
SkMatrix::RotateDeg(45),
kNearestSampling);
static const DlMatrixImageFilter kTestMatrixImageFilter2(
SkMatrix::RotateDeg(85),
kNearestSampling);
static const DlMatrixImageFilter kTestMatrixImageFilter3(
SkMatrix::RotateDeg(45),
kLinearSampling);
static const DlComposeImageFilter kTestComposeImageFilter1(
kTestBlurImageFilter1,
kTestMatrixImageFilter1);
static const DlComposeImageFilter kTestComposeImageFilter2(
kTestBlurImageFilter2,
kTestMatrixImageFilter1);
static const DlComposeImageFilter kTestComposeImageFilter3(
kTestBlurImageFilter1,
kTestMatrixImageFilter2);
static const DlColorFilterImageFilter kTestCFImageFilter1(
kTestBlendColorFilter1);
static const DlColorFilterImageFilter kTestCFImageFilter2(
kTestBlendColorFilter2);
static const std::shared_ptr<DlPathEffect> kTestPathEffect1 =
DlDashPathEffect::Make(kTestDashes1, 2, 0.0f);
static const std::shared_ptr<DlPathEffect> kTestPathEffect2 =
DlDashPathEffect::Make(kTestDashes2, 2, 0.0f);
static const DlBlurMaskFilter kTestMaskFilter1(kNormal_SkBlurStyle, 3.0);
static const DlBlurMaskFilter kTestMaskFilter2(kNormal_SkBlurStyle, 5.0);
static const DlBlurMaskFilter kTestMaskFilter3(kSolid_SkBlurStyle, 3.0);
static const DlBlurMaskFilter kTestMaskFilter4(kInner_SkBlurStyle, 3.0);
static const DlBlurMaskFilter kTestMaskFilter5(kOuter_SkBlurStyle, 3.0);
constexpr SkRect kTestBounds = SkRect::MakeLTRB(10, 10, 50, 60);
static const SkRRect kTestRRect = SkRRect::MakeRectXY(kTestBounds, 5, 5);
static const SkRRect kTestRRectRect = SkRRect::MakeRect(kTestBounds);
static const SkRRect kTestInnerRRect =
SkRRect::MakeRectXY(kTestBounds.makeInset(5, 5), 2, 2);
static const SkPath kTestPathRect = SkPath::Rect(kTestBounds);
static const SkPath kTestPathOval = SkPath::Oval(kTestBounds);
static const SkPath kTestPath1 =
SkPath::Polygon({{0, 0}, {10, 10}, {10, 0}, {0, 10}}, true);
static const SkPath kTestPath2 =
SkPath::Polygon({{0, 0}, {10, 10}, {0, 10}, {10, 0}}, true);
static const SkPath kTestPath3 =
SkPath::Polygon({{0, 0}, {10, 10}, {10, 0}, {0, 10}}, false);
static const SkMatrix kTestMatrix1 = SkMatrix::Scale(2, 2);
static const SkMatrix kTestMatrix2 = SkMatrix::RotateDeg(45);
static std::shared_ptr<const DlVertices> TestVertices1 =
DlVertices::Make(DlVertexMode::kTriangles, //
3,
TestPoints,
nullptr,
kColors);
static std::shared_ptr<const DlVertices> TestVertices2 =
DlVertices::Make(DlVertexMode::kTriangleFan, //
3,
TestPoints,
nullptr,
kColors);
static constexpr int kTestDivs1[] = {10, 20, 30};
static constexpr int kTestDivs2[] = {15, 20, 25};
static constexpr int kTestDivs3[] = {15, 25};
static constexpr SkCanvas::Lattice::RectType kTestRTypes[] = {
SkCanvas::Lattice::RectType::kDefault,
SkCanvas::Lattice::RectType::kTransparent,
SkCanvas::Lattice::RectType::kFixedColor,
SkCanvas::Lattice::RectType::kDefault,
SkCanvas::Lattice::RectType::kTransparent,
SkCanvas::Lattice::RectType::kFixedColor,
SkCanvas::Lattice::RectType::kDefault,
SkCanvas::Lattice::RectType::kTransparent,
SkCanvas::Lattice::RectType::kFixedColor,
};
static constexpr SkColor kTestLatticeColors[] = {
SK_ColorBLUE, SK_ColorGREEN, SK_ColorYELLOW,
SK_ColorBLUE, SK_ColorGREEN, SK_ColorYELLOW,
SK_ColorBLUE, SK_ColorGREEN, SK_ColorYELLOW,
};
static constexpr SkIRect kTestLatticeSrcRect = {1, 1, 39, 39};
static sk_sp<SkPicture> MakeTestPicture(int w, int h, SkColor color) {
SkPictureRecorder recorder;
SkRTreeFactory rtree_factory;
SkCanvas* cv = recorder.beginRecording(kTestBounds, &rtree_factory);
SkPaint paint;
paint.setColor(color);
paint.setStyle(SkPaint::kFill_Style);
cv->drawRect(SkRect::MakeWH(w, h), paint);
return recorder.finishRecordingAsPicture();
}
static sk_sp<SkPicture> TestPicture1 = MakeTestPicture(20, 20, SK_ColorGREEN);
static sk_sp<SkPicture> TestPicture2 = MakeTestPicture(25, 25, SK_ColorBLUE);
static sk_sp<DisplayList> MakeTestDisplayList(int w, int h, SkColor color) {
DisplayListBuilder builder;
builder.setColor(color);
builder.drawRect(SkRect::MakeWH(w, h));
return builder.Build();
}
static sk_sp<DisplayList> TestDisplayList1 =
MakeTestDisplayList(20, 20, SK_ColorGREEN);
static sk_sp<DisplayList> TestDisplayList2 =
MakeTestDisplayList(25, 25, SK_ColorBLUE);
static sk_sp<SkTextBlob> MakeTextBlob(std::string string) {
return SkTextBlob::MakeFromText(string.c_str(), string.size(), SkFont(),
SkTextEncoding::kUTF8);
}
static sk_sp<SkTextBlob> TestBlob1 = MakeTextBlob("TestBlob1");
static sk_sp<SkTextBlob> TestBlob2 = MakeTextBlob("TestBlob2");
// ---------------
// Test Suite data
// ---------------
typedef const std::function<void(DisplayListBuilder&)> DlInvoker;
struct DisplayListInvocation {
unsigned int op_count_;
size_t byte_count_;
// in some cases, running the sequence through an SkCanvas will result
// in fewer ops/bytes. Attribute invocations are recorded in an SkPaint
// and not forwarded on, and SkCanvas culls unused save/restore/transforms.
int sk_op_count_;
size_t sk_byte_count_;
DlInvoker invoker;
bool supports_group_opacity_ = false;
bool sk_version_matches() {
return (static_cast<int>(op_count_) == sk_op_count_ &&
byte_count_ == sk_byte_count_);
}
// A negative sk_op_count means "do not test this op".
// Used mainly for these cases:
// - we cannot encode a DrawShadowRec (Skia private header)
// - SkCanvas cannot receive a DisplayList
// - SkCanvas may or may not inline an SkPicture
bool sk_testing_invalid() { return sk_op_count_ < 0; }
bool is_empty() { return byte_count_ == 0; }
bool supports_group_opacity() { return supports_group_opacity_; }
unsigned int op_count() { return op_count_; }
// byte count for the individual ops, no DisplayList overhead
size_t raw_byte_count() { return byte_count_; }
// byte count for the ops with DisplayList overhead, comparable
// to |DisplayList.byte_count().
size_t byte_count() { return sizeof(DisplayList) + byte_count_; }
int sk_op_count() { return sk_op_count_; }
// byte count for the ops with DisplayList overhead as translated
// through an SkCanvas interface, comparable to |DisplayList.byte_count().
size_t sk_byte_count() { return sizeof(DisplayList) + sk_byte_count_; }
sk_sp<DisplayList> Build() {
DisplayListBuilder builder;
invoker(builder);
return builder.Build();
}
};
struct DisplayListInvocationGroup {
std::string op_name;
std::vector<DisplayListInvocation> variants;
};
std::vector<DisplayListInvocationGroup> allGroups = {
{ "SetAntiAlias", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setAntiAlias(true);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setAntiAlias(false);}},
}
},
{ "SetDither", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setDither(true);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setDither(false);}},
}
},
{ "SetInvertColors", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setInvertColors(true);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setInvertColors(false);}},
}
},
{ "SetStrokeCap", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeCap(DlStrokeCap::kRound);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeCap(DlStrokeCap::kSquare);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeCap(DlStrokeCap::kButt);}},
}
},
{ "SetStrokeJoin", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(DlStrokeJoin::kBevel);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(DlStrokeJoin::kRound);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(DlStrokeJoin::kMiter);}},
}
},
{ "SetStyle", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStyle(DlDrawStyle::kStroke);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStyle(DlDrawStyle::kStrokeAndFill);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStyle(DlDrawStyle::kFill);}},
}
},
{ "SetStrokeWidth", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(1.0);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(5.0);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(0.0);}},
}
},
{ "SetStrokeMiter", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeMiter(0.0);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeMiter(5.0);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeMiter(4.0);}},
}
},
{ "SetColor", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setColor(SK_ColorGREEN);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setColor(SK_ColorBLUE);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setColor(SK_ColorBLACK);}},
}
},
{ "SetBlendModeOrBlender", {
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setBlendMode(DlBlendMode::kSrcIn);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setBlendMode(DlBlendMode::kDstIn);}},
{0, 16, 0, 0, [](DisplayListBuilder& b) {b.setBlender(kTestBlender1);}},
{0, 16, 0, 0, [](DisplayListBuilder& b) {b.setBlender(kTestBlender2);}},
{0, 16, 0, 0, [](DisplayListBuilder& b) {b.setBlender(kTestBlender3);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setBlendMode(DlBlendMode::kSrcOver);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setBlender(nullptr);}},
}
},
{ "SetColorSource", {
{0, 96, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(&kTestSource1);}},
// stop_count * (sizeof(float) + sizeof(uint32_t)) = 80
{0, 80 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(kTestSource2.get());}},
{0, 80 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(kTestSource3.get());}},
{0, 88 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(kTestSource4.get());}},
{0, 80 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(kTestSource5.get());}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(nullptr);}},
}
},
{ "SetImageFilter", {
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestBlurImageFilter1);}},
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestBlurImageFilter2);}},
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestBlurImageFilter3);}},
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestBlurImageFilter4);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestDilateImageFilter1);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestDilateImageFilter2);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestDilateImageFilter3);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestErodeImageFilter1);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestErodeImageFilter2);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestErodeImageFilter3);}},
{0, 64, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestMatrixImageFilter1);}},
{0, 64, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestMatrixImageFilter2);}},
{0, 64, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestMatrixImageFilter3);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestComposeImageFilter1);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestComposeImageFilter2);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestComposeImageFilter3);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestCFImageFilter1);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&kTestCFImageFilter2);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(nullptr);}},
}
},
{ "SetColorFilter", {
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(&kTestBlendColorFilter1);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(&kTestBlendColorFilter2);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(&kTestBlendColorFilter3);}},
{0, 96, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(&kTestMatrixColorFilter1);}},
{0, 96, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(&kTestMatrixColorFilter2);}},
{0, 16, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(DlSrgbToLinearGammaColorFilter::instance.get());}},
{0, 16, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(DlLinearToSrgbGammaColorFilter::instance.get());}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(nullptr);}},
}
},
{ "SetPathEffect", {
// sizeof(DlDashPathEffect) + 2 * sizeof(SkScalar)
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setPathEffect(kTestPathEffect1.get());}},
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setPathEffect(kTestPathEffect2.get());}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setPathEffect(nullptr);}},
}
},
{ "SetMaskFilter", {
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&kTestMaskFilter1);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&kTestMaskFilter2);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&kTestMaskFilter3);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&kTestMaskFilter4);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&kTestMaskFilter5);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(nullptr);}},
}
},
{ "Save(Layer)+Restore", {
{5, 104, 5, 104, [](DisplayListBuilder& b) {
b.saveLayer(nullptr, SaveLayerOptions::kNoAttributes, &kTestCFImageFilter1);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
// There are many reasons that save and restore can elide content, including
// whether or not there are any draw operations between them, whether or not
// there are any state changes to restore, and whether group rendering (opacity)
// optimizations can allow attributes to be distributed to the children.
// To prevent those cases we include at least one clip operation and 2 overlapping
// rendering primitives between each save/restore pair.
{5, 88, 5, 88, [](DisplayListBuilder& b) {
b.save();
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
{5, 88, 5, 88, [](DisplayListBuilder& b) {
b.saveLayer(nullptr, false);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
{5, 88, 5, 88, [](DisplayListBuilder& b) {
b.saveLayer(nullptr, true);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
{5, 104, 5, 104, [](DisplayListBuilder& b) {
b.saveLayer(&kTestBounds, false);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
{5, 104, 5, 104, [](DisplayListBuilder& b) {
b.saveLayer(&kTestBounds, true);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
// backdrop variants - using the TestCFImageFilter because it can be
// reconstituted in the DL->SkCanvas->DL stream
// {5, 104, 5, 104, [](DisplayListBuilder& b) {
// b.saveLayer(nullptr, SaveLayerOptions::kNoAttributes, &kTestCFImageFilter1);
// b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
// b.drawRect({5, 5, 15, 15});
// b.drawRect({10, 10, 20, 20});
// b.restore();
// }},
{5, 104, 5, 104, [](DisplayListBuilder& b) {
b.saveLayer(nullptr, SaveLayerOptions::kWithAttributes, &kTestCFImageFilter1);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
{5, 120, 5, 120, [](DisplayListBuilder& b) {
b.saveLayer(&kTestBounds, SaveLayerOptions::kNoAttributes, &kTestCFImageFilter1);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
{5, 120, 5, 120, [](DisplayListBuilder& b) {
b.saveLayer(&kTestBounds, SaveLayerOptions::kWithAttributes, &kTestCFImageFilter1);
b.clipRect({0, 0, 25, 25}, SkClipOp::kIntersect, true);
b.drawRect({5, 5, 15, 15});
b.drawRect({10, 10, 20, 20});
b.restore();
}},
}
},
{ "Translate", {
// cv.translate(0, 0) is ignored
{1, 16, 1, 16, [](DisplayListBuilder& b) {b.translate(10, 10);}},
{1, 16, 1, 16, [](DisplayListBuilder& b) {b.translate(10, 15);}},
{1, 16, 1, 16, [](DisplayListBuilder& b) {b.translate(15, 10);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.translate(0, 0);}},
}
},
{ "Scale", {
// cv.scale(1, 1) is ignored
{1, 16, 1, 16, [](DisplayListBuilder& b) {b.scale(2, 2);}},
{1, 16, 1, 16, [](DisplayListBuilder& b) {b.scale(2, 3);}},
{1, 16, 1, 16, [](DisplayListBuilder& b) {b.scale(3, 2);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.scale(1, 1);}},
}
},
{ "Rotate", {
// cv.rotate(0) is ignored, otherwise expressed as concat(rotmatrix)
{1, 8, 1, 32, [](DisplayListBuilder& b) {b.rotate(30);}},
{1, 8, 1, 32, [](DisplayListBuilder& b) {b.rotate(45);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.rotate(0);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.rotate(360);}},
}
},
{ "Skew", {
// cv.skew(0, 0) is ignored, otherwise expressed as concat(skewmatrix)
{1, 16, 1, 32, [](DisplayListBuilder& b) {b.skew(0.1, 0.1);}},
{1, 16, 1, 32, [](DisplayListBuilder& b) {b.skew(0.1, 0.2);}},
{1, 16, 1, 32, [](DisplayListBuilder& b) {b.skew(0.2, 0.1);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.skew(0, 0);}},
}
},
{ "Transform2DAffine", {
{1, 32, 1, 32, [](DisplayListBuilder& b) {b.transform2DAffine(0, 1, 12, 1, 0, 33);}},
// b.transform(identity) is ignored
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.transform2DAffine(1, 0, 0, 0, 1, 0);}},
}
},
{ "TransformFullPerspective", {
{1, 72, 1, 72, [](DisplayListBuilder& b) {b.transformFullPerspective(0, 1, 0, 12,
1, 0, 0, 33,
3, 2, 5, 29,
0, 0, 0, 12);}},
// b.transform(2D affine) is reduced to 2x3
{1, 32, 1, 32, [](DisplayListBuilder& b) {b.transformFullPerspective(2, 1, 0, 4,
1, 3, 0, 5,
0, 0, 1, 0,
0, 0, 0, 1);}},
// b.transform(identity) is ignored
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.transformFullPerspective(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);}},
}
},
{ "ClipRect", {
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipRect(kTestBounds, SkClipOp::kIntersect, true);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipRect(kTestBounds.makeOffset(1, 1),
SkClipOp::kIntersect, true);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipRect(kTestBounds, SkClipOp::kIntersect, false);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipRect(kTestBounds, SkClipOp::kDifference, true);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipRect(kTestBounds, SkClipOp::kDifference, false);}},
}
},
{ "ClipRRect", {
{1, 64, 1, 64, [](DisplayListBuilder& b) {b.clipRRect(kTestRRect, SkClipOp::kIntersect, true);}},
{1, 64, 1, 64, [](DisplayListBuilder& b) {b.clipRRect(kTestRRect.makeOffset(1, 1),
SkClipOp::kIntersect, true);}},
{1, 64, 1, 64, [](DisplayListBuilder& b) {b.clipRRect(kTestRRect, SkClipOp::kIntersect, false);}},
{1, 64, 1, 64, [](DisplayListBuilder& b) {b.clipRRect(kTestRRect, SkClipOp::kDifference, true);}},
{1, 64, 1, 64, [](DisplayListBuilder& b) {b.clipRRect(kTestRRect, SkClipOp::kDifference, false);}},
}
},
{ "ClipPath", {
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipPath(kTestPath1, SkClipOp::kIntersect, true);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipPath(kTestPath2, SkClipOp::kIntersect, true);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipPath(kTestPath3, SkClipOp::kIntersect, true);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipPath(kTestPath1, SkClipOp::kIntersect, false);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipPath(kTestPath1, SkClipOp::kDifference, true);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipPath(kTestPath1, SkClipOp::kDifference, false);}},
// clipPath(rect) becomes clipRect
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.clipPath(kTestPathRect, SkClipOp::kIntersect, true);}},
// clipPath(oval) becomes clipRRect
{1, 64, 1, 64, [](DisplayListBuilder& b) {b.clipPath(kTestPathOval, SkClipOp::kIntersect, true);}},
}
},
{ "DrawPaint", {
{1, 8, 1, 8, [](DisplayListBuilder& b) {b.drawPaint();}},
}
},
{ "DrawColor", {
// cv.drawColor becomes cv.drawPaint(paint)
{1, 16, 1, 24, [](DisplayListBuilder& b) {b.drawColor(SK_ColorBLUE, DlBlendMode::kSrcIn);}},
{1, 16, 1, 24, [](DisplayListBuilder& b) {b.drawColor(SK_ColorBLUE, DlBlendMode::kDstIn);}},
{1, 16, 1, 24, [](DisplayListBuilder& b) {b.drawColor(SK_ColorCYAN, DlBlendMode::kSrcIn);}},
}
},
{ "DrawLine", {
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawLine({0, 0}, {10, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawLine({0, 1}, {10, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawLine({0, 0}, {20, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawLine({0, 0}, {10, 20});}},
}
},
{ "DrawRect", {
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawRect({0, 0, 10, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawRect({0, 1, 10, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawRect({0, 0, 20, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawRect({0, 0, 10, 20});}},
}
},
{ "DrawOval", {
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawOval({0, 0, 10, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawOval({0, 1, 10, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawOval({0, 0, 20, 10});}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawOval({0, 0, 10, 20});}},
}
},
{ "DrawCircle", {
// cv.drawCircle becomes cv.drawOval
{1, 16, 1, 24, [](DisplayListBuilder& b) {b.drawCircle({0, 0}, 10);}},
{1, 16, 1, 24, [](DisplayListBuilder& b) {b.drawCircle({0, 5}, 10);}},
{1, 16, 1, 24, [](DisplayListBuilder& b) {b.drawCircle({0, 0}, 20);}},
}
},
{ "DrawRRect", {
{1, 56, 1, 56, [](DisplayListBuilder& b) {b.drawRRect(kTestRRect);}},
{1, 56, 1, 56, [](DisplayListBuilder& b) {b.drawRRect(kTestRRect.makeOffset(5, 5));}},
}
},
{ "DrawDRRect", {
{1, 112, 1, 112, [](DisplayListBuilder& b) {b.drawDRRect(kTestRRect, kTestInnerRRect);}},
{1, 112, 1, 112, [](DisplayListBuilder& b) {b.drawDRRect(kTestRRect.makeOffset(5, 5),
kTestInnerRRect.makeOffset(4, 4));}},
}
},
{ "DrawPath", {
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawPath(kTestPath1);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawPath(kTestPath2);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawPath(kTestPath3);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawPath(kTestPathRect);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawPath(kTestPathOval);}},
}
},
{ "DrawArc", {
{1, 32, 1, 32, [](DisplayListBuilder& b) {b.drawArc(kTestBounds, 45, 270, false);}},
{1, 32, 1, 32, [](DisplayListBuilder& b) {b.drawArc(kTestBounds.makeOffset(1, 1),
45, 270, false);}},
{1, 32, 1, 32, [](DisplayListBuilder& b) {b.drawArc(kTestBounds, 30, 270, false);}},
{1, 32, 1, 32, [](DisplayListBuilder& b) {b.drawArc(kTestBounds, 45, 260, false);}},
{1, 32, 1, 32, [](DisplayListBuilder& b) {b.drawArc(kTestBounds, 45, 270, true);}},
}
},
{ "DrawPoints", {
{1, 8 + TestPointCount * 8, 1, 8 + TestPointCount * 8,
[](DisplayListBuilder& b) {b.drawPoints(SkCanvas::kPoints_PointMode,
TestPointCount,
TestPoints);}},
{1, 8 + (TestPointCount - 1) * 8, 1, 8 + (TestPointCount - 1) * 8,
[](DisplayListBuilder& b) {b.drawPoints(SkCanvas::kPoints_PointMode,
TestPointCount - 1,
TestPoints);}},
{1, 8 + TestPointCount * 8, 1, 8 + TestPointCount * 8,
[](DisplayListBuilder& b) {b.drawPoints(SkCanvas::kLines_PointMode,
TestPointCount,
TestPoints);}},
{1, 8 + TestPointCount * 8, 1, 8 + TestPointCount * 8,
[](DisplayListBuilder& b) {b.drawPoints(SkCanvas::kPolygon_PointMode,
TestPointCount,
TestPoints);}},
}
},
{ "DrawVertices", {
{1, 112, 1, 16, [](DisplayListBuilder& b) {b.drawVertices(TestVertices1, DlBlendMode::kSrcIn);}},
{1, 112, 1, 16, [](DisplayListBuilder& b) {b.drawVertices(TestVertices1, DlBlendMode::kDstIn);}},
{1, 112, 1, 16, [](DisplayListBuilder& b) {b.drawVertices(TestVertices2, DlBlendMode::kSrcIn);}},
}
},
{ "DrawImage", {
{1, 24, -1, 48, [](DisplayListBuilder& b) {b.drawImage(TestImage1, {10, 10}, kNearestSampling, false);}},
{1, 24, -1, 48, [](DisplayListBuilder& b) {b.drawImage(TestImage1, {10, 10}, kNearestSampling, true);}},
{1, 24, -1, 48, [](DisplayListBuilder& b) {b.drawImage(TestImage1, {20, 10}, kNearestSampling, false);}},
{1, 24, -1, 48, [](DisplayListBuilder& b) {b.drawImage(TestImage1, {10, 20}, kNearestSampling, false);}},
{1, 24, -1, 48, [](DisplayListBuilder& b) {b.drawImage(TestImage1, {10, 10}, kLinearSampling, false);}},
{1, 24, -1, 48, [](DisplayListBuilder& b) {b.drawImage(TestImage2, {10, 10}, kNearestSampling, false);}},
}
},
{ "DrawImageRect", {
{1, 56, -1, 80, [](DisplayListBuilder& b) {b.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80},
kNearestSampling, false);}},
{1, 56, -1, 80, [](DisplayListBuilder& b) {b.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80},
kNearestSampling, true);}},
{1, 56, -1, 80, [](DisplayListBuilder& b) {b.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80},
kNearestSampling, false,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint);}},
{1, 56, -1, 80, [](DisplayListBuilder& b) {b.drawImageRect(TestImage1, {10, 10, 25, 20}, {10, 10, 80, 80},
kNearestSampling, false);}},
{1, 56, -1, 80, [](DisplayListBuilder& b) {b.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 85, 80},
kNearestSampling, false);}},
{1, 56, -1, 80, [](DisplayListBuilder& b) {b.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80},
kLinearSampling, false);}},
{1, 56, -1, 80, [](DisplayListBuilder& b) {b.drawImageRect(TestImage2, {10, 10, 15, 15}, {10, 10, 80, 80},
kNearestSampling, false);}},
}
},
{ "DrawImageNine", {
// SkVanvas::drawImageNine is immediately converted to drawImageLattice
{1, 48, -1, 80, [](DisplayListBuilder& b) {b.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80},
DlFilterMode::kNearest, false);}},
{1, 48, -1, 80, [](DisplayListBuilder& b) {b.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80},
DlFilterMode::kNearest, true);}},
{1, 48, -1, 80, [](DisplayListBuilder& b) {b.drawImageNine(TestImage1, {10, 10, 25, 20}, {10, 10, 80, 80},
DlFilterMode::kNearest, false);}},
{1, 48, -1, 80, [](DisplayListBuilder& b) {b.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 85, 80},
DlFilterMode::kNearest, false);}},
{1, 48, -1, 80, [](DisplayListBuilder& b) {b.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80},
DlFilterMode::kLinear, false);}},
{1, 48, -1, 80, [](DisplayListBuilder& b) {b.drawImageNine(TestImage2, {10, 10, 15, 15}, {10, 10, 80, 80},
DlFilterMode::kNearest, false);}},
}
},
{ "DrawImageLattice", {
// Lattice:
// const int* fXDivs; //!< x-axis values dividing bitmap
// const int* fYDivs; //!< y-axis values dividing bitmap
// const RectType* fRectTypes; //!< array of fill types
// int fXCount; //!< number of x-coordinates
// int fYCount; //!< number of y-coordinates
// const SkIRect* fBounds; //!< source bounds to draw from
// const SkColor* fColors; //!< array of colors
// size = 64 + fXCount * 4 + fYCount * 4
// if fColors and fRectTypes are not null, add (fXCount + 1) * (fYCount + 1) * 5
{1, 88, -1, 88, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage1,
{kTestDivs1, kTestDivs1, nullptr, 3, 3, nullptr, nullptr},
{10, 10, 40, 40}, DlFilterMode::kNearest, false);}},
{1, 88, -1, 88, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage1,
{kTestDivs1, kTestDivs1, nullptr, 3, 3, nullptr, nullptr},
{10, 10, 40, 45}, DlFilterMode::kNearest, false);}},
{1, 88, -1, 88, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage1,
{kTestDivs2, kTestDivs1, nullptr, 3, 3, nullptr, nullptr},
{10, 10, 40, 40}, DlFilterMode::kNearest, false);}},
// One less yDiv does not change the allocation due to 8-byte alignment
{1, 88, -1, 88, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage1,
{kTestDivs1, kTestDivs1, nullptr, 3, 2, nullptr, nullptr},
{10, 10, 40, 40}, DlFilterMode::kNearest, false);}},
{1, 88, -1, 88, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage1,
{kTestDivs1, kTestDivs1, nullptr, 3, 3, nullptr, nullptr},
{10, 10, 40, 40}, DlFilterMode::kLinear, false);}},
{1, 96, -1, 96, [](DisplayListBuilder& b) {b.setColor(SK_ColorMAGENTA);
b.drawImageLattice(TestImage1,
{kTestDivs1, kTestDivs1, nullptr, 3, 3, nullptr, nullptr},
{10, 10, 40, 40}, DlFilterMode::kNearest, true);}},
{1, 88, -1, 88, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage2,
{kTestDivs1, kTestDivs1, nullptr, 3, 3, nullptr, nullptr},
{10, 10, 40, 40}, DlFilterMode::kNearest, false);}},
// Supplying fBounds does not change size because the Op record always includes it
{1, 88, -1, 88, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage1,
{kTestDivs1, kTestDivs1, nullptr, 3, 3, &kTestLatticeSrcRect, nullptr},
{10, 10, 40, 40}, DlFilterMode::kNearest, false);}},
{1, 128, -1, 128, [](DisplayListBuilder& b) {b.drawImageLattice(TestImage1,
{kTestDivs3, kTestDivs3, kTestRTypes, 2, 2, nullptr, kTestLatticeColors},
{10, 10, 40, 40}, DlFilterMode::kNearest, false);}},
}
},
{ "DrawAtlas", {
{1, 48 + 32 + 8, -1, 48 + 32 + 32, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
b.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn,
kNearestSampling, nullptr, false);}},
{1, 48 + 32 + 8, -1, 48 + 32 + 32, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
b.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn,
kNearestSampling, nullptr, true);}},
{1, 48 + 32 + 8, -1, 48 + 32 + 32, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {0, 1, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
b.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn,
kNearestSampling, nullptr, false);}},
{1, 48 + 32 + 8, -1, 48 + 32 + 32, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 25, 30, 30} };
b.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn,
kNearestSampling, nullptr, false);}},
{1, 48 + 32 + 8, -1, 48 + 32 + 32, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
b.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn,
kLinearSampling, nullptr, false);}},
{1, 48 + 32 + 8, -1, 48 + 32 + 32, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
b.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kDstIn,
kNearestSampling, nullptr, false);}},
{1, 64 + 32 + 8, -1, 64 + 32 + 32, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
static SkRect cullRect = { 0, 0, 200, 200 };
b.drawAtlas(TestImage2, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn,
kNearestSampling, &cullRect, false);}},
{1, 48 + 32 + 8 + 8, -1, 48 + 32 + 32 + 8, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
static DlColor colors[] = { DlColor::kBlue(), DlColor::kGreen() };
b.drawAtlas(TestImage1, xforms, texs, colors, 2, DlBlendMode::kSrcIn,
kNearestSampling, nullptr, false);}},
{1, 64 + 32 + 8 + 8, -1, 64 + 32 + 32 + 8, [](DisplayListBuilder& b) {
static SkRSXform xforms[] = { {1, 0, 0, 0}, {0, 1, 0, 0} };
static SkRect texs[] = { { 10, 10, 20, 20 }, {20, 20, 30, 30} };
static DlColor colors[] = { DlColor::kBlue(), DlColor::kGreen() };
static SkRect cullRect = { 0, 0, 200, 200 };
b.drawAtlas(TestImage1, xforms, texs, colors, 2, DlBlendMode::kSrcIn,
kNearestSampling, &cullRect, false);}},
}
},
{ "DrawPicture", {
// cv.drawPicture cannot be compared as SkCanvas may inline it
{1, 16, -1, 16, [](DisplayListBuilder& b) {b.drawPicture(TestPicture1, nullptr, false);}},
{1, 16, -1, 16, [](DisplayListBuilder& b) {b.drawPicture(TestPicture2, nullptr, false);}},
{1, 16, -1, 16, [](DisplayListBuilder& b) {b.drawPicture(TestPicture1, nullptr, true);}},
{1, 56, -1, 56, [](DisplayListBuilder& b) {b.drawPicture(TestPicture1, &kTestMatrix1, false);}},
{1, 56, -1, 56, [](DisplayListBuilder& b) {b.drawPicture(TestPicture1, &kTestMatrix2, false);}},
{1, 56, -1, 56, [](DisplayListBuilder& b) {b.drawPicture(TestPicture1, &kTestMatrix1, true);}},
}
},
{ "DrawDisplayList", {
// cv.drawDL does not exist
{1, 16, -1, 16, [](DisplayListBuilder& b) {b.drawDisplayList(TestDisplayList1);}},
{1, 16, -1, 16, [](DisplayListBuilder& b) {b.drawDisplayList(TestDisplayList2);}},
}
},
{ "DrawTextBlob", {
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawTextBlob(TestBlob1, 10, 10);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawTextBlob(TestBlob1, 20, 10);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawTextBlob(TestBlob1, 10, 20);}},
{1, 24, 1, 24, [](DisplayListBuilder& b) {b.drawTextBlob(TestBlob2, 10, 10);}},
}
},
// The -1 op counts below are to indicate to the framework not to test
// SkCanvas conversion of these ops as it converts the operation into a
// format that is not exposed publicly and so we cannot recapture the
// operation.
// See: https://bugs.chromium.org/p/skia/issues/detail?id=12125
{ "DrawShadow", {
// cv shadows are turned into an opaque ShadowRec which is not exposed
{1, 32, -1, 32, [](DisplayListBuilder& b) {b.drawShadow(kTestPath1, SK_ColorGREEN, 1.0, false, 1.0);}},
{1, 32, -1, 32, [](DisplayListBuilder& b) {b.drawShadow(kTestPath2, SK_ColorGREEN, 1.0, false, 1.0);}},
{1, 32, -1, 32, [](DisplayListBuilder& b) {b.drawShadow(kTestPath1, SK_ColorBLUE, 1.0, false, 1.0);}},
{1, 32, -1, 32, [](DisplayListBuilder& b) {b.drawShadow(kTestPath1, SK_ColorGREEN, 2.0, false, 1.0);}},
{1, 32, -1, 32, [](DisplayListBuilder& b) {b.drawShadow(kTestPath1, SK_ColorGREEN, 1.0, true, 1.0);}},
{1, 32, -1, 32, [](DisplayListBuilder& b) {b.drawShadow(kTestPath1, SK_ColorGREEN, 1.0, false, 2.5);}},
}
},
};
static std::vector<testing::DisplayListInvocationGroup> allGroups =
CreateAllGroups();
TEST(DisplayList, SingleOpSizes) {
for (auto& group : allGroups) {

View File

@ -13,4 +13,5 @@ set -ex
./fml_benchmarks --benchmark_format=json > fml_benchmarks.json
./shell_benchmarks --benchmark_format=json > shell_benchmarks.json
./ui_benchmarks --benchmark_format=json > ui_benchmarks.json
./display_list_builder_benchmarks --benchmark_format=json > display_list_builder_benchmarks.json

View File

@ -440,6 +440,10 @@ def RunEngineBenchmarks(build_dir, filter):
RunEngineExecutable(build_dir, 'ui_benchmarks', filter, icu_flags)
RunEngineExecutable(
build_dir, 'display_list_builder_benchmarks', filter, icu_flags
)
if IsLinux():
RunEngineExecutable(build_dir, 'txt_benchmarks', filter, icu_flags)