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