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