1 /* 2 * Copyright 2011 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 "SkBitmapCache.h" 9 #include "SkBitmapController.h" 10 #include "SkBitmapProcState.h" 11 #include "SkColorPriv.h" 12 #include "SkPaint.h" 13 #include "SkShader.h" // for tilemodes 14 #include "SkUtilsArm.h" 15 #include "SkBitmapScaler.h" 16 #include "SkMipMap.h" 17 #include "SkPixelRef.h" 18 #include "SkImageEncoder.h" 19 #include "SkResourceCache.h" 20 21 #if defined(SK_ARM_HAS_NEON) 22 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp 23 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; 24 #endif 25 26 extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void*, int, int, uint32_t*, int); 27 28 #define NAME_WRAP(x) x 29 #include "SkBitmapProcState_filter.h" 30 #include "SkBitmapProcState_procs.h" 31 32 SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmapProvider& provider, 33 SkShader::TileMode tmx, SkShader::TileMode tmy) 34 : fProvider(provider) 35 , fTileModeX(tmx) 36 , fTileModeY(tmy) 37 , fBMState(nullptr) 38 {} 39 40 SkBitmapProcInfo::~SkBitmapProcInfo() { 41 SkInPlaceDeleteCheck(fBMState, fBMStateStorage.get()); 42 } 43 44 /////////////////////////////////////////////////////////////////////////////// 45 46 // true iff the matrix has a scale and no more than an optional translate. 47 static bool matrix_only_scale_translate(const SkMatrix& m) { 48 return (m.getType() & ~SkMatrix::kTranslate_Mask) == SkMatrix::kScale_Mask; 49 } 50 51 /** 52 * For the purposes of drawing bitmaps, if a matrix is "almost" translate 53 * go ahead and treat it as if it were, so that subsequent code can go fast. 54 */ 55 static bool just_trans_general(const SkMatrix& matrix) { 56 SkASSERT(matrix_only_scale_translate(matrix)); 57 58 const SkScalar tol = SK_Scalar1 / 32768; 59 60 return SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol) 61 && SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol); 62 } 63 64 /** 65 * Determine if the matrix can be treated as integral-only-translate, 66 * for the purpose of filtering. 67 */ 68 static bool just_trans_integral(const SkMatrix& m) { 69 #ifdef SK_SUPPORT_LEGACY_BILERP 70 return false; 71 #else 72 static constexpr SkScalar tol = SK_Scalar1 / 256; 73 74 return m.getType() <= SkMatrix::kTranslate_Mask 75 && SkScalarNearlyEqual(m.getTranslateX(), SkScalarRoundToScalar(m.getTranslateX()), tol) 76 && SkScalarNearlyEqual(m.getTranslateY(), SkScalarRoundToScalar(m.getTranslateY()), tol); 77 #endif 78 } 79 80 static bool valid_for_filtering(unsigned dimension) { 81 // for filtering, width and height must fit in 14bits, since we use steal 82 // 2 bits from each to store our 4bit subpixel data 83 return (dimension & ~0x3FFF) == 0; 84 } 85 86 bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) { 87 SkASSERT(!inv.hasPerspective()); 88 89 fPixmap.reset(); 90 fInvMatrix = inv; 91 fFilterQuality = paint.getFilterQuality(); 92 93 SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kNo); 94 fBMState = controller.requestBitmap(fProvider, inv, paint.getFilterQuality(), 95 fBMStateStorage.get(), fBMStateStorage.size()); 96 // Note : we allow the controller to return an empty (zero-dimension) result. Should we? 97 if (nullptr == fBMState || fBMState->pixmap().info().isEmpty()) { 98 return false; 99 } 100 fPixmap = fBMState->pixmap(); 101 fInvMatrix = fBMState->invMatrix(); 102 fRealInvMatrix = fBMState->invMatrix(); 103 fPaintColor = paint.getColor(); 104 fFilterQuality = fBMState->quality(); 105 SkASSERT(fPixmap.addr()); 106 107 // Most of the scanline procs deal with "unit" texture coordinates, as this 108 // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate 109 // those, we divide the matrix by its dimensions here. 110 // 111 // We don't do this if we're either trivial (can ignore the matrix) or clamping 112 // in both X and Y since clamping to width,height is just as easy as to 0xFFFF. 113 114 if (fTileModeX != SkShader::kClamp_TileMode || 115 fTileModeY != SkShader::kClamp_TileMode) { 116 fInvMatrix.postIDiv(fPixmap.width(), fPixmap.height()); 117 } 118 119 // Now that all possible changes to the matrix have taken place, check 120 // to see if we're really close to a no-scale matrix. If so, explicitly 121 // set it to be so. Subsequent code may inspect this matrix to choose 122 // a faster path in this case. 123 124 // This code will only execute if the matrix has some scale component; 125 // if it's already pure translate then we won't do this inversion. 126 127 if (matrix_only_scale_translate(fInvMatrix)) { 128 SkMatrix forward; 129 if (fInvMatrix.invert(&forward) && just_trans_general(forward)) { 130 fInvMatrix.setTranslate(-forward.getTranslateX(), -forward.getTranslateY()); 131 } 132 } 133 134 fInvType = fInvMatrix.getType(); 135 136 if (kLow_SkFilterQuality == fFilterQuality && 137 (!valid_for_filtering(fPixmap.width() | fPixmap.height()) || 138 just_trans_integral(fInvMatrix))) { 139 fFilterQuality = kNone_SkFilterQuality; 140 } 141 142 return true; 143 } 144 145 /* 146 * Analyze filter-quality and matrix, and decide how to implement that. 147 * 148 * In general, we cascade down the request level [ High ... None ] 149 * - for a given level, if we can fulfill it, fine, else 150 * - else we downgrade to the next lower level and try again. 151 * We can always fulfill requests for Low and None 152 * - sometimes we will "ignore" Low and give None, but this is likely a legacy perf hack 153 * and may be removed. 154 */ 155 bool SkBitmapProcState::chooseProcs() { 156 fInvProc = fInvMatrix.getMapXYProc(); 157 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX()); 158 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX()); 159 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY()); 160 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY()); 161 162 fAlphaScale = SkAlpha255To256(SkColorGetA(fPaintColor)); 163 164 fShaderProc32 = nullptr; 165 fShaderProc16 = nullptr; 166 fSampleProc32 = nullptr; 167 168 const bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; 169 const bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && 170 SkShader::kClamp_TileMode == fTileModeY; 171 172 return this->chooseScanlineProcs(trivialMatrix, clampClamp); 173 } 174 175 bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp) { 176 SkASSERT(fPixmap.colorType() == kN32_SkColorType); 177 178 fMatrixProc = this->chooseMatrixProc(trivialMatrix); 179 // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns nullptr. 180 if (nullptr == fMatrixProc) { 181 return false; 182 } 183 184 const SkAlphaType at = fPixmap.alphaType(); 185 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) { 186 return false; 187 } 188 189 // No need to do this if we're doing HQ sampling; if filter quality is 190 // still set to HQ by the time we get here, then we must have installed 191 // the shader procs above and can skip all this. 192 193 if (fFilterQuality < kHigh_SkFilterQuality) { 194 int index = 0; 195 if (fAlphaScale < 256) { // note: this distinction is not used for D16 196 index |= 1; 197 } 198 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 199 index |= 2; 200 } 201 if (fFilterQuality > kNone_SkFilterQuality) { 202 index |= 4; 203 } 204 205 #if !defined(SK_ARM_HAS_NEON) 206 static const SampleProc32 gSkBitmapProcStateSample32[] = { 207 S32_opaque_D32_nofilter_DXDY, 208 S32_alpha_D32_nofilter_DXDY, 209 S32_opaque_D32_nofilter_DX, 210 S32_alpha_D32_nofilter_DX, 211 S32_opaque_D32_filter_DXDY, 212 S32_alpha_D32_filter_DXDY, 213 S32_opaque_D32_filter_DX, 214 S32_alpha_D32_filter_DX, 215 }; 216 #endif 217 218 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index]; 219 220 // our special-case shaderprocs 221 if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) { 222 fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc; 223 } 224 225 if (nullptr == fShaderProc32) { 226 fShaderProc32 = this->chooseShaderProc32(); 227 } 228 } 229 230 // see if our platform has any accelerated overrides 231 this->platformProcs(); 232 233 return true; 234 } 235 236 static void Clamp_S32_D32_nofilter_trans_shaderproc(const void* sIn, 237 int x, int y, 238 SkPMColor* SK_RESTRICT colors, 239 int count) { 240 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn); 241 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 242 SkASSERT(s.fInvKy == 0); 243 SkASSERT(count > 0 && colors != nullptr); 244 SkASSERT(kNone_SkFilterQuality == s.fFilterQuality); 245 246 const int maxX = s.fPixmap.width() - 1; 247 const int maxY = s.fPixmap.height() - 1; 248 int ix = s.fFilterOneX + x; 249 int iy = SkClampMax(s.fFilterOneY + y, maxY); 250 const SkPMColor* row = s.fPixmap.addr32(0, iy); 251 252 // clamp to the left 253 if (ix < 0) { 254 int n = SkMin32(-ix, count); 255 sk_memset32(colors, row[0], n); 256 count -= n; 257 if (0 == count) { 258 return; 259 } 260 colors += n; 261 SkASSERT(-ix == n); 262 ix = 0; 263 } 264 // copy the middle 265 if (ix <= maxX) { 266 int n = SkMin32(maxX - ix + 1, count); 267 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 268 count -= n; 269 if (0 == count) { 270 return; 271 } 272 colors += n; 273 } 274 SkASSERT(count > 0); 275 // clamp to the right 276 sk_memset32(colors, row[maxX], count); 277 } 278 279 static inline int sk_int_mod(int x, int n) { 280 SkASSERT(n > 0); 281 if ((unsigned)x >= (unsigned)n) { 282 if (x < 0) { 283 x = n + ~(~x % n); 284 } else { 285 x = x % n; 286 } 287 } 288 return x; 289 } 290 291 static inline int sk_int_mirror(int x, int n) { 292 x = sk_int_mod(x, 2 * n); 293 if (x >= n) { 294 x = n + ~(x - n); 295 } 296 return x; 297 } 298 299 static void Repeat_S32_D32_nofilter_trans_shaderproc(const void* sIn, 300 int x, int y, 301 SkPMColor* SK_RESTRICT colors, 302 int count) { 303 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn); 304 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 305 SkASSERT(s.fInvKy == 0); 306 SkASSERT(count > 0 && colors != nullptr); 307 SkASSERT(kNone_SkFilterQuality == s.fFilterQuality); 308 309 const int stopX = s.fPixmap.width(); 310 const int stopY = s.fPixmap.height(); 311 int ix = s.fFilterOneX + x; 312 int iy = sk_int_mod(s.fFilterOneY + y, stopY); 313 const SkPMColor* row = s.fPixmap.addr32(0, iy); 314 315 ix = sk_int_mod(ix, stopX); 316 for (;;) { 317 int n = SkMin32(stopX - ix, count); 318 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 319 count -= n; 320 if (0 == count) { 321 return; 322 } 323 colors += n; 324 ix = 0; 325 } 326 } 327 328 static void S32_D32_constX_shaderproc(const void* sIn, 329 int x, int y, 330 SkPMColor* SK_RESTRICT colors, 331 int count) { 332 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn); 333 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0); 334 SkASSERT(s.fInvKy == 0); 335 SkASSERT(count > 0 && colors != nullptr); 336 SkASSERT(1 == s.fPixmap.width()); 337 338 int iY0; 339 int iY1 SK_INIT_TO_AVOID_WARNING; 340 int iSubY SK_INIT_TO_AVOID_WARNING; 341 342 if (kNone_SkFilterQuality != s.fFilterQuality) { 343 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc(); 344 uint32_t xy[2]; 345 346 mproc(s, xy, 1, x, y); 347 348 iY0 = xy[0] >> 18; 349 iY1 = xy[0] & 0x3FFF; 350 iSubY = (xy[0] >> 14) & 0xF; 351 } else { 352 int yTemp; 353 354 if (s.fInvType > SkMatrix::kTranslate_Mask) { 355 const SkBitmapProcStateAutoMapper mapper(s, x, y); 356 357 // When the matrix has a scale component the setup code in 358 // chooseProcs multiples the inverse matrix by the inverse of the 359 // bitmap's width and height. Since this method is going to do 360 // its own tiling and sampling we need to undo that here. 361 if (SkShader::kClamp_TileMode != s.fTileModeX || 362 SkShader::kClamp_TileMode != s.fTileModeY) { 363 yTemp = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height()); 364 } else { 365 yTemp = mapper.intY(); 366 } 367 } else { 368 yTemp = s.fFilterOneY + y; 369 } 370 371 const int stopY = s.fPixmap.height(); 372 switch (s.fTileModeY) { 373 case SkShader::kClamp_TileMode: 374 iY0 = SkClampMax(yTemp, stopY-1); 375 break; 376 case SkShader::kRepeat_TileMode: 377 iY0 = sk_int_mod(yTemp, stopY); 378 break; 379 case SkShader::kMirror_TileMode: 380 default: 381 iY0 = sk_int_mirror(yTemp, stopY); 382 break; 383 } 384 385 #ifdef SK_DEBUG 386 { 387 const SkBitmapProcStateAutoMapper mapper(s, x, y); 388 int iY2; 389 390 if (s.fInvType > SkMatrix::kTranslate_Mask && 391 (SkShader::kClamp_TileMode != s.fTileModeX || 392 SkShader::kClamp_TileMode != s.fTileModeY)) { 393 iY2 = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height()); 394 } else { 395 iY2 = mapper.intY(); 396 } 397 398 switch (s.fTileModeY) { 399 case SkShader::kClamp_TileMode: 400 iY2 = SkClampMax(iY2, stopY-1); 401 break; 402 case SkShader::kRepeat_TileMode: 403 iY2 = sk_int_mod(iY2, stopY); 404 break; 405 case SkShader::kMirror_TileMode: 406 default: 407 iY2 = sk_int_mirror(iY2, stopY); 408 break; 409 } 410 411 SkASSERT(iY0 == iY2); 412 } 413 #endif 414 } 415 416 const SkPMColor* row0 = s.fPixmap.addr32(0, iY0); 417 SkPMColor color; 418 419 if (kNone_SkFilterQuality != s.fFilterQuality) { 420 const SkPMColor* row1 = s.fPixmap.addr32(0, iY1); 421 422 if (s.fAlphaScale < 256) { 423 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale); 424 } else { 425 Filter_32_opaque(iSubY, *row0, *row1, &color); 426 } 427 } else { 428 if (s.fAlphaScale < 256) { 429 color = SkAlphaMulQ(*row0, s.fAlphaScale); 430 } else { 431 color = *row0; 432 } 433 } 434 435 sk_memset32(colors, color, count); 436 } 437 438 static void DoNothing_shaderproc(const void*, int x, int y, 439 SkPMColor* SK_RESTRICT colors, int count) { 440 // if we get called, the matrix is too tricky, so we just draw nothing 441 sk_memset32(colors, 0, count); 442 } 443 444 bool SkBitmapProcState::setupForTranslate() { 445 SkPoint pt; 446 const SkBitmapProcStateAutoMapper mapper(*this, 0, 0, &pt); 447 448 /* 449 * if the translate is larger than our ints, we can get random results, or 450 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't 451 * negate it. 452 */ 453 const SkScalar too_big = SkIntToScalar(1 << 30); 454 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) { 455 return false; 456 } 457 458 // Since we know we're not filtered, we re-purpose these fields allow 459 // us to go from device -> src coordinates w/ just an integer add, 460 // rather than running through the inverse-matrix 461 fFilterOneX = mapper.intX(); 462 fFilterOneY = mapper.intY(); 463 464 return true; 465 } 466 467 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() { 468 469 if (kN32_SkColorType != fPixmap.colorType()) { 470 return nullptr; 471 } 472 473 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 474 475 if (1 == fPixmap.width() && 0 == (fInvType & ~kMask)) { 476 if (kNone_SkFilterQuality == fFilterQuality && 477 fInvType <= SkMatrix::kTranslate_Mask && 478 !this->setupForTranslate()) { 479 return DoNothing_shaderproc; 480 } 481 return S32_D32_constX_shaderproc; 482 } 483 484 if (fAlphaScale < 256) { 485 return nullptr; 486 } 487 if (fInvType > SkMatrix::kTranslate_Mask) { 488 return nullptr; 489 } 490 if (kNone_SkFilterQuality != fFilterQuality) { 491 return nullptr; 492 } 493 494 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX; 495 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY; 496 497 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) { 498 if (this->setupForTranslate()) { 499 return Clamp_S32_D32_nofilter_trans_shaderproc; 500 } 501 return DoNothing_shaderproc; 502 } 503 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) { 504 if (this->setupForTranslate()) { 505 return Repeat_S32_D32_nofilter_trans_shaderproc; 506 } 507 return DoNothing_shaderproc; 508 } 509 return nullptr; 510 } 511 512 /////////////////////////////////////////////////////////////////////////////// 513 514 #ifdef SK_DEBUG 515 516 static void check_scale_nofilter(uint32_t bitmapXY[], int count, 517 unsigned mx, unsigned my) { 518 unsigned y = *bitmapXY++; 519 SkASSERT(y < my); 520 521 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY); 522 for (int i = 0; i < count; ++i) { 523 SkASSERT(xptr[i] < mx); 524 } 525 } 526 527 static void check_scale_filter(uint32_t bitmapXY[], int count, 528 unsigned mx, unsigned my) { 529 uint32_t YY = *bitmapXY++; 530 unsigned y0 = YY >> 18; 531 unsigned y1 = YY & 0x3FFF; 532 SkASSERT(y0 < my); 533 SkASSERT(y1 < my); 534 535 for (int i = 0; i < count; ++i) { 536 uint32_t XX = bitmapXY[i]; 537 unsigned x0 = XX >> 18; 538 unsigned x1 = XX & 0x3FFF; 539 SkASSERT(x0 < mx); 540 SkASSERT(x1 < mx); 541 } 542 } 543 544 static void check_affine_nofilter(uint32_t bitmapXY[], int count, 545 unsigned mx, unsigned my) { 546 for (int i = 0; i < count; ++i) { 547 uint32_t XY = bitmapXY[i]; 548 unsigned x = XY & 0xFFFF; 549 unsigned y = XY >> 16; 550 SkASSERT(x < mx); 551 SkASSERT(y < my); 552 } 553 } 554 555 static void check_affine_filter(uint32_t bitmapXY[], int count, 556 unsigned mx, unsigned my) { 557 for (int i = 0; i < count; ++i) { 558 uint32_t YY = *bitmapXY++; 559 unsigned y0 = YY >> 18; 560 unsigned y1 = YY & 0x3FFF; 561 SkASSERT(y0 < my); 562 SkASSERT(y1 < my); 563 564 uint32_t XX = *bitmapXY++; 565 unsigned x0 = XX >> 18; 566 unsigned x1 = XX & 0x3FFF; 567 SkASSERT(x0 < mx); 568 SkASSERT(x1 < mx); 569 } 570 } 571 572 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state, 573 uint32_t bitmapXY[], int count, 574 int x, int y) { 575 SkASSERT(bitmapXY); 576 SkASSERT(count > 0); 577 578 state.fMatrixProc(state, bitmapXY, count, x, y); 579 580 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my); 581 582 // There are four formats possible: 583 // scale -vs- affine 584 // filter -vs- nofilter 585 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 586 proc = state.fFilterQuality != kNone_SkFilterQuality ? 587 check_scale_filter : check_scale_nofilter; 588 } else { 589 proc = state.fFilterQuality != kNone_SkFilterQuality ? 590 check_affine_filter : check_affine_nofilter; 591 } 592 proc(bitmapXY, count, state.fPixmap.width(), state.fPixmap.height()); 593 } 594 595 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const { 596 return DebugMatrixProc; 597 } 598 599 #endif 600 601 /////////////////////////////////////////////////////////////////////////////// 602 /* 603 The storage requirements for the different matrix procs are as follows, 604 where each X or Y is 2 bytes, and N is the number of pixels/elements: 605 606 scale/translate nofilter Y(4bytes) + N * X 607 affine/perspective nofilter N * (X Y) 608 scale/translate filter Y Y + N * (X X) 609 affine filter N * (Y Y X X) 610 */ 611 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { 612 int32_t size = static_cast<int32_t>(bufferSize); 613 614 size &= ~3; // only care about 4-byte aligned chunks 615 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 616 size -= 4; // the shared Y (or YY) coordinate 617 if (size < 0) { 618 size = 0; 619 } 620 size >>= 1; 621 } else { 622 size >>= 2; 623 } 624 625 if (fFilterQuality != kNone_SkFilterQuality) { 626 size >>= 1; 627 } 628 629 return size; 630 } 631 632 /////////////////////// 633 634 void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void* sIn, int x, int y, 635 SkPMColor* SK_RESTRICT dst, int count) { 636 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn); 637 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | 638 SkMatrix::kScale_Mask)) == 0); 639 640 const unsigned maxX = s.fPixmap.width() - 1; 641 SkFractionalInt fx; 642 int dstY; 643 { 644 const SkBitmapProcStateAutoMapper mapper(s, x, y); 645 const unsigned maxY = s.fPixmap.height() - 1; 646 dstY = SkClampMax(mapper.intY(), maxY); 647 fx = mapper.fractionalIntX(); 648 } 649 650 const SkPMColor* SK_RESTRICT src = s.fPixmap.addr32(0, dstY); 651 const SkFractionalInt dx = s.fInvSxFractionalInt; 652 653 // Check if we're safely inside [0...maxX] so no need to clamp each computed index. 654 // 655 if ((uint64_t)SkFractionalIntToInt(fx) <= maxX && 656 (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX) 657 { 658 int count4 = count >> 2; 659 for (int i = 0; i < count4; ++i) { 660 SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx; 661 SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx; 662 SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx; 663 SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx; 664 dst[0] = src0; 665 dst[1] = src1; 666 dst[2] = src2; 667 dst[3] = src3; 668 dst += 4; 669 } 670 for (int i = (count4 << 2); i < count; ++i) { 671 unsigned index = SkFractionalIntToInt(fx); 672 SkASSERT(index <= maxX); 673 *dst++ = src[index]; 674 fx += dx; 675 } 676 } else { 677 for (int i = 0; i < count; ++i) { 678 dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)]; 679 fx += dx; 680 } 681 } 682 } 683