|
1 #include "SkConfig8888.h" |
|
2 #include "SkMathPriv.h" |
|
3 #include "SkUnPreMultiply.h" |
|
4 |
|
5 namespace { |
|
6 |
|
7 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX> |
|
8 inline uint32_t pack_config8888(uint32_t a, uint32_t r, |
|
9 uint32_t g, uint32_t b) { |
|
10 #ifdef SK_CPU_LENDIAN |
|
11 return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) | |
|
12 (g << (G_IDX * 8)) | (b << (B_IDX * 8)); |
|
13 #else |
|
14 return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) | |
|
15 (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8)); |
|
16 #endif |
|
17 } |
|
18 |
|
19 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX> |
|
20 inline void unpack_config8888(uint32_t color, |
|
21 uint32_t* a, uint32_t* r, |
|
22 uint32_t* g, uint32_t* b) { |
|
23 #ifdef SK_CPU_LENDIAN |
|
24 *a = (color >> (A_IDX * 8)) & 0xff; |
|
25 *r = (color >> (R_IDX * 8)) & 0xff; |
|
26 *g = (color >> (G_IDX * 8)) & 0xff; |
|
27 *b = (color >> (B_IDX * 8)) & 0xff; |
|
28 #else |
|
29 *a = (color >> ((3 - A_IDX) * 8)) & 0xff; |
|
30 *r = (color >> ((3 - R_IDX) * 8)) & 0xff; |
|
31 *g = (color >> ((3 - G_IDX) * 8)) & 0xff; |
|
32 *b = (color >> ((3 - B_IDX) * 8)) & 0xff; |
|
33 #endif |
|
34 } |
|
35 |
|
36 #ifdef SK_CPU_LENDIAN |
|
37 static const int SK_NATIVE_A_IDX = SK_A32_SHIFT / 8; |
|
38 static const int SK_NATIVE_R_IDX = SK_R32_SHIFT / 8; |
|
39 static const int SK_NATIVE_G_IDX = SK_G32_SHIFT / 8; |
|
40 static const int SK_NATIVE_B_IDX = SK_B32_SHIFT / 8; |
|
41 #else |
|
42 static const int SK_NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8); |
|
43 static const int SK_NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8); |
|
44 static const int SK_NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8); |
|
45 static const int SK_NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8); |
|
46 #endif |
|
47 |
|
48 /** |
|
49 * convert_pixel<OUT_CFG, IN_CFG converts a pixel value from one Config8888 to |
|
50 * another. It is implemented by first expanding OUT_CFG to r, g, b, a indices |
|
51 * and an is_premul bool as params to another template function. Then IN_CFG is |
|
52 * expanded via another function call. |
|
53 */ |
|
54 |
|
55 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_IDX, |
|
56 bool IN_PM, int IN_A_IDX, int IN_R_IDX, int IN_G_IDX, int IN_B_IDX> |
|
57 inline uint32_t convert_pixel(uint32_t pixel) { |
|
58 uint32_t a, r, g, b; |
|
59 unpack_config8888<IN_A_IDX, IN_R_IDX, IN_G_IDX, IN_B_IDX>(pixel, &a, &r, &g, &b); |
|
60 if (IN_PM && !OUT_PM) { |
|
61 // Using SkUnPreMultiply::ApplyScale is faster than (value * 0xff) / a. |
|
62 if (a) { |
|
63 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(a); |
|
64 r = SkUnPreMultiply::ApplyScale(scale, r); |
|
65 g = SkUnPreMultiply::ApplyScale(scale, g); |
|
66 b = SkUnPreMultiply::ApplyScale(scale, b); |
|
67 } else { |
|
68 return 0; |
|
69 } |
|
70 } else if (!IN_PM && OUT_PM) { |
|
71 // This matches SkUnPreMultiply conversion which we are replacing. |
|
72 r = SkMulDiv255Round(r, a); |
|
73 g = SkMulDiv255Round(g, a); |
|
74 b = SkMulDiv255Round(b, a); |
|
75 } |
|
76 return pack_config8888<OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX>(a, r, g, b); |
|
77 } |
|
78 |
|
79 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_IDX, SkCanvas::Config8888 IN_CFG> |
|
80 inline uint32_t convert_pixel(uint32_t pixel) { |
|
81 switch(IN_CFG) { |
|
82 case SkCanvas::kNative_Premul_Config8888: |
|
83 return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX, |
|
84 true, SK_NATIVE_A_IDX, SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(pixel); |
|
85 break; |
|
86 case SkCanvas::kNative_Unpremul_Config8888: |
|
87 return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX, |
|
88 false, SK_NATIVE_A_IDX, SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(pixel); |
|
89 break; |
|
90 case SkCanvas::kBGRA_Premul_Config8888: |
|
91 return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX, |
|
92 true, 3, 2, 1, 0>(pixel); |
|
93 break; |
|
94 case SkCanvas::kBGRA_Unpremul_Config8888: |
|
95 return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX, |
|
96 false, 3, 2, 1, 0>(pixel); |
|
97 break; |
|
98 case SkCanvas::kRGBA_Premul_Config8888: |
|
99 return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX, |
|
100 true, 3, 0, 1, 2>(pixel); |
|
101 break; |
|
102 case SkCanvas::kRGBA_Unpremul_Config8888: |
|
103 return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX, |
|
104 false, 3, 0, 1, 2>(pixel); |
|
105 break; |
|
106 default: |
|
107 SkDEBUGFAIL("Unexpected config8888"); |
|
108 return 0; |
|
109 break; |
|
110 } |
|
111 } |
|
112 |
|
113 template <SkCanvas::Config8888 OUT_CFG, SkCanvas::Config8888 IN_CFG> |
|
114 inline uint32_t convert_pixel(uint32_t pixel) { |
|
115 switch(OUT_CFG) { |
|
116 case SkCanvas::kNative_Premul_Config8888: |
|
117 return convert_pixel<true, SK_NATIVE_A_IDX, SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX, IN_CFG>(pixel); |
|
118 break; |
|
119 case SkCanvas::kNative_Unpremul_Config8888: |
|
120 return convert_pixel<false, SK_NATIVE_A_IDX, SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX, IN_CFG>(pixel); |
|
121 break; |
|
122 case SkCanvas::kBGRA_Premul_Config8888: |
|
123 return convert_pixel<true, 3, 2, 1, 0, IN_CFG>(pixel); |
|
124 break; |
|
125 case SkCanvas::kBGRA_Unpremul_Config8888: |
|
126 return convert_pixel<false, 3, 2, 1, 0, IN_CFG>(pixel); |
|
127 break; |
|
128 case SkCanvas::kRGBA_Premul_Config8888: |
|
129 return convert_pixel<true, 3, 0, 1, 2, IN_CFG>(pixel); |
|
130 break; |
|
131 case SkCanvas::kRGBA_Unpremul_Config8888: |
|
132 return convert_pixel<false, 3, 0, 1, 2, IN_CFG>(pixel); |
|
133 break; |
|
134 default: |
|
135 SkDEBUGFAIL("Unexpected config8888"); |
|
136 return 0; |
|
137 break; |
|
138 } |
|
139 } |
|
140 |
|
141 /** |
|
142 * SkConvertConfig8888Pixels has 6 * 6 possible combinations of src and dst |
|
143 * configs. Each is implemented as an instantiation templated function. Two |
|
144 * levels of switch statements are used to select the correct instantiation, one |
|
145 * for the src config and one for the dst config. |
|
146 */ |
|
147 |
|
148 template <SkCanvas::Config8888 DST_CFG, SkCanvas::Config8888 SRC_CFG> |
|
149 inline void convert_config8888(uint32_t* dstPixels, |
|
150 size_t dstRowBytes, |
|
151 const uint32_t* srcPixels, |
|
152 size_t srcRowBytes, |
|
153 int width, |
|
154 int height) { |
|
155 intptr_t dstPix = reinterpret_cast<intptr_t>(dstPixels); |
|
156 intptr_t srcPix = reinterpret_cast<intptr_t>(srcPixels); |
|
157 |
|
158 for (int y = 0; y < height; ++y) { |
|
159 srcPixels = reinterpret_cast<const uint32_t*>(srcPix); |
|
160 dstPixels = reinterpret_cast<uint32_t*>(dstPix); |
|
161 for (int x = 0; x < width; ++x) { |
|
162 dstPixels[x] = convert_pixel<DST_CFG, SRC_CFG>(srcPixels[x]); |
|
163 } |
|
164 dstPix += dstRowBytes; |
|
165 srcPix += srcRowBytes; |
|
166 } |
|
167 } |
|
168 |
|
169 template <SkCanvas::Config8888 SRC_CFG> |
|
170 inline void convert_config8888(uint32_t* dstPixels, |
|
171 size_t dstRowBytes, |
|
172 SkCanvas::Config8888 dstConfig, |
|
173 const uint32_t* srcPixels, |
|
174 size_t srcRowBytes, |
|
175 int width, |
|
176 int height) { |
|
177 switch(dstConfig) { |
|
178 case SkCanvas::kNative_Premul_Config8888: |
|
179 convert_config8888<SkCanvas::kNative_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
|
180 break; |
|
181 case SkCanvas::kNative_Unpremul_Config8888: |
|
182 convert_config8888<SkCanvas::kNative_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
|
183 break; |
|
184 case SkCanvas::kBGRA_Premul_Config8888: |
|
185 convert_config8888<SkCanvas::kBGRA_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
|
186 break; |
|
187 case SkCanvas::kBGRA_Unpremul_Config8888: |
|
188 convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
|
189 break; |
|
190 case SkCanvas::kRGBA_Premul_Config8888: |
|
191 convert_config8888<SkCanvas::kRGBA_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
|
192 break; |
|
193 case SkCanvas::kRGBA_Unpremul_Config8888: |
|
194 convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
|
195 break; |
|
196 default: |
|
197 SkDEBUGFAIL("Unexpected config8888"); |
|
198 break; |
|
199 } |
|
200 } |
|
201 |
|
202 } |
|
203 |
|
204 void SkConvertConfig8888Pixels(uint32_t* dstPixels, |
|
205 size_t dstRowBytes, |
|
206 SkCanvas::Config8888 dstConfig, |
|
207 const uint32_t* srcPixels, |
|
208 size_t srcRowBytes, |
|
209 SkCanvas::Config8888 srcConfig, |
|
210 int width, |
|
211 int height) { |
|
212 if (srcConfig == dstConfig) { |
|
213 if (srcPixels == dstPixels) { |
|
214 return; |
|
215 } |
|
216 if (dstRowBytes == srcRowBytes && |
|
217 4U * width == srcRowBytes) { |
|
218 memcpy(dstPixels, srcPixels, srcRowBytes * height); |
|
219 return; |
|
220 } else { |
|
221 intptr_t srcPix = reinterpret_cast<intptr_t>(srcPixels); |
|
222 intptr_t dstPix = reinterpret_cast<intptr_t>(dstPixels); |
|
223 for (int y = 0; y < height; ++y) { |
|
224 srcPixels = reinterpret_cast<const uint32_t*>(srcPix); |
|
225 dstPixels = reinterpret_cast<uint32_t*>(dstPix); |
|
226 memcpy(dstPixels, srcPixels, 4 * width); |
|
227 srcPix += srcRowBytes; |
|
228 dstPix += dstRowBytes; |
|
229 } |
|
230 return; |
|
231 } |
|
232 } |
|
233 switch(srcConfig) { |
|
234 case SkCanvas::kNative_Premul_Config8888: |
|
235 convert_config8888<SkCanvas::kNative_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
|
236 break; |
|
237 case SkCanvas::kNative_Unpremul_Config8888: |
|
238 convert_config8888<SkCanvas::kNative_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
|
239 break; |
|
240 case SkCanvas::kBGRA_Premul_Config8888: |
|
241 convert_config8888<SkCanvas::kBGRA_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
|
242 break; |
|
243 case SkCanvas::kBGRA_Unpremul_Config8888: |
|
244 convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
|
245 break; |
|
246 case SkCanvas::kRGBA_Premul_Config8888: |
|
247 convert_config8888<SkCanvas::kRGBA_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
|
248 break; |
|
249 case SkCanvas::kRGBA_Unpremul_Config8888: |
|
250 convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
|
251 break; |
|
252 default: |
|
253 SkDEBUGFAIL("Unexpected config8888"); |
|
254 break; |
|
255 } |
|
256 } |
|
257 |
|
258 uint32_t SkPackConfig8888(SkCanvas::Config8888 config, |
|
259 uint32_t a, |
|
260 uint32_t r, |
|
261 uint32_t g, |
|
262 uint32_t b) { |
|
263 switch (config) { |
|
264 case SkCanvas::kNative_Premul_Config8888: |
|
265 case SkCanvas::kNative_Unpremul_Config8888: |
|
266 return pack_config8888<SK_NATIVE_A_IDX, |
|
267 SK_NATIVE_R_IDX, |
|
268 SK_NATIVE_G_IDX, |
|
269 SK_NATIVE_B_IDX>(a, r, g, b); |
|
270 case SkCanvas::kBGRA_Premul_Config8888: |
|
271 case SkCanvas::kBGRA_Unpremul_Config8888: |
|
272 return pack_config8888<3, 2, 1, 0>(a, r, g, b); |
|
273 case SkCanvas::kRGBA_Premul_Config8888: |
|
274 case SkCanvas::kRGBA_Unpremul_Config8888: |
|
275 return pack_config8888<3, 0, 1, 2>(a, r, g, b); |
|
276 default: |
|
277 SkDEBUGFAIL("Unexpected config8888"); |
|
278 return 0; |
|
279 } |
|
280 } |