blob: 55fdd74f0a8aff6cad3fa3e183294e6d9835dca9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@google.com83acbe02011-04-22 19:18:20 +00008#include "Test.h"
9#include "SkColor.h"
tomhudson@google.com13e812c2012-01-18 21:28:01 +000010#include "SkColorPriv.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000011#include "SkMathPriv.h"
tomhudson@google.com13e812c2012-01-18 21:28:01 +000012#include "SkRandom.h"
reed@google.com83acbe02011-04-22 19:18:20 +000013#include "SkUnPreMultiply.h"
14
reed@google.com223d81d2012-10-12 14:43:28 +000015#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
19static 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
33static 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
47static 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
65static 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
79static int SkDiv65025Round(int x) {
80 return (x + 65025/2) / 65025;
81// return x / 65025;
82}
83static 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
98static 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
reed@google.com83acbe02011-04-22 19:18:20 +0000121static 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);
reed@google.com75595d92011-05-03 21:27:49 +0000133
134 {
135 int ax = SkMulDiv255Ceiling(x, a);
136 REPORTER_ASSERT(reporter, ax <= a);
137 }
reed@google.com83acbe02011-04-22 19:18:20 +0000138 }
139 }
140}
141
tomhudson@google.com13e812c2012-01-18 21:28:01 +0000142/**
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/*
148static 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
165static 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}
reed@google.com83acbe02011-04-22 19:18:20 +0000180
181static void TestColor(skiatest::Reporter* reporter) {
182 test_premul(reporter);
tomhudson@google.com13e812c2012-01-18 21:28:01 +0000183 //test_interp(reporter);
184 test_fast_interp(reporter);
reed@google.com223d81d2012-10-12 14:43:28 +0000185// test_565blend(reporter);
reed@google.com83acbe02011-04-22 19:18:20 +0000186}
187
188#include "TestClassDef.h"
189DEFINE_TESTCLASS("Color", ColorTestClass, TestColor)