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#include "SkBitmapScaler.h" 15#include "SkMipMap.h" 16#include "SkScaledImageCache.h" 17 18#if !SK_ARM_NEON_IS_NONE 19// These are defined in src/opts/SkBitmapProcState_arm_neon.cpp 20extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[]; 21extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; 22extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); 23extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 24extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 25extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*); 26extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); 27extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); 28#endif 29 30#define NAME_WRAP(x) x 31#include "SkBitmapProcState_filter.h" 32#include "SkBitmapProcState_procs.h" 33 34/////////////////////////////////////////////////////////////////////////////// 35 36// true iff the matrix contains, at most, scale and translate elements 37static bool matrix_only_scale_translate(const SkMatrix& m) { 38 return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask); 39} 40 41/** 42 * For the purposes of drawing bitmaps, if a matrix is "almost" translate 43 * go ahead and treat it as if it were, so that subsequent code can go fast. 44 */ 45static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) { 46 SkASSERT(matrix_only_scale_translate(matrix)); 47 48 if (matrix.getType() & SkMatrix::kScale_Mask) { 49 SkRect src, dst; 50 bitmap.getBounds(&src); 51 52 // Can't call mapRect(), since that will fix up inverted rectangles, 53 // e.g. when scale is negative, and we don't want to return true for 54 // those. 55 matrix.mapPoints(SkTCast<SkPoint*>(&dst), 56 SkTCast<const SkPoint*>(&src), 57 2); 58 59 // Now round all 4 edges to device space, and then compare the device 60 // width/height to the original. Note: we must map all 4 and subtract 61 // rather than map the "width" and compare, since we care about the 62 // phase (in pixel space) that any translate in the matrix might impart. 63 SkIRect idst; 64 dst.round(&idst); 65 return idst.width() == bitmap.width() && idst.height() == bitmap.height(); 66 } 67 // if we got here, we're either kTranslate_Mask or identity 68 return true; 69} 70 71static bool just_trans_general(const SkMatrix& matrix) { 72 SkASSERT(matrix_only_scale_translate(matrix)); 73 74 if (matrix.getType() & SkMatrix::kScale_Mask) { 75 const SkScalar tol = SK_Scalar1 / 32768; 76 77 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) { 78 return false; 79 } 80 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) { 81 return false; 82 } 83 } 84 // if we got here, treat us as either kTranslate_Mask or identity 85 return true; 86} 87 88/////////////////////////////////////////////////////////////////////////////// 89 90static bool valid_for_filtering(unsigned dimension) { 91 // for filtering, width and height must fit in 14bits, since we use steal 92 // 2 bits from each to store our 4bit subpixel data 93 return (dimension & ~0x3FFF) == 0; 94} 95 96static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) { 97 SkPoint v1, v2; 98 99 v1.fX = mat.getScaleX(); 100 v1.fY = mat.getSkewY(); 101 102 v2.fX = mat.getSkewX(); 103 v2.fY = mat.getScaleY(); 104 105 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd()); 106} 107 108// TODO -- we may want to pass the clip into this function so we only scale 109// the portion of the image that we're going to need. This will complicate 110// the interface to the cache, but might be well worth it. 111 112void SkBitmapProcState::possiblyScaleImage() { 113 114 if (fFilterLevel <= SkPaint::kLow_FilterLevel) { 115 // none or low (bilerp) does not need to look any further 116 return; 117 } 118 119 // see if our platform has any specialized convolution code. 120 121 122 // Set up a pointer to a local (instead of storing the structure in the 123 // proc state) to avoid introducing a header dependency; this makes 124 // recompiles a lot less painful. 125 126 SkConvolutionProcs simd; 127 fConvolutionProcs = &simd; 128 129 fConvolutionProcs->fExtraHorizontalReads = 0; 130 fConvolutionProcs->fConvolveVertically = NULL; 131 fConvolutionProcs->fConvolve4RowsHorizontally = NULL; 132 fConvolutionProcs->fConvolveHorizontally = NULL; 133 fConvolutionProcs->fApplySIMDPadding = NULL; 134 135 this->platformConvolutionProcs(); 136 137 // STEP 1: Highest quality direct scale? 138 139 // Check to see if the transformation matrix is simple, and if we're 140 // doing high quality scaling. If so, do the bitmap scale here and 141 // remove the scaling component from the matrix. 142 143 if (SkPaint::kHigh_FilterLevel == fFilterLevel && 144 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) && 145 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) { 146 147 SkScalar invScaleX = fInvMatrix.getScaleX(); 148 SkScalar invScaleY = fInvMatrix.getScaleY(); 149 150 SkASSERT(NULL == fScaledCacheID); 151 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, 152 invScaleX, invScaleY, 153 &fScaledBitmap); 154 if (NULL == fScaledCacheID) { 155 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX); 156 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY); 157 158 // All the criteria are met; let's make a new bitmap. 159 160 if (!SkBitmapScaler::Resize(&fScaledBitmap, 161 fOrigBitmap, 162 SkBitmapScaler::RESIZE_BEST, 163 dest_width, 164 dest_height, 165 fConvolutionProcs)) { 166 // we failed to create fScaledBitmap, so just return and let 167 // the scanline proc handle it. 168 return; 169 170 } 171 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, 172 invScaleX, 173 invScaleY, 174 fScaledBitmap); 175 } 176 fScaledBitmap.lockPixels(); 177 178 fBitmap = &fScaledBitmap; 179 180 // set the inv matrix type to translate-only; 181 182 fInvMatrix.setTranslate( 1/fInvMatrix.getScaleX() * fInvMatrix.getTranslateX(), 183 1/fInvMatrix.getScaleY() * fInvMatrix.getTranslateY() ); 184 185 // no need for any further filtering; we just did it! 186 187 fFilterLevel = SkPaint::kNone_FilterLevel; 188 189 return; 190 } 191 192 /* 193 * If we get here, the caller has requested either Med or High filter-level 194 * 195 * If High, then our special-case for scale-only did not take, and so we 196 * have to make a choice: 197 * 1. fall back on mipmaps + bilerp 198 * 2. fall back on scanline bicubic filter 199 * For now, we compute the "scale" value from the matrix, and have a 200 * threshold to decide when bicubic is better, and when mips are better. 201 * No doubt a fancier decision tree could be used uere. 202 * 203 * If Medium, then we just try to build a mipmap and select a level, 204 * setting the filter-level to kLow to signal that we just need bilerp 205 * to process the selected level. 206 */ 207 208 SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix); 209 210 if (SkPaint::kHigh_FilterLevel == fFilterLevel) { 211 // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller 212 // than this, then the mipmaps quality may be greater (certainly faster) 213 // so we only keep High quality if the scale is greater than this. 214 // 215 // Since we're dealing with the inverse, we compare against its inverse. 216 const SkScalar bicubicLimit = SkFloatToScalar(4.0f); 217 const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit; 218 if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline 219 return; 220 } 221 222 // else set the filter-level to Medium, since we're scaling down and 223 // want to reqeust mipmaps 224 fFilterLevel = SkPaint::kMedium_FilterLevel; 225 } 226 227 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel); 228 229 /** 230 * Medium quality means use a mipmap for down-scaling, and just bilper 231 * for upscaling. Since we're examining the inverse matrix, we look for 232 * a scale > 1 to indicate down scaling by the CTM. 233 */ 234 if (scaleSqd > SK_Scalar1) { 235 const SkMipMap* mip = NULL; 236 237 SkASSERT(NULL == fScaledCacheID); 238 fScaledCacheID = SkScaledImageCache::FindAndLockMip(fOrigBitmap, &mip); 239 if (!fScaledCacheID) { 240 SkASSERT(NULL == mip); 241 mip = SkMipMap::Build(fOrigBitmap); 242 if (mip) { 243 fScaledCacheID = SkScaledImageCache::AddAndLockMip(fOrigBitmap, 244 mip); 245 mip->unref(); // the cache took a ref 246 SkASSERT(fScaledCacheID); 247 } 248 } else { 249 SkASSERT(mip); 250 } 251 252 if (mip) { 253 SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd)); 254 SkMipMap::Level level; 255 if (mip->extractLevel(levelScale, &level)) { 256 SkScalar invScaleFixup = level.fScale; 257 fInvMatrix.postScale(invScaleFixup, invScaleFixup); 258 259 fScaledBitmap.setConfig(fOrigBitmap.config(), 260 level.fWidth, level.fHeight, 261 level.fRowBytes); 262 fScaledBitmap.setPixels(level.fPixels); 263 fBitmap = &fScaledBitmap; 264 } 265 } 266 } 267 268 /* 269 * At this point, we may or may not have built a mipmap. Regardless, we 270 * now fall back on Low so will bilerp whatever fBitmap now points at. 271 */ 272 fFilterLevel = SkPaint::kLow_FilterLevel; 273} 274 275void SkBitmapProcState::endContext() { 276 SkDELETE(fBitmapFilter); 277 fBitmapFilter = NULL; 278 fScaledBitmap.reset(); 279 280 if (fScaledCacheID) { 281 SkScaledImageCache::Unlock(fScaledCacheID); 282 fScaledCacheID = NULL; 283 } 284} 285 286SkBitmapProcState::~SkBitmapProcState() { 287 if (fScaledCacheID) { 288 SkScaledImageCache::Unlock(fScaledCacheID); 289 } 290 SkDELETE(fBitmapFilter); 291} 292 293bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { 294 if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { 295 return false; 296 } 297 298 bool trivialMatrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0; 299 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && 300 SkShader::kClamp_TileMode == fTileModeY; 301 302 fInvMatrix = inv; 303 if (!(clampClamp || trivialMatrix)) { 304 fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height()); 305 } 306 307 fBitmap = &fOrigBitmap; 308 309 // initialize our filter quality to the one requested by the caller. 310 // We may downgrade it later if we determine that we either don't need 311 // or can't provide as high a quality filtering as the user requested. 312 313 fFilterLevel = paint.getFilterLevel(); 314 315#ifndef SK_IGNORE_IMAGE_PRESCALE 316 // possiblyScaleImage will look to see if it can rescale the image as a 317 // preprocess; either by scaling up to the target size, or by selecting 318 // a nearby mipmap level. If it does, it will adjust the working 319 // matrix as well as the working bitmap. It may also adjust the filter 320 // quality to avoid re-filtering an already perfectly scaled image. 321 322 this->possiblyScaleImage(); 323#endif 324 325 // Now that all possible changes to the matrix have taken place, check 326 // to see if we're really close to a no-scale matrix. If so, explicitly 327 // set it to be so. Subsequent code may inspect this matrix to choose 328 // a faster path in this case. 329 330 // This code will only execute if the matrix has some scale component; 331 // if it's already pure translate then we won't do this inversion. 332 333 if (matrix_only_scale_translate(fInvMatrix)) { 334 SkMatrix forward; 335 if (fInvMatrix.invert(&forward)) { 336 if (clampClamp ? just_trans_clamp(forward, *fBitmap) 337 : just_trans_general(forward)) { 338 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); 339 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); 340 fInvMatrix.setTranslate(tx, ty); 341 342 } 343 } 344 } 345 346 fInvProc = fInvMatrix.getMapXYProc(); 347 fInvType = fInvMatrix.getType(); 348 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX()); 349 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX()); 350 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY()); 351 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY()); 352 353 fAlphaScale = SkAlpha255To256(paint.getAlpha()); 354 355 fShaderProc32 = NULL; 356 fShaderProc16 = NULL; 357 fSampleProc32 = NULL; 358 fSampleProc16 = NULL; 359 360 // recompute the triviality of the matrix here because we may have 361 // changed it! 362 363 trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; 364 365 if (SkPaint::kHigh_FilterLevel == fFilterLevel) { 366 // If this is still set, that means we wanted HQ sampling 367 // but couldn't do it as a preprocess. Let's try to install 368 // the scanline version of the HQ sampler. If that process fails, 369 // downgrade to bilerp. 370 371 // NOTE: Might need to be careful here in the future when we want 372 // to have the platform proc have a shot at this; it's possible that 373 // the chooseBitmapFilterProc will fail to install a shader but a 374 // platform-specific one might succeed, so it might be premature here 375 // to fall back to bilerp. This needs thought. 376 377 SkASSERT(fInvType > SkMatrix::kTranslate_Mask); 378 379 fShaderProc32 = this->chooseBitmapFilterProc(); 380 if (!fShaderProc32) { 381 fFilterLevel = SkPaint::kLow_FilterLevel; 382 } 383 } 384 385 if (SkPaint::kLow_FilterLevel == fFilterLevel) { 386 // Only try bilerp if the matrix is "interesting" and 387 // the image has a suitable size. 388 389 if (fInvType <= SkMatrix::kTranslate_Mask || 390 !valid_for_filtering(fBitmap->width() | fBitmap->height())) { 391 fFilterLevel = SkPaint::kNone_FilterLevel; 392 } 393 } 394 395 // At this point, we know exactly what kind of sampling the per-scanline 396 // shader will perform. 397 398 fMatrixProc = this->chooseMatrixProc(trivialMatrix); 399 if (NULL == fMatrixProc) { 400 return false; 401 } 402 403 /////////////////////////////////////////////////////////////////////// 404 405 // No need to do this if we're doing HQ sampling; if filter quality is 406 // still set to HQ by the time we get here, then we must have installed 407 // the shader proc above and can skip all this. 408 409 if (fFilterLevel < SkPaint::kHigh_FilterLevel) { 410 411 int index = 0; 412 if (fAlphaScale < 256) { // note: this distinction is not used for D16 413 index |= 1; 414 } 415 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 416 index |= 2; 417 } 418 if (fFilterLevel > SkPaint::kNone_FilterLevel) { 419 index |= 4; 420 } 421 // bits 3,4,5 encoding the source bitmap format 422 switch (fBitmap->config()) { 423 case SkBitmap::kARGB_8888_Config: 424 index |= 0; 425 break; 426 case SkBitmap::kRGB_565_Config: 427 index |= 8; 428 break; 429 case SkBitmap::kIndex8_Config: 430 index |= 16; 431 break; 432 case SkBitmap::kARGB_4444_Config: 433 index |= 24; 434 break; 435 case SkBitmap::kA8_Config: 436 index |= 32; 437 fPaintPMColor = SkPreMultiplyColor(paint.getColor()); 438 break; 439 default: 440 return false; 441 } 442 443 #if !SK_ARM_NEON_IS_ALWAYS 444 static const SampleProc32 gSkBitmapProcStateSample32[] = { 445 S32_opaque_D32_nofilter_DXDY, 446 S32_alpha_D32_nofilter_DXDY, 447 S32_opaque_D32_nofilter_DX, 448 S32_alpha_D32_nofilter_DX, 449 S32_opaque_D32_filter_DXDY, 450 S32_alpha_D32_filter_DXDY, 451 S32_opaque_D32_filter_DX, 452 S32_alpha_D32_filter_DX, 453 454 S16_opaque_D32_nofilter_DXDY, 455 S16_alpha_D32_nofilter_DXDY, 456 S16_opaque_D32_nofilter_DX, 457 S16_alpha_D32_nofilter_DX, 458 S16_opaque_D32_filter_DXDY, 459 S16_alpha_D32_filter_DXDY, 460 S16_opaque_D32_filter_DX, 461 S16_alpha_D32_filter_DX, 462 463 SI8_opaque_D32_nofilter_DXDY, 464 SI8_alpha_D32_nofilter_DXDY, 465 SI8_opaque_D32_nofilter_DX, 466 SI8_alpha_D32_nofilter_DX, 467 SI8_opaque_D32_filter_DXDY, 468 SI8_alpha_D32_filter_DXDY, 469 SI8_opaque_D32_filter_DX, 470 SI8_alpha_D32_filter_DX, 471 472 S4444_opaque_D32_nofilter_DXDY, 473 S4444_alpha_D32_nofilter_DXDY, 474 S4444_opaque_D32_nofilter_DX, 475 S4444_alpha_D32_nofilter_DX, 476 S4444_opaque_D32_filter_DXDY, 477 S4444_alpha_D32_filter_DXDY, 478 S4444_opaque_D32_filter_DX, 479 S4444_alpha_D32_filter_DX, 480 481 // A8 treats alpha/opaque the same (equally efficient) 482 SA8_alpha_D32_nofilter_DXDY, 483 SA8_alpha_D32_nofilter_DXDY, 484 SA8_alpha_D32_nofilter_DX, 485 SA8_alpha_D32_nofilter_DX, 486 SA8_alpha_D32_filter_DXDY, 487 SA8_alpha_D32_filter_DXDY, 488 SA8_alpha_D32_filter_DX, 489 SA8_alpha_D32_filter_DX 490 }; 491 492 static const SampleProc16 gSkBitmapProcStateSample16[] = { 493 S32_D16_nofilter_DXDY, 494 S32_D16_nofilter_DX, 495 S32_D16_filter_DXDY, 496 S32_D16_filter_DX, 497 498 S16_D16_nofilter_DXDY, 499 S16_D16_nofilter_DX, 500 S16_D16_filter_DXDY, 501 S16_D16_filter_DX, 502 503 SI8_D16_nofilter_DXDY, 504 SI8_D16_nofilter_DX, 505 SI8_D16_filter_DXDY, 506 SI8_D16_filter_DX, 507 508 // Don't support 4444 -> 565 509 NULL, NULL, NULL, NULL, 510 // Don't support A8 -> 565 511 NULL, NULL, NULL, NULL 512 }; 513 #endif 514 515 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index]; 516 index >>= 1; // shift away any opaque/alpha distinction 517 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index]; 518 519 // our special-case shaderprocs 520 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) { 521 if (clampClamp) { 522 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc); 523 } else if (SkShader::kRepeat_TileMode == fTileModeX && 524 SkShader::kRepeat_TileMode == fTileModeY) { 525 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc); 526 } 527 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) { 528 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc); 529 } 530 531 if (NULL == fShaderProc32) { 532 fShaderProc32 = this->chooseShaderProc32(); 533 } 534 } 535 536 // see if our platform has any accelerated overrides 537 this->platformProcs(); 538 539 return true; 540} 541 542static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, 543 int x, int y, 544 SkPMColor* SK_RESTRICT colors, 545 int count) { 546 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 547 SkASSERT(s.fInvKy == 0); 548 SkASSERT(count > 0 && colors != NULL); 549 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel); 550 551 const int maxX = s.fBitmap->width() - 1; 552 const int maxY = s.fBitmap->height() - 1; 553 int ix = s.fFilterOneX + x; 554 int iy = SkClampMax(s.fFilterOneY + y, maxY); 555#ifdef SK_DEBUG 556 { 557 SkPoint pt; 558 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, 559 SkIntToScalar(y) + SK_ScalarHalf, &pt); 560 int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY); 561 int ix2 = SkScalarFloorToInt(pt.fX); 562 563 SkASSERT(iy == iy2); 564 SkASSERT(ix == ix2); 565 } 566#endif 567 const SkPMColor* row = s.fBitmap->getAddr32(0, iy); 568 569 // clamp to the left 570 if (ix < 0) { 571 int n = SkMin32(-ix, count); 572 sk_memset32(colors, row[0], n); 573 count -= n; 574 if (0 == count) { 575 return; 576 } 577 colors += n; 578 SkASSERT(-ix == n); 579 ix = 0; 580 } 581 // copy the middle 582 if (ix <= maxX) { 583 int n = SkMin32(maxX - ix + 1, count); 584 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 585 count -= n; 586 if (0 == count) { 587 return; 588 } 589 colors += n; 590 } 591 SkASSERT(count > 0); 592 // clamp to the right 593 sk_memset32(colors, row[maxX], count); 594} 595 596static inline int sk_int_mod(int x, int n) { 597 SkASSERT(n > 0); 598 if ((unsigned)x >= (unsigned)n) { 599 if (x < 0) { 600 x = n + ~(~x % n); 601 } else { 602 x = x % n; 603 } 604 } 605 return x; 606} 607 608static inline int sk_int_mirror(int x, int n) { 609 x = sk_int_mod(x, 2 * n); 610 if (x >= n) { 611 x = n + ~(x - n); 612 } 613 return x; 614} 615 616static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, 617 int x, int y, 618 SkPMColor* SK_RESTRICT colors, 619 int count) { 620 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 621 SkASSERT(s.fInvKy == 0); 622 SkASSERT(count > 0 && colors != NULL); 623 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel); 624 625 const int stopX = s.fBitmap->width(); 626 const int stopY = s.fBitmap->height(); 627 int ix = s.fFilterOneX + x; 628 int iy = sk_int_mod(s.fFilterOneY + y, stopY); 629#ifdef SK_DEBUG 630 { 631 SkPoint pt; 632 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, 633 SkIntToScalar(y) + SK_ScalarHalf, &pt); 634 int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY); 635 int ix2 = SkScalarFloorToInt(pt.fX); 636 637 SkASSERT(iy == iy2); 638 SkASSERT(ix == ix2); 639 } 640#endif 641 const SkPMColor* row = s.fBitmap->getAddr32(0, iy); 642 643 ix = sk_int_mod(ix, stopX); 644 for (;;) { 645 int n = SkMin32(stopX - ix, count); 646 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 647 count -= n; 648 if (0 == count) { 649 return; 650 } 651 colors += n; 652 ix = 0; 653 } 654} 655 656static void S32_D32_constX_shaderproc(const SkBitmapProcState& s, 657 int x, int y, 658 SkPMColor* SK_RESTRICT colors, 659 int count) { 660 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0); 661 SkASSERT(s.fInvKy == 0); 662 SkASSERT(count > 0 && colors != NULL); 663 SkASSERT(1 == s.fBitmap->width()); 664 665 int iY0; 666 int iY1 SK_INIT_TO_AVOID_WARNING; 667 int iSubY SK_INIT_TO_AVOID_WARNING; 668 669 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) { 670 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc(); 671 uint32_t xy[2]; 672 673 mproc(s, xy, 1, x, y); 674 675 iY0 = xy[0] >> 18; 676 iY1 = xy[0] & 0x3FFF; 677 iSubY = (xy[0] >> 14) & 0xF; 678 } else { 679 int yTemp; 680 681 if (s.fInvType > SkMatrix::kTranslate_Mask) { 682 SkPoint pt; 683 s.fInvProc(s.fInvMatrix, 684 SkIntToScalar(x) + SK_ScalarHalf, 685 SkIntToScalar(y) + SK_ScalarHalf, 686 &pt); 687 // When the matrix has a scale component the setup code in 688 // chooseProcs multiples the inverse matrix by the inverse of the 689 // bitmap's width and height. Since this method is going to do 690 // its own tiling and sampling we need to undo that here. 691 if (SkShader::kClamp_TileMode != s.fTileModeX || 692 SkShader::kClamp_TileMode != s.fTileModeY) { 693 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height()); 694 } else { 695 yTemp = SkScalarFloorToInt(pt.fY); 696 } 697 } else { 698 yTemp = s.fFilterOneY + y; 699 } 700 701 const int stopY = s.fBitmap->height(); 702 switch (s.fTileModeY) { 703 case SkShader::kClamp_TileMode: 704 iY0 = SkClampMax(yTemp, stopY-1); 705 break; 706 case SkShader::kRepeat_TileMode: 707 iY0 = sk_int_mod(yTemp, stopY); 708 break; 709 case SkShader::kMirror_TileMode: 710 default: 711 iY0 = sk_int_mirror(yTemp, stopY); 712 break; 713 } 714 715#ifdef SK_DEBUG 716 { 717 SkPoint pt; 718 s.fInvProc(s.fInvMatrix, 719 SkIntToScalar(x) + SK_ScalarHalf, 720 SkIntToScalar(y) + SK_ScalarHalf, 721 &pt); 722 if (s.fInvType > SkMatrix::kTranslate_Mask && 723 (SkShader::kClamp_TileMode != s.fTileModeX || 724 SkShader::kClamp_TileMode != s.fTileModeY)) { 725 pt.fY *= s.fBitmap->height(); 726 } 727 int iY2; 728 729 switch (s.fTileModeY) { 730 case SkShader::kClamp_TileMode: 731 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1); 732 break; 733 case SkShader::kRepeat_TileMode: 734 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY); 735 break; 736 case SkShader::kMirror_TileMode: 737 default: 738 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY); 739 break; 740 } 741 742 SkASSERT(iY0 == iY2); 743 } 744#endif 745 } 746 747 const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0); 748 SkPMColor color; 749 750 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) { 751 const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1); 752 753 if (s.fAlphaScale < 256) { 754 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale); 755 } else { 756 Filter_32_opaque(iSubY, *row0, *row1, &color); 757 } 758 } else { 759 if (s.fAlphaScale < 256) { 760 color = SkAlphaMulQ(*row0, s.fAlphaScale); 761 } else { 762 color = *row0; 763 } 764 } 765 766 sk_memset32(colors, color, count); 767} 768 769static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y, 770 SkPMColor* SK_RESTRICT colors, int count) { 771 // if we get called, the matrix is too tricky, so we just draw nothing 772 sk_memset32(colors, 0, count); 773} 774 775bool SkBitmapProcState::setupForTranslate() { 776 SkPoint pt; 777 fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt); 778 779 /* 780 * if the translate is larger than our ints, we can get random results, or 781 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't 782 * negate it. 783 */ 784 const SkScalar too_big = SkIntToScalar(1 << 30); 785 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) { 786 return false; 787 } 788 789 // Since we know we're not filtered, we re-purpose these fields allow 790 // us to go from device -> src coordinates w/ just an integer add, 791 // rather than running through the inverse-matrix 792 fFilterOneX = SkScalarFloorToInt(pt.fX); 793 fFilterOneY = SkScalarFloorToInt(pt.fY); 794 return true; 795} 796 797SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() { 798 799 if (SkBitmap::kARGB_8888_Config != fBitmap->config()) { 800 return NULL; 801 } 802 803 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 804 805 if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) { 806 if (SkPaint::kNone_FilterLevel == fFilterLevel && 807 fInvType <= SkMatrix::kTranslate_Mask && 808 !this->setupForTranslate()) { 809 return DoNothing_shaderproc; 810 } 811 return S32_D32_constX_shaderproc; 812 } 813 814 if (fAlphaScale < 256) { 815 return NULL; 816 } 817 if (fInvType > SkMatrix::kTranslate_Mask) { 818 return NULL; 819 } 820 if (SkPaint::kNone_FilterLevel != fFilterLevel) { 821 return NULL; 822 } 823 824 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX; 825 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY; 826 827 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) { 828 if (this->setupForTranslate()) { 829 return Clamp_S32_D32_nofilter_trans_shaderproc; 830 } 831 return DoNothing_shaderproc; 832 } 833 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) { 834 if (this->setupForTranslate()) { 835 return Repeat_S32_D32_nofilter_trans_shaderproc; 836 } 837 return DoNothing_shaderproc; 838 } 839 return NULL; 840} 841 842/////////////////////////////////////////////////////////////////////////////// 843 844#ifdef SK_DEBUG 845 846static void check_scale_nofilter(uint32_t bitmapXY[], int count, 847 unsigned mx, unsigned my) { 848 unsigned y = *bitmapXY++; 849 SkASSERT(y < my); 850 851 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY); 852 for (int i = 0; i < count; ++i) { 853 SkASSERT(xptr[i] < mx); 854 } 855} 856 857static void check_scale_filter(uint32_t bitmapXY[], int count, 858 unsigned mx, unsigned my) { 859 uint32_t YY = *bitmapXY++; 860 unsigned y0 = YY >> 18; 861 unsigned y1 = YY & 0x3FFF; 862 SkASSERT(y0 < my); 863 SkASSERT(y1 < my); 864 865 for (int i = 0; i < count; ++i) { 866 uint32_t XX = bitmapXY[i]; 867 unsigned x0 = XX >> 18; 868 unsigned x1 = XX & 0x3FFF; 869 SkASSERT(x0 < mx); 870 SkASSERT(x1 < mx); 871 } 872} 873 874static void check_affine_nofilter(uint32_t bitmapXY[], int count, 875 unsigned mx, unsigned my) { 876 for (int i = 0; i < count; ++i) { 877 uint32_t XY = bitmapXY[i]; 878 unsigned x = XY & 0xFFFF; 879 unsigned y = XY >> 16; 880 SkASSERT(x < mx); 881 SkASSERT(y < my); 882 } 883} 884 885static void check_affine_filter(uint32_t bitmapXY[], int count, 886 unsigned mx, unsigned my) { 887 for (int i = 0; i < count; ++i) { 888 uint32_t YY = *bitmapXY++; 889 unsigned y0 = YY >> 18; 890 unsigned y1 = YY & 0x3FFF; 891 SkASSERT(y0 < my); 892 SkASSERT(y1 < my); 893 894 uint32_t XX = *bitmapXY++; 895 unsigned x0 = XX >> 18; 896 unsigned x1 = XX & 0x3FFF; 897 SkASSERT(x0 < mx); 898 SkASSERT(x1 < mx); 899 } 900} 901 902void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state, 903 uint32_t bitmapXY[], int count, 904 int x, int y) { 905 SkASSERT(bitmapXY); 906 SkASSERT(count > 0); 907 908 state.fMatrixProc(state, bitmapXY, count, x, y); 909 910 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my); 911 912 // There are four formats possible: 913 // scale -vs- affine 914 // filter -vs- nofilter 915 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 916 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter; 917 } else { 918 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter; 919 } 920 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height()); 921} 922 923SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const { 924 return DebugMatrixProc; 925} 926 927#endif 928 929/////////////////////////////////////////////////////////////////////////////// 930/* 931 The storage requirements for the different matrix procs are as follows, 932 where each X or Y is 2 bytes, and N is the number of pixels/elements: 933 934 scale/translate nofilter Y(4bytes) + N * X 935 affine/perspective nofilter N * (X Y) 936 scale/translate filter Y Y + N * (X X) 937 affine/perspective filter N * (Y Y X X) 938 */ 939int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { 940 int32_t size = static_cast<int32_t>(bufferSize); 941 942 size &= ~3; // only care about 4-byte aligned chunks 943 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 944 size -= 4; // the shared Y (or YY) coordinate 945 if (size < 0) { 946 size = 0; 947 } 948 size >>= 1; 949 } else { 950 size >>= 2; 951 } 952 953 if (fFilterLevel != SkPaint::kNone_FilterLevel) { 954 size >>= 1; 955 } 956 957 return size; 958} 959