1
2 /*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8 #include "Test.h"
9 #include "SkColor.h"
10 #include "SkColorPriv.h"
11 #include "SkMathPriv.h"
12 #include "SkRandom.h"
13 #include "SkUnPreMultiply.h"
14
15 #define GetPackedR16As32(packed) (SkGetPackedR16(dc) << (8 - SK_R16_BITS))
16 #define GetPackedG16As32(packed) (SkGetPackedG16(dc) << (8 - SK_G16_BITS))
17 #define GetPackedB16As32(packed) (SkGetPackedB16(dc) << (8 - SK_B16_BITS))
18
S32A_D565_Blend_0(SkPMColor sc,uint16_t dc,U8CPU alpha)19 static inline bool S32A_D565_Blend_0(SkPMColor sc, uint16_t dc, U8CPU alpha) {
20 unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
21 unsigned dr = SkMulS16(SkPacked32ToR16(sc), alpha) + SkMulS16(SkGetPackedR16(dc), dst_scale);
22 unsigned dg = SkMulS16(SkPacked32ToG16(sc), alpha) + SkMulS16(SkGetPackedG16(dc), dst_scale);
23
24 unsigned rr = SkDiv255Round(dr);
25 unsigned rg = SkDiv255Round(dg);
26
27 if (rr <= 31 && rg <= 63) {
28 return true;
29 }
30 return false;
31 }
32
S32A_D565_Blend_01(SkPMColor sc,uint16_t dc,U8CPU alpha)33 static inline bool S32A_D565_Blend_01(SkPMColor sc, uint16_t dc, U8CPU alpha) {
34 unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
35 unsigned dr = SkMulS16(SkGetPackedR32(sc), alpha) + SkMulS16(SkGetPackedR16(dc) << 3, dst_scale);
36 unsigned dg = SkMulS16(SkGetPackedG32(sc), alpha) + SkMulS16(SkGetPackedG16(dc) << 2, dst_scale);
37
38 unsigned rr = SkDiv255Round(dr) >> 3;
39 unsigned rg = SkDiv255Round(dg) >> 2;
40
41 if (rr <= 31 && rg <= 63) {
42 return true;
43 }
44 return false;
45 }
46
S32A_D565_Blend_02(SkPMColor sc,uint16_t dc,U8CPU alpha)47 static inline bool S32A_D565_Blend_02(SkPMColor sc, uint16_t dc, U8CPU alpha) {
48 unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
49 unsigned dr = SkMulS16(SkGetPackedR32(sc), alpha) + SkMulS16(GetPackedR16As32(dc), dst_scale);
50 unsigned dg = SkMulS16(SkGetPackedG32(sc), alpha) + SkMulS16(GetPackedG16As32(dc), dst_scale);
51 unsigned db = SkMulS16(SkGetPackedB32(sc), alpha) + SkMulS16(GetPackedB16As32(dc), dst_scale);
52 int rc = SkPack888ToRGB16(SkDiv255Round(dr),
53 SkDiv255Round(dg),
54 SkDiv255Round(db));
55
56 unsigned rr = SkGetPackedR16(rc);
57 unsigned rg = SkGetPackedG16(rc);
58
59 if (rr <= 31 && rg <= 63) {
60 return true;
61 }
62 return false;
63 }
64
S32A_D565_Blend_1(SkPMColor sc,uint16_t dc,U8CPU alpha)65 static inline bool S32A_D565_Blend_1(SkPMColor sc, uint16_t dc, U8CPU alpha) {
66 unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
67 unsigned dr = (SkMulS16(SkGetPackedR32(sc), alpha) >> 3) + SkMulS16(SkGetPackedR16(dc), dst_scale);
68 unsigned dg = (SkMulS16(SkGetPackedG32(sc), alpha) >> 2) + SkMulS16(SkGetPackedG16(dc), dst_scale);
69
70 unsigned rr = SkDiv255Round(dr);
71 unsigned rg = SkDiv255Round(dg);
72
73 if (rr <= 31 && rg <= 63) {
74 return true;
75 }
76 return false;
77 }
78
SkDiv65025Round(int x)79 static inline int SkDiv65025Round(int x) {
80 return (x + 65025/2) / 65025;
81 // return x / 65025;
82 }
S32A_D565_Blend_2(SkPMColor sc,uint16_t dc,U8CPU alpha)83 static inline bool S32A_D565_Blend_2(SkPMColor sc, uint16_t dc, U8CPU alpha) {
84 unsigned dst_scale = 255*255 - SkGetPackedA32(sc) * alpha;
85 alpha *= 255;
86 unsigned dr = (SkGetPackedR32(sc) >> 3) * alpha + SkGetPackedR16(dc) * dst_scale;
87 unsigned dg = (SkGetPackedG32(sc) >> 2) * alpha + SkGetPackedG16(dc) * dst_scale;
88
89 unsigned rr = SkDiv65025Round(dr);
90 unsigned rg = SkDiv65025Round(dg);
91
92 if (rr <= 31 && rg <= 63) {
93 return true;
94 }
95 return false;
96 }
97
test_565blend(skiatest::Reporter * reporter)98 static inline void test_565blend(skiatest::Reporter* reporter) {
99 int total_failures = 0;
100 for (int global_alpha = 0; global_alpha <= 255; ++global_alpha) {
101 int failures = 0;
102 int total = 0;
103 for (int src_a = 0; src_a <= 255; ++src_a) {
104 for (int src_c = 0; src_c <= src_a; ++src_c) {
105 SkPMColor sc = SkPackARGB32(src_a, src_c, src_c, src_c);
106 for (int dst_r = 0; dst_r <= 31; ++dst_r) {
107 for (int dst_g = 0; dst_g <= 63; ++dst_g) {
108 uint16_t dc = SkPackRGB16(dst_r, dst_g, dst_r);
109 failures += !S32A_D565_Blend_0(sc, dc, global_alpha);
110 total += 1;
111 }
112 }
113 }
114 }
115 SkDebugf("global_alpha=%d failures=%d total=%d %g\n", global_alpha, failures, total, failures * 100.0 / total);
116 total_failures += failures;
117 }
118 SkDebugf("total failures %d\n", total_failures);
119 }
120
test_premul(skiatest::Reporter * reporter)121 static inline void test_premul(skiatest::Reporter* reporter) {
122 for (int a = 0; a <= 255; a++) {
123 for (int x = 0; x <= 255; x++) {
124 SkColor c0 = SkColorSetARGB(a, x, x, x);
125 SkPMColor p0 = SkPreMultiplyColor(c0);
126
127 SkColor c1 = SkUnPreMultiply::PMColorToColor(p0);
128 SkPMColor p1 = SkPreMultiplyColor(c1);
129
130 // we can't promise that c0 == c1, since c0 -> p0 is a many to one
131 // function, however, we can promise that p0 -> c1 -> p1 : p0 == p1
132 REPORTER_ASSERT(reporter, p0 == p1);
133
134 {
135 int ax = SkMulDiv255Ceiling(x, a);
136 REPORTER_ASSERT(reporter, ax <= a);
137 }
138 }
139 }
140 }
141
142 /**
143 This test fails: SkFourByteInterp does *not* preserve opaque destinations.
144 SkAlpha255To256 implemented as (alpha + 1) is faster than
145 (alpha + (alpha >> 7)), but inaccurate, and Skia intends to phase it out.
146 */
147 /*
148 static void test_interp(skiatest::Reporter* reporter) {
149 SkRandom r;
150
151 U8CPU a0 = 0;
152 U8CPU a255 = 255;
153 for (int i = 0; i < 200; i++) {
154 SkColor colorSrc = r.nextU();
155 SkColor colorDst = r.nextU();
156 SkPMColor src = SkPreMultiplyColor(colorSrc);
157 SkPMColor dst = SkPreMultiplyColor(colorDst);
158
159 REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a0) == dst);
160 REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a255) == src);
161 }
162 }
163 */
164
test_fast_interp(skiatest::Reporter * reporter)165 static inline void test_fast_interp(skiatest::Reporter* reporter) {
166 SkRandom r;
167
168 U8CPU a0 = 0;
169 U8CPU a255 = 255;
170 for (int i = 0; i < 200; i++) {
171 SkColor colorSrc = r.nextU();
172 SkColor colorDst = r.nextU();
173 SkPMColor src = SkPreMultiplyColor(colorSrc);
174 SkPMColor dst = SkPreMultiplyColor(colorDst);
175
176 REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a0) == dst);
177 REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a255) == src);
178 }
179 }
180
TestColor(skiatest::Reporter * reporter)181 static void TestColor(skiatest::Reporter* reporter) {
182 test_premul(reporter);
183 //test_interp(reporter);
184 test_fast_interp(reporter);
185 // test_565blend(reporter);
186 }
187
188 #include "TestClassDef.h"
189 DEFINE_TESTCLASS("Color", ColorTestClass, TestColor)
190