blob: ad3eb2ce9b28b8bc3bf55dc516435fa940bf2dd3 [file] [log] [blame]
Mike Klein68c50d02019-05-29 12:57:54 -05001/*
2 * Copyright 2019 Google LLC
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 "include/core/SkColorPriv.h"
9#include "include/private/SkColorData.h"
10#include "src/core/SkVM.h"
11#include "tests/Test.h"
12
13enum Fmt { A8, G8, RGBA_8888 };
14const char* fmt_name(Fmt fmt) {
15 switch (fmt) {
16 case A8: return "A8";
17 case G8: return "G8";
18 case RGBA_8888: return "RGBA_8888";
19 }
20 return "";
21}
22
23// Here's a cute little trick that avoids the need to explicitly thread
24// and skvm::Builder* through and make a lot of builder->foo() calls.
25// Instead the builder becomes this, with this-> omitted for clarity.
26//
27// Think of this as
28// static void srcover(skvm::Builder*, Fmt srcFmt, Fmt dstFmt) { ... }
29//
30// Some parts of this builder code are written less fluently than possible,
31// to avoid any ambiguity of function argument evaluation order. This lets
32// our golden tests (kExpected) work portably. In general there's no reason
33// to fear nesting calls to Builder routines.
34
35struct SrcoverBuilder : public skvm::Builder {
36 SrcoverBuilder(Fmt srcFmt, Fmt dstFmt) {
37 skvm::Arg src = arg(0),
38 dst = arg(1);
39
40 auto byte_to_f32 = [&](skvm::I32 byte) {
41 skvm::F32 _1_255 = splat(1/255.0f);
42 return mul(_1_255, to_f32(byte));
43 };
44
45 auto load = [&](skvm::Arg ptr, Fmt fmt,
46 skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) {
47 switch (fmt) {
48 case A8: {
49 *r = *g = *b = splat(0.0f);
50 *a = byte_to_f32(load8(ptr));
51 } break;
52
53 case G8: {
54 *r = *g = *b = byte_to_f32(load8(ptr));
55 *a = splat(1.0f);
56 } break;
57
58 case RGBA_8888: {
59 skvm::I32 rgba = load32(ptr),
60 _255 = splat(255);
61 *r = byte_to_f32(bit_and( rgba , _255));
62 *g = byte_to_f32(bit_and(shr(rgba, 8), _255));
63 *b = byte_to_f32(bit_and(shr(rgba, 16), _255));
64 *a = byte_to_f32( shr(rgba, 24) );
65 } break;
66 }
67 };
68
69 skvm::F32 r,g,b,a;
70 load(src, srcFmt, &r,&g,&b,&a);
71
72 skvm::F32 dr,dg,db,da;
73 load(dst, dstFmt, &dr,&dg,&db,&da);
74
75 skvm::F32 invA = sub(splat(1.0f), a);
76 r = mad(dr, invA, r);
77 g = mad(dg, invA, g);
78 b = mad(db, invA, b);
79 a = mad(da, invA, a);
80
81 auto f32_to_byte = [&](skvm::F32 f32) {
82 skvm::F32 _255 = splat(255.0f),
83 _0_5 = splat(0.5f);
84 return to_i32(mad(f32, _255, _0_5));
85 };
86 switch (dstFmt) {
87 case A8: {
88 store8(dst, f32_to_byte(a));
89 } break;
90
91 case G8: {
92 skvm::F32 _2126 = splat(0.2126f),
93 _7152 = splat(0.7152f),
94 _0722 = splat(0.0722f);
95 store8(dst, f32_to_byte(mad(r, _2126,
96 mad(g, _7152,
97 mul(b, _0722)))));
98 } break;
99
100 case RGBA_8888: {
101 skvm::I32 R = f32_to_byte(r) ,
102 G = shl(f32_to_byte(g), 8),
103 B = shl(f32_to_byte(b), 16),
104 A = shl(f32_to_byte(a), 24);
105
106 R = bit_or(R,G);
107 R = bit_or(R,B);
108 R = bit_or(R,A);
109
110 store32(dst, R);
111 } break;
112 }
113 }
114};
115
116static const char* kExpected[] = {
117R"(r0 = load8 arg(0)
118r1 = splat 3B808081 (0.0039215689)
119r0 = to_f32 r0
120r0 = mul_f32 r1 r0
121r2 = load8 arg(1)
122r2 = to_f32 r2
123r2 = mul_f32 r1 r2
124r1 = splat 3F800000 (1)
125r1 = sub_f32 r1 r0
126r1 = mad_f32 r2 r1 r0
127r2 = splat 437F0000 (255)
128r0 = splat 3F000000 (0.5)
129r0 = mad_f32 r1 r2 r0
130r0 = to_i32 r0
131store8 arg(1) r0
132)",
133R"(r0 = splat 0 (0)
134r1 = load8 arg(0)
135r2 = splat 3B808081 (0.0039215689)
136r1 = to_f32 r1
137r1 = mul_f32 r2 r1
138r3 = load8 arg(1)
139r3 = to_f32 r3
140r3 = mul_f32 r2 r3
141r2 = splat 3F800000 (1)
142r2 = sub_f32 r2 r1
143r2 = mad_f32 r3 r2 r0
144r3 = splat 3E59B3D0 (0.21259999)
145r0 = splat 3F371759 (0.71520001)
146r1 = splat 3D93DD98 (0.0722)
147r1 = mul_f32 r2 r1
148r1 = mad_f32 r2 r0 r1
149r1 = mad_f32 r2 r3 r1
150r3 = splat 437F0000 (255)
151r2 = splat 3F000000 (0.5)
152r2 = mad_f32 r1 r3 r2
153r2 = to_i32 r2
154store8 arg(1) r2
155)",
156R"(r0 = splat 0 (0)
157r1 = load8 arg(0)
158r2 = splat 3B808081 (0.0039215689)
159r1 = to_f32 r1
160r1 = mul_f32 r2 r1
161r3 = load32 arg(1)
162r4 = splat FF (3.5733111e-43)
163r5 = bit_and r3 r4
164r5 = to_f32 r5
165r5 = mul_f32 r2 r5
166r6 = shr r3 8 (1.1210388e-44)
167r6 = bit_and r6 r4
168r6 = to_f32 r6
169r6 = mul_f32 r2 r6
170r7 = shr r3 10 (2.2420775e-44)
171r7 = bit_and r7 r4
172r7 = to_f32 r7
173r7 = mul_f32 r2 r7
174r3 = shr r3 18 (3.3631163e-44)
175r3 = to_f32 r3
176r3 = mul_f32 r2 r3
177r2 = splat 3F800000 (1)
178r2 = sub_f32 r2 r1
179r5 = mad_f32 r5 r2 r0
180r6 = mad_f32 r6 r2 r0
181r7 = mad_f32 r7 r2 r0
182r2 = mad_f32 r3 r2 r1
183r3 = splat 437F0000 (255)
184r1 = splat 3F000000 (0.5)
185r5 = mad_f32 r5 r3 r1
186r5 = to_i32 r5
187r6 = mad_f32 r6 r3 r1
188r6 = to_i32 r6
189r6 = shl r6 8 (1.1210388e-44)
190r7 = mad_f32 r7 r3 r1
191r7 = to_i32 r7
192r7 = shl r7 10 (2.2420775e-44)
193r1 = mad_f32 r2 r3 r1
194r1 = to_i32 r1
195r1 = shl r1 18 (3.3631163e-44)
196r6 = bit_or r5 r6
197r6 = bit_or r6 r7
198r6 = bit_or r6 r1
199store32 arg(1) r6
200)",
201R"(r0 = splat 3B808081 (0.0039215689)
202r1 = splat 3F800000 (1)
203r2 = load8 arg(1)
204r2 = to_f32 r2
205r2 = mul_f32 r0 r2
206r0 = sub_f32 r1 r1
207r0 = mad_f32 r2 r0 r1
208r2 = splat 437F0000 (255)
209r1 = splat 3F000000 (0.5)
210r1 = mad_f32 r0 r2 r1
211r1 = to_i32 r1
212store8 arg(1) r1
213)",
214R"(r0 = load8 arg(0)
215r1 = splat 3B808081 (0.0039215689)
216r0 = to_f32 r0
217r0 = mul_f32 r1 r0
218r2 = splat 3F800000 (1)
219r3 = load8 arg(1)
220r3 = to_f32 r3
221r3 = mul_f32 r1 r3
222r2 = sub_f32 r2 r2
223r2 = mad_f32 r3 r2 r0
224r3 = splat 3E59B3D0 (0.21259999)
225r0 = splat 3F371759 (0.71520001)
226r1 = splat 3D93DD98 (0.0722)
227r1 = mul_f32 r2 r1
228r1 = mad_f32 r2 r0 r1
229r1 = mad_f32 r2 r3 r1
230r3 = splat 437F0000 (255)
231r2 = splat 3F000000 (0.5)
232r2 = mad_f32 r1 r3 r2
233r2 = to_i32 r2
234store8 arg(1) r2
235)",
236R"(r0 = load8 arg(0)
237r1 = splat 3B808081 (0.0039215689)
238r0 = to_f32 r0
239r0 = mul_f32 r1 r0
240r2 = splat 3F800000 (1)
241r3 = load32 arg(1)
242r4 = splat FF (3.5733111e-43)
243r5 = bit_and r3 r4
244r5 = to_f32 r5
245r5 = mul_f32 r1 r5
246r6 = shr r3 8 (1.1210388e-44)
247r6 = bit_and r6 r4
248r6 = to_f32 r6
249r6 = mul_f32 r1 r6
250r7 = shr r3 10 (2.2420775e-44)
251r7 = bit_and r7 r4
252r7 = to_f32 r7
253r7 = mul_f32 r1 r7
254r3 = shr r3 18 (3.3631163e-44)
255r3 = to_f32 r3
256r3 = mul_f32 r1 r3
257r1 = sub_f32 r2 r2
258r5 = mad_f32 r5 r1 r0
259r6 = mad_f32 r6 r1 r0
260r7 = mad_f32 r7 r1 r0
261r1 = mad_f32 r3 r1 r2
262r3 = splat 437F0000 (255)
263r2 = splat 3F000000 (0.5)
264r5 = mad_f32 r5 r3 r2
265r5 = to_i32 r5
266r6 = mad_f32 r6 r3 r2
267r6 = to_i32 r6
268r6 = shl r6 8 (1.1210388e-44)
269r7 = mad_f32 r7 r3 r2
270r7 = to_i32 r7
271r7 = shl r7 10 (2.2420775e-44)
272r2 = mad_f32 r1 r3 r2
273r2 = to_i32 r2
274r2 = shl r2 18 (3.3631163e-44)
275r6 = bit_or r5 r6
276r6 = bit_or r6 r7
277r6 = bit_or r6 r2
278store32 arg(1) r6
279)",
280R"(r0 = load32 arg(0)
281r1 = splat 3B808081 (0.0039215689)
282r0 = shr r0 18 (3.3631163e-44)
283r0 = to_f32 r0
284r0 = mul_f32 r1 r0
285r2 = load8 arg(1)
286r2 = to_f32 r2
287r2 = mul_f32 r1 r2
288r1 = splat 3F800000 (1)
289r1 = sub_f32 r1 r0
290r1 = mad_f32 r2 r1 r0
291r2 = splat 437F0000 (255)
292r0 = splat 3F000000 (0.5)
293r0 = mad_f32 r1 r2 r0
294r0 = to_i32 r0
295store8 arg(1) r0
296)",
297R"(r0 = load32 arg(0)
298r1 = splat FF (3.5733111e-43)
299r2 = bit_and r0 r1
300r3 = splat 3B808081 (0.0039215689)
301r2 = to_f32 r2
302r2 = mul_f32 r3 r2
303r4 = shr r0 8 (1.1210388e-44)
304r4 = bit_and r4 r1
305r4 = to_f32 r4
306r4 = mul_f32 r3 r4
307r5 = shr r0 10 (2.2420775e-44)
308r5 = bit_and r5 r1
309r5 = to_f32 r5
310r5 = mul_f32 r3 r5
311r0 = shr r0 18 (3.3631163e-44)
312r0 = to_f32 r0
313r0 = mul_f32 r3 r0
314r1 = load8 arg(1)
315r1 = to_f32 r1
316r1 = mul_f32 r3 r1
317r3 = splat 3F800000 (1)
318r3 = sub_f32 r3 r0
319r2 = mad_f32 r1 r3 r2
320r4 = mad_f32 r1 r3 r4
321r3 = mad_f32 r1 r3 r5
322r1 = splat 3E59B3D0 (0.21259999)
323r5 = splat 3F371759 (0.71520001)
324r0 = splat 3D93DD98 (0.0722)
325r0 = mul_f32 r3 r0
326r0 = mad_f32 r4 r5 r0
327r0 = mad_f32 r2 r1 r0
328r1 = splat 437F0000 (255)
329r2 = splat 3F000000 (0.5)
330r2 = mad_f32 r0 r1 r2
331r2 = to_i32 r2
332store8 arg(1) r2
333)",
334R"(r0 = load32 arg(0)
335r1 = splat FF (3.5733111e-43)
336r2 = bit_and r0 r1
337r3 = splat 3B808081 (0.0039215689)
338r2 = to_f32 r2
339r2 = mul_f32 r3 r2
340r4 = shr r0 8 (1.1210388e-44)
341r4 = bit_and r4 r1
342r4 = to_f32 r4
343r4 = mul_f32 r3 r4
344r5 = shr r0 10 (2.2420775e-44)
345r5 = bit_and r5 r1
346r5 = to_f32 r5
347r5 = mul_f32 r3 r5
348r0 = shr r0 18 (3.3631163e-44)
349r0 = to_f32 r0
350r0 = mul_f32 r3 r0
351r6 = load32 arg(1)
352r7 = bit_and r6 r1
353r7 = to_f32 r7
354r7 = mul_f32 r3 r7
355r8 = shr r6 8 (1.1210388e-44)
356r8 = bit_and r8 r1
357r8 = to_f32 r8
358r8 = mul_f32 r3 r8
359r9 = shr r6 10 (2.2420775e-44)
360r9 = bit_and r9 r1
361r9 = to_f32 r9
362r9 = mul_f32 r3 r9
363r6 = shr r6 18 (3.3631163e-44)
364r6 = to_f32 r6
365r6 = mul_f32 r3 r6
366r3 = splat 3F800000 (1)
367r3 = sub_f32 r3 r0
368r7 = mad_f32 r7 r3 r2
369r8 = mad_f32 r8 r3 r4
370r9 = mad_f32 r9 r3 r5
371r3 = mad_f32 r6 r3 r0
372r6 = splat 437F0000 (255)
373r0 = splat 3F000000 (0.5)
374r7 = mad_f32 r7 r6 r0
375r7 = to_i32 r7
376r8 = mad_f32 r8 r6 r0
377r8 = to_i32 r8
378r8 = shl r8 8 (1.1210388e-44)
379r9 = mad_f32 r9 r6 r0
380r9 = to_i32 r9
381r9 = shl r9 10 (2.2420775e-44)
382r0 = mad_f32 r3 r6 r0
383r0 = to_i32 r0
384r0 = shl r0 18 (3.3631163e-44)
385r8 = bit_or r7 r8
386r8 = bit_or r8 r9
387r8 = bit_or r8 r0
388store32 arg(1) r8
389)",
390};
391
392DEF_TEST(SkVM, r) {
393 for (int s = 0; s < 3; s++)
394 for (int d = 0; d < 3; d++) {
395 auto srcFmt = (Fmt)s,
396 dstFmt = (Fmt)d;
397 skvm::Program program = SrcoverBuilder{srcFmt, dstFmt}.done();
398
399 SkDynamicMemoryWStream buf;
400 program.dump(&buf);
401 sk_sp<SkData> blob = buf.detachAsData();
402
403 bool train = false;
404 if (train) {
405 SkDebugf("R\"(%.*s)\",\n", blob->size(), blob->data());
406 } else if (0 != memcmp(kExpected[3*s+d], blob->data(), blob->size())) {
407 ERRORF(r, "SkVMTest needs retraining.\n");
408 }
409 }
410
411 {
412 skvm::Program program = SrcoverBuilder{RGBA_8888, RGBA_8888}.done();
413
414 uint32_t src = 0xbb007733,
415 dst = 0xffaaccee;
416 SkPMColor want = SkPMSrcOver(src, dst); // 0xff2dad73
417
418 program.eval(1, &src, &dst);
419
420 // dst is probably 0xff2dad72.
421 for (int i = 0; i < 4; i++) {
422 uint8_t d = dst,
423 w = want;
424 REPORTER_ASSERT(r, abs(d-w) < 2);
425 dst >>= 8;
426 want >>= 8;
427 }
428 }
429
430 {
431 skvm::Program program = SrcoverBuilder{RGBA_8888, G8}.done();
432
433 uint32_t src = 0xbb007733;
434 uint8_t dst = 0x42;
435 SkPMColor over = SkPMSrcOver(SkPackARGB32(0xbb, 0x33, 0x77, 0x00), 0xff424242);
436
437 uint8_t want = SkComputeLuminance(SkGetPackedR32(over),
438 SkGetPackedG32(over),
439 SkGetPackedB32(over));
440 program.eval(1, &src, &dst);
441
442 REPORTER_ASSERT(r, abs(dst-want) < 3);
443 }
444
445 {
446 skvm::Program program = SrcoverBuilder{A8, A8}.done();
447
448 uint8_t src[256],
449 dst[256];
450 for (int i = 0; i < 256; i++) {
451 src[i] = 255 - i;
452 dst[i] = i;
453 }
454
455 program.eval(256, src, dst);
456
457 for (int i = 0; i < 256; i++) {
458 uint8_t want = SkGetPackedA32(SkPMSrcOver(SkPackARGB32(src[i], 0,0,0),
459 SkPackARGB32( i, 0,0,0)));
460 REPORTER_ASSERT(r, abs(dst[i]-want) < 2);
461 }
462 }
463}