| Index: bench/SkBlend_optsBench.cpp
|
| diff --git a/bench/SkBlend_optsBench.cpp b/bench/SkBlend_optsBench.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9c34d49f34bc3b60b68321ef1fca748858f34a16
|
| --- /dev/null
|
| +++ b/bench/SkBlend_optsBench.cpp
|
| @@ -0,0 +1,167 @@
|
| +/*
|
| + * Copyright 2016 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include <tuple>
|
| +
|
| +#include "Benchmark.h"
|
| +#include "Resources.h"
|
| +#include "SkCpu.h"
|
| +#include "SkImage.h"
|
| +#include "SkImage_Base.h"
|
| +#include "SkNx.h"
|
| +#include "SkOpts.h"
|
| +#include "SkString.h"
|
| +
|
| +#define INNER_LOOPS 10
|
| +
|
| +namespace sk_default {
|
| +extern void brute_force_srcover_srgb_srgb(
|
| + uint32_t* dst, const uint32_t* const srcStart, int ndst, const int nsrc);
|
| +}
|
| +
|
| +class SrcOverVSkOptsBruteForce {
|
| +public:
|
| + static SkString Name() { return SkString{"VSkOptsBruteForce"}; }
|
| + static bool WorksOnCpu() { return true; }
|
| + static void BlendN(uint32_t* dst, int count, const uint32_t* src) {
|
| + sk_default::brute_force_srcover_srgb_srgb(dst, src, count, count);
|
| + }
|
| +};
|
| +
|
| +namespace sk_default {
|
| +extern void trivial_srcover_srgb_srgb(
|
| + uint32_t* dst, const uint32_t* const srcStart, int ndst, const int nsrc);
|
| +}
|
| +
|
| +class SrcOverVSkOptsTrivial {
|
| +public:
|
| + static SkString Name() { return SkString{"VSkOptsTrivial"}; }
|
| + static bool WorksOnCpu() { return true; }
|
| + static void BlendN(uint32_t* dst, int count, const uint32_t* src) {
|
| + sk_default::trivial_srcover_srgb_srgb(dst, src, count, count);
|
| + }
|
| +};
|
| +
|
| +namespace sk_default {
|
| +extern void best_non_simd_srcover_srgb_srgb(
|
| + uint32_t* dst, const uint32_t* const srcStart, int ndst, const int nsrc);
|
| +}
|
| +
|
| +class SrcOverVSkOptsNonSimdCore {
|
| +public:
|
| + static SkString Name() { return SkString{"VSkOptsNonSimdCore"}; }
|
| + static bool WorksOnCpu() { return true; }
|
| + static void BlendN(uint32_t* dst, int count, const uint32_t* src) {
|
| + sk_default::best_non_simd_srcover_srgb_srgb(dst, src, count, count);
|
| + }
|
| +};
|
| +
|
| +namespace sk_default {
|
| +extern void srcover_srgb_srgb(
|
| + uint32_t* dst, const uint32_t* const srcStart, int ndst, const int nsrc);
|
| +}
|
| +
|
| +class SrcOverVSkOptsDefault {
|
| +public:
|
| + static SkString Name() { return SkString{"VSkOptsDefault"}; }
|
| + static bool WorksOnCpu() { return true; }
|
| + static void BlendN(uint32_t* dst, int count, const uint32_t* src) {
|
| + sk_default::srcover_srgb_srgb(dst, src, count, count);
|
| + }
|
| +};
|
| +
|
| +namespace sk_sse41 {
|
| + extern void srcover_srgb_srgb(
|
| + uint32_t* dst, const uint32_t* const srcStart, int ndst, const int nsrc);
|
| +}
|
| +
|
| +class SrcOverVSkOptsSSE41 {
|
| +public:
|
| + static SkString Name() { return SkString{"VSkOptsSSE41"}; }
|
| + static bool WorksOnCpu() { return SkCpu::Supports(SkCpu::SSE41); }
|
| + static void BlendN(uint32_t* dst, int count, const uint32_t* src) {
|
| + sk_sse41::srcover_srgb_srgb(dst, src, count, count);
|
| + }
|
| +};
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +template <typename Blender>
|
| +class LinearSrcOverBench : public Benchmark {
|
| +public:
|
| + LinearSrcOverBench(const char* fileName) {
|
| + fName = "LinearSrcOver";
|
| + fName.append(fileName);
|
| + fName.append(Blender::Name());
|
| +
|
| + sk_sp<SkImage> image = GetResourceAsImage(fileName);
|
| + SkBitmap bm;
|
| + if (!as_IB(image)->getROPixels(&bm)) {
|
| + SkFAIL("Could not read resource");
|
| + }
|
| + bm.peekPixels(&fPixmap);
|
| + fCount = fPixmap.rowBytesAsPixels();
|
| + fDst.reset(fCount);
|
| + memset(fDst.get(), 0, fPixmap.rowBytes());
|
| + }
|
| +
|
| +protected:
|
| + bool isSuitableFor(Backend backend) override {
|
| + return backend == kNonRendering_Backend && Blender::WorksOnCpu();
|
| + }
|
| + const char* onGetName() override { return fName.c_str(); }
|
| + void onDraw(int loops, SkCanvas*) override {
|
| + SkASSERT(fPixmap.colorType() == kN32_SkColorType);
|
| +
|
| + const int width = fPixmap.rowBytesAsPixels();
|
| +
|
| + for (int i = 0; i < loops * INNER_LOOPS; ++i) {
|
| + const uint32_t* src = fPixmap.addr32();
|
| + for (int y = 0; y < fPixmap.height(); y++) {
|
| + Blender::BlendN(fDst.get(), width, src);
|
| + src += width;
|
| + }
|
| + }
|
| + }
|
| +
|
| + void onPostDraw(SkCanvas*) override {
|
| + // Make sure the compiler does not optimize away the operation.
|
| + volatile uint32_t v = 0;
|
| + for (int i = 0; i < fCount; i++) {
|
| + v ^= fDst[i];
|
| + }
|
| + }
|
| +
|
| +private:
|
| + int fCount;
|
| + SkAutoTArray<uint32_t> fDst;
|
| + SkString fName;
|
| + SkPixmap fPixmap;
|
| +
|
| + typedef Benchmark INHERITED;
|
| +};
|
| +
|
| +#if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
|
| +#define BENCHES(fileName) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsBruteForce>(fileName); ) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsTrivial>(fileName); ) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsNonSimdCore>(fileName); ) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsDefault>(fileName); ) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsSSE41>(fileName); )
|
| +#else
|
| +#define BENCHES(fileName) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsBruteForce>(fileName); ) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsTrivial>(fileName); ) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsNonSimdCore>(fileName); ) \
|
| +DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsDefault>(fileName); )
|
| +#endif
|
| +
|
| +BENCHES("yellow_rose.png")
|
| +BENCHES("baby_tux.png")
|
| +BENCHES("plane.png")
|
| +BENCHES("mandrill_512.png")
|
| +BENCHES("iconstrip.png")
|
|
|