1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkBitmapProcState.h" 9 #include "SkColorPriv.h" 10 #include "SkFilterProc.h" 11 #include "SkPaint.h" 12 #include "SkShader.h" // for tilemodes 13 #include "SkUtilsArm.h" 14 15 #if !SK_ARM_NEON_IS_NONE 16 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp 17 extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[]; 18 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; 19 extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); 20 extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 21 extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 22 extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*); 23 extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); 24 extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); 25 #endif 26 27 #define NAME_WRAP(x) x 28 #include "SkBitmapProcState_filter.h" 29 #include "SkBitmapProcState_procs.h" 30 31 /////////////////////////////////////////////////////////////////////////////// 32 33 /** 34 * For the purposes of drawing bitmaps, if a matrix is "almost" translate 35 * go ahead and treat it as if it were, so that subsequent code can go fast. 36 */ 37 static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) { 38 SkMatrix::TypeMask mask = matrix.getType(); 39 40 if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 41 return false; 42 } 43 if (mask & SkMatrix::kScale_Mask) { 44 SkScalar sx = matrix[SkMatrix::kMScaleX]; 45 SkScalar sy = matrix[SkMatrix::kMScaleY]; 46 int w = bitmap.width(); 47 int h = bitmap.height(); 48 int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w))); 49 int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h))); 50 return sw == w && sh == h; 51 } 52 // if we got here, we're either kTranslate_Mask or identity 53 return true; 54 } 55 56 static bool just_trans_general(const SkMatrix& matrix) { 57 SkMatrix::TypeMask mask = matrix.getType(); 58 59 if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 60 return false; 61 } 62 if (mask & SkMatrix::kScale_Mask) { 63 const SkScalar tol = SK_Scalar1 / 32768; 64 65 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) { 66 return false; 67 } 68 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) { 69 return false; 70 } 71 } 72 // if we got here, treat us as either kTranslate_Mask or identity 73 return true; 74 } 75 76 /////////////////////////////////////////////////////////////////////////////// 77 78 static bool valid_for_filtering(unsigned dimension) { 79 // for filtering, width and height must fit in 14bits, since we use steal 80 // 2 bits from each to store our 4bit subpixel data 81 return (dimension & ~0x3FFF) == 0; 82 } 83 84 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { 85 if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { 86 return false; 87 } 88 89 const SkMatrix* m; 90 bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0; 91 bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX && 92 SkShader::kClamp_TileMode == fTileModeY; 93 94 if (clamp_clamp || trivial_matrix) { 95 m = &inv; 96 } else { 97 fUnitInvMatrix = inv; 98 fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height()); 99 m = &fUnitInvMatrix; 100 } 101 102 fBitmap = &fOrigBitmap; 103 if (fOrigBitmap.hasMipMap()) { 104 int shift = fOrigBitmap.extractMipLevel(&fMipBitmap, 105 SkScalarToFixed(m->getScaleX()), 106 SkScalarToFixed(m->getSkewY())); 107 108 if (shift > 0) { 109 if (m != &fUnitInvMatrix) { 110 fUnitInvMatrix = *m; 111 m = &fUnitInvMatrix; 112 } 113 114 SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift); 115 fUnitInvMatrix.postScale(scale, scale); 116 117 // now point here instead of fOrigBitmap 118 fBitmap = &fMipBitmap; 119 } 120 } 121 122 // wack our matrix to exactly no-scale, if we're really close to begin with 123 { 124 bool fixupMatrix = clamp_clamp ? 125 just_trans_clamp(*m, *fBitmap) : just_trans_general(*m); 126 if (fixupMatrix) { 127 #ifdef SK_IGNORE_TRANS_CLAMP_FIX 128 if (m != &fUnitInvMatrix) { // can't mutate the original 129 fUnitInvMatrix = inv; 130 m = &fUnitInvMatrix; 131 } 132 fUnitInvMatrix.set(SkMatrix::kMScaleX, SK_Scalar1); 133 fUnitInvMatrix.set(SkMatrix::kMScaleY, SK_Scalar1); 134 #else 135 // If we can be treated just like translate, construct that inverse 136 // such that we landed in the proper place. Given that m may have 137 // some slight scale, we have to invert it to compute this new 138 // matrix. 139 SkMatrix forward; 140 if (m->invert(&forward)) { 141 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); 142 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); 143 fUnitInvMatrix.setTranslate(tx, ty); 144 m = &fUnitInvMatrix; 145 // now the following code will sniff m, and decide to take the 146 // fast case (since m is purely translate). 147 } 148 #endif 149 } 150 } 151 152 // Below this point, we should never refer to the inv parameter, since we 153 // may be using a munged version for "our" inverse. 154 155 fInvMatrix = m; 156 fInvProc = m->getMapXYProc(); 157 fInvType = m->getType(); 158 fInvSx = SkScalarToFixed(m->getScaleX()); 159 fInvSxFractionalInt = SkScalarToFractionalInt(m->getScaleX()); 160 fInvKy = SkScalarToFixed(m->getSkewY()); 161 fInvKyFractionalInt = SkScalarToFractionalInt(m->getSkewY()); 162 163 fAlphaScale = SkAlpha255To256(paint.getAlpha()); 164 165 // pick-up filtering from the paint, but only if the matrix is 166 // more complex than identity/translate (i.e. no need to pay the cost 167 // of filtering if we're not scaled etc.). 168 // note: we explicitly check inv, since m might be scaled due to unitinv 169 // trickery, but we don't want to see that for this test 170 fDoFilter = paint.isFilterBitmap() && 171 (fInvType > SkMatrix::kTranslate_Mask && 172 valid_for_filtering(fBitmap->width() | fBitmap->height())); 173 174 fShaderProc32 = NULL; 175 fShaderProc16 = NULL; 176 fSampleProc32 = NULL; 177 fSampleProc16 = NULL; 178 179 fMatrixProc = this->chooseMatrixProc(trivial_matrix); 180 if (NULL == fMatrixProc) { 181 return false; 182 } 183 184 /////////////////////////////////////////////////////////////////////// 185 186 int index = 0; 187 if (fAlphaScale < 256) { // note: this distinction is not used for D16 188 index |= 1; 189 } 190 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 191 index |= 2; 192 } 193 if (fDoFilter) { 194 index |= 4; 195 } 196 // bits 3,4,5 encoding the source bitmap format 197 switch (fBitmap->config()) { 198 case SkBitmap::kARGB_8888_Config: 199 index |= 0; 200 break; 201 case SkBitmap::kRGB_565_Config: 202 index |= 8; 203 break; 204 case SkBitmap::kIndex8_Config: 205 index |= 16; 206 break; 207 case SkBitmap::kARGB_4444_Config: 208 index |= 24; 209 break; 210 case SkBitmap::kA8_Config: 211 index |= 32; 212 fPaintPMColor = SkPreMultiplyColor(paint.getColor()); 213 break; 214 default: 215 return false; 216 } 217 218 #if !SK_ARM_NEON_IS_ALWAYS 219 static const SampleProc32 gSkBitmapProcStateSample32[] = { 220 S32_opaque_D32_nofilter_DXDY, 221 S32_alpha_D32_nofilter_DXDY, 222 S32_opaque_D32_nofilter_DX, 223 S32_alpha_D32_nofilter_DX, 224 S32_opaque_D32_filter_DXDY, 225 S32_alpha_D32_filter_DXDY, 226 S32_opaque_D32_filter_DX, 227 S32_alpha_D32_filter_DX, 228 229 S16_opaque_D32_nofilter_DXDY, 230 S16_alpha_D32_nofilter_DXDY, 231 S16_opaque_D32_nofilter_DX, 232 S16_alpha_D32_nofilter_DX, 233 S16_opaque_D32_filter_DXDY, 234 S16_alpha_D32_filter_DXDY, 235 S16_opaque_D32_filter_DX, 236 S16_alpha_D32_filter_DX, 237 238 SI8_opaque_D32_nofilter_DXDY, 239 SI8_alpha_D32_nofilter_DXDY, 240 SI8_opaque_D32_nofilter_DX, 241 SI8_alpha_D32_nofilter_DX, 242 SI8_opaque_D32_filter_DXDY, 243 SI8_alpha_D32_filter_DXDY, 244 SI8_opaque_D32_filter_DX, 245 SI8_alpha_D32_filter_DX, 246 247 S4444_opaque_D32_nofilter_DXDY, 248 S4444_alpha_D32_nofilter_DXDY, 249 S4444_opaque_D32_nofilter_DX, 250 S4444_alpha_D32_nofilter_DX, 251 S4444_opaque_D32_filter_DXDY, 252 S4444_alpha_D32_filter_DXDY, 253 S4444_opaque_D32_filter_DX, 254 S4444_alpha_D32_filter_DX, 255 256 // A8 treats alpha/opaque the same (equally efficient) 257 SA8_alpha_D32_nofilter_DXDY, 258 SA8_alpha_D32_nofilter_DXDY, 259 SA8_alpha_D32_nofilter_DX, 260 SA8_alpha_D32_nofilter_DX, 261 SA8_alpha_D32_filter_DXDY, 262 SA8_alpha_D32_filter_DXDY, 263 SA8_alpha_D32_filter_DX, 264 SA8_alpha_D32_filter_DX 265 }; 266 267 static const SampleProc16 gSkBitmapProcStateSample16[] = { 268 S32_D16_nofilter_DXDY, 269 S32_D16_nofilter_DX, 270 S32_D16_filter_DXDY, 271 S32_D16_filter_DX, 272 273 S16_D16_nofilter_DXDY, 274 S16_D16_nofilter_DX, 275 S16_D16_filter_DXDY, 276 S16_D16_filter_DX, 277 278 SI8_D16_nofilter_DXDY, 279 SI8_D16_nofilter_DX, 280 SI8_D16_filter_DXDY, 281 SI8_D16_filter_DX, 282 283 // Don't support 4444 -> 565 284 NULL, NULL, NULL, NULL, 285 // Don't support A8 -> 565 286 NULL, NULL, NULL, NULL 287 }; 288 #endif 289 290 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index]; 291 index >>= 1; // shift away any opaque/alpha distinction 292 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index]; 293 294 // our special-case shaderprocs 295 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) { 296 if (clamp_clamp) { 297 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc); 298 } else if (SkShader::kRepeat_TileMode == fTileModeX && 299 SkShader::kRepeat_TileMode == fTileModeY) { 300 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc); 301 } 302 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clamp_clamp) { 303 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc); 304 } 305 306 if (NULL == fShaderProc32) { 307 fShaderProc32 = this->chooseShaderProc32(); 308 } 309 310 // see if our platform has any accelerated overrides 311 this->platformProcs(); 312 return true; 313 } 314 315 static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, 316 int x, int y, 317 SkPMColor* SK_RESTRICT colors, 318 int count) { 319 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 320 SkASSERT(s.fInvKy == 0); 321 SkASSERT(count > 0 && colors != NULL); 322 SkASSERT(!s.fDoFilter); 323 324 const int maxX = s.fBitmap->width() - 1; 325 const int maxY = s.fBitmap->height() - 1; 326 int ix = s.fFilterOneX + x; 327 int iy = SkClampMax(s.fFilterOneY + y, maxY); 328 #ifdef SK_DEBUG 329 { 330 SkPoint pt; 331 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, 332 SkIntToScalar(y) + SK_ScalarHalf, &pt); 333 int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY); 334 int ix2 = SkScalarFloorToInt(pt.fX); 335 336 SkASSERT(iy == iy2); 337 SkASSERT(ix == ix2); 338 } 339 #endif 340 const SkPMColor* row = s.fBitmap->getAddr32(0, iy); 341 342 // clamp to the left 343 if (ix < 0) { 344 int n = SkMin32(-ix, count); 345 sk_memset32(colors, row[0], n); 346 count -= n; 347 if (0 == count) { 348 return; 349 } 350 colors += n; 351 SkASSERT(-ix == n); 352 ix = 0; 353 } 354 // copy the middle 355 if (ix <= maxX) { 356 int n = SkMin32(maxX - ix + 1, count); 357 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 358 count -= n; 359 if (0 == count) { 360 return; 361 } 362 colors += n; 363 } 364 SkASSERT(count > 0); 365 // clamp to the right 366 sk_memset32(colors, row[maxX], count); 367 } 368 369 static inline int sk_int_mod(int x, int n) { 370 SkASSERT(n > 0); 371 if ((unsigned)x >= (unsigned)n) { 372 if (x < 0) { 373 x = n + ~(~x % n); 374 } else { 375 x = x % n; 376 } 377 } 378 return x; 379 } 380 381 static inline int sk_int_mirror(int x, int n) { 382 x = sk_int_mod(x, 2 * n); 383 if (x >= n) { 384 x = n + ~(x - n); 385 } 386 return x; 387 } 388 389 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, 390 int x, int y, 391 SkPMColor* SK_RESTRICT colors, 392 int count) { 393 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 394 SkASSERT(s.fInvKy == 0); 395 SkASSERT(count > 0 && colors != NULL); 396 SkASSERT(!s.fDoFilter); 397 398 const int stopX = s.fBitmap->width(); 399 const int stopY = s.fBitmap->height(); 400 int ix = s.fFilterOneX + x; 401 int iy = sk_int_mod(s.fFilterOneY + y, stopY); 402 #ifdef SK_DEBUG 403 { 404 SkPoint pt; 405 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, 406 SkIntToScalar(y) + SK_ScalarHalf, &pt); 407 int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY); 408 int ix2 = SkScalarFloorToInt(pt.fX); 409 410 SkASSERT(iy == iy2); 411 SkASSERT(ix == ix2); 412 } 413 #endif 414 const SkPMColor* row = s.fBitmap->getAddr32(0, iy); 415 416 ix = sk_int_mod(ix, stopX); 417 for (;;) { 418 int n = SkMin32(stopX - ix, count); 419 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 420 count -= n; 421 if (0 == count) { 422 return; 423 } 424 colors += n; 425 ix = 0; 426 } 427 } 428 429 static void S32_D32_constX_shaderproc(const SkBitmapProcState& s, 430 int x, int y, 431 SkPMColor* SK_RESTRICT colors, 432 int count) { 433 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0); 434 SkASSERT(s.fInvKy == 0); 435 SkASSERT(count > 0 && colors != NULL); 436 SkASSERT(1 == s.fBitmap->width()); 437 438 int iY0, iY1, iSubY; 439 440 if (s.fDoFilter) { 441 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc(); 442 uint32_t xy[2]; 443 444 mproc(s, xy, 1, x, y); 445 446 iY0 = xy[0] >> 18; 447 iY1 = xy[0] & 0x3FFF; 448 iSubY = (xy[0] >> 14) & 0xF; 449 } else { 450 int yTemp; 451 452 if (s.fInvType > SkMatrix::kTranslate_Mask) { 453 SkPoint pt; 454 s.fInvProc(*s.fInvMatrix, 455 SkIntToScalar(x) + SK_ScalarHalf, 456 SkIntToScalar(y) + SK_ScalarHalf, 457 &pt); 458 // When the matrix has a scale component the setup code in 459 // chooseProcs multiples the inverse matrix by the inverse of the 460 // bitmap's width and height. Since this method is going to do 461 // its own tiling and sampling we need to undo that here. 462 if (SkShader::kClamp_TileMode != s.fTileModeX || 463 SkShader::kClamp_TileMode != s.fTileModeY) { 464 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height()); 465 } else { 466 yTemp = SkScalarFloorToInt(pt.fY); 467 } 468 } else { 469 yTemp = s.fFilterOneY + y; 470 } 471 472 const int stopY = s.fBitmap->height(); 473 switch (s.fTileModeY) { 474 case SkShader::kClamp_TileMode: 475 iY0 = SkClampMax(yTemp, stopY-1); 476 break; 477 case SkShader::kRepeat_TileMode: 478 iY0 = sk_int_mod(yTemp, stopY); 479 break; 480 case SkShader::kMirror_TileMode: 481 default: 482 iY0 = sk_int_mirror(yTemp, stopY); 483 break; 484 } 485 486 #ifdef SK_DEBUG 487 { 488 SkPoint pt; 489 s.fInvProc(*s.fInvMatrix, 490 SkIntToScalar(x) + SK_ScalarHalf, 491 SkIntToScalar(y) + SK_ScalarHalf, 492 &pt); 493 if (s.fInvType > SkMatrix::kTranslate_Mask && 494 (SkShader::kClamp_TileMode != s.fTileModeX || 495 SkShader::kClamp_TileMode != s.fTileModeY)) { 496 pt.fY *= s.fBitmap->height(); 497 } 498 int iY2; 499 500 switch (s.fTileModeY) { 501 case SkShader::kClamp_TileMode: 502 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1); 503 break; 504 case SkShader::kRepeat_TileMode: 505 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY); 506 break; 507 case SkShader::kMirror_TileMode: 508 default: 509 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY); 510 break; 511 } 512 513 SkASSERT(iY0 == iY2); 514 } 515 #endif 516 } 517 518 const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0); 519 SkPMColor color; 520 521 if (s.fDoFilter) { 522 const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1); 523 524 if (s.fAlphaScale < 256) { 525 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale); 526 } else { 527 Filter_32_opaque(iSubY, *row0, *row1, &color); 528 } 529 } else { 530 if (s.fAlphaScale < 256) { 531 color = SkAlphaMulQ(*row0, s.fAlphaScale); 532 } else { 533 color = *row0; 534 } 535 } 536 537 sk_memset32(colors, color, count); 538 } 539 540 static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y, 541 SkPMColor* SK_RESTRICT colors, int count) { 542 // if we get called, the matrix is too tricky, so we just draw nothing 543 sk_memset32(colors, 0, count); 544 } 545 546 bool SkBitmapProcState::setupForTranslate() { 547 SkPoint pt; 548 fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt); 549 550 /* 551 * if the translate is larger than our ints, we can get random results, or 552 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't 553 * negate it. 554 */ 555 const SkScalar too_big = SkIntToScalar(1 << 30); 556 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) { 557 return false; 558 } 559 560 // Since we know we're not filtered, we re-purpose these fields allow 561 // us to go from device -> src coordinates w/ just an integer add, 562 // rather than running through the inverse-matrix 563 fFilterOneX = SkScalarFloorToInt(pt.fX); 564 fFilterOneY = SkScalarFloorToInt(pt.fY); 565 return true; 566 } 567 568 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() { 569 570 if (SkBitmap::kARGB_8888_Config != fBitmap->config()) { 571 return NULL; 572 } 573 574 #ifndef SK_IGNORE_1XN_BITMAP_OPT 575 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 576 577 if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) { 578 if (!fDoFilter && fInvType <= SkMatrix::kTranslate_Mask && !this->setupForTranslate()) { 579 return DoNothing_shaderproc; 580 } 581 return S32_D32_constX_shaderproc; 582 } 583 #endif 584 585 if (fAlphaScale < 256) { 586 return NULL; 587 } 588 if (fInvType > SkMatrix::kTranslate_Mask) { 589 return NULL; 590 } 591 if (fDoFilter) { 592 return NULL; 593 } 594 595 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX; 596 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY; 597 598 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) { 599 if (this->setupForTranslate()) { 600 return Clamp_S32_D32_nofilter_trans_shaderproc; 601 } 602 return DoNothing_shaderproc; 603 } 604 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) { 605 if (this->setupForTranslate()) { 606 return Repeat_S32_D32_nofilter_trans_shaderproc; 607 } 608 return DoNothing_shaderproc; 609 } 610 return NULL; 611 } 612 613 /////////////////////////////////////////////////////////////////////////////// 614 615 #ifdef SK_DEBUG 616 617 static void check_scale_nofilter(uint32_t bitmapXY[], int count, 618 unsigned mx, unsigned my) { 619 unsigned y = *bitmapXY++; 620 SkASSERT(y < my); 621 622 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY); 623 for (int i = 0; i < count; ++i) { 624 SkASSERT(xptr[i] < mx); 625 } 626 } 627 628 static void check_scale_filter(uint32_t bitmapXY[], int count, 629 unsigned mx, unsigned my) { 630 uint32_t YY = *bitmapXY++; 631 unsigned y0 = YY >> 18; 632 unsigned y1 = YY & 0x3FFF; 633 SkASSERT(y0 < my); 634 SkASSERT(y1 < my); 635 636 for (int i = 0; i < count; ++i) { 637 uint32_t XX = bitmapXY[i]; 638 unsigned x0 = XX >> 18; 639 unsigned x1 = XX & 0x3FFF; 640 SkASSERT(x0 < mx); 641 SkASSERT(x1 < mx); 642 } 643 } 644 645 static void check_affine_nofilter(uint32_t bitmapXY[], int count, 646 unsigned mx, unsigned my) { 647 for (int i = 0; i < count; ++i) { 648 uint32_t XY = bitmapXY[i]; 649 unsigned x = XY & 0xFFFF; 650 unsigned y = XY >> 16; 651 SkASSERT(x < mx); 652 SkASSERT(y < my); 653 } 654 } 655 656 static void check_affine_filter(uint32_t bitmapXY[], int count, 657 unsigned mx, unsigned my) { 658 for (int i = 0; i < count; ++i) { 659 uint32_t YY = *bitmapXY++; 660 unsigned y0 = YY >> 18; 661 unsigned y1 = YY & 0x3FFF; 662 SkASSERT(y0 < my); 663 SkASSERT(y1 < my); 664 665 uint32_t XX = *bitmapXY++; 666 unsigned x0 = XX >> 18; 667 unsigned x1 = XX & 0x3FFF; 668 SkASSERT(x0 < mx); 669 SkASSERT(x1 < mx); 670 } 671 } 672 673 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state, 674 uint32_t bitmapXY[], int count, 675 int x, int y) { 676 SkASSERT(bitmapXY); 677 SkASSERT(count > 0); 678 679 state.fMatrixProc(state, bitmapXY, count, x, y); 680 681 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my); 682 683 // There are four formats possible: 684 // scale -vs- affine 685 // filter -vs- nofilter 686 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 687 proc = state.fDoFilter ? check_scale_filter : check_scale_nofilter; 688 } else { 689 proc = state.fDoFilter ? check_affine_filter : check_affine_nofilter; 690 } 691 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height()); 692 } 693 694 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const { 695 return DebugMatrixProc; 696 } 697 698 #endif 699 700 /////////////////////////////////////////////////////////////////////////////// 701 /* 702 The storage requirements for the different matrix procs are as follows, 703 where each X or Y is 2 bytes, and N is the number of pixels/elements: 704 705 scale/translate nofilter Y(4bytes) + N * X 706 affine/perspective nofilter N * (X Y) 707 scale/translate filter Y Y + N * (X X) 708 affine/perspective filter N * (Y Y X X) 709 */ 710 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { 711 int32_t size = static_cast<int32_t>(bufferSize); 712 713 size &= ~3; // only care about 4-byte aligned chunks 714 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 715 size -= 4; // the shared Y (or YY) coordinate 716 if (size < 0) { 717 size = 0; 718 } 719 size >>= 1; 720 } else { 721 size >>= 2; 722 } 723 724 if (fDoFilter) { 725 size >>= 1; 726 } 727 728 return size; 729 } 730