Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkBitmapCache.h" | 8 #include "SkBitmapCache.h" |
| 9 #include "SkBitmapProcState.h" | 9 #include "SkBitmapProcState.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 return true; | 271 return true; |
| 272 } else { | 272 } else { |
| 273 // failed to extract, so release the mipmap | 273 // failed to extract, so release the mipmap |
| 274 fCurrMip.reset(NULL); | 274 fCurrMip.reset(NULL); |
| 275 } | 275 } |
| 276 } | 276 } |
| 277 | 277 |
| 278 return false; | 278 return false; |
| 279 } | 279 } |
| 280 | 280 |
| 281 /* | |
| 282 * Extract the "best" scale factors from a matrix. | |
| 283 */ | |
| 284 static bool extract_scale(const SkMatrix& matrix, SkVector* scale) { | |
| 285 SkASSERT(!matrix.hasPerspective()); | |
| 286 SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::k MSkewY]); | |
| 287 SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::k MScaleY]); | |
| 288 if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) || | |
| 289 SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) | |
| 290 { | |
| 291 return false; | |
| 292 } | |
| 293 scale->set(sx, sy); | |
| 294 return true; | |
| 295 } | |
| 296 | |
| 297 /* | |
|
robertphillips
2015/01/16 19:45:00
implemented
reed1
2015/01/16 19:48:20
Done.
| |
| 298 * High quality is implement by performing up-right scale-only filtering and th en | |
| 299 * using bilerp for any remaining transformations. | |
| 300 */ | |
| 301 void SkBitmapProcState::processHQRequest() { | |
| 302 SkASSERT(SkPaint::kHigh_FilterLevel == fFilterLevel); | |
| 303 | |
| 304 // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap | |
| 305 // to a valid bitmap. If we succeed, we will set this to Low instead. | |
| 306 fFilterLevel = SkPaint::kMedium_FilterLevel; | |
| 307 | |
| 308 if (kN32_SkColorType != fOrigBitmap.colorType() || !cache_size_okay(fOrigBit map, fInvMatrix) || | |
| 309 fInvMatrix.hasPerspective()) | |
| 310 { | |
| 311 return; // can't handle the reqeust | |
| 312 } | |
| 313 | |
| 314 SkScalar invScaleX = fInvMatrix.getScaleX(); | |
| 315 SkScalar invScaleY = fInvMatrix.getScaleY(); | |
| 316 if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) { | |
| 317 SkVector scale; | |
| 318 if (!extract_scale(fInvMatrix, &scale)) { | |
| 319 return; // can't find suitable scale factors | |
| 320 } | |
| 321 invScaleX = scale.x(); | |
| 322 invScaleY = scale.y(); | |
| 323 } | |
| 324 if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) { | |
| 325 return; // no need for HQ | |
| 326 } | |
| 327 | |
| 328 SkScalar trueDestWidth = fOrigBitmap.width() / invScaleX; | |
| 329 SkScalar trueDestHeight = fOrigBitmap.height() / invScaleY; | |
| 330 SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth); | |
| 331 SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight); | |
| 332 | |
| 333 if (!SkBitmapCache::Find(fOrigBitmap, roundedDestWidth, roundedDestHeight, & fScaledBitmap)) { | |
| 334 if (!SkBitmapScaler::Resize(&fScaledBitmap, | |
| 335 fOrigBitmap, | |
| 336 SkBitmapScaler::RESIZE_BEST, | |
| 337 roundedDestWidth, | |
| 338 roundedDestHeight, | |
| 339 SkResourceCache::GetAllocator())) { | |
| 340 return; // we failed to create fScaledBitmap | |
| 341 } | |
| 342 | |
| 343 SkASSERT(fScaledBitmap.getPixels()); | |
| 344 fScaledBitmap.setImmutable(); | |
| 345 SkBitmapCache::Add(fOrigBitmap, roundedDestWidth, roundedDestHeight, fSc aledBitmap); | |
| 346 } | |
| 347 | |
| 348 SkASSERT(fScaledBitmap.getPixels()); | |
| 349 fBitmap = &fScaledBitmap; | |
| 350 | |
| 351 fInvMatrix.postScale(roundedDestWidth / fOrigBitmap.width(), | |
| 352 roundedDestHeight / fOrigBitmap.height()); | |
| 353 fFilterLevel = SkPaint::kLow_FilterLevel; | |
| 354 } | |
| 355 | |
| 356 /* | |
| 357 * Modulo internal errors, this should always succeed *if* the matrix is downsc aling | |
| 358 * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscalin g) | |
| 359 */ | |
| 360 void SkBitmapProcState::processMediumRequest() { | |
| 361 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel); | |
| 362 | |
| 363 // Our default return state is to downgrade the request to Low, w/ or w/o se tting fBitmap | |
| 364 // to a valid bitmap. | |
| 365 fFilterLevel = SkPaint::kLow_FilterLevel; | |
| 366 | |
| 367 SkScalar invScaleSqd = effective_matrix_scale_sqrd(fInvMatrix); | |
| 368 | |
| 369 if (invScaleSqd > SK_Scalar1) { | |
| 370 fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap)); | |
| 371 if (NULL == fCurrMip.get()) { | |
| 372 fCurrMip.reset(SkMipMapCache::AddAndRef(fOrigBitmap)); | |
| 373 if (NULL == fCurrMip.get()) { | |
| 374 return; | |
| 375 } | |
| 376 } | |
| 377 // diagnostic for a crasher... | |
| 378 if (NULL == fCurrMip->data()) { | |
| 379 sk_throw(); | |
| 380 } | |
| 381 | |
| 382 SkScalar levelScale = SkScalarInvert(SkScalarSqrt(invScaleSqd)); | |
| 383 SkMipMap::Level level; | |
| 384 if (fCurrMip->extractLevel(levelScale, &level)) { | |
| 385 SkScalar invScaleFixup = level.fScale; | |
| 386 fInvMatrix.postScale(invScaleFixup, invScaleFixup); | |
| 387 | |
| 388 const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, lev el.fHeight); | |
| 389 // todo: if we could wrap the fCurrMip in a pixelref, then we could just install | |
| 390 // that here, and not need to explicitly track it ourselves. | |
| 391 fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes); | |
| 392 fBitmap = &fScaledBitmap; | |
| 393 } else { | |
| 394 // failed to extract, so release the mipmap | |
| 395 fCurrMip.reset(NULL); | |
| 396 } | |
| 397 } | |
| 398 } | |
| 399 | |
| 281 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { | 400 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { |
| 282 SkPixelRef* pr = src.pixelRef(); | 401 SkPixelRef* pr = src.pixelRef(); |
| 283 if (pr && pr->decodeInto(pow2, dst)) { | 402 if (pr && pr->decodeInto(pow2, dst)) { |
| 284 return true; | 403 return true; |
| 285 } | 404 } |
| 286 | 405 |
| 287 /* | 406 /* |
| 288 * If decodeInto() fails, it is possibe that we have an old subclass that | 407 * If decodeInto() fails, it is possibe that we have an old subclass that |
| 289 * does not, or cannot, implement that. In that case we fall back to the | 408 * does not, or cannot, implement that. In that case we fall back to the |
| 290 * older protocol of having the pixelRef handle the caching for us. | 409 * older protocol of having the pixelRef handle the caching for us. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 } | 456 } |
| 338 if (kIndex_8_SkColorType == bm.colorType()) { | 457 if (kIndex_8_SkColorType == bm.colorType()) { |
| 339 SkAutoLockPixels alp(bm); // but we need to call it before getColorTable () is safe. | 458 SkAutoLockPixels alp(bm); // but we need to call it before getColorTable () is safe. |
| 340 if (!bm.getColorTable()) { | 459 if (!bm.getColorTable()) { |
| 341 return false; | 460 return false; |
| 342 } | 461 } |
| 343 } | 462 } |
| 344 return true; | 463 return true; |
| 345 } | 464 } |
| 346 | 465 |
| 466 /* | |
| 467 * Analyze filter-quality and matrix, and decide how to implement that. | |
| 468 * | |
| 469 * In general, we cascade down the request level [ High ... None ] | |
| 470 * - for a given level, if we can fullfil it, fine, else | |
| 471 * - else we downgrade to the next lower level and try again. | |
|
robertphillips
2015/01/16 19:44:59
fulfill
| |
| 472 * We can always fullfil requests for Low and None | |
|
robertphillips
2015/01/16 19:45:00
and given ?
reed1
2015/01/16 19:48:20
Done.
| |
| 473 * - sometimes we will "ignore" Low and given none, but this is likely a legacy perf hack | |
| 474 * and may be removed. | |
| 475 */ | |
| 347 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { | 476 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| 348 if (!valid_for_drawing(fOrigBitmap)) { | 477 if (!valid_for_drawing(fOrigBitmap)) { |
| 349 return false; | 478 return false; |
| 350 } | 479 } |
| 351 | 480 |
| 352 fBitmap = NULL; | 481 fBitmap = NULL; |
| 353 fInvMatrix = inv; | 482 fInvMatrix = inv; |
| 354 fFilterLevel = paint.getFilterLevel(); | 483 fFilterLevel = paint.getFilterLevel(); |
| 355 | 484 |
| 485 #ifdef SK_SUPPORT_LEGACY_HQ_SCALING | |
| 356 // possiblyScaleImage will look to see if it can rescale the image as a | 486 // possiblyScaleImage will look to see if it can rescale the image as a |
| 357 // preprocess; either by scaling up to the target size, or by selecting | 487 // preprocess; either by scaling up to the target size, or by selecting |
| 358 // a nearby mipmap level. If it does, it will adjust the working | 488 // a nearby mipmap level. If it does, it will adjust the working |
| 359 // matrix as well as the working bitmap. It may also adjust the filter | 489 // matrix as well as the working bitmap. It may also adjust the filter |
| 360 // quality to avoid re-filtering an already perfectly scaled image. | 490 // quality to avoid re-filtering an already perfectly scaled image. |
| 361 if (!this->possiblyScaleImage()) { | 491 if (!this->possiblyScaleImage()) { |
| 362 if (!this->lockBaseBitmap()) { | 492 if (!this->lockBaseBitmap()) { |
| 363 return false; | 493 return false; |
| 364 } | 494 } |
| 365 } | 495 } |
| 366 // The above logic should have always assigned fBitmap, but in case it | 496 // The above logic should have always assigned fBitmap, but in case it |
| 367 // didn't, we check for that now... | 497 // didn't, we check for that now... |
| 368 // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)? | 498 // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)? |
| 369 if (NULL == fBitmap) { | 499 if (NULL == fBitmap) { |
| 370 return false; | 500 return false; |
| 371 } | 501 } |
| 372 | 502 |
| 373 // If we are "still" kMedium_FilterLevel, then the request was not fulfilled by possiblyScale, | 503 // If we are "still" kMedium_FilterLevel, then the request was not fulfilled by possiblyScale, |
| 374 // so we downgrade to kLow (so the rest of the sniffing code can assume that ) | 504 // so we downgrade to kLow (so the rest of the sniffing code can assume that ) |
| 375 if (SkPaint::kMedium_FilterLevel == fFilterLevel) { | 505 if (SkPaint::kMedium_FilterLevel == fFilterLevel) { |
| 376 fFilterLevel = SkPaint::kLow_FilterLevel; | 506 fFilterLevel = SkPaint::kLow_FilterLevel; |
| 377 } | 507 } |
| 508 #else | |
| 509 if (SkPaint::kHigh_FilterLevel == fFilterLevel) { | |
| 510 this->processHQRequest(); | |
| 511 } | |
| 512 SkASSERT(fFilterLevel < SkPaint::kHigh_FilterLevel); | |
| 513 | |
| 514 if (SkPaint::kMedium_FilterLevel == fFilterLevel) { | |
| 515 this->processMediumRequest(); | |
| 516 } | |
| 517 SkASSERT(fFilterLevel < SkPaint::kMedium_FilterLevel); | |
| 518 | |
| 519 if (NULL == fBitmap) { | |
| 520 if (!this->lockBaseBitmap()) { | |
| 521 return false; | |
| 522 } | |
| 523 } | |
| 524 SkASSERT(fBitmap); | |
| 525 #endif | |
| 378 | 526 |
| 379 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; | 527 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; |
| 380 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && | 528 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && |
| 381 SkShader::kClamp_TileMode == fTileModeY; | 529 SkShader::kClamp_TileMode == fTileModeY; |
| 382 | 530 |
| 383 // Most of the scanline procs deal with "unit" texture coordinates, as this | 531 // Most of the scanline procs deal with "unit" texture coordinates, as this |
| 384 // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generat e | 532 // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generat e |
| 385 // those, we divide the matrix by its dimensions here. | 533 // those, we divide the matrix by its dimensions here. |
| 386 // | 534 // |
| 387 // We don't do this if we're either trivial (can ignore the matrix) or clamp ing | 535 // We don't do this if we're either trivial (can ignore the matrix) or clamp ing |
| 388 // in both X and Y since clamping to width,height is just as easy as to 0xFF FF. | 536 // in both X and Y since clamping to width,height is just as easy as to 0xFF FF. |
| 389 | 537 |
| 390 if (!(clampClamp || trivialMatrix)) { | 538 if (!(clampClamp || trivialMatrix)) { |
| 391 fInvMatrix.postIDiv(fBitmap->width(), fBitmap->height()); | 539 fInvMatrix.postIDiv(fBitmap->width(), fBitmap->height()); |
| 392 } | 540 } |
| 393 | 541 |
| 394 // Now that all possible changes to the matrix have taken place, check | 542 // Now that all possible changes to the matrix have taken place, check |
| 395 // to see if we're really close to a no-scale matrix. If so, explicitly | 543 // to see if we're really close to a no-scale matrix. If so, explicitly |
| 396 // set it to be so. Subsequent code may inspect this matrix to choose | 544 // set it to be so. Subsequent code may inspect this matrix to choose |
| 397 // a faster path in this case. | 545 // a faster path in this case. |
| 398 | 546 |
| 399 // This code will only execute if the matrix has some scale component; | 547 // This code will only execute if the matrix has some scale component; |
| 400 // if it's already pure translate then we won't do this inversion. | 548 // if it's already pure translate then we won't do this inversion. |
| 401 | 549 |
| 402 if (matrix_only_scale_translate(fInvMatrix)) { | 550 if (matrix_only_scale_translate(fInvMatrix)) { |
| 403 SkMatrix forward; | 551 SkMatrix forward; |
| 404 if (fInvMatrix.invert(&forward)) { | 552 if (fInvMatrix.invert(&forward)) { |
| 405 if (clampClamp ? just_trans_clamp(forward, *fBitmap) | 553 if (clampClamp ? just_trans_clamp(forward, *fBitmap) |
| 406 : just_trans_general(forward)) { | 554 : just_trans_general(forward)) { |
| 407 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); | 555 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); |
| 408 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); | 556 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); |
| 409 fInvMatrix.setTranslate(tx, ty); | 557 fInvMatrix.setTranslate(tx, ty); |
| 410 } | 558 } |
| 411 } | 559 } |
| 412 } | 560 } |
| 413 | 561 |
| 414 fInvProc = fInvMatrix.getMapXYProc(); | 562 fInvProc = fInvMatrix.getMapXYProc(); |
| 415 fInvType = fInvMatrix.getType(); | 563 fInvType = fInvMatrix.getType(); |
| 416 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX()); | 564 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX()); |
| 417 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX()); | 565 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX()); |
| 418 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY()); | 566 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY()); |
| 419 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY()); | 567 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY()); |
| 420 | 568 |
| 421 fAlphaScale = SkAlpha255To256(paint.getAlpha()); | 569 fAlphaScale = SkAlpha255To256(paint.getAlpha()); |
| 422 | 570 |
| 423 fShaderProc32 = NULL; | 571 fShaderProc32 = NULL; |
| 424 fShaderProc16 = NULL; | 572 fShaderProc16 = NULL; |
| 425 fSampleProc32 = NULL; | 573 fSampleProc32 = NULL; |
| 426 fSampleProc16 = NULL; | 574 fSampleProc16 = NULL; |
| 427 | 575 |
| 428 // recompute the triviality of the matrix here because we may have | 576 // recompute the triviality of the matrix here because we may have |
| 429 // changed it! | 577 // changed it! |
| 430 | 578 |
| 431 trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; | 579 trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; |
| 432 | 580 |
| 433 if (SkPaint::kHigh_FilterLevel == fFilterLevel) { | 581 if (SkPaint::kHigh_FilterLevel == fFilterLevel) { |
| 434 // If this is still set, that means we wanted HQ sampling | 582 // If this is still set, that means we wanted HQ sampling |
| 435 // but couldn't do it as a preprocess. Let's try to install | 583 // but couldn't do it as a preprocess. Let's try to install |
| 436 // the scanline version of the HQ sampler. If that process fails, | 584 // the scanline version of the HQ sampler. If that process fails, |
| 437 // downgrade to bilerp. | 585 // downgrade to bilerp. |
| 438 | 586 |
| 439 // NOTE: Might need to be careful here in the future when we want | 587 // NOTE: Might need to be careful here in the future when we want |
| 440 // to have the platform proc have a shot at this; it's possible that | 588 // to have the platform proc have a shot at this; it's possible that |
| 441 // the chooseBitmapFilterProc will fail to install a shader but a | 589 // the chooseBitmapFilterProc will fail to install a shader but a |
| 442 // platform-specific one might succeed, so it might be premature here | 590 // platform-specific one might succeed, so it might be premature here |
| 443 // to fall back to bilerp. This needs thought. | 591 // to fall back to bilerp. This needs thought. |
| 444 | 592 |
| 445 if (!this->setBitmapFilterProcs()) { | 593 if (!this->setBitmapFilterProcs()) { |
| 446 fFilterLevel = SkPaint::kLow_FilterLevel; | 594 fFilterLevel = SkPaint::kLow_FilterLevel; |
| 447 } | 595 } |
| 448 } | 596 } |
| 449 | 597 |
| 450 if (SkPaint::kLow_FilterLevel == fFilterLevel) { | 598 if (SkPaint::kLow_FilterLevel == fFilterLevel) { |
| 451 // Only try bilerp if the matrix is "interesting" and | 599 // Only try bilerp if the matrix is "interesting" and |
| 452 // the image has a suitable size. | 600 // the image has a suitable size. |
| 453 | 601 |
| 454 if (fInvType <= SkMatrix::kTranslate_Mask || | 602 if (fInvType <= SkMatrix::kTranslate_Mask || |
| 455 !valid_for_filtering(fBitmap->width() | fBitmap->height())) { | 603 !valid_for_filtering(fBitmap->width() | fBitmap->height())) |
| 604 { | |
| 456 fFilterLevel = SkPaint::kNone_FilterLevel; | 605 fFilterLevel = SkPaint::kNone_FilterLevel; |
| 457 } | 606 } |
| 458 } | 607 } |
| 459 | 608 |
| 460 return this->chooseScanlineProcs(trivialMatrix, clampClamp, paint); | 609 return this->chooseScanlineProcs(trivialMatrix, clampClamp, paint); |
| 461 } | 610 } |
| 462 | 611 |
| 463 bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp, | 612 bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp, |
| 464 const SkPaint& paint) { | 613 const SkPaint& paint) { |
| 465 fMatrixProc = this->chooseMatrixProc(trivialMatrix); | 614 fMatrixProc = this->chooseMatrixProc(trivialMatrix); |
| (...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1086 fx += dx; | 1235 fx += dx; |
| 1087 } | 1236 } |
| 1088 } else { | 1237 } else { |
| 1089 for (int i = 0; i < count; ++i) { | 1238 for (int i = 0; i < count; ++i) { |
| 1090 dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)]; | 1239 dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)]; |
| 1091 fx += dx; | 1240 fx += dx; |
| 1092 } | 1241 } |
| 1093 } | 1242 } |
| 1094 } | 1243 } |
| 1095 | 1244 |
| OLD | NEW |