SkSwizzler.cpp revision cbb12ca953c8db8030e4e52bb12e2dae98d2692b
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#include "SkUtils.h" 13 14SkSwizzler::ResultAlpha SkSwizzler::GetResult(uint8_t zeroAlpha, 15 uint8_t maxAlpha) { 16 // In the transparent case, this returns 0x0000 17 // In the opaque case, this returns 0xFFFF 18 // If the row is neither transparent nor opaque, returns something else 19 return (((uint16_t) maxAlpha) << 8) | zeroAlpha; 20} 21 22// kBit 23// These routines exclusively choose between white and black 24 25#define GRAYSCALE_BLACK 0 26#define GRAYSCALE_WHITE 0xFF 27 28static SkSwizzler::ResultAlpha swizzle_bit_to_grayscale( 29 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 30 int /*bitsPerPixel*/, const SkPMColor* /*ctable*/) { 31 uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow; 32 33 // Determine how many full bytes are in the row 34 int bytesInRow = width >> 3; 35 int i; 36 for (i = 0; i < bytesInRow; i++) { 37 U8CPU currByte = src[i]; 38 for (int j = 0; j < 8; j++) { 39 dst[j] = ((currByte >> (7 - j)) & 1) ? GRAYSCALE_WHITE : GRAYSCALE_BLACK; 40 } 41 dst += 8; 42 } 43 44 // Finish the remaining bits 45 width &= 7; 46 if (width > 0) { 47 U8CPU currByte = src[i]; 48 for (int j = 0; j < width; j++) { 49 dst[j] = ((currByte >> 7) & 1) ? GRAYSCALE_WHITE : GRAYSCALE_BLACK; 50 currByte <<= 1; 51 } 52 } 53 return SkSwizzler::kOpaque_ResultAlpha; 54} 55 56#undef GRAYSCALE_BLACK 57#undef GRAYSCALE_WHITE 58 59static SkSwizzler::ResultAlpha swizzle_bit_to_index( 60 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 61 int /*bitsPerPixel*/, const SkPMColor* /*ctable*/) { 62 uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow; 63 64 // Determine how many full bytes are in the row 65 int bytesInRow = width >> 3; 66 int i; 67 for (i = 0; i < bytesInRow; i++) { 68 U8CPU currByte = src[i]; 69 for (int j = 0; j < 8; j++) { 70 dst[j] = (currByte >> (7 - j)) & 1; 71 } 72 dst += 8; 73 } 74 75 // Finish the remaining bits 76 width &= 7; 77 if (width > 0) { 78 U8CPU currByte = src[i]; 79 for (int j = 0; j < width; j++) { 80 dst[j] = ((currByte >> 7) & 1); 81 currByte <<= 1; 82 } 83 } 84 return SkSwizzler::kOpaque_ResultAlpha; 85} 86 87static SkSwizzler::ResultAlpha swizzle_bit_to_n32( 88 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 89 int /*bitsPerPixel*/, const SkPMColor* /*ctable*/) { 90 SkPMColor* SK_RESTRICT dst = (SkPMColor*) dstRow; 91 92 // Determine how many full bytes are in the row 93 int bytesInRow = width >> 3; 94 int i; 95 for (i = 0; i < bytesInRow; i++) { 96 U8CPU currByte = src[i]; 97 for (int j = 0; j < 8; j++) { 98 dst[j] = ((currByte >> (7 - j)) & 1) ? SK_ColorWHITE : SK_ColorBLACK; 99 } 100 dst += 8; 101 } 102 103 // Finish the remaining bits 104 width &= 7; 105 if (width > 0) { 106 U8CPU currByte = src[i]; 107 for (int j = 0; j < width; j++) { 108 dst[j] = ((currByte >> 7) & 1) ? SK_ColorWHITE : SK_ColorBLACK; 109 currByte <<= 1; 110 } 111 } 112 return SkSwizzler::kOpaque_ResultAlpha; 113} 114 115// kIndex1, kIndex2, kIndex4 116 117static SkSwizzler::ResultAlpha swizzle_small_index_to_index( 118 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 119 int bitsPerPixel, const SkPMColor ctable[]) { 120 121 uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow; 122 INIT_RESULT_ALPHA; 123 const uint32_t pixelsPerByte = 8 / bitsPerPixel; 124 const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte); 125 const uint8_t mask = (1 << bitsPerPixel) - 1; 126 int x = 0; 127 for (uint32_t byte = 0; byte < rowBytes; byte++) { 128 uint8_t pixelData = src[byte]; 129 for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) { 130 uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask; 131 UPDATE_RESULT_ALPHA(ctable[index] >> SK_A32_SHIFT); 132 dst[x] = index; 133 pixelData <<= bitsPerPixel; 134 x++; 135 } 136 } 137 return COMPUTE_RESULT_ALPHA; 138} 139 140static SkSwizzler::ResultAlpha swizzle_small_index_to_n32( 141 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 142 int bitsPerPixel, const SkPMColor ctable[]) { 143 144 SkPMColor* SK_RESTRICT dst = (SkPMColor*) dstRow; 145 INIT_RESULT_ALPHA; 146 const uint32_t pixelsPerByte = 8 / bitsPerPixel; 147 const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte); 148 const uint8_t mask = (1 << bitsPerPixel) - 1; 149 int x = 0; 150 for (uint32_t byte = 0; byte < rowBytes; byte++) { 151 uint8_t pixelData = src[byte]; 152 for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) { 153 uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask; 154 SkPMColor c = ctable[index]; 155 UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); 156 dst[x] = c; 157 pixelData <<= bitsPerPixel; 158 x++; 159 } 160 } 161 return COMPUTE_RESULT_ALPHA; 162} 163 164// kIndex 165 166static SkSwizzler::ResultAlpha swizzle_index_to_index( 167 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 168 int bytesPerPixel, const SkPMColor ctable[]) { 169 170 uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow; 171 memcpy(dst, src, width); 172 // TODO (msarett): Should we skip the loop here and guess that the row is opaque/not opaque? 173 // SkScaledBitmap sampler just guesses that it is opaque. This is dangerous 174 // and probably wrong since gif and bmp (rarely) may have alpha. 175 INIT_RESULT_ALPHA; 176 for (int x = 0; x < width; x++) { 177 UPDATE_RESULT_ALPHA(ctable[src[x]] >> SK_A32_SHIFT); 178 } 179 return COMPUTE_RESULT_ALPHA; 180} 181 182static SkSwizzler::ResultAlpha swizzle_index_to_n32( 183 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 184 int bytesPerPixel, const SkPMColor ctable[]) { 185 186 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 187 INIT_RESULT_ALPHA; 188 for (int x = 0; x < width; x++) { 189 SkPMColor c = ctable[src[x]]; 190 UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); 191 dst[x] = c; 192 } 193 return COMPUTE_RESULT_ALPHA; 194} 195 196static SkSwizzler::ResultAlpha swizzle_index_to_n32_skipZ( 197 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 198 int bytesPerPixel, const SkPMColor ctable[]) { 199 200 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 201 INIT_RESULT_ALPHA; 202 for (int x = 0; x < width; x++) { 203 SkPMColor c = ctable[src[x]]; 204 UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); 205 if (c != 0) { 206 dst[x] = c; 207 } 208 } 209 return COMPUTE_RESULT_ALPHA; 210} 211 212#undef A32_MASK_IN_PLACE 213 214// kGray 215 216static SkSwizzler::ResultAlpha swizzle_gray_to_n32( 217 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 218 int bytesPerPixel, const SkPMColor ctable[]) { 219 220 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 221 for (int x = 0; x < width; x++) { 222 dst[x] = SkPackARGB32NoCheck(0xFF, src[x], src[x], src[x]); 223 } 224 return SkSwizzler::kOpaque_ResultAlpha; 225} 226 227static SkSwizzler::ResultAlpha swizzle_gray_to_gray( 228 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 229 int bytesPerPixel, const SkPMColor ctable[]) { 230 memcpy(dstRow, src, width); 231 return SkSwizzler::kOpaque_ResultAlpha; 232} 233 234// kBGRX 235 236static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32( 237 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 238 int bytesPerPixel, const SkPMColor ctable[]) { 239 240 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 241 for (int x = 0; x < width; x++) { 242 dst[x] = SkPackARGB32NoCheck(0xFF, src[2], src[1], src[0]); 243 src += bytesPerPixel; 244 } 245 return SkSwizzler::kOpaque_ResultAlpha; 246} 247 248// kBGRA 249 250static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_unpremul( 251 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 252 int bytesPerPixel, const SkPMColor ctable[]) { 253 254 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 255 INIT_RESULT_ALPHA; 256 for (int x = 0; x < width; x++) { 257 uint8_t alpha = src[3]; 258 UPDATE_RESULT_ALPHA(alpha); 259 dst[x] = SkPackARGB32NoCheck(alpha, src[2], src[1], src[0]); 260 src += bytesPerPixel; 261 } 262 return COMPUTE_RESULT_ALPHA; 263} 264 265static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_premul( 266 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 267 int bytesPerPixel, const SkPMColor ctable[]) { 268 269 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 270 INIT_RESULT_ALPHA; 271 for (int x = 0; x < width; x++) { 272 uint8_t alpha = src[3]; 273 UPDATE_RESULT_ALPHA(alpha); 274 dst[x] = SkPreMultiplyARGB(alpha, src[2], src[1], src[0]); 275 src += bytesPerPixel; 276 } 277 return COMPUTE_RESULT_ALPHA; 278} 279 280// n32 281static SkSwizzler::ResultAlpha swizzle_rgbx_to_n32( 282 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 283 int bytesPerPixel, const SkPMColor ctable[]) { 284 285 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 286 for (int x = 0; x < width; x++) { 287 dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]); 288 src += bytesPerPixel; 289 } 290 return SkSwizzler::kOpaque_ResultAlpha; 291} 292 293static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul( 294 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 295 int bytesPerPixel, const SkPMColor ctable[]) { 296 297 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 298 INIT_RESULT_ALPHA; 299 for (int x = 0; x < width; x++) { 300 unsigned alpha = src[3]; 301 UPDATE_RESULT_ALPHA(alpha); 302 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 303 src += bytesPerPixel; 304 } 305 return COMPUTE_RESULT_ALPHA; 306} 307 308static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_unpremul( 309 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 310 int bytesPerPixel, const SkPMColor ctable[]) { 311 312 uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow); 313 INIT_RESULT_ALPHA; 314 for (int x = 0; x < width; x++) { 315 unsigned alpha = src[3]; 316 UPDATE_RESULT_ALPHA(alpha); 317 dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); 318 src += bytesPerPixel; 319 } 320 return COMPUTE_RESULT_ALPHA; 321} 322 323static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul_skipZ( 324 void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, 325 int bytesPerPixel, const SkPMColor ctable[]) { 326 327 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 328 INIT_RESULT_ALPHA; 329 for (int x = 0; x < width; x++) { 330 unsigned alpha = src[3]; 331 UPDATE_RESULT_ALPHA(alpha); 332 if (0 != alpha) { 333 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 334 } 335 src += bytesPerPixel; 336 } 337 return COMPUTE_RESULT_ALPHA; 338} 339 340/** 341 FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes. 342 This would be fine for drawing normally, but not for drawing with transfer modes. Being 343 honest means we can draw correctly with transfer modes, with the cost of not being able 344 to take advantage of Android's free unwritten pages. Something to keep in mind when we 345 decide whether to switch to unpremul default. 346static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow, 347 const uint8_t* SK_RESTRICT src, 348 int width, int bitsPerPixel, 349 const SkPMColor[]) { 350 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 351 unsigned alphaMask = 0xFF; 352 for (int x = 0; x < width; x++) { 353 unsigned alpha = src[3]; 354 // NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible 355 // the color components are not zero, but we skip them anyway, meaning they'll remain 356 // zero (implied by the request to skip zeroes). 357 if (0 != alpha) { 358 dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); 359 } 360 src += deltaSrc; 361 alphaMask &= alpha; 362 } 363 return alphaMask != 0xFF; 364} 365*/ 366 367SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, 368 const SkPMColor* ctable, 369 const SkImageInfo& info, 370 SkCodec::ZeroInitialized zeroInit) { 371 if (info.colorType() == kUnknown_SkColorType || kUnknown == sc) { 372 return NULL; 373 } 374 if ((kIndex == sc || kIndex4 == sc || kIndex2 == sc || kIndex1 == sc) 375 && NULL == ctable) { 376 return NULL; 377 } 378 RowProc proc = NULL; 379 switch (sc) { 380 case kBit: 381 switch (info.colorType()) { 382 case kN32_SkColorType: 383 proc = &swizzle_bit_to_n32; 384 break; 385 case kIndex_8_SkColorType: 386 proc = &swizzle_bit_to_index; 387 break; 388 case kGray_8_SkColorType: 389 proc = &swizzle_bit_to_grayscale; 390 break; 391 default: 392 break; 393 } 394 break; 395 case kIndex1: 396 case kIndex2: 397 case kIndex4: 398 switch (info.colorType()) { 399 case kN32_SkColorType: 400 proc = &swizzle_small_index_to_n32; 401 break; 402 case kIndex_8_SkColorType: 403 proc = &swizzle_small_index_to_index; 404 break; 405 default: 406 break; 407 } 408 break; 409 case kIndex: 410 switch (info.colorType()) { 411 case kN32_SkColorType: 412 // We assume the color premultiplied ctable (or not) as desired. 413 if (SkCodec::kYes_ZeroInitialized == zeroInit) { 414 proc = &swizzle_index_to_n32_skipZ; 415 break; 416 } else { 417 proc = &swizzle_index_to_n32; 418 break; 419 } 420 break; 421 case kIndex_8_SkColorType: 422 proc = &swizzle_index_to_index; 423 break; 424 default: 425 break; 426 } 427 break; 428 case kGray: 429 switch (info.colorType()) { 430 case kN32_SkColorType: 431 proc = &swizzle_gray_to_n32; 432 break; 433 case kGray_8_SkColorType: 434 proc = &swizzle_gray_to_gray; 435 default: 436 break; 437 } 438 break; 439 case kBGR: 440 case kBGRX: 441 switch (info.colorType()) { 442 case kN32_SkColorType: 443 proc = &swizzle_bgrx_to_n32; 444 break; 445 default: 446 break; 447 } 448 break; 449 case kBGRA: 450 switch (info.colorType()) { 451 case kN32_SkColorType: 452 switch (info.alphaType()) { 453 case kUnpremul_SkAlphaType: 454 proc = &swizzle_bgra_to_n32_unpremul; 455 break; 456 case kPremul_SkAlphaType: 457 proc = &swizzle_bgra_to_n32_premul; 458 break; 459 default: 460 break; 461 } 462 break; 463 default: 464 break; 465 } 466 break; 467 case kRGBX: 468 // TODO: Support other swizzles. 469 switch (info.colorType()) { 470 case kN32_SkColorType: 471 proc = &swizzle_rgbx_to_n32; 472 break; 473 default: 474 break; 475 } 476 break; 477 case kRGBA: 478 switch (info.colorType()) { 479 case kN32_SkColorType: 480 if (info.alphaType() == kUnpremul_SkAlphaType) { 481 // Respect zeroInit? 482 proc = &swizzle_rgba_to_n32_unpremul; 483 } else { 484 if (SkCodec::kYes_ZeroInitialized == zeroInit) { 485 proc = &swizzle_rgba_to_n32_premul_skipZ; 486 } else { 487 proc = &swizzle_rgba_to_n32_premul; 488 } 489 } 490 break; 491 default: 492 break; 493 } 494 break; 495 case kRGB: 496 switch (info.colorType()) { 497 case kN32_SkColorType: 498 proc = &swizzle_rgbx_to_n32; 499 break; 500 default: 501 break; 502 } 503 break; 504 default: 505 break; 506 } 507 if (NULL == proc) { 508 return NULL; 509 } 510 511 // Store deltaSrc in bytes if it is an even multiple, otherwise use bits 512 int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : 513 BitsPerPixel(sc); 514 return SkNEW_ARGS(SkSwizzler, (proc, ctable, deltaSrc, info)); 515} 516 517SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, 518 int deltaSrc, const SkImageInfo& info) 519 : fRowProc(proc) 520 , fColorTable(ctable) 521 , fDeltaSrc(deltaSrc) 522 , fDstInfo(info) 523{} 524 525SkSwizzler::ResultAlpha SkSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) { 526 SkASSERT(NULL != dst && NULL != src); 527 return fRowProc(dst, src, fDstInfo.width(), fDeltaSrc, fColorTable); 528} 529 530void SkSwizzler::Fill(void* dstStartRow, const SkImageInfo& dstInfo, size_t dstRowBytes, 531 uint32_t numRows, uint32_t colorOrIndex, const SkPMColor* colorTable) { 532 SkASSERT(dstStartRow != NULL); 533 SkASSERT(numRows <= (uint32_t) dstInfo.height()); 534 535 // Calculate bytes to fill. We use getSafeSize since the last row may not be padded. 536 const size_t bytesToFill = dstInfo.makeWH(dstInfo.width(), numRows).getSafeSize(dstRowBytes); 537 538 // Use the proper memset routine to fill the remaining bytes 539 switch(dstInfo.colorType()) { 540 case kN32_SkColorType: 541 // Assume input is an index if we have a color table 542 uint32_t color; 543 if (NULL != colorTable) { 544 SkASSERT(colorOrIndex == (uint8_t) colorOrIndex); 545 color = colorTable[colorOrIndex]; 546 // Otherwise, assume the input is a color 547 } else { 548 color = colorOrIndex; 549 } 550 551 // We must fill row by row in the case of unaligned row bytes 552 if (SkIsAlign4((size_t) dstStartRow) && SkIsAlign4(dstRowBytes)) { 553 sk_memset32((uint32_t*) dstStartRow, color, 554 (uint32_t) bytesToFill / sizeof(SkPMColor)); 555 } else { 556 // This is an unlikely, slow case 557 SkCodecPrintf("Warning: Strange number of row bytes, fill will be slow.\n"); 558 uint32_t* dstRow = (uint32_t*) dstStartRow; 559 for (uint32_t row = 0; row < numRows; row++) { 560 for (int32_t col = 0; col < dstInfo.width(); col++) { 561 dstRow[col] = color; 562 } 563 dstRow = SkTAddOffset<uint32_t>(dstRow, dstRowBytes); 564 } 565 } 566 break; 567 // On an index destination color type, always assume the input is an index 568 case kIndex_8_SkColorType: 569 SkASSERT(colorOrIndex == (uint8_t) colorOrIndex); 570 memset(dstStartRow, colorOrIndex, bytesToFill); 571 break; 572 case kGray_8_SkColorType: 573 // If the destination is kGray, the caller passes in an 8-bit color. 574 // We will not assert that the high bits of colorOrIndex must be zeroed. 575 // This allows us to take advantage of the fact that the low 8 bits of an 576 // SKPMColor may be a valid a grayscale color. For example, the low 8 577 // bits of SK_ColorBLACK are identical to the grayscale representation 578 // for black. 579 memset(dstStartRow, (uint8_t) colorOrIndex, bytesToFill); 580 break; 581 case kRGB_565_SkColorType: 582 // If the destination is k565, the caller passes in a 16-bit color. 583 // We will not assert that the high bits of colorOrIndex must be zeroed. 584 // This allows us to take advantage of the fact that the low 16 bits of an 585 // SKPMColor may be a valid a 565 color. For example, the low 16 586 // bits of SK_ColorBLACK are identical to the 565 representation 587 // for black. 588 memset(dstStartRow, (uint16_t) colorOrIndex, bytesToFill); 589 break; 590 default: 591 SkCodecPrintf("Error: Unsupported dst color type for fill(). Doing nothing.\n"); 592 SkASSERT(false); 593 break; 594 } 595} 596