Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: tests/BlendTest.cpp

Issue 179733005: Check in today's exhaustive blend experiments. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gyp/tests.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #include "Test.h"
2 #include "SkColor.h"
3
4 #define ASSERT(x) REPORTER_ASSERT(r, x)
5
6 // All algorithms we're testing have this interface.
7 // We want a single channel blend, src over dst, assuming src is premultiplied b y srcAlpha.
8 typedef uint8_t(*Blend)(uint8_t dst, uint8_t src, uint8_t srcAlpha);
9
10 // This is our golden algorithm.
11 static uint8_t blend_double_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
12 SkASSERT(src <= srcAlpha);
13 return 0.5 + src + dst * (255.0 - srcAlpha) / 255.0;
14 }
15
16 static uint8_t abs_diff(uint8_t a, uint8_t b) {
17 const int diff = a - b;
18 return diff > 0 ? diff : -diff;
19 }
20
21 static void test(skiatest::Reporter* r, int maxDiff, Blend algorithm,
22 uint8_t dst, uint8_t src, uint8_t alpha) {
23 const uint8_t golden = blend_double_round(dst, src, alpha);
24 const uint8_t blend = algorithm(dst, src, alpha);
25 if (abs_diff(blend, golden) > maxDiff) {
26 SkDebugf("dst %02x, src %02x, alpha %02x, |%02x - %02x| > %d\n",
27 dst, src, alpha, blend, golden, maxDiff);
28 ASSERT(abs_diff(blend, golden) <= maxDiff);
29 }
30 }
31
32 // Exhaustively compare an algorithm against our golden, for a given alpha.
33 static void test_alpha(skiatest::Reporter* r, uint8_t alpha, int maxDiff, Blend algorithm) {
34 SkASSERT(maxDiff >= 0);
35
36 for (unsigned src = 0; src <= alpha; src++) {
37 for (unsigned dst = 0; dst < 256; dst++) {
38 test(r, maxDiff, algorithm, dst, src, alpha);
39 }
40 }
41 }
42
43 // Exhaustively compare an algorithm against our golden, for a given dst.
44 static void test_dst(skiatest::Reporter* r, uint8_t dst, int maxDiff, Blend algo rithm) {
45 SkASSERT(maxDiff >= 0);
46
47 for (unsigned alpha = 0; alpha < 256; alpha++) {
48 for (unsigned src = 0; src <= alpha; src++) {
49 test(r, maxDiff, algorithm, dst, src, alpha);
50 }
51 }
52 }
53
54 static uint8_t blend_double_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
55 return src + dst * (255.0 - srcAlpha) / 255.0;
56 }
57
58 static uint8_t blend_float_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
59 return src + dst * (255.0f - srcAlpha) / 255.0f;
60 }
61
62 static uint8_t blend_float_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
63 return 0.5f + src + dst * (255.0f - srcAlpha) / 255.0f;
64 }
65
66 static uint8_t blend_255_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
67 const uint16_t invAlpha = 255 - srcAlpha;
68 const uint16_t product = dst * invAlpha;
69 return src + (product >> 8);
70 }
71
72 static uint8_t blend_255_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
73 const uint16_t invAlpha = 255 - srcAlpha;
74 const uint16_t product = dst * invAlpha + 128;
75 return src + (product >> 8);
76 }
77
78 static uint8_t blend_256_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
79 const uint16_t invAlpha = 256 - (srcAlpha + (srcAlpha >> 7));
80 const uint16_t product = dst * invAlpha;
81 return src + (product >> 8);
82 }
83
84 static uint8_t blend_256_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
85 const uint16_t invAlpha = 256 - (srcAlpha + (srcAlpha >> 7));
86 const uint16_t product = dst * invAlpha + 128;
87 return src + (product >> 8);
88 }
89
90 static uint8_t blend_256_round_alt(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
91 const uint8_t invAlpha8 = 255 - srcAlpha;
92 const uint16_t invAlpha = invAlpha8 + (invAlpha8 >> 7);
93 const uint16_t product = dst * invAlpha + 128;
94 return src + (product >> 8);
95 }
96
97 static uint8_t blend_256_plus1_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
98 const uint16_t invAlpha = 256 - (srcAlpha + 1);
99 const uint16_t product = dst * invAlpha;
100 return src + (product >> 8);
101 }
102
103 static uint8_t blend_256_plus1_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
104 const uint16_t invAlpha = 256 - (srcAlpha + 1);
105 const uint16_t product = dst * invAlpha + 128;
106 return src + (product >> 8);
107 }
108
109 static uint8_t blend_perfect(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
110 const uint8_t invAlpha = 255 - srcAlpha;
111 const uint16_t product = dst * invAlpha + 128;
112 return src + ((product + (product >> 8)) >> 8);
113 }
114
115
116 // We want 0 diff whenever src is fully transparent.
117 DEF_TEST(Blend_alpha_0x00, r) {
118 const uint8_t alpha = 0x00;
119
120 // GOOD
121 test_alpha(r, alpha, 0, blend_256_round);
122 test_alpha(r, alpha, 0, blend_256_round_alt);
123 test_alpha(r, alpha, 0, blend_256_trunc);
124 test_alpha(r, alpha, 0, blend_double_trunc);
125 test_alpha(r, alpha, 0, blend_float_round);
126 test_alpha(r, alpha, 0, blend_float_trunc);
127 test_alpha(r, alpha, 0, blend_perfect);
128
129 // BAD
130 test_alpha(r, alpha, 1, blend_255_round);
131 test_alpha(r, alpha, 1, blend_255_trunc);
132 test_alpha(r, alpha, 1, blend_256_plus1_round);
133 test_alpha(r, alpha, 1, blend_256_plus1_trunc);
134 }
135
136 // We want 0 diff whenever dst is 0.
137 DEF_TEST(Blend_dst_0x00, r) {
138 const uint8_t dst = 0x00;
139
140 // GOOD
141 test_dst(r, dst, 0, blend_255_round);
142 test_dst(r, dst, 0, blend_255_trunc);
143 test_dst(r, dst, 0, blend_256_plus1_round);
144 test_dst(r, dst, 0, blend_256_plus1_trunc);
145 test_dst(r, dst, 0, blend_256_round);
146 test_dst(r, dst, 0, blend_256_round_alt);
147 test_dst(r, dst, 0, blend_256_trunc);
148 test_dst(r, dst, 0, blend_double_trunc);
149 test_dst(r, dst, 0, blend_float_round);
150 test_dst(r, dst, 0, blend_float_trunc);
151 test_dst(r, dst, 0, blend_perfect);
152
153 // BAD
154 }
155
156 // We want 0 diff whenever src is fully opaque.
157 DEF_TEST(Blend_alpha_0xFF, r) {
158 const uint8_t alpha = 0xFF;
159
160 // GOOD
161 test_alpha(r, alpha, 0, blend_255_round);
162 test_alpha(r, alpha, 0, blend_255_trunc);
163 test_alpha(r, alpha, 0, blend_256_plus1_round);
164 test_alpha(r, alpha, 0, blend_256_plus1_trunc);
165 test_alpha(r, alpha, 0, blend_256_round);
166 test_alpha(r, alpha, 0, blend_256_round_alt);
167 test_alpha(r, alpha, 0, blend_256_trunc);
168 test_alpha(r, alpha, 0, blend_double_trunc);
169 test_alpha(r, alpha, 0, blend_float_round);
170 test_alpha(r, alpha, 0, blend_float_trunc);
171 test_alpha(r, alpha, 0, blend_perfect);
172
173 // BAD
174 }
175
176 // We want 0 diff whenever dst is 0xFF.
177 DEF_TEST(Blend_dst_0xFF, r) {
178 const uint8_t dst = 0xFF;
179
180 // GOOD
181 test_dst(r, dst, 0, blend_256_round);
182 test_dst(r, dst, 0, blend_256_round_alt);
183 test_dst(r, dst, 0, blend_double_trunc);
184 test_dst(r, dst, 0, blend_float_round);
185 test_dst(r, dst, 0, blend_float_trunc);
186 test_dst(r, dst, 0, blend_perfect);
187
188 // BAD
189 test_dst(r, dst, 1, blend_255_round);
190 test_dst(r, dst, 1, blend_255_trunc);
191 test_dst(r, dst, 1, blend_256_plus1_round);
192 test_dst(r, dst, 1, blend_256_plus1_trunc);
193 test_dst(r, dst, 1, blend_256_trunc);
194 }
195
196 // We'd like diff <= 1 everywhere.
197 DEF_TEST(Blend_alpha_Exhaustive, r) {
198 for (unsigned alpha = 0; alpha < 256; alpha++) {
199 // PERFECT
200 test_alpha(r, alpha, 0, blend_float_round);
201 test_alpha(r, alpha, 0, blend_perfect);
202
203 // GOOD
204 test_alpha(r, alpha, 1, blend_255_round);
205 test_alpha(r, alpha, 1, blend_256_plus1_round);
206 test_alpha(r, alpha, 1, blend_256_round);
207 test_alpha(r, alpha, 1, blend_256_round_alt);
208 test_alpha(r, alpha, 1, blend_256_trunc);
209 test_alpha(r, alpha, 1, blend_double_trunc);
210 test_alpha(r, alpha, 1, blend_float_trunc);
211
212 // BAD
213 test_alpha(r, alpha, 2, blend_255_trunc);
214 test_alpha(r, alpha, 2, blend_256_plus1_trunc);
215 }
216 }
217
218 // We'd like diff <= 1 everywhere.
219 DEF_TEST(Blend_dst_Exhaustive, r) {
220 for (unsigned dst = 0; dst < 256; dst++) {
221 // PERFECT
222 test_dst(r, dst, 0, blend_float_round);
223 test_dst(r, dst, 0, blend_perfect);
224
225 // GOOD
226 test_dst(r, dst, 1, blend_255_round);
227 test_dst(r, dst, 1, blend_256_plus1_round);
228 test_dst(r, dst, 1, blend_256_round);
229 test_dst(r, dst, 1, blend_256_round_alt);
230 test_dst(r, dst, 1, blend_256_trunc);
231 test_dst(r, dst, 1, blend_double_trunc);
232 test_dst(r, dst, 1, blend_float_trunc);
233
234 // BAD
235 test_dst(r, dst, 2, blend_255_trunc);
236 test_dst(r, dst, 2, blend_256_plus1_trunc);
237 }
238 }
239 // Overall summary:
240 // PERFECT
241 // blend_double_round
242 // blend_float_round
243 // blend_perfect
244 // GOOD ENOUGH
245 // blend_double_trunc
246 // blend_float_trunc
247 // blend_256_round
248 // blend_256_round_alt
249 // NOT GOOD ENOUGH
250 // all others
251 //
252 // Algorithms that make sense to use in Skia: blend_256_round, blend_256_round_ alt, blend_perfect
OLDNEW
« no previous file with comments | « gyp/tests.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698