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

Unified Diff: src/core/SkBitmapProcState.cpp

Issue 19825002: stop using bitmap-filter flags outside of paint itself, as a step towards really changing them into… (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkBitmapProcState.h ('k') | src/core/SkBitmapProcState_matrixProcs.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkBitmapProcState.cpp
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index ebb010fd0a656c1ff6f996fd30cb8513e4c9f723..2298398bd5dca47028db1b14fc7df41d92802623 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -91,13 +91,26 @@ static bool valid_for_filtering(unsigned dimension) {
return (dimension & ~0x3FFF) == 0;
}
+static bool effective_matrix_scale_sqrd(const SkMatrix& mat) {
+ SkPoint v1, v2;
+
+ v1.fX = mat.getScaleX();
+ v1.fY = mat.getSkewY();
+
+ v2.fX = mat.getSkewX();
+ v2.fY = mat.getScaleY();
+
+ return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
+}
+
// TODO -- we may want to pass the clip into this function so we only scale
// the portion of the image that we're going to need. This will complicate
// the interface to the cache, but might be well worth it.
void SkBitmapProcState::possiblyScaleImage() {
- if (fFilterQuality != kHQ_BitmapFilter) {
+ if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
+ // none or low (bilerp) does not need to look any further
return;
}
@@ -125,7 +138,7 @@ void SkBitmapProcState::possiblyScaleImage() {
// doing high quality scaling. If so, do the bitmap scale here and
// remove the scaling component from the matrix.
- if (fFilterQuality == kHQ_BitmapFilter &&
+ if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) {
@@ -148,55 +161,73 @@ void SkBitmapProcState::possiblyScaleImage() {
// no need for any further filtering; we just did it!
- fFilterQuality = kNone_BitmapFilter;
+ fFilterLevel = SkPaint::kNone_FilterLevel;
return;
}
- if (!fOrigBitmap.hasMipMap() && fFilterQuality != kNone_BitmapFilter) {
-
- // STEP 2: MIPMAP DOWNSAMPLE?
-
- // Check to see if the transformation matrix is scaling *down*.
- // If so, automatically build mipmaps.
-
- SkPoint v1, v2;
-
- // conservatively estimate if the matrix is scaling down by seeing
- // what its upper left 2x2 portion does to two unit vectors.
+ /*
+ * If we get here, the caller has requested either Med or High filter-level
+ *
+ * If High, then our special-case for scale-only did not take, and so we
+ * have to make a choice:
+ * 1. fall back on mipmaps + bilerp
+ * 2. fall back on scanline bicubic filter
+ * For now, we compute the "scale" value from the matrix, and have a
+ * threshold to decide when bicubic is better, and when mips are better.
+ * No doubt a fancier decision tree could be used uere.
+ *
+ * If Medium, then we just try to build a mipmap and select a level,
+ * setting the filter-level to kLow to signal that we just need bilerp
+ * to process the selected level.
+ */
- v1.fX = fInvMatrix.getScaleX();
- v1.fY = fInvMatrix.getSkewY();
+ SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
+
+ if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
+ // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
+ // than this, then the mipmaps quality may be greater (certainly faster)
+ // so we only keep High quality if the scale is greater than this.
+ //
+ // Since we're dealing with the inverse, we compare against its inverse.
+ const SkScalar bicubicLimit = SkFloatToScalar(4.0f);
+ const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
+ if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline
+ return;
+ }
- v2.fX = fInvMatrix.getSkewX();
- v2.fY = fInvMatrix.getScaleY();
+ // else set the filter-level to Medium, since we're scaling down and
+ // want to reqeust mipmaps
+ fFilterLevel = SkPaint::kMedium_FilterLevel;
+ }
+
+ SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
- if (v1.fX * v1.fX + v1.fY * v1.fY > 1 ||
- v2.fX * v2.fX + v2.fY * v2.fY > 1) {
+ /**
+ * Medium quality means use a mipmap for down-scaling, and just bilper
+ * for upscaling. Since we're examining the inverse matrix, we look for
+ * a scale > 1 to indicate down scaling by the CTM.
+ */
+ if (scaleSqd > SK_Scalar1) {
+ if (!fOrigBitmap.hasMipMap()) {
fOrigBitmap.buildMipMap();
-
- // Now that we've built the mipmaps and we know we're downsampling,
- // downgrade to bilinear interpolation for the mip level.
-
- fFilterQuality = kBilerp_BitmapFilter;
+ // build may fail, so we need to check again
}
- }
-
- if (fOrigBitmap.hasMipMap()) {
-
- // STEP 3: We've got mipmaps, let's choose the closest level as our render
- // source and adjust the matrix accordingly.
-
- int shift = fOrigBitmap.extractMipLevel(&fScaledBitmap,
- SkScalarToFixed(fInvMatrix.getScaleX()),
- SkScalarToFixed(fInvMatrix.getSkewY()));
-
- if (shift > 0) {
- SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
- fInvMatrix.postScale(scale, scale);
- fBitmap = &fScaledBitmap;
+ if (fOrigBitmap.hasMipMap()) {
+ int shift = fOrigBitmap.extractMipLevel(&fScaledBitmap,
+ SkScalarToFixed(fInvMatrix.getScaleX()),
+ SkScalarToFixed(fInvMatrix.getSkewY()));
+ if (shift > 0) {
+ SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
+ fInvMatrix.postScale(scale, scale);
+ fBitmap = &fScaledBitmap;
+ }
}
}
+
+ // Now that we've built the mipmaps (if applicable), we set the filter-level
+ // bilinear interpolation.
+ fFilterLevel = SkPaint::kLow_FilterLevel;
}
void SkBitmapProcState::endContext() {
@@ -225,14 +256,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
// We may downgrade it later if we determine that we either don't need
// or can't provide as high a quality filtering as the user requested.
- fFilterQuality = kNone_BitmapFilter;
- if (paint.isFilterBitmap()) {
- if (paint.getFlags() & SkPaint::kHighQualityFilterBitmap_Flag) {
- fFilterQuality = kHQ_BitmapFilter;
- } else {
- fFilterQuality = kBilerp_BitmapFilter;
- }
- }
+ fFilterLevel = paint.getFilterLevel();
#ifndef SK_IGNORE_IMAGE_PRESCALE
// possiblyScaleImage will look to see if it can rescale the image as a
@@ -284,7 +308,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
- if (kHQ_BitmapFilter == fFilterQuality) {
+ if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
// If this is still set, that means we wanted HQ sampling
// but couldn't do it as a preprocess. Let's try to install
// the scanline version of the HQ sampler. If that process fails,
@@ -300,17 +324,17 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
fShaderProc32 = this->chooseBitmapFilterProc();
if (!fShaderProc32) {
- fFilterQuality = kBilerp_BitmapFilter;
+ fFilterLevel = SkPaint::kLow_FilterLevel;
}
}
- if (kBilerp_BitmapFilter == fFilterQuality) {
+ if (SkPaint::kLow_FilterLevel == fFilterLevel) {
// Only try bilerp if the matrix is "interesting" and
// the image has a suitable size.
if (fInvType <= SkMatrix::kTranslate_Mask ||
- !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
- fFilterQuality = kNone_BitmapFilter;
+ !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
+ fFilterLevel = SkPaint::kNone_FilterLevel;
}
}
@@ -328,7 +352,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
// still set to HQ by the time we get here, then we must have installed
// the shader proc above and can skip all this.
- if (fFilterQuality < kHQ_BitmapFilter) {
+ if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
int index = 0;
if (fAlphaScale < 256) { // note: this distinction is not used for D16
@@ -337,7 +361,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
index |= 2;
}
- if (fFilterQuality != kNone_BitmapFilter) {
+ if (fFilterLevel > SkPaint::kNone_FilterLevel) {
index |= 4;
}
// bits 3,4,5 encoding the source bitmap format
@@ -468,7 +492,7 @@ static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
SkASSERT(s.fInvKy == 0);
SkASSERT(count > 0 && colors != NULL);
- SkASSERT(SkBitmapProcState::kNone_BitmapFilter == s.fFilterQuality);
+ SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
const int maxX = s.fBitmap->width() - 1;
const int maxY = s.fBitmap->height() - 1;
@@ -542,7 +566,7 @@ static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
SkASSERT(s.fInvKy == 0);
SkASSERT(count > 0 && colors != NULL);
- SkASSERT(SkBitmapProcState::kNone_BitmapFilter == s.fFilterQuality);
+ SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
const int stopX = s.fBitmap->width();
const int stopY = s.fBitmap->height();
@@ -588,7 +612,7 @@ static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
int iY1 SK_INIT_TO_AVOID_WARNING;
int iSubY SK_INIT_TO_AVOID_WARNING;
- if (s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter) {
+ if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
uint32_t xy[2];
@@ -669,7 +693,7 @@ static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
SkPMColor color;
- if (s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter) {
+ if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
if (s.fAlphaScale < 256) {
@@ -725,7 +749,7 @@ SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
- if (kNone_BitmapFilter == fFilterQuality &&
+ if (SkPaint::kNone_FilterLevel == fFilterLevel &&
fInvType <= SkMatrix::kTranslate_Mask &&
!this->setupForTranslate()) {
return DoNothing_shaderproc;
@@ -739,7 +763,7 @@ SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
if (fInvType > SkMatrix::kTranslate_Mask) {
return NULL;
}
- if (fFilterQuality != kNone_BitmapFilter) {
+ if (SkPaint::kNone_FilterLevel != fFilterLevel) {
return NULL;
}
@@ -835,9 +859,9 @@ void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
// scale -vs- affine
// filter -vs- nofilter
if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
- proc = state.fFilterQuality != kNone_BitmapFilter ? check_scale_filter : check_scale_nofilter;
+ proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter;
} else {
- proc = state.fFilterQuality != kNone_BitmapFilter ? check_affine_filter : check_affine_nofilter;
+ proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
}
proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
}
@@ -872,7 +896,7 @@ int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
size >>= 2;
}
- if (fFilterQuality != kNone_BitmapFilter) {
+ if (fFilterLevel != SkPaint::kNone_FilterLevel) {
size >>= 1;
}
« no previous file with comments | « src/core/SkBitmapProcState.h ('k') | src/core/SkBitmapProcState_matrixProcs.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698