OLD | NEW |
1 #include "SkConfig8888.h" | 1 #include "SkConfig8888.h" |
2 #include "SkColorPriv.h" | |
3 #include "SkMathPriv.h" | 2 #include "SkMathPriv.h" |
4 #include "SkUnPreMultiply.h" | 3 #include "SkUnPreMultiply.h" |
5 | 4 |
6 enum AlphaVerb { | 5 namespace { |
7 kNothing_AlphaVerb, | 6 |
8 kPremul_AlphaVerb, | 7 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX> |
9 kUnpremul_AlphaVerb, | 8 inline uint32_t pack_config8888(uint32_t a, uint32_t r, |
10 }; | 9 uint32_t g, uint32_t b) { |
11 | 10 #ifdef SK_CPU_LENDIAN |
12 template <bool doSwapRB, AlphaVerb doAlpha> uint32_t convert32(uint32_t c) { | 11 return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) | |
13 if (doSwapRB) { | 12 (g << (G_IDX * 8)) | (b << (B_IDX * 8)); |
14 c = SkSwizzle_RB(c); | 13 #else |
15 } | 14 return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) | |
16 | 15 (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8)); |
17 // Lucky for us, in both RGBA and BGRA, the alpha component is always in the
same place, so | 16 #endif |
18 // we can perform premul or unpremul the same way without knowing the swizzl
es for RGB. | 17 } |
19 switch (doAlpha) { | 18 |
20 case kNothing_AlphaVerb: | 19 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX> |
21 // no change | 20 inline void unpack_config8888(uint32_t color, |
22 break; | 21 uint32_t* a, uint32_t* r, |
23 case kPremul_AlphaVerb: | 22 uint32_t* g, uint32_t* b) { |
24 c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c), | 23 #ifdef SK_CPU_LENDIAN |
25 SkGetPackedG32(c), SkGetPackedB32(c)); | 24 *a = (color >> (A_IDX * 8)) & 0xff; |
26 break; | 25 *r = (color >> (R_IDX * 8)) & 0xff; |
27 case kUnpremul_AlphaVerb: | 26 *g = (color >> (G_IDX * 8)) & 0xff; |
28 c = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(c); | 27 *b = (color >> (B_IDX * 8)) & 0xff; |
29 break; | 28 #else |
30 } | 29 *a = (color >> ((3 - A_IDX) * 8)) & 0xff; |
31 return c; | 30 *r = (color >> ((3 - R_IDX) * 8)) & 0xff; |
32 } | 31 *g = (color >> ((3 - G_IDX) * 8)) & 0xff; |
33 | 32 *b = (color >> ((3 - B_IDX) * 8)) & 0xff; |
34 template <bool doSwapRB, AlphaVerb doAlpha> | 33 #endif |
35 void convert32_row(uint32_t* dst, const uint32_t* src, int count) { | 34 } |
36 // This has to be correct if src == dst (but not partial overlap) | 35 |
37 for (int i = 0; i < count; ++i) { | 36 #ifdef SK_CPU_LENDIAN |
38 dst[i] = convert32<doSwapRB, doAlpha>(src[i]); | 37 static const int SK_NATIVE_A_IDX = SK_A32_SHIFT / 8; |
39 } | 38 static const int SK_NATIVE_R_IDX = SK_R32_SHIFT / 8; |
40 } | 39 static const int SK_NATIVE_G_IDX = SK_G32_SHIFT / 8; |
41 | 40 static const int SK_NATIVE_B_IDX = SK_B32_SHIFT / 8; |
42 static bool is_32bit_colortype(SkColorType ct) { | 41 #else |
43 return kRGBA_8888_SkColorType == ct || kBGRA_8888_SkColorType == ct; | 42 static const int SK_NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8); |
44 } | 43 static const int SK_NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8); |
45 | 44 static const int SK_NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8); |
46 static AlphaVerb compute_AlphaVerb(SkAlphaType src, SkAlphaType dst) { | 45 static const int SK_NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8); |
47 SkASSERT(kIgnore_SkAlphaType != src); | 46 #endif |
48 SkASSERT(kIgnore_SkAlphaType != dst); | 47 |
49 | 48 /** |
50 if (kOpaque_SkAlphaType == src || kOpaque_SkAlphaType == dst || src == dst)
{ | 49 * convert_pixel<OUT_CFG, IN_CFG converts a pixel value from one Config8888 to |
51 return kNothing_AlphaVerb; | 50 * another. It is implemented by first expanding OUT_CFG to r, g, b, a indices |
52 } | 51 * and an is_premul bool as params to another template function. Then IN_CFG is |
53 if (kPremul_SkAlphaType == dst) { | 52 * expanded via another function call. |
54 SkASSERT(kUnpremul_SkAlphaType == src); | 53 */ |
55 return kPremul_AlphaVerb; | 54 |
56 } else { | 55 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_ID
X, |
57 SkASSERT(kPremul_SkAlphaType == src); | 56 bool IN_PM, int IN_A_IDX, int IN_R_IDX, int IN_G_IDX, int IN_B_IDX
> |
58 SkASSERT(kUnpremul_SkAlphaType == dst); | 57 inline uint32_t convert_pixel(uint32_t pixel) { |
59 return kUnpremul_AlphaVerb; | 58 uint32_t a, r, g, b; |
60 } | 59 unpack_config8888<IN_A_IDX, IN_R_IDX, IN_G_IDX, IN_B_IDX>(pixel, &a, &r, &g,
&b); |
61 } | 60 if (IN_PM && !OUT_PM) { |
62 | 61 // Using SkUnPreMultiply::ApplyScale is faster than (value * 0xff) / a. |
63 static void memcpy32_row(uint32_t* dst, const uint32_t* src, int count) { | 62 if (a) { |
64 memcpy(dst, src, count * 4); | 63 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(a); |
65 } | 64 r = SkUnPreMultiply::ApplyScale(scale, r); |
66 | 65 g = SkUnPreMultiply::ApplyScale(scale, g); |
67 bool SkSrcPixelInfo::convertPixelsTo(SkDstPixelInfo* dst, int width, int height)
const { | 66 b = SkUnPreMultiply::ApplyScale(scale, b); |
68 if (width <= 0 || height <= 0) { | 67 } else { |
69 return false; | 68 return 0; |
70 } | 69 } |
71 | 70 } else if (!IN_PM && OUT_PM) { |
72 if (!is_32bit_colortype(fColorType) || !is_32bit_colortype(dst->fColorType))
{ | 71 // This matches SkUnPreMultiply conversion which we are replacing. |
73 return false; | 72 r = SkMulDiv255Round(r, a); |
74 } | 73 g = SkMulDiv255Round(g, a); |
75 | 74 b = SkMulDiv255Round(b, a); |
76 void (*proc)(uint32_t* dst, const uint32_t* src, int count); | 75 } |
77 AlphaVerb doAlpha = compute_AlphaVerb(fAlphaType, dst->fAlphaType); | 76 return pack_config8888<OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX>(a, r, g,
b); |
78 bool doSwapRB = fColorType != dst->fColorType; | 77 } |
79 | 78 |
80 switch (doAlpha) { | 79 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_ID
X, SkCanvas::Config8888 IN_CFG> |
81 case kNothing_AlphaVerb: | 80 inline uint32_t convert_pixel(uint32_t pixel) { |
82 if (doSwapRB) { | 81 switch(IN_CFG) { |
83 proc = convert32_row<true, kNothing_AlphaVerb>; | 82 case SkCanvas::kNative_Premul_Config8888: |
84 } else { | 83 return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G
_IDX, OUT_B_IDX, |
85 if (fPixels == dst->fPixels) { | 84 true, SK_NATIVE_A_IDX, SK_NATIVE_R_IDX, SK_NA
TIVE_G_IDX, SK_NATIVE_B_IDX>(pixel); |
86 return true; | 85 break; |
87 } | 86 case SkCanvas::kNative_Unpremul_Config8888: |
88 proc = memcpy32_row; | 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_NA
TIVE_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>(pixe
l); |
| 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>(pix
el); |
| 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>(pixe
l); |
| 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>(pix
el); |
| 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_NA
TIVE_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_N
ATIVE_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>(dst
Pixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
| 180 break; |
| 181 case SkCanvas::kNative_Unpremul_Config8888: |
| 182 convert_config8888<SkCanvas::kNative_Unpremul_Config8888, SRC_CFG>(d
stPixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
| 183 break; |
| 184 case SkCanvas::kBGRA_Premul_Config8888: |
| 185 convert_config8888<SkCanvas::kBGRA_Premul_Config8888, SRC_CFG>(dstPi
xels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
| 186 break; |
| 187 case SkCanvas::kBGRA_Unpremul_Config8888: |
| 188 convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888, SRC_CFG>(dst
Pixels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
| 189 break; |
| 190 case SkCanvas::kRGBA_Premul_Config8888: |
| 191 convert_config8888<SkCanvas::kRGBA_Premul_Config8888, SRC_CFG>(dstPi
xels, dstRowBytes, srcPixels, srcRowBytes, width, height); |
| 192 break; |
| 193 case SkCanvas::kRGBA_Unpremul_Config8888: |
| 194 convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888, SRC_CFG>(dst
Pixels, 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; |
89 } | 229 } |
90 break; | 230 return; |
91 case kPremul_AlphaVerb: | 231 } |
92 if (doSwapRB) { | 232 } |
93 proc = convert32_row<true, kPremul_AlphaVerb>; | 233 switch(srcConfig) { |
94 } else { | 234 case SkCanvas::kNative_Premul_Config8888: |
95 proc = convert32_row<false, kPremul_AlphaVerb>; | 235 convert_config8888<SkCanvas::kNative_Premul_Config8888>(dstPixels, d
stRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
96 } | 236 break; |
97 break; | 237 case SkCanvas::kNative_Unpremul_Config8888: |
98 case kUnpremul_AlphaVerb: | 238 convert_config8888<SkCanvas::kNative_Unpremul_Config8888>(dstPixels,
dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
99 if (doSwapRB) { | 239 break; |
100 proc = convert32_row<true, kUnpremul_AlphaVerb>; | 240 case SkCanvas::kBGRA_Premul_Config8888: |
101 } else { | 241 convert_config8888<SkCanvas::kBGRA_Premul_Config8888>(dstPixels, dst
RowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
102 proc = convert32_row<false, kUnpremul_AlphaVerb>; | 242 break; |
103 } | 243 case SkCanvas::kBGRA_Unpremul_Config8888: |
104 break; | 244 convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888>(dstPixels, d
stRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
105 } | 245 break; |
106 | 246 case SkCanvas::kRGBA_Premul_Config8888: |
107 uint32_t* dstP = static_cast<uint32_t*>(dst->fPixels); | 247 convert_config8888<SkCanvas::kRGBA_Premul_Config8888>(dstPixels, dst
RowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
108 const uint32_t* srcP = static_cast<const uint32_t*>(fPixels); | 248 break; |
109 size_t srcInc = fRowBytes >> 2; | 249 case SkCanvas::kRGBA_Unpremul_Config8888: |
110 size_t dstInc = dst->fRowBytes >> 2; | 250 convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888>(dstPixels, d
stRowBytes, dstConfig, srcPixels, srcRowBytes, width, height); |
111 for (int y = 0; y < height; ++y) { | 251 break; |
112 proc(dstP, srcP, width); | 252 default: |
113 dstP += dstInc; | 253 SkDEBUGFAIL("Unexpected config8888"); |
114 srcP += srcInc; | 254 break; |
115 } | 255 } |
116 return true; | 256 } |
117 } | 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 } |
OLD | NEW |