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