Second attempt to land the integral image scaling change.

Scale all images to the nearest rounded integer, and if there's still
any scaling factor left over, pass it on to the subsequent bilerp code.
Should avoid artifacts when tiling scaled images.

Original CL received an LGTM from reed; new version disabled tiling
in the downsamplebitmap GM; I verified that this fixes the issue
we were seeing there on non-neon androids.

BUG=skia:2888
R=reed@android.com
TBR=reed

Author: humper@google.com

Review URL: https://codereview.chromium.org/514383003
This commit is contained in:
humper 2014-08-28 14:27:42 -07:00 committed by Commit bot
parent 0209e95cc2
commit d73c169637
6 changed files with 56 additions and 18 deletions

View File

@ -41,3 +41,20 @@ matrixconvolution
# Added as part of https://codereview.chromium.org/466363009/
fontcache
#humper: https://codereview.chromium.org/470233002/
downsamplebitmap_checkerboard_high_512_256
downsamplebitmap_image_high_mandrill_512.png
downsamplebitmap_text_high_72.00pt
filterbitmap_checkerboard_192_192
filterbitmap_checkerboard_32_2
filterbitmap_checkerboard_32_32
filterbitmap_checkerboard_32_8
filterbitmap_checkerboard_4_4
filterbitmap_image_mandrill_128.png
filterbitmap_image_mandrill_16.png
filterbitmap_image_mandrill_256.png
filterbitmap_image_mandrill_32.png
filterbitmap_image_mandrill_64.png
filterbitmap_text_3.00pt
filterbitmap_text_7.00pt

View File

@ -41,10 +41,7 @@ public:
protected:
virtual uint32_t onGetFlags() const SK_OVERRIDE {
if (SkPaint::kHigh_FilterLevel != fFilterLevel) {
return kSkipTiled_Flag;
}
return 0;
return kSkipTiled_Flag;
}
virtual SkString onShortName() SK_OVERRIDE {

View File

@ -13,6 +13,7 @@
# If these become 'permanent', they should be moved into skia_common.gypi
#
'skia_for_chromium_defines': [
'SK_IGNORE_PROPER_FRACTIONAL_SCALING',
'SK_SUPPORT_LEGACY_PICTURE_CLONE',
'SK_SUPPORT_LEGACY_GETDEVICE',
'SK_IGNORE_ETC1_SUPPORT',

View File

@ -129,21 +129,34 @@ static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
bool SkBitmapProcState::possiblyScaleImage() {
SkASSERT(NULL == fBitmap);
fAdjustedMatrix = false;
if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
return false;
}
// Check to see if the transformation matrix is simple, and if we're
// doing high quality scaling. If so, do the bitmap scale here and
// remove the scaling component from the matrix.
// remove the (non-fractional) scaling component from the matrix.
SkScalar invScaleX = fInvMatrix.getScaleX();
SkScalar invScaleY = fInvMatrix.getScaleY();
float trueDestWidth = fOrigBitmap.width() / invScaleX;
float trueDestHeight = fOrigBitmap.height() / invScaleY;
#ifndef SK_IGNORE_PROPER_FRACTIONAL_SCALING
float roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
float roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
#else
float roundedDestWidth = trueDestWidth;
float roundedDestHeight = trueDestHeight;
#endif
if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
kN32_SkColorType == fOrigBitmap.colorType() &&
cache_size_okay(fOrigBitmap, fInvMatrix)) {
SkScalar invScaleX = fInvMatrix.getScaleX();
SkScalar invScaleY = fInvMatrix.getScaleY();
if (SkScalarNearlyEqual(invScaleX,1.0f) &&
SkScalarNearlyEqual(invScaleY,1.0f)) {
// short-circuit identity scaling; the output is supposed to
@ -160,17 +173,14 @@ bool SkBitmapProcState::possiblyScaleImage() {
return false;
}
if (!SkBitmapCache::Find(fOrigBitmap, invScaleX, invScaleY, &fScaledBitmap)) {
float dest_width = fOrigBitmap.width() / invScaleX;
float dest_height = fOrigBitmap.height() / invScaleY;
if (!SkBitmapCache::Find(fOrigBitmap, roundedDestWidth, roundedDestHeight, &fScaledBitmap)) {
// All the criteria are met; let's make a new bitmap.
if (!SkBitmapScaler::Resize(&fScaledBitmap,
fOrigBitmap,
SkBitmapScaler::RESIZE_BEST,
dest_width,
dest_height,
roundedDestWidth,
roundedDestHeight,
SkResourceCache::GetAllocator())) {
// we failed to create fScaledBitmap, so just return and let
// the scanline proc handle it.
@ -179,7 +189,7 @@ bool SkBitmapProcState::possiblyScaleImage() {
}
SkASSERT(NULL != fScaledBitmap.getPixels());
SkBitmapCache::Add(fOrigBitmap, invScaleX, invScaleY, fScaledBitmap);
SkBitmapCache::Add(fOrigBitmap, roundedDestWidth, roundedDestHeight, fScaledBitmap);
}
SkASSERT(NULL != fScaledBitmap.getPixels());
@ -189,9 +199,19 @@ bool SkBitmapProcState::possiblyScaleImage() {
fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScaleX(),
fInvMatrix.getTranslateY() / fInvMatrix.getScaleY());
#ifndef SK_IGNORE_PROPER_FRACTIONAL_SCALING
// reintroduce any fractional scaling missed by our integral scale done above.
float fractionalScaleX = roundedDestWidth/trueDestWidth;
float fractionalScaleY = roundedDestHeight/trueDestHeight;
fInvMatrix.postScale(fractionalScaleX, fractionalScaleY);
#endif
fAdjustedMatrix = true;
// Set our filter level to low -- the only post-filtering this
// image might require is some interpolation if the translation
// is fractional.
// is fractional or if there's any remaining scaling to be done.
fFilterLevel = SkPaint::kLow_FilterLevel;
return true;
}
@ -347,7 +367,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
SkShader::kClamp_TileMode == fTileModeY;
if (!(clampClamp || trivialMatrix)) {
if (!(fAdjustedMatrix || clampClamp || trivialMatrix)) {
fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
}

View File

@ -141,6 +141,7 @@ private:
SkBitmap fScaledBitmap; // chooseProcs
SkAutoTUnref<const SkMipMap> fCurrMip;
bool fAdjustedMatrix; // set by possiblyScaleImage
MatrixProc chooseMatrixProc(bool trivial_matrix);
bool chooseProcs(const SkMatrix& inv, const SkPaint&);

View File

@ -17,7 +17,9 @@ static bool is_in_scaled_image_cache(const SkBitmap& orig,
SkScalar xScale,
SkScalar yScale) {
SkBitmap scaled;
return SkBitmapCache::Find(orig, SkScalarInvert(xScale), SkScalarInvert(yScale), &scaled);
float roundedImageWidth = SkScalarRoundToScalar(orig.width() * xScale);
float roundedImageHeight = SkScalarRoundToScalar(orig.height() * xScale);
return SkBitmapCache::Find(orig, roundedImageWidth, roundedImageHeight, &scaled);
}
// Draw a scaled bitmap, then return true iff it has been cached.