aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--expectations/gm/ignored-tests.txt7
-rw-r--r--src/core/SkBitmapProcShader.cpp42
-rw-r--r--src/gpu/SkGpuDevice.cpp24
-rw-r--r--src/gpu/effects/GrBicubicEffect.cpp33
-rw-r--r--src/gpu/effects/GrBicubicEffect.h10
5 files changed, 73 insertions, 43 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index f78b79ac44..c134382420 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -45,3 +45,10 @@ ninepatch-stretch
# humper: https://codereview.chromium.org/292773003/
# changed texture coordinate generation for GPU rrect blur; will rebaseline after land.
simpleblurroundrect
+
+# bsalomon: https://codereview.chromium.org/282293004/
+# Conditionally fallback from bicubic filtering based on matrix.
+downsamplebitmap_checkerboard_high_512_256
+downsamplebitmap_image_high_mandrill_512.png
+filterbitmap_checkerboard_192_192
+downsamplebitmap_text_high_72.00pt \ No newline at end of file
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index 3ac26f0a19..8e25530cee 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -382,17 +382,6 @@ void SkBitmapProcShader::toString(SkString* str) const {
#include "effects/GrSimpleTextureEffect.h"
#include "SkGr.h"
-// Note that this will return -1 if either matrix is perspective.
-static SkScalar get_combined_min_stretch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix) {
- if (localMatrix.isIdentity()) {
- return viewMatrix.getMinScale();
- } else {
- SkMatrix combined;
- combined.setConcat(viewMatrix, localMatrix);
- return combined.getMinScale();
- }
-}
-
GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint,
const SkMatrix* localMatrix) const {
SkMatrix matrix;
@@ -420,37 +409,32 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
// we check the matrix scale factors to determine how to interpret the filter quality setting.
// This completely ignores the complexity of the drawVertices case where explicit local coords
// are provided by the caller.
- SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
+ bool useBicubic = false;
GrTextureParams::FilterMode textureFilterMode;
- switch(paintFilterLevel) {
+ switch(paint.getFilterLevel()) {
case SkPaint::kNone_FilterLevel:
textureFilterMode = GrTextureParams::kNone_FilterMode;
break;
case SkPaint::kLow_FilterLevel:
textureFilterMode = GrTextureParams::kBilerp_FilterMode;
break;
- case SkPaint::kMedium_FilterLevel:
- if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) <
- SK_Scalar1) {
+ case SkPaint::kMedium_FilterLevel: {
+ SkMatrix matrix;
+ matrix.setConcat(context->getMatrix(), this->getLocalMatrix());
+ if (matrix.getMinScale() < SK_Scalar1) {
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
} else {
// Don't trigger MIP level generation unnecessarily.
textureFilterMode = GrTextureParams::kBilerp_FilterMode;
}
break;
- case SkPaint::kHigh_FilterLevel:
- // Minification can look bad with bicubic filtering.
- if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) >=
- SK_Scalar1) {
- // fall back to no filtering here; we will install another shader that will do the
- // HQ filtering.
- textureFilterMode = GrTextureParams::kNone_FilterMode;
- } else {
- // Fall back to MIP-mapping.
- paintFilterLevel = SkPaint::kMedium_FilterLevel;
- textureFilterMode = GrTextureParams::kMipMap_FilterMode;
- }
+ }
+ case SkPaint::kHigh_FilterLevel: {
+ SkMatrix matrix;
+ matrix.setConcat(context->getMatrix(), this->getLocalMatrix());
+ useBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
break;
+ }
default:
SkErrorInternals::SetError( kInvalidPaint_SkError,
"Sorry, I don't understand the filtering "
@@ -470,7 +454,7 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
}
GrEffectRef* effect = NULL;
- if (paintFilterLevel == SkPaint::kHigh_FilterLevel) {
+ if (useBicubic) {
effect = GrBicubicEffect::Create(texture, matrix, tm);
} else {
effect = GrSimpleTextureEffect::Create(texture, matrix, params);
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index cddf50a98c..ec471ecc68 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1170,20 +1170,16 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
GrTextureParams::FilterMode textureFilterMode;
- int tileFilterPad;
bool doBicubic = false;
switch(paintFilterLevel) {
case SkPaint::kNone_FilterLevel:
- tileFilterPad = 0;
textureFilterMode = GrTextureParams::kNone_FilterMode;
break;
case SkPaint::kLow_FilterLevel:
- tileFilterPad = 1;
textureFilterMode = GrTextureParams::kBilerp_FilterMode;
break;
case SkPaint::kMedium_FilterLevel:
- tileFilterPad = 1;
if (fContext->getMatrix().getMinScale() < SK_Scalar1) {
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
} else {
@@ -1193,26 +1189,26 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
break;
case SkPaint::kHigh_FilterLevel:
// Minification can look bad with the bicubic effect.
- if (fContext->getMatrix().getMinScale() >= SK_Scalar1) {
- // We will install an effect that does the filtering in the shader.
- textureFilterMode = GrTextureParams::kNone_FilterMode;
- tileFilterPad = GrBicubicEffect::kFilterTexelPad;
- doBicubic = true;
- } else {
- textureFilterMode = GrTextureParams::kMipMap_FilterMode;
- tileFilterPad = 1;
- }
+ doBicubic =
+ GrBicubicEffect::ShouldUseBicubic(fContext->getMatrix(), &textureFilterMode);
break;
default:
SkErrorInternals::SetError( kInvalidPaint_SkError,
"Sorry, I don't understand the filtering "
"mode you asked for. Falling back to "
"MIPMaps.");
- tileFilterPad = 1;
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
break;
}
+ int tileFilterPad;
+ if (doBicubic) {
+ tileFilterPad = GrBicubicEffect::kFilterTexelPad;
+ } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
+ tileFilterPad = 0;
+ } else {
+ tileFilterPad = 1;
+ }
params.setFilterMode(textureFilterMode);
int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 89124ff667..9c6d1a3f8c 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -177,3 +177,36 @@ GrEffectRef* GrBicubicEffect::TestCreate(SkRandom* random,
}
return GrBicubicEffect::Create(textures[texIdx], coefficients);
}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool GrBicubicEffect::ShouldUseBicubic(const SkMatrix& matrix,
+ GrTextureParams::FilterMode* filterMode) {
+ if (matrix.isIdentity()) {
+ *filterMode = GrTextureParams::kNone_FilterMode;
+ return false;
+ }
+
+ SkScalar scales[2];
+ if (!matrix.getMinMaxScales(scales) || scales[0] < SK_Scalar1) {
+ // Bicubic doesn't handle arbitrary minimization well, as src texels can be skipped
+ // entirely,
+ *filterMode = GrTextureParams::kMipMap_FilterMode;
+ return false;
+ }
+ // At this point if scales[1] == SK_Scalar1 then the matrix doesn't do any scaling.
+ if (scales[1] == SK_Scalar1) {
+ if (matrix.rectStaysRect() && SkScalarIsInt(matrix.getTranslateX()) &&
+ SkScalarIsInt(matrix.getTranslateY())) {
+ *filterMode = GrTextureParams::kNone_FilterMode;
+ } else {
+ // Use bilerp to handle rotation or fractional translation.
+ *filterMode = GrTextureParams::kBilerp_FilterMode;
+ }
+ return false;
+ }
+ // When we use the bicubic filtering effect each sample is read from the texture using
+ // nearest neighbor sampling.
+ *filterMode = GrTextureParams::kNone_FilterMode;
+ return true;
+}
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index cc8b120863..1998e68780 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -78,6 +78,16 @@ public:
return CreateEffectRef(effect);
}
+ /**
+ * Determines whether the bicubic effect should be used based on the transformation from the
+ * local coords to the device. Returns true if the bicubic effect should be used. filterMode
+ * is set to appropriate filtering mode to use regardless of the return result (e.g. when this
+ * returns false it may indicate that the best fallback is to use kMipMap, kBilerp, or
+ * kNearest).
+ */
+ static bool ShouldUseBicubic(const SkMatrix& localCoordsToDevice,
+ GrTextureParams::FilterMode* filterMode);
+
private:
GrBicubicEffect(GrTexture*, const SkScalar coefficients[16],
const SkMatrix &matrix, const SkShader::TileMode tileModes[2]);