SkSwizzler.cpp revision 741143878b23d22cd9cb7b9cba8055179115ce17
1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkCodecPriv.h" 9#include "SkColorPriv.h" 10#include "SkSwizzler.h" 11#include "SkTemplates.h" 12 13SkSwizzler::ResultAlpha SkSwizzler::GetResult(uint8_t zeroAlpha, 14 uint8_t maxAlpha) { 15 // In the transparent case, this returns 0x0000 16 // In the opaque case, this returns 0xFFFF 17 // If the row is neither transparent nor opaque, returns something else 18 return (((uint16_t) maxAlpha) << 8) | zeroAlpha; 19} 20 21// kIndex1, kIndex2, kIndex4 22 23static SkSwizzler::ResultAlpha swizzle_small_index_to_n32( 24 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 25 int bitsPerPixel, int y, const SkPMColor ctable[]) { 26 27 SkPMColor* SK_RESTRICT dst = (SkPMColor*) dstRow; 28 INIT_RESULT_ALPHA; 29 const uint32_t pixelsPerByte = 8 / bitsPerPixel; 30 const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte); 31 const uint8_t mask = (1 << bitsPerPixel) - 1; 32 int x = 0; 33 for (uint32_t byte = 0; byte < rowBytes; byte++) { 34 uint8_t pixelData = src[byte]; 35 for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) { 36 uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask; 37 SkPMColor c = ctable[index]; 38 UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); 39 dst[x] = c; 40 pixelData <<= bitsPerPixel; 41 x++; 42 } 43 } 44 return COMPUTE_RESULT_ALPHA; 45} 46 47// kIndex 48 49static SkSwizzler::ResultAlpha swizzle_index_to_n32( 50 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 51 int bytesPerPixel, int y, const SkPMColor ctable[]) { 52 53 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 54 INIT_RESULT_ALPHA; 55 for (int x = 0; x < width; x++) { 56 SkPMColor c = ctable[*src]; 57 UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); 58 dst[x] = c; 59 src++; 60 } 61 return COMPUTE_RESULT_ALPHA; 62} 63 64static SkSwizzler::ResultAlpha swizzle_index_to_n32_skipZ( 65 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 66 int bytesPerPixel, int y, const SkPMColor ctable[]) { 67 68 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 69 INIT_RESULT_ALPHA; 70 for (int x = 0; x < width; x++) { 71 SkPMColor c = ctable[*src]; 72 UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); 73 if (c != 0) { 74 dst[x] = c; 75 } 76 src++; 77 } 78 return COMPUTE_RESULT_ALPHA; 79} 80 81#undef A32_MASK_IN_PLACE 82 83static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32( 84 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 85 int bytesPerPixel, int y, const SkPMColor ctable[]) { 86 87 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 88 for (int x = 0; x < width; x++) { 89 dst[x] = SkPackARGB32NoCheck(0xFF, src[2], src[1], src[0]); 90 src += bytesPerPixel; 91 } 92 return SkSwizzler::kOpaque_ResultAlpha; 93} 94 95// kBGRA 96 97static SkSwizzler::ResultAlpha swizzle_bgra_to_n32( 98 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 99 int bytesPerPixel, int y, const SkPMColor ctable[]) { 100 101 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 102 INIT_RESULT_ALPHA; 103 for (int x = 0; x < width; x++) { 104 uint8_t alpha = src[3]; 105 UPDATE_RESULT_ALPHA(alpha); 106 dst[x] = SkPackARGB32NoCheck(alpha, src[2], src[1], src[0]); 107 src += bytesPerPixel; 108 } 109 return COMPUTE_RESULT_ALPHA; 110} 111 112// n32 113static SkSwizzler::ResultAlpha swizzle_rgbx_to_n32( 114 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 115 int bytesPerPixel, int y, const SkPMColor ctable[]) { 116 117 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 118 for (int x = 0; x < width; x++) { 119 dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]); 120 src += bytesPerPixel; 121 } 122 return SkSwizzler::kOpaque_ResultAlpha; 123} 124 125static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul( 126 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 127 int bytesPerPixel, int y, const SkPMColor ctable[]) { 128 129 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 130 INIT_RESULT_ALPHA; 131 for (int x = 0; x < width; x++) { 132 unsigned alpha = src[3]; 133 UPDATE_RESULT_ALPHA(alpha); 134 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 135 src += bytesPerPixel; 136 } 137 return COMPUTE_RESULT_ALPHA; 138} 139 140static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_unpremul( 141 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 142 int bytesPerPixel, int y, const SkPMColor ctable[]) { 143 144 uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow); 145 INIT_RESULT_ALPHA; 146 for (int x = 0; x < width; x++) { 147 unsigned alpha = src[3]; 148 UPDATE_RESULT_ALPHA(alpha); 149 dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); 150 src += bytesPerPixel; 151 } 152 return COMPUTE_RESULT_ALPHA; 153} 154 155static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul_skipZ( 156 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 157 int bytesPerPixel, int y, const SkPMColor ctable[]) { 158 159 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 160 INIT_RESULT_ALPHA; 161 for (int x = 0; x < width; x++) { 162 unsigned alpha = src[3]; 163 UPDATE_RESULT_ALPHA(alpha); 164 if (0 != alpha) { 165 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 166 } 167 src += bytesPerPixel; 168 } 169 return COMPUTE_RESULT_ALPHA; 170} 171 172/** 173 FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes. 174 This would be fine for drawing normally, but not for drawing with transfer modes. Being 175 honest means we can draw correctly with transfer modes, with the cost of not being able 176 to take advantage of Android's free unwritten pages. Something to keep in mind when we 177 decide whether to switch to unpremul default. 178static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow, 179 const uint8_t* SK_RESTRICT src, 180 int width, int bitsPerPixel, 181 const SkPMColor[]) { 182 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 183 unsigned alphaMask = 0xFF; 184 for (int x = 0; x < width; x++) { 185 unsigned alpha = src[3]; 186 // NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible 187 // the color components are not zero, but we skip them anyway, meaning they'll remain 188 // zero (implied by the request to skip zeroes). 189 if (0 != alpha) { 190 dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); 191 } 192 src += deltaSrc; 193 alphaMask &= alpha; 194 } 195 return alphaMask != 0xFF; 196} 197*/ 198 199SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, 200 const SkPMColor* ctable, 201 const SkImageInfo& info, void* dst, 202 size_t dstRowBytes, bool skipZeroes) { 203 if (kUnknown_SkColorType == info.colorType()) { 204 return NULL; 205 } 206 if (info.minRowBytes() > dstRowBytes) { 207 return NULL; 208 } 209 if ((kIndex == sc || kIndex4 == sc || kIndex2 == sc || kIndex1 == sc) 210 && NULL == ctable) { 211 return NULL; 212 } 213 RowProc proc = NULL; 214 switch (sc) { 215 case kIndex1: 216 case kIndex2: 217 case kIndex4: 218 switch (info.colorType()) { 219 case kN32_SkColorType: 220 proc = &swizzle_small_index_to_n32; 221 break; 222 default: 223 break; 224 } 225 break; 226 case kIndex: 227 switch (info.colorType()) { 228 case kN32_SkColorType: 229 if (skipZeroes) { 230 proc = &swizzle_index_to_n32_skipZ; 231 } else { 232 proc = &swizzle_index_to_n32; 233 } 234 break; 235 default: 236 break; 237 } 238 break; 239 case kBGR: 240 case kBGRX: 241 switch (info.colorType()) { 242 case kN32_SkColorType: 243 proc = &swizzle_bgrx_to_n32; 244 break; 245 default: 246 break; 247 } 248 break; 249 case kBGRA: 250 switch (info.colorType()) { 251 case kN32_SkColorType: 252 proc = &swizzle_bgra_to_n32; 253 break; 254 default: 255 break; 256 } 257 break; 258 case kRGBX: 259 // TODO: Support other swizzles. 260 switch (info.colorType()) { 261 case kN32_SkColorType: 262 proc = &swizzle_rgbx_to_n32; 263 break; 264 default: 265 break; 266 } 267 break; 268 case kRGBA: 269 switch (info.colorType()) { 270 case kN32_SkColorType: 271 if (info.alphaType() == kUnpremul_SkAlphaType) { 272 // Respect skipZeroes? 273 proc = &swizzle_rgba_to_n32_unpremul; 274 } else { 275 if (skipZeroes) { 276 proc = &swizzle_rgba_to_n32_premul_skipZ; 277 } else { 278 proc = &swizzle_rgba_to_n32_premul; 279 } 280 } 281 break; 282 default: 283 break; 284 } 285 break; 286 case kRGB: 287 switch (info.colorType()) { 288 case kN32_SkColorType: 289 proc = &swizzle_rgbx_to_n32; 290 break; 291 default: 292 break; 293 } 294 break; 295 default: 296 break; 297 } 298 if (NULL == proc) { 299 return NULL; 300 } 301 302 // Store deltaSrc in bytes if it is an even multiple, otherwise use bits 303 int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : 304 BitsPerPixel(sc); 305 return SkNEW_ARGS(SkSwizzler, (proc, ctable, deltaSrc, info, dst, 306 dstRowBytes)); 307} 308 309SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, 310 int deltaSrc, const SkImageInfo& info, void* dst, 311 size_t rowBytes) 312 : fRowProc(proc) 313 , fColorTable(ctable) 314 , fDeltaSrc(deltaSrc) 315 , fDstInfo(info) 316 , fDstRow(dst) 317 , fDstRowBytes(rowBytes) 318 , fCurrY(0) 319{ 320 SkDEBUGCODE(fNextMode = kUninitialized_NextMode); 321} 322 323SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src) { 324 SkASSERT(0 <= fCurrY && fCurrY < fDstInfo.height()); 325 SkASSERT(kDesignateRow_NextMode != fNextMode); 326 SkDEBUGCODE(fNextMode = kConsecutive_NextMode); 327 328 // Decode a row 329 const ResultAlpha result = fRowProc(fDstRow, src, fDstInfo.width(), 330 fDeltaSrc, fCurrY, fColorTable); 331 332 // Move to the next row and return the result 333 fDstRow = SkTAddOffset<void>(fDstRow, fDstRowBytes); 334 return result; 335} 336 337SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src, 338 int y) { 339 SkASSERT(0 <= y && y < fDstInfo.height()); 340 SkASSERT(kConsecutive_NextMode != fNextMode); 341 SkDEBUGCODE(fNextMode = kDesignateRow_NextMode); 342 343 // Choose the row 344 void* row = SkTAddOffset<void>(fDstRow, y*fDstRowBytes); 345 346 // Decode the row 347 return fRowProc(row, src, fDstInfo.width(), fDeltaSrc, fCurrY, 348 fColorTable); 349} 350