blob: 93d7ef0113499e496659312dedbd370b7f7d7672 [file] [log] [blame]
// Copyright 2013 The Chromium 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 <utility>
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
#include "cc/base/lap_timer.h"
#include "cc/paint/paint_op_buffer.h"
#include "cc/paint/paint_op_buffer_serializer.h"
#include "cc/test/transfer_cache_test_helper.h"
#include "testing/perf/perf_test.h"
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
namespace cc {
namespace {
static const int kTimeLimitMillis = 2000;
static const int kNumWarmupRuns = 20;
static const int kTimeCheckInterval = 1;
static const size_t kMaxSerializedBufferBytes = 100000;
class PaintOpPerfTest : public testing::Test {
public:
PaintOpPerfTest()
: timer_(kNumWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval),
serialized_data_(static_cast<char*>(
base::AlignedAlloc(kMaxSerializedBufferBytes,
PaintOpBuffer::PaintOpAlign))),
deserialized_data_(static_cast<char*>(
base::AlignedAlloc(sizeof(LargestPaintOp),
PaintOpBuffer::PaintOpAlign))) {}
void RunTest(const std::string& name, const PaintOpBuffer& buffer) {
TransferCacheTestHelper helper;
PaintOp::SerializeOptions serialize_options;
serialize_options.transfer_cache = &helper;
PaintOp::DeserializeOptions deserialize_options;
deserialize_options.transfer_cache = &helper;
size_t bytes_written = 0u;
PaintOpBufferSerializer::Preamble preamble;
timer_.Reset();
do {
SimpleBufferSerializer serializer(
serialized_data_.get(), kMaxSerializedBufferBytes,
serialize_options.image_provider, serialize_options.transfer_cache);
serializer.Serialize(&buffer, nullptr, preamble);
bytes_written = serializer.written();
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
CHECK_GT(bytes_written, 0u);
perf_test::PrintResult(name.c_str(), "", " serialize",
buffer.size() * timer_.LapsPerSecond(), "ops/s",
true);
size_t bytes_read = 0;
timer_.Reset();
do {
size_t remaining_read_bytes = bytes_written;
char* to_read = serialized_data_.get();
while (true) {
PaintOp* deserialized_op = PaintOp::Deserialize(
to_read, remaining_read_bytes, deserialized_data_.get(),
sizeof(LargestPaintOp), &bytes_read, deserialize_options);
deserialized_op->DestroyThis();
DCHECK_GE(remaining_read_bytes, bytes_read);
if (remaining_read_bytes == bytes_read)
break;
remaining_read_bytes -= bytes_read;
to_read += bytes_read;
}
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
perf_test::PrintResult(name.c_str(), "", "deserialize",
buffer.size() * timer_.LapsPerSecond(), "ops/s",
true);
}
protected:
LapTimer timer_;
std::unique_ptr<char, base::AlignedFreeDeleter> serialized_data_;
std::unique_ptr<char, base::AlignedFreeDeleter> deserialized_data_;
};
// Ops that can be memcopied both when serializing and deserializing.
TEST_F(PaintOpPerfTest, SimpleOps) {
PaintOpBuffer buffer;
for (size_t i = 0; i < 100; ++i)
buffer.push<ConcatOp>(SkMatrix::I());
RunTest("simple", buffer);
}
// Drawing ops with flags that don't have nested objects.
TEST_F(PaintOpPerfTest, DrawOps) {
PaintOpBuffer buffer;
PaintFlags flags;
for (size_t i = 0; i < 100; ++i)
buffer.push<DrawRectOp>(SkRect::MakeXYWH(1, 1, 1, 1), flags);
RunTest("draw", buffer);
}
// Ops with worst case flags.
TEST_F(PaintOpPerfTest, ManyFlagsOps) {
PaintOpBuffer buffer;
PaintFlags flags;
SkScalar intervals[] = {1.f, 1.f};
flags.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
flags.setMaskFilter(SkBlurMaskFilter::Make(SkBlurStyle::kOuter_SkBlurStyle,
4.3f, SkRect::MakeXYWH(1, 1, 1, 1),
kHigh_SkBlurQuality));
flags.setColorFilter(
SkColorMatrixFilter::MakeLightingFilter(SK_ColorYELLOW, SK_ColorGREEN));
SkLayerDrawLooper::Builder looper_builder;
looper_builder.addLayer();
looper_builder.addLayer(2.3f, 4.5f);
SkLayerDrawLooper::LayerInfo layer_info;
looper_builder.addLayer(layer_info);
flags.setLooper(looper_builder.detach());
sk_sp<PaintShader> shader = PaintShader::MakeColor(SK_ColorTRANSPARENT);
flags.setShader(std::move(shader));
SkPath path;
path.addCircle(2, 2, 5);
path.addCircle(3, 4, 2);
path.addArc(SkRect::MakeXYWH(1, 2, 3, 4), 5, 6);
for (size_t i = 0; i < 100; ++i)
buffer.push<DrawPathOp>(path, flags);
RunTest("flags", buffer);
}
// DrawTextBlobOps,
TEST_F(PaintOpPerfTest, TextOps) {
PaintOpBuffer buffer;
auto typeface = PaintTypeface::TestTypeface();
SkPaint font;
font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
font.setTypeface(typeface.ToSkTypeface());
SkTextBlobBuilder builder;
int glyph_count = 5;
SkRect rect = SkRect::MakeXYWH(1, 1, 1, 1);
const auto& run = builder.allocRun(font, glyph_count, 1.2f, 2.3f, &rect);
std::fill(run.glyphs, run.glyphs + glyph_count, 0);
std::vector<PaintTypeface> typefaces = {typeface};
auto blob = base::MakeRefCounted<PaintTextBlob>(builder.make(), typefaces);
PaintFlags flags;
for (size_t i = 0; i < 100; ++i)
buffer.push<DrawTextBlobOp>(blob, 0.f, 0.f, flags);
RunTest("text", buffer);
}
} // namespace
} // namespace cc