Home | History | Annotate | Download | only in bench
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include <tuple>
      9 
     10 #include "Benchmark.h"
     11 #include "Resources.h"
     12 #include "SkCpu.h"
     13 #include "SkImage.h"
     14 #include "SkImage_Base.h"
     15 #include "SkNx.h"
     16 #include "SkOpts.h"
     17 #include "SkPM4fPriv.h"
     18 #include "SkString.h"
     19 
     20 #define INNER_LOOPS 10
     21 
     22 static inline void brute_srcover_srgb_srgb_1(uint32_t* dst, uint32_t src) {
     23     auto d = Sk4f_fromS32(*dst),
     24          s = Sk4f_fromS32( src);
     25     *dst = Sk4f_toS32(s + d * (1.0f - s[3]));
     26 }
     27 
     28 static inline void srcover_srgb_srgb_1(uint32_t* dst, uint32_t src) {
     29     if (src >= 0xFF000000) {
     30         *dst = src;
     31         return;
     32     }
     33     brute_srcover_srgb_srgb_1(dst, src);
     34 }
     35 
     36 static void brute_force_srcover_srgb_srgb(
     37     uint32_t* dst, const uint32_t* const src, int ndst, const int nsrc) {
     38     while (ndst > 0) {
     39         int n = SkTMin(ndst, nsrc);
     40 
     41         for (int i = 0; i < n; i++) {
     42             brute_srcover_srgb_srgb_1(dst++, src[i]);
     43         }
     44         ndst -= n;
     45     }
     46 }
     47 
     48 static void trivial_srcover_srgb_srgb(
     49     uint32_t* dst, const uint32_t* const src, int ndst, const int nsrc) {
     50     while (ndst > 0) {
     51         int n = SkTMin(ndst, nsrc);
     52 
     53         for (int i = 0; i < n; i++) {
     54             srcover_srgb_srgb_1(dst++, src[i]);
     55         }
     56         ndst -= n;
     57     }
     58 }
     59 
     60 static void best_non_simd_srcover_srgb_srgb(
     61     uint32_t* dst, const uint32_t* const src, int ndst, const int nsrc) {
     62     uint64_t* ddst = reinterpret_cast<uint64_t*>(dst);
     63 
     64     auto srcover_srgb_srgb_2 = [](uint32_t* dst, const uint32_t* src) {
     65         srcover_srgb_srgb_1(dst++, *src++);
     66         srcover_srgb_srgb_1(dst, *src);
     67     };
     68 
     69     while (ndst >0) {
     70         int count = SkTMin(ndst, nsrc);
     71         ndst -= count;
     72         const uint64_t* dsrc = reinterpret_cast<const uint64_t*>(src);
     73         const uint64_t* end = dsrc + (count >> 1);
     74         do {
     75             if ((~*dsrc & 0xFF000000FF000000) == 0) {
     76                 do {
     77                     *ddst++ = *dsrc++;
     78                 } while (dsrc < end && (~*dsrc & 0xFF000000FF000000) == 0);
     79             } else if ((*dsrc & 0xFF000000FF000000) == 0) {
     80                 do {
     81                     dsrc++;
     82                     ddst++;
     83                 } while (dsrc < end && (*dsrc & 0xFF000000FF000000) == 0);
     84             } else {
     85                 srcover_srgb_srgb_2(reinterpret_cast<uint32_t*>(ddst++),
     86                                     reinterpret_cast<const uint32_t*>(dsrc++));
     87             }
     88         } while (dsrc < end);
     89 
     90         if ((count & 1) != 0) {
     91             uint32_t s1;
     92             memcpy(&s1, dsrc, 4);
     93             srcover_srgb_srgb_1(reinterpret_cast<uint32_t*>(ddst), s1);
     94         }
     95     }
     96 }
     97 
     98 class SrcOverVSkOptsBruteForce {
     99 public:
    100     static SkString Name() { return SkString{"VSkOptsBruteForce"}; }
    101     static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
    102         brute_force_srcover_srgb_srgb(dst, src, count, count);
    103     }
    104 };
    105 
    106 class SrcOverVSkOptsTrivial {
    107 public:
    108     static SkString Name() { return SkString{"VSkOptsTrivial"}; }
    109     static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
    110         trivial_srcover_srgb_srgb(dst, src, count, count);
    111     }
    112 };
    113 
    114 class SrcOverVSkOptsNonSimdCore {
    115 public:
    116     static SkString Name() { return SkString{"VSkOptsNonSimdCore"}; }
    117     static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
    118         best_non_simd_srcover_srgb_srgb(dst, src, count, count);
    119     }
    120 };
    121 
    122 class SrcOverVSkOptsDefault {
    123 public:
    124     static SkString Name() { return SkString{"VSkOptsDefault"}; }
    125     static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
    126         SkOpts::srcover_srgb_srgb(dst, src, count, count);
    127     }
    128 };
    129 
    130 ///////////////////////////////////////////////////////////////////////////////////////////////////
    131 
    132 template <typename Blender>
    133 class LinearSrcOverBench : public Benchmark {
    134 public:
    135     LinearSrcOverBench(const char* fileName) : fFileName(fileName) {
    136         fName = "LinearSrcOver_";
    137         fName.append(fileName);
    138         fName.append(Blender::Name());
    139     }
    140 
    141 protected:
    142     bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
    143     const char* onGetName() override { return fName.c_str(); }
    144 
    145     void onPreDraw(SkCanvas*) override {
    146         if (!fPixmap.addr()) {
    147             sk_sp<SkImage> image = GetResourceAsImage(fFileName.c_str());
    148             SkBitmap bm;
    149             SkColorSpace* legacyColorSpace = nullptr;
    150             if (!as_IB(image)->getROPixels(&bm, legacyColorSpace)) {
    151                 SkFAIL("Could not read resource");
    152             }
    153             bm.peekPixels(&fPixmap);
    154             fCount = fPixmap.rowBytesAsPixels();
    155             fDst.reset(fCount);
    156             sk_bzero(fDst.get(), fPixmap.rowBytes());
    157         }
    158     }
    159 
    160     void onDraw(int loops, SkCanvas*) override {
    161         SkASSERT(fPixmap.colorType() == kN32_SkColorType);
    162 
    163         const int width = fPixmap.rowBytesAsPixels();
    164 
    165         for (int i = 0; i < loops * INNER_LOOPS; ++i) {
    166             const uint32_t* src = fPixmap.addr32();
    167             for (int y = 0; y < fPixmap.height(); y++) {
    168                 Blender::BlendN(fDst.get(), src, width);
    169                 src += width;
    170             }
    171         }
    172     }
    173 
    174     void onPostDraw(SkCanvas*) override {
    175         // Make sure the compiler does not optimize away the operation.
    176         volatile uint32_t v = 0;
    177         for (int i = 0; i < fCount; i++) {
    178             v ^= fDst[i];
    179         }
    180     }
    181 
    182 private:
    183     int fCount;
    184     SkAutoTArray<uint32_t> fDst;
    185     SkString fFileName;
    186     SkString fName;
    187     SkPixmap fPixmap;
    188 
    189     typedef Benchmark INHERITED;
    190 };
    191 
    192 #define BENCHES(fileName)                                                            \
    193     DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsBruteForce>(fileName); )  \
    194     DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsTrivial>(fileName); )     \
    195     DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsNonSimdCore>(fileName); ) \
    196     DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsDefault>(fileName); )
    197 
    198 BENCHES("yellow_rose.png")
    199 BENCHES("baby_tux.png")
    200 BENCHES("plane.png")
    201 BENCHES("mandrill_512.png")
    202 BENCHES("iconstrip.png")
    203