• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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