Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(360)

Side by Side Diff: src/core/SkBitmapProcState.cpp

Issue 844913004: reorg filter quality cascade (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: more misspelling Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkBitmapProcState.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 /*
298 * High quality is implemented by performing up-right scale-only filtering and then
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
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 fulfill it, fine, else
471 * - else we downgrade to the next lower level and try again.
472 * We can always fulfill requests for Low and None
473 * - sometimes we will "ignore" Low and give 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
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
OLDNEW
« no previous file with comments | « src/core/SkBitmapProcState.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698