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