diff --git a/gm/filterbitmap.cpp b/gm/filterbitmap.cpp index 1ec6c8f378..efe4d4aa2b 100644 --- a/gm/filterbitmap.cpp +++ b/gm/filterbitmap.cpp @@ -23,8 +23,7 @@ static SkSize computeSize(const SkBitmap& bm, const SkMatrix& mat) { return SkSize::Make(bounds.width(), bounds.height()); } -static void draw_col(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& mat, - SkScalar dx) { +static void draw_row(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& mat, SkScalar dx) { SkPaint paint; SkAutoCanvasRestore acr(canvas, true); @@ -35,6 +34,10 @@ static void draw_col(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& mat, canvas->translate(dx, 0); canvas->drawBitmapMatrix(bm, mat, &paint); + paint.setFilterLevel(SkPaint::kMedium_FilterLevel); + canvas->translate(dx, 0); + canvas->drawBitmapMatrix(bm, mat, &paint); + paint.setFilterLevel(SkPaint::kHigh_FilterLevel); canvas->translate(dx, 0); canvas->drawBitmapMatrix(bm, mat, &paint); @@ -43,20 +46,23 @@ static void draw_col(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& mat, class FilterBitmapGM : public skiagm::GM { void onOnceBeforeDraw() { - make_bitmap(); + this->makeBitmap(); SkScalar cx = SkScalarHalf(fBM.width()); SkScalar cy = SkScalarHalf(fBM.height()); - SkScalar scale = get_scale(); - + SkScalar scale = this->getScale(); + // these two matrices use a scale factor configured by the subclass fMatrix[0].setScale(scale, scale); fMatrix[1].setRotate(30, cx, cy); fMatrix[1].postScale(scale, scale); + + // up/down scaling mix + fMatrix[2].setScale(0.7f, 1.05f); } public: SkBitmap fBM; - SkMatrix fMatrix[2]; + SkMatrix fMatrix[3]; SkString fName; FilterBitmapGM() @@ -70,11 +76,11 @@ protected: } virtual SkISize onISize() SK_OVERRIDE { - return SkISize::Make(920, 480); + return SkISize::Make(1024, 768); } - virtual void make_bitmap() = 0; - virtual SkScalar get_scale() = 0; + virtual void makeBitmap() = 0; + virtual SkScalar getScale() = 0; virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { @@ -84,7 +90,7 @@ protected: size.fWidth += 20; size.fHeight += 20; - draw_col(canvas, fBM, fMatrix[i], size.fWidth); + draw_row(canvas, fBM, fMatrix[i], size.fWidth); canvas->translate(0, size.fHeight); } } @@ -104,11 +110,11 @@ class FilterBitmapTextGM: public FilterBitmapGM { protected: float fTextSize; - SkScalar get_scale() SK_OVERRIDE { + SkScalar getScale() SK_OVERRIDE { return 32.f/fTextSize; } - void make_bitmap() SK_OVERRIDE { + void makeBitmap() SK_OVERRIDE { fBM.setConfig(SkBitmap::kARGB_8888_Config, int(fTextSize * 8), int(fTextSize * 6)); fBM.allocPixels(); SkCanvas canvas(fBM); @@ -144,11 +150,11 @@ class FilterBitmapCheckerboardGM: public FilterBitmapGM { int fSize; int fNumChecks; - SkScalar get_scale() SK_OVERRIDE { + SkScalar getScale() SK_OVERRIDE { return 192.f/fSize; } - void make_bitmap() SK_OVERRIDE { + void makeBitmap() SK_OVERRIDE { fBM.setConfig(SkBitmap::kARGB_8888_Config, fSize, fSize); fBM.allocPixels(); SkAutoLockPixels lock(fBM); @@ -181,11 +187,11 @@ class FilterBitmapImageGM: public FilterBitmapGM { SkString fFilename; int fSize; - SkScalar get_scale() SK_OVERRIDE { + SkScalar getScale() SK_OVERRIDE { return 192.f/fSize; } - void make_bitmap() SK_OVERRIDE { + void makeBitmap() SK_OVERRIDE { SkString path(skiagm::GM::gResourcePath); path.append("/"); path.append(fFilename); diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp index bb16119276..9a94676d6e 100644 --- a/src/core/SkBitmapProcShader.cpp +++ b/src/core/SkBitmapProcShader.cpp @@ -354,22 +354,36 @@ 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.getMinStretch(); + } else { + SkMatrix combined; + combined.setConcat(viewMatrix, localMatrix); + return combined.getMinStretch(); + } +} + GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const { SkMatrix matrix; matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); - SkMatrix inverse; - if (!this->getLocalMatrix().invert(&inverse)) { + SkMatrix lmInverse; + if (!this->getLocalMatrix().invert(&lmInverse)) { return NULL; } - matrix.preConcat(inverse); + matrix.preConcat(lmInverse); SkShader::TileMode tm[] = { (TileMode)fState.fTileModeX, (TileMode)fState.fTileModeY, }; - // Must set wrap and filter on the sampler before requesting a texture. + // Must set wrap and filter on the sampler before requesting a texture. In two places below + // 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(); GrTextureParams::FilterMode textureFilterMode; switch(paintFilterLevel) { @@ -380,21 +394,23 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& textureFilterMode = GrTextureParams::kBilerp_FilterMode; break; case SkPaint::kMedium_FilterLevel: - textureFilterMode = GrTextureParams::kMipMap_FilterMode; + if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) < + 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 the bicubic effect. This is an overly aggressive - // check for MIP fallbacks. It doesn't consider the fact that minification in the local - // matrix could be offset by the view matrix and vice versa. We also don't know whether - // the draw has explicit local coords (e.g. drawVertices) where the scale factor is - // unknown and varies. - if (context->getMatrix().getMinStretch() >= SK_Scalar1 && - this->getLocalMatrix().getMaxStretch() <= SK_Scalar1) { - // fall back to no filtering here; we will install another - // shader that will do the HQ filtering. + // 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. + // Fall back to MIP-mapping. paintFilterLevel = SkPaint::kMedium_FilterLevel; textureFilterMode = GrTextureParams::kMipMap_FilterMode; } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index a0692d09b2..71d0ebf29e 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1204,9 +1204,14 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, break; case SkPaint::kMedium_FilterLevel: tileFilterPad = 1; - textureFilterMode = GrTextureParams::kMipMap_FilterMode; + if (fContext->getMatrix().getMinStretch() < SK_Scalar1) { + textureFilterMode = GrTextureParams::kMipMap_FilterMode; + } else { + // Don't trigger MIP level generation unnecessarily. + textureFilterMode = GrTextureParams::kBilerp_FilterMode; + } break; - case SkPaint::kHigh_FilterLevel: { + case SkPaint::kHigh_FilterLevel: // Minification can look bad with the bicubic effect. if (fContext->getMatrix().getMinStretch() >= SK_Scalar1) { // We will install an effect that does the filtering in the shader. @@ -1214,13 +1219,10 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, tileFilterPad = GrBicubicEffect::kFilterTexelPad; doBicubic = true; } else { - // We don't yet support doing bicubic filtering with an interior clamp. Fall back - // to MIPs textureFilterMode = GrTextureParams::kMipMap_FilterMode; tileFilterPad = 1; } break; - } default: SkErrorInternals::SetError( kInvalidPaint_SkError, "Sorry, I don't understand the filtering "