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) { | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |