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