// 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 #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/core/SkMaskFilter.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( base::AlignedAlloc(kMaxSerializedBufferBytes, PaintOpBuffer::PaintOpAlign))), deserialized_data_(static_cast( 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 serialized_data_; std::unique_ptr 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(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(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(SkMaskFilter::MakeBlur( SkBlurStyle::kOuter_SkBlurStyle, 4.3f, SkRect::MakeXYWH(1, 1, 1, 1))); 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 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(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 typefaces = {typeface}; auto blob = base::MakeRefCounted(builder.make(), typefaces); PaintFlags flags; for (size_t i = 0; i < 100; ++i) buffer.push(blob, 0.f, 0.f, flags); RunTest("text", buffer); } } // namespace } // namespace cc