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