Tweaks in how to apply bitmap filter levels in GPU.

Fix fallback to MIP from bicubic for bitmap shaders
Skip MIP level generation on GPU when not minifying
Add medium quality and mixed up/down matrix test cases to filterbitmap tests

R=robertphillips@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/103913012

git-svn-id: http://skia.googlecode.com/svn/trunk@12697 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2013-12-16 21:02:29 +00:00
parent 0207683157
commit 79b7eeebdf
3 changed files with 60 additions and 36 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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 "