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