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

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