• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
brute_srcover_srgb_srgb_1(uint32_t * dst,uint32_t src)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 
srcover_srgb_srgb_1(uint32_t * dst,uint32_t src)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 
brute_force_srcover_srgb_srgb(uint32_t * dst,const uint32_t * const src,int ndst,const int nsrc)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 
trivial_srcover_srgb_srgb(uint32_t * dst,const uint32_t * const src,int ndst,const int nsrc)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 
best_non_simd_srcover_srgb_srgb(uint32_t * dst,const uint32_t * const src,int ndst,const int nsrc)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:
Name()100     static SkString Name() { return SkString{"VSkOptsBruteForce"}; }
BlendN(uint32_t * dst,const uint32_t * src,int count)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:
Name()108     static SkString Name() { return SkString{"VSkOptsTrivial"}; }
BlendN(uint32_t * dst,const uint32_t * src,int count)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:
Name()116     static SkString Name() { return SkString{"VSkOptsNonSimdCore"}; }
BlendN(uint32_t * dst,const uint32_t * src,int count)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:
Name()124     static SkString Name() { return SkString{"VSkOptsDefault"}; }
BlendN(uint32_t * dst,const uint32_t * src,int count)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:
LinearSrcOverBench(const char * fileName)135     LinearSrcOverBench(const char* fileName) : fFileName(fileName) {
136         fName = "LinearSrcOver_";
137         fName.append(fileName);
138         fName.append(Blender::Name());
139     }
140 
141 protected:
isSuitableFor(Backend backend)142     bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
onGetName()143     const char* onGetName() override { return fName.c_str(); }
144 
onPreDraw(SkCanvas *)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 
onDraw(int loops,SkCanvas *)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 
onPostDraw(SkCanvas *)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