SkBitmapProcState.cpp revision b088947f27496a9b9dc48a7cfb170f9d59589825
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 17extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[]; 18extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; 19extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); 20extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 21extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 22extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*); 23extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); 24extern 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// true iff the matrix contains, at most, scale and translate elements 34static bool matrix_only_scale_translate(const SkMatrix& m) { 35 return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask); 36} 37 38/** 39 * For the purposes of drawing bitmaps, if a matrix is "almost" translate 40 * go ahead and treat it as if it were, so that subsequent code can go fast. 41 */ 42static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) { 43 SkASSERT(matrix_only_scale_translate(matrix)); 44 45 if (matrix.getType() & SkMatrix::kScale_Mask) { 46 SkRect src, dst; 47 bitmap.getBounds(&src); 48 49 // Can't call mapRect(), since that will fix up inverted rectangles, 50 // e.g. when scale is negative, and we don't want to return true for 51 // those. 52 matrix.mapPoints(SkTCast<SkPoint*>(&dst), 53 SkTCast<const SkPoint*>(&src), 54 2); 55 56 // Now round all 4 edges to device space, and then compare the device 57 // width/height to the original. Note: we must map all 4 and subtract 58 // rather than map the "width" and compare, since we care about the 59 // phase (in pixel space) that any translate in the matrix might impart. 60 SkIRect idst; 61 dst.round(&idst); 62 return idst.width() == bitmap.width() && idst.height() == bitmap.height(); 63 } 64 // if we got here, we're either kTranslate_Mask or identity 65 return true; 66} 67 68static bool just_trans_general(const SkMatrix& matrix) { 69 SkASSERT(matrix_only_scale_translate(matrix)); 70 71 if (matrix.getType() & SkMatrix::kScale_Mask) { 72 const SkScalar tol = SK_Scalar1 / 32768; 73 74 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) { 75 return false; 76 } 77 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) { 78 return false; 79 } 80 } 81 // if we got here, treat us as either kTranslate_Mask or identity 82 return true; 83} 84 85/////////////////////////////////////////////////////////////////////////////// 86 87static bool valid_for_filtering(unsigned dimension) { 88 // for filtering, width and height must fit in 14bits, since we use steal 89 // 2 bits from each to store our 4bit subpixel data 90 return (dimension & ~0x3FFF) == 0; 91} 92 93bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { 94 if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { 95 return false; 96 } 97 98 const SkMatrix* m; 99 bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0; 100 bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX && 101 SkShader::kClamp_TileMode == fTileModeY; 102 103 if (clamp_clamp || trivial_matrix) { 104 m = &inv; 105 } else { 106 fUnitInvMatrix = inv; 107 fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height()); 108 m = &fUnitInvMatrix; 109 } 110 111 fBitmap = &fOrigBitmap; 112 if (fOrigBitmap.hasMipMap()) { 113 int shift = fOrigBitmap.extractMipLevel(&fMipBitmap, 114 SkScalarToFixed(m->getScaleX()), 115 SkScalarToFixed(m->getSkewY())); 116 117 if (shift > 0) { 118 if (m != &fUnitInvMatrix) { 119 fUnitInvMatrix = *m; 120 m = &fUnitInvMatrix; 121 } 122 123 SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift); 124 fUnitInvMatrix.postScale(scale, scale); 125 126 // now point here instead of fOrigBitmap 127 fBitmap = &fMipBitmap; 128 } 129 } 130 131 // wack our matrix to exactly no-scale, if we're really close to begin with 132 if (matrix_only_scale_translate(*m)) { 133 SkMatrix forward; 134 if (m->invert(&forward)) { 135 if (clamp_clamp ? just_trans_clamp(forward, *fBitmap) 136 : just_trans_general(forward)) { 137 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); 138 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); 139 fUnitInvMatrix.setTranslate(tx, ty); 140 m = &fUnitInvMatrix; 141 // now the following code will sniff m, and decide to take the 142 // fast case (since m is purely translate). 143 } 144 } 145 } 146 147 // Below this point, we should never refer to the inv parameter, since we 148 // may be using a munged version for "our" inverse. 149 150 fInvMatrix = m; 151 fInvProc = m->getMapXYProc(); 152 fInvType = m->getType(); 153 fInvSx = SkScalarToFixed(m->getScaleX()); 154 fInvSxFractionalInt = SkScalarToFractionalInt(m->getScaleX()); 155 fInvKy = SkScalarToFixed(m->getSkewY()); 156 fInvKyFractionalInt = SkScalarToFractionalInt(m->getSkewY()); 157 158 fAlphaScale = SkAlpha255To256(paint.getAlpha()); 159 160 // pick-up filtering from the paint, but only if the matrix is 161 // more complex than identity/translate (i.e. no need to pay the cost 162 // of filtering if we're not scaled etc.). 163 // note: we explicitly check inv, since m might be scaled due to unitinv 164 // trickery, but we don't want to see that for this test 165 fDoFilter = paint.isFilterBitmap() && 166 (fInvType > SkMatrix::kTranslate_Mask && 167 valid_for_filtering(fBitmap->width() | fBitmap->height())); 168 169 fShaderProc32 = NULL; 170 fShaderProc16 = NULL; 171 fSampleProc32 = NULL; 172 fSampleProc16 = NULL; 173 174 fMatrixProc = this->chooseMatrixProc(trivial_matrix); 175 if (NULL == fMatrixProc) { 176 return false; 177 } 178 179 /////////////////////////////////////////////////////////////////////// 180 181 int index = 0; 182 if (fAlphaScale < 256) { // note: this distinction is not used for D16 183 index |= 1; 184 } 185 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 186 index |= 2; 187 } 188 if (fDoFilter) { 189 index |= 4; 190 } 191 // bits 3,4,5 encoding the source bitmap format 192 switch (fBitmap->config()) { 193 case SkBitmap::kARGB_8888_Config: 194 index |= 0; 195 break; 196 case SkBitmap::kRGB_565_Config: 197 index |= 8; 198 break; 199 case SkBitmap::kIndex8_Config: 200 index |= 16; 201 break; 202 case SkBitmap::kARGB_4444_Config: 203 index |= 24; 204 break; 205 case SkBitmap::kA8_Config: 206 index |= 32; 207 fPaintPMColor = SkPreMultiplyColor(paint.getColor()); 208 break; 209 default: 210 return false; 211 } 212 213#if !SK_ARM_NEON_IS_ALWAYS 214 static const SampleProc32 gSkBitmapProcStateSample32[] = { 215 S32_opaque_D32_nofilter_DXDY, 216 S32_alpha_D32_nofilter_DXDY, 217 S32_opaque_D32_nofilter_DX, 218 S32_alpha_D32_nofilter_DX, 219 S32_opaque_D32_filter_DXDY, 220 S32_alpha_D32_filter_DXDY, 221 S32_opaque_D32_filter_DX, 222 S32_alpha_D32_filter_DX, 223 224 S16_opaque_D32_nofilter_DXDY, 225 S16_alpha_D32_nofilter_DXDY, 226 S16_opaque_D32_nofilter_DX, 227 S16_alpha_D32_nofilter_DX, 228 S16_opaque_D32_filter_DXDY, 229 S16_alpha_D32_filter_DXDY, 230 S16_opaque_D32_filter_DX, 231 S16_alpha_D32_filter_DX, 232 233 SI8_opaque_D32_nofilter_DXDY, 234 SI8_alpha_D32_nofilter_DXDY, 235 SI8_opaque_D32_nofilter_DX, 236 SI8_alpha_D32_nofilter_DX, 237 SI8_opaque_D32_filter_DXDY, 238 SI8_alpha_D32_filter_DXDY, 239 SI8_opaque_D32_filter_DX, 240 SI8_alpha_D32_filter_DX, 241 242 S4444_opaque_D32_nofilter_DXDY, 243 S4444_alpha_D32_nofilter_DXDY, 244 S4444_opaque_D32_nofilter_DX, 245 S4444_alpha_D32_nofilter_DX, 246 S4444_opaque_D32_filter_DXDY, 247 S4444_alpha_D32_filter_DXDY, 248 S4444_opaque_D32_filter_DX, 249 S4444_alpha_D32_filter_DX, 250 251 // A8 treats alpha/opaque the same (equally efficient) 252 SA8_alpha_D32_nofilter_DXDY, 253 SA8_alpha_D32_nofilter_DXDY, 254 SA8_alpha_D32_nofilter_DX, 255 SA8_alpha_D32_nofilter_DX, 256 SA8_alpha_D32_filter_DXDY, 257 SA8_alpha_D32_filter_DXDY, 258 SA8_alpha_D32_filter_DX, 259 SA8_alpha_D32_filter_DX 260 }; 261 262 static const SampleProc16 gSkBitmapProcStateSample16[] = { 263 S32_D16_nofilter_DXDY, 264 S32_D16_nofilter_DX, 265 S32_D16_filter_DXDY, 266 S32_D16_filter_DX, 267 268 S16_D16_nofilter_DXDY, 269 S16_D16_nofilter_DX, 270 S16_D16_filter_DXDY, 271 S16_D16_filter_DX, 272 273 SI8_D16_nofilter_DXDY, 274 SI8_D16_nofilter_DX, 275 SI8_D16_filter_DXDY, 276 SI8_D16_filter_DX, 277 278 // Don't support 4444 -> 565 279 NULL, NULL, NULL, NULL, 280 // Don't support A8 -> 565 281 NULL, NULL, NULL, NULL 282 }; 283#endif 284 285 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index]; 286 index >>= 1; // shift away any opaque/alpha distinction 287 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index]; 288 289 // our special-case shaderprocs 290 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) { 291 if (clamp_clamp) { 292 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc); 293 } else if (SkShader::kRepeat_TileMode == fTileModeX && 294 SkShader::kRepeat_TileMode == fTileModeY) { 295 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc); 296 } 297 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clamp_clamp) { 298 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc); 299 } 300 301 if (NULL == fShaderProc32) { 302 fShaderProc32 = this->chooseShaderProc32(); 303 } 304 305 if (NULL == fShaderProc32) { 306 fShaderProc32 = this->chooseBitmapFilterProc(paint); 307 } 308 309 // see if our platform has any accelerated overrides 310 this->platformProcs(); 311 312 return true; 313} 314 315static 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 369static 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 381static 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 389static 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 429static 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; 439 int iY1 SK_INIT_TO_AVOID_WARNING; 440 int iSubY SK_INIT_TO_AVOID_WARNING; 441 442 if (s.fDoFilter) { 443 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc(); 444 uint32_t xy[2]; 445 446 mproc(s, xy, 1, x, y); 447 448 iY0 = xy[0] >> 18; 449 iY1 = xy[0] & 0x3FFF; 450 iSubY = (xy[0] >> 14) & 0xF; 451 } else { 452 int yTemp; 453 454 if (s.fInvType > SkMatrix::kTranslate_Mask) { 455 SkPoint pt; 456 s.fInvProc(*s.fInvMatrix, 457 SkIntToScalar(x) + SK_ScalarHalf, 458 SkIntToScalar(y) + SK_ScalarHalf, 459 &pt); 460 // When the matrix has a scale component the setup code in 461 // chooseProcs multiples the inverse matrix by the inverse of the 462 // bitmap's width and height. Since this method is going to do 463 // its own tiling and sampling we need to undo that here. 464 if (SkShader::kClamp_TileMode != s.fTileModeX || 465 SkShader::kClamp_TileMode != s.fTileModeY) { 466 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height()); 467 } else { 468 yTemp = SkScalarFloorToInt(pt.fY); 469 } 470 } else { 471 yTemp = s.fFilterOneY + y; 472 } 473 474 const int stopY = s.fBitmap->height(); 475 switch (s.fTileModeY) { 476 case SkShader::kClamp_TileMode: 477 iY0 = SkClampMax(yTemp, stopY-1); 478 break; 479 case SkShader::kRepeat_TileMode: 480 iY0 = sk_int_mod(yTemp, stopY); 481 break; 482 case SkShader::kMirror_TileMode: 483 default: 484 iY0 = sk_int_mirror(yTemp, stopY); 485 break; 486 } 487 488#ifdef SK_DEBUG 489 { 490 SkPoint pt; 491 s.fInvProc(*s.fInvMatrix, 492 SkIntToScalar(x) + SK_ScalarHalf, 493 SkIntToScalar(y) + SK_ScalarHalf, 494 &pt); 495 if (s.fInvType > SkMatrix::kTranslate_Mask && 496 (SkShader::kClamp_TileMode != s.fTileModeX || 497 SkShader::kClamp_TileMode != s.fTileModeY)) { 498 pt.fY *= s.fBitmap->height(); 499 } 500 int iY2; 501 502 switch (s.fTileModeY) { 503 case SkShader::kClamp_TileMode: 504 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1); 505 break; 506 case SkShader::kRepeat_TileMode: 507 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY); 508 break; 509 case SkShader::kMirror_TileMode: 510 default: 511 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY); 512 break; 513 } 514 515 SkASSERT(iY0 == iY2); 516 } 517#endif 518 } 519 520 const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0); 521 SkPMColor color; 522 523 if (s.fDoFilter) { 524 const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1); 525 526 if (s.fAlphaScale < 256) { 527 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale); 528 } else { 529 Filter_32_opaque(iSubY, *row0, *row1, &color); 530 } 531 } else { 532 if (s.fAlphaScale < 256) { 533 color = SkAlphaMulQ(*row0, s.fAlphaScale); 534 } else { 535 color = *row0; 536 } 537 } 538 539 sk_memset32(colors, color, count); 540} 541 542static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y, 543 SkPMColor* SK_RESTRICT colors, int count) { 544 // if we get called, the matrix is too tricky, so we just draw nothing 545 sk_memset32(colors, 0, count); 546} 547 548bool SkBitmapProcState::setupForTranslate() { 549 SkPoint pt; 550 fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt); 551 552 /* 553 * if the translate is larger than our ints, we can get random results, or 554 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't 555 * negate it. 556 */ 557 const SkScalar too_big = SkIntToScalar(1 << 30); 558 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) { 559 return false; 560 } 561 562 // Since we know we're not filtered, we re-purpose these fields allow 563 // us to go from device -> src coordinates w/ just an integer add, 564 // rather than running through the inverse-matrix 565 fFilterOneX = SkScalarFloorToInt(pt.fX); 566 fFilterOneY = SkScalarFloorToInt(pt.fY); 567 return true; 568} 569 570SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() { 571 572 if (SkBitmap::kARGB_8888_Config != fBitmap->config()) { 573 return NULL; 574 } 575 576 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 577 578 if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) { 579 if (!fDoFilter && fInvType <= SkMatrix::kTranslate_Mask && !this->setupForTranslate()) { 580 return DoNothing_shaderproc; 581 } 582 return S32_D32_constX_shaderproc; 583 } 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 617static 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 628static 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 645static 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 656static 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 673void 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 694SkBitmapProcState::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 */ 710int 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