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