blob: eae0b709bcac555247dabe292bce3b53b09f106f [file] [log] [blame]
Mike Klein68c50d02019-05-29 12:57:54 -05001/*
2 * Copyright 2019 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 "bench/Benchmark.h"
9#include "src/core/SkOpts.h"
10#include "src/core/SkVM.h"
11
Mike Klein68c50d02019-05-29 12:57:54 -050012namespace {
13
14 enum Mode {Opts, RP, F32, I32, I32_SWAR};
15 static const char* kMode_name[] = { "Opts", "RP","F32", "I32", "I32_SWAR" };
16
17 struct SrcoverBuilder_F32 : public skvm::Builder {
18 SrcoverBuilder_F32() {
19
20 skvm::Arg src = arg(0),
21 dst = arg(1);
22
23 auto byte_to_f32 = [&](skvm::I32 byte) {
24 return mul(splat(1/255.0f), to_f32(byte));
25 };
26 auto f32_to_byte = [&](skvm::F32 f32) {
27 return to_i32(mad(f32, splat(255.0f), splat(0.5f)));
28 };
29
30 auto load = [&](skvm::Arg ptr,
31 skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) {
32 skvm::I32 rgba = load32(ptr);
33 *r = byte_to_f32(bit_and( rgba , splat(0xff)));
34 *g = byte_to_f32(bit_and(shr(rgba, 8), splat(0xff)));
35 *b = byte_to_f32(bit_and(shr(rgba, 16), splat(0xff)));
36 *a = byte_to_f32( shr(rgba, 24) );
37 };
38
39 skvm::F32 r,g,b,a;
40 load(src, &r,&g,&b,&a);
41
42 skvm::F32 dr,dg,db,da;
43 load(dst, &dr,&dg,&db,&da);
44
45 skvm::F32 invA = sub(splat(1.0f), a);
46 r = mad(dr, invA, r);
47 g = mad(dg, invA, g);
48 b = mad(db, invA, b);
49 a = mad(da, invA, a);
50
51 store32(dst, bit_or( f32_to_byte(r) ,
52 bit_or(shl(f32_to_byte(g), 8),
53 bit_or(shl(f32_to_byte(b), 16),
54 shl(f32_to_byte(a), 24)))));
55 }
56 };
57
58 struct SrcoverBuilder_I32 : public skvm::Builder {
59 SrcoverBuilder_I32() {
60 skvm::Arg src = arg(0),
61 dst = arg(1);
62
63 auto load = [&](skvm::Arg ptr,
64 skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) {
65 skvm::I32 rgba = load32(ptr);
66 *r = bit_and( rgba , splat(0xff));
67 *g = bit_and(shr(rgba, 8), splat(0xff));
68 *b = bit_and(shr(rgba, 16), splat(0xff));
69 *a = shr(rgba, 24) ;
70 };
71
72 auto mul_unorm8 = [&](skvm::I32 x, skvm::I32 y) {
73 // (x*y + 127)/255 ~= (x*y+255)/256
74 return shr(add(mul(x, y), splat(0xff)), 8);
75 };
76
77 skvm::I32 r,g,b,a;
78 load(src, &r,&g,&b,&a);
79
80 skvm::I32 dr,dg,db,da;
81 load(dst, &dr,&dg,&db,&da);
82
83 skvm::I32 invA = sub(splat(0xff), a);
84 r = add(r, mul_unorm8(dr, invA));
Mike Klein03ce6752019-06-03 14:53:15 -050085 g = add(g, mul_unorm8(dg, invA));
86 b = add(b, mul_unorm8(db, invA));
87 a = add(a, mul_unorm8(da, invA));
Mike Klein68c50d02019-05-29 12:57:54 -050088
89 store32(dst, bit_or( r ,
90 bit_or(shl(g, 8),
91 bit_or(shl(b, 16),
92 shl(a, 24)))));
93 }
94 };
95
96 struct SrcoverBuilder_I32_SWAR : public skvm::Builder {
97 SrcoverBuilder_I32_SWAR() {
98 skvm::Arg src = arg(0),
99 dst = arg(1);
100
101 auto load = [&](skvm::Arg ptr,
102 skvm::I32* rb, skvm::I32* ga) {
103 skvm::I32 rgba = load32(ptr);
104 *rb = bit_and( rgba, splat(0x00ff00ff));
105 *ga = bit_and(shr(rgba, 8), splat(0x00ff00ff));
106 };
107
108 auto mul_unorm8 = [&](skvm::I32 x, skvm::I32 y) {
109 // As above, assuming x is two SWAR bytes in lanes 0 and 2, and y is a byte.
Mike Klein03ce6752019-06-03 14:53:15 -0500110 return bit_and(shr(add(mul(x, y),
111 splat(0x00ff00ff)),
112 8),
113 splat(0x00ff00ff));
Mike Klein68c50d02019-05-29 12:57:54 -0500114 };
115
116 skvm::I32 rb, ga;
117 load(src, &rb, &ga);
118
119 skvm::I32 drb, dga;
120 load(dst, &drb, &dga);
121
122 skvm::I32 invA = sub(splat(0xff), shr(ga, 16));
123 rb = add(rb, mul_unorm8(drb, invA));
124 ga = add(ga, mul_unorm8(dga, invA));
125
126 store32(dst, bit_or(rb, shl(ga, 8)));
127 }
128 };
129}
130
131class SkVMBench : public Benchmark {
132public:
133 SkVMBench(int pixels, Mode mode)
134 : fPixels(pixels)
135 , fMode(mode)
136 , fName(SkStringPrintf("SkVM_%d_%s", pixels, kMode_name[mode]))
137 {}
138
139private:
140 const char* onGetName() override { return fName.c_str(); }
141 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
142
143 void onDelayedSetup() override {
144 this->setUnits(fPixels);
145 fSrc.resize(fPixels, 0x7f123456); // Arbitrary non-opaque non-transparent value.
146 fDst.resize(fPixels, 0xff987654); // Arbitrary value.
147
148 if (fMode == F32 ) { fProgram = SrcoverBuilder_F32 {}.done(); }
149 if (fMode == I32 ) { fProgram = SrcoverBuilder_I32 {}.done(); }
150 if (fMode == I32_SWAR) { fProgram = SrcoverBuilder_I32_SWAR{}.done(); }
151
152 if (fMode == RP) {
153 fSrcCtx = { fSrc.data(), 0 };
154 fDstCtx = { fDst.data(), 0 };
155 fPipeline.append(SkRasterPipeline::load_8888 , &fSrcCtx);
156 fPipeline.append(SkRasterPipeline::load_8888_dst, &fDstCtx);
157 fPipeline.append(SkRasterPipeline::srcover);
158 fPipeline.append(SkRasterPipeline::store_8888, &fDstCtx);
159 }
Mike Klein03ce6752019-06-03 14:53:15 -0500160
161 // Trigger one run now so we can do a quick correctness check.
162 this->draw(1,nullptr);
163 for (int i = 0; i < fPixels; i++) {
164 SkASSERT(fDst[i] == 0xff5e6f80);
165 }
Mike Klein68c50d02019-05-29 12:57:54 -0500166 }
167
168 void onDraw(int loops, SkCanvas*) override {
169 while (loops --> 0) {
170 if (fMode == Opts) {
171 SkOpts::blit_row_s32a_opaque(fDst.data(), fSrc.data(), fPixels, 0xff);
172 } else if (fMode == RP) {
173 fPipeline.run(0,0,fPixels,1);
174 } else {
175 fProgram.eval(fPixels, fSrc.data(), fDst.data());
176 }
177 }
178 }
179
180 int fPixels;
181 Mode fMode;
182 SkString fName;
183 std::vector<uint32_t> fSrc,
184 fDst;
185 skvm::Program fProgram;
186
187 SkRasterPipeline_MemoryCtx fSrcCtx,
188 fDstCtx;
189 SkRasterPipeline_<256> fPipeline;
190};
191
192DEF_BENCH(return (new SkVMBench{ 1, Opts});)
193DEF_BENCH(return (new SkVMBench{ 4, Opts});)
194DEF_BENCH(return (new SkVMBench{ 16, Opts});)
195DEF_BENCH(return (new SkVMBench{ 64, Opts});)
196DEF_BENCH(return (new SkVMBench{ 256, Opts});)
197DEF_BENCH(return (new SkVMBench{1024, Opts});)
198DEF_BENCH(return (new SkVMBench{4096, Opts});)
199
200DEF_BENCH(return (new SkVMBench{ 1, RP});)
201DEF_BENCH(return (new SkVMBench{ 4, RP});)
202DEF_BENCH(return (new SkVMBench{ 16, RP});)
203DEF_BENCH(return (new SkVMBench{ 64, RP});)
204DEF_BENCH(return (new SkVMBench{ 256, RP});)
205DEF_BENCH(return (new SkVMBench{1024, RP});)
206DEF_BENCH(return (new SkVMBench{4096, RP});)
207
208DEF_BENCH(return (new SkVMBench{ 1, F32});)
209DEF_BENCH(return (new SkVMBench{ 4, F32});)
210DEF_BENCH(return (new SkVMBench{ 16, F32});)
211DEF_BENCH(return (new SkVMBench{ 64, F32});)
212DEF_BENCH(return (new SkVMBench{ 256, F32});)
213DEF_BENCH(return (new SkVMBench{1024, F32});)
214DEF_BENCH(return (new SkVMBench{4096, F32});)
215
216DEF_BENCH(return (new SkVMBench{ 1, I32});)
217DEF_BENCH(return (new SkVMBench{ 4, I32});)
218DEF_BENCH(return (new SkVMBench{ 16, I32});)
219DEF_BENCH(return (new SkVMBench{ 64, I32});)
220DEF_BENCH(return (new SkVMBench{ 256, I32});)
221DEF_BENCH(return (new SkVMBench{1024, I32});)
222DEF_BENCH(return (new SkVMBench{4096, I32});)
223
224DEF_BENCH(return (new SkVMBench{ 1, I32_SWAR});)
225DEF_BENCH(return (new SkVMBench{ 4, I32_SWAR});)
226DEF_BENCH(return (new SkVMBench{ 16, I32_SWAR});)
227DEF_BENCH(return (new SkVMBench{ 64, I32_SWAR});)
228DEF_BENCH(return (new SkVMBench{ 256, I32_SWAR});)
229DEF_BENCH(return (new SkVMBench{1024, I32_SWAR});)
230DEF_BENCH(return (new SkVMBench{4096, I32_SWAR});)