blob: d2dfbcd55161d5e9cd3b6703bccc1e93ab29302b [file] [log] [blame]
// 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/display_list/display_list.h"
#include "flutter/display_list/display_list_builder.h"
#include "flutter/display_list/display_list_complexity.h"
#include "flutter/display_list/display_list_complexity_gl.h"
#include "flutter/display_list/display_list_complexity_metal.h"
#include "flutter/display_list/display_list_sampling_options.h"
#include "flutter/display_list/display_list_test_utils.h"
#include "flutter/testing/testing.h"
#include "third_party/skia/include/core/SkColor.h"
namespace flutter {
namespace testing {
namespace {
std::vector<DisplayListComplexityCalculator*> Calculators() {
return {DisplayListMetalComplexityCalculator::GetInstance(),
DisplayListGLComplexityCalculator::GetInstance(),
DisplayListNaiveComplexityCalculator::GetInstance()};
}
std::vector<DisplayListComplexityCalculator*> AccumulatorCalculators() {
return {DisplayListMetalComplexityCalculator::GetInstance(),
DisplayListGLComplexityCalculator::GetInstance()};
}
std::vector<SkPoint> GetTestPoints() {
std::vector<SkPoint> points;
points.push_back(SkPoint::Make(0, 0));
points.push_back(SkPoint::Make(10, 0));
points.push_back(SkPoint::Make(10, 10));
points.push_back(SkPoint::Make(20, 10));
points.push_back(SkPoint::Make(20, 20));
return points;
}
} // namespace
TEST(DisplayListComplexity, EmptyDisplayList) {
auto display_list = GetSampleDisplayList(0);
auto calculators = Calculators();
for (auto calculator : calculators) {
ASSERT_EQ(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DisplayListCeiling) {
auto display_list = GetSampleDisplayList();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
calculator->SetComplexityCeiling(10u);
ASSERT_EQ(calculator->Compute(display_list.get()), 10u);
calculator->SetComplexityCeiling(std::numeric_limits<unsigned int>::max());
}
}
TEST(DisplayListComplexity, NestedDisplayList) {
auto display_list = GetSampleNestedDisplayList();
auto calculators = Calculators();
for (auto calculator : calculators) {
// There's only one draw call in the "outer" DisplayList, which calls
// drawDisplayList with the "inner" DisplayList. To ensure we are
// recursing correctly into the inner DisplayList, check that we aren't
// returning 0 (if the function is a no-op) or 1 (as the op_count is 1)
ASSERT_GT(calculator->Compute(display_list.get()), 1u);
}
}
TEST(DisplayListComplexity, AntiAliasing) {
DisplayListBuilder builder_no_aa;
builder_no_aa.drawLine(SkPoint::Make(0, 0), SkPoint::Make(100, 100));
auto display_list_no_aa = builder_no_aa.Build();
DisplayListBuilder builder_aa;
builder_aa.setAntiAlias(true);
builder_aa.drawLine(SkPoint::Make(0, 0), SkPoint::Make(100, 100));
auto display_list_aa = builder_aa.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list_no_aa.get()),
calculator->Compute(display_list_aa.get()));
}
}
TEST(DisplayListComplexity, StrokeWidth) {
DisplayListBuilder builder_stroke_0;
builder_stroke_0.setStrokeWidth(0.0f);
builder_stroke_0.drawLine(SkPoint::Make(0, 0), SkPoint::Make(100, 100));
auto display_list_stroke_0 = builder_stroke_0.Build();
DisplayListBuilder builder_stroke_1;
builder_stroke_1.setStrokeWidth(1.0f);
builder_stroke_1.drawLine(SkPoint::Make(0, 0), SkPoint::Make(100, 100));
auto display_list_stroke_1 = builder_stroke_1.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list_stroke_0.get()),
calculator->Compute(display_list_stroke_1.get()));
}
}
TEST(DisplayListComplexity, Style) {
DisplayListBuilder builder_filled;
builder_filled.setStyle(DlDrawStyle::kFill);
builder_filled.drawRect(SkRect::MakeXYWH(10, 10, 80, 80));
auto display_list_filled = builder_filled.Build();
DisplayListBuilder builder_stroked;
builder_stroked.setStyle(DlDrawStyle::kStroke);
builder_stroked.drawRect(SkRect::MakeXYWH(10, 10, 80, 80));
auto display_list_stroked = builder_stroked.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list_filled.get()),
calculator->Compute(display_list_stroked.get()));
}
}
TEST(DisplayListComplexity, SaveLayers) {
DisplayListBuilder builder;
builder.saveLayer(nullptr, true);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawPath) {
DisplayListBuilder builder_line;
SkPath line_path;
line_path.moveTo(SkPoint::Make(0, 0));
line_path.lineTo(SkPoint::Make(10, 10));
line_path.close();
builder_line.drawPath(line_path);
auto display_list_line = builder_line.Build();
DisplayListBuilder builder_quad;
SkPath quad_path;
quad_path.moveTo(SkPoint::Make(0, 0));
quad_path.quadTo(SkPoint::Make(10, 10), SkPoint::Make(10, 20));
quad_path.close();
builder_quad.drawPath(quad_path);
auto display_list_quad = builder_quad.Build();
DisplayListBuilder builder_conic;
SkPath conic_path;
conic_path.moveTo(SkPoint::Make(0, 0));
conic_path.conicTo(SkPoint::Make(10, 10), SkPoint::Make(10, 20), 1.5f);
conic_path.close();
builder_conic.drawPath(conic_path);
auto display_list_conic = builder_conic.Build();
DisplayListBuilder builder_cubic;
SkPath cubic_path;
cubic_path.moveTo(SkPoint::Make(0, 0));
cubic_path.cubicTo(SkPoint::Make(10, 10), SkPoint::Make(10, 20),
SkPoint::Make(20, 20));
builder_cubic.drawPath(cubic_path);
auto display_list_cubic = builder_cubic.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list_line.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_quad.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_conic.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_cubic.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawShadow) {
DisplayListBuilder builder_line;
SkPath line_path;
line_path.moveTo(SkPoint::Make(0, 0));
line_path.lineTo(SkPoint::Make(10, 10));
line_path.close();
builder_line.drawShadow(line_path, SK_ColorRED, 10.0f, false, 1.0f);
auto display_list_line = builder_line.Build();
DisplayListBuilder builder_quad;
SkPath quad_path;
quad_path.moveTo(SkPoint::Make(0, 0));
quad_path.quadTo(SkPoint::Make(10, 10), SkPoint::Make(10, 20));
quad_path.close();
builder_quad.drawShadow(quad_path, SK_ColorRED, 10.0f, false, 1.0f);
auto display_list_quad = builder_quad.Build();
DisplayListBuilder builder_conic;
SkPath conic_path;
conic_path.moveTo(SkPoint::Make(0, 0));
conic_path.conicTo(SkPoint::Make(10, 10), SkPoint::Make(10, 20), 1.5f);
conic_path.close();
builder_conic.drawShadow(conic_path, SK_ColorRED, 10.0f, false, 1.0f);
auto display_list_conic = builder_conic.Build();
DisplayListBuilder builder_cubic;
SkPath cubic_path;
cubic_path.moveTo(SkPoint::Make(0, 0));
cubic_path.cubicTo(SkPoint::Make(10, 10), SkPoint::Make(10, 20),
SkPoint::Make(20, 20));
builder_cubic.drawShadow(cubic_path, SK_ColorRED, 10.0f, false, 1.0f);
auto display_list_cubic = builder_cubic.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list_line.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_quad.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_conic.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_cubic.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawOval) {
DisplayListBuilder builder;
builder.drawOval(SkRect::MakeXYWH(10, 10, 100, 80));
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawCircle) {
DisplayListBuilder builder;
builder.drawCircle(SkPoint::Make(50, 50), 10.0f);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawRRect) {
DisplayListBuilder builder;
builder.drawRRect(
SkRRect::MakeRectXY(SkRect::MakeXYWH(10, 10, 80, 80), 2.0f, 3.0f));
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawDRRect) {
DisplayListBuilder builder;
SkRRect outer =
SkRRect::MakeRectXY(SkRect::MakeXYWH(10, 10, 80, 80), 2.0f, 3.0f);
SkRRect inner =
SkRRect::MakeRectXY(SkRect::MakeXYWH(15, 15, 70, 70), 1.5f, 1.5f);
builder.drawDRRect(outer, inner);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawArc) {
DisplayListBuilder builder;
builder.drawArc(SkRect::MakeXYWH(10, 10, 100, 80), 0.0f, 10.0f, true);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawVertices) {
auto points = GetTestPoints();
auto vertices = DlVertices::Make(DlVertexMode::kTriangles, points.size(),
points.data(), nullptr, nullptr);
DisplayListBuilder builder;
builder.drawVertices(vertices, DlBlendMode::kSrc);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawTextBlob) {
auto text_blob = SkTextBlob::MakeFromString(
"The quick brown fox jumps over the lazy dog.", SkFont());
DisplayListBuilder builder;
builder.drawTextBlob(text_blob, 0.0f, 0.0f);
auto display_list = builder.Build();
DisplayListBuilder builder_multiple;
builder_multiple.drawTextBlob(text_blob, 0.0f, 0.0f);
builder_multiple.drawTextBlob(text_blob, 0.0f, 0.0f);
auto display_list_multiple = builder_multiple.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
ASSERT_GT(calculator->Compute(display_list_multiple.get()),
calculator->Compute(display_list.get()));
}
}
TEST(DisplayListComplexity, DrawPoints) {
auto points = GetTestPoints();
DisplayListBuilder builder_lines;
builder_lines.drawPoints(SkCanvas::kLines_PointMode, points.size(),
points.data());
auto display_list_lines = builder_lines.Build();
DisplayListBuilder builder_points;
builder_points.drawPoints(SkCanvas::kPoints_PointMode, points.size(),
points.data());
auto display_list_points = builder_points.Build();
DisplayListBuilder builder_polygon;
builder_polygon.drawPoints(SkCanvas::kPolygon_PointMode, points.size(),
points.data());
auto display_list_polygon = builder_polygon.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list_lines.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_points.get()), 0u);
ASSERT_NE(calculator->Compute(display_list_polygon.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawImage) {
SkImageInfo info =
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
SkAlphaType::kPremul_SkAlphaType);
SkBitmap bitmap;
bitmap.allocPixels(info, 0);
auto image = SkImage::MakeFromBitmap(bitmap);
DisplayListBuilder builder;
builder.drawImage(DlImage::Make(image), SkPoint::Make(0, 0),
DlImageSampling::kNearestNeighbor, false);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawImageNine) {
SkImageInfo info =
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
SkAlphaType::kPremul_SkAlphaType);
SkBitmap bitmap;
bitmap.allocPixels(info, 0);
auto image = SkImage::MakeFromBitmap(bitmap);
SkIRect center = SkIRect::MakeXYWH(5, 5, 20, 20);
SkRect dest = SkRect::MakeXYWH(0, 0, 50, 50);
DisplayListBuilder builder;
builder.drawImageNine(DlImage::Make(image), center, dest,
DlFilterMode::kNearest, true);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawImageRect) {
SkImageInfo info =
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
SkAlphaType::kPremul_SkAlphaType);
SkBitmap bitmap;
bitmap.allocPixels(info, 0);
auto image = SkImage::MakeFromBitmap(bitmap);
SkRect src = SkRect::MakeXYWH(0, 0, 50, 50);
SkRect dest = SkRect::MakeXYWH(0, 0, 50, 50);
DisplayListBuilder builder;
builder.drawImageRect(DlImage::Make(image), src, dest,
DlImageSampling::kNearestNeighbor, true);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
TEST(DisplayListComplexity, DrawAtlas) {
SkImageInfo info =
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
SkAlphaType::kPremul_SkAlphaType);
SkBitmap bitmap;
bitmap.allocPixels(info, 0);
auto image = SkImage::MakeFromBitmap(bitmap);
std::vector<SkRect> rects;
std::vector<SkRSXform> xforms;
for (int i = 0; i < 10; i++) {
rects.push_back(SkRect::MakeXYWH(0, 0, 10, 10));
xforms.push_back(SkRSXform::Make(0, 0, 0, 0));
}
DisplayListBuilder builder;
builder.drawAtlas(DlImage::Make(image), xforms.data(), rects.data(), nullptr,
10, DlBlendMode::kSrc, DlImageSampling::kNearestNeighbor,
nullptr, true);
auto display_list = builder.Build();
auto calculators = AccumulatorCalculators();
for (auto calculator : calculators) {
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
}
}
} // namespace testing
} // namespace flutter