aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar humper@google.com <humper@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-09-04 19:23:53 +0000
committerGravatar humper@google.com <humper@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-09-04 19:23:53 +0000
commit3aad3b01afc77993ff051c02e49186294e312980 (patch)
tree2ea966765798c8e402b0cef6ec2399ba12ed0f37
parentf0595b39a97a1c53e47e179a8ee4fa35d9f00fa0 (diff)
add support for high quality image filtering on the GPU
R=bsalomon@google.com, reed@google.com Review URL: https://codereview.chromium.org/23779003 git-svn-id: http://skia.googlecode.com/svn/trunk@11087 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gm/tilemodes_scaled.cpp282
-rw-r--r--gyp/effects.gyp1
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/core/SkError.h7
-rw-r--r--src/core/SkBitmapProcShader.cpp23
-rw-r--r--src/effects/SkBicubicImageFilter.cpp201
-rw-r--r--src/gpu/effects/GrBicubicEffect.cpp175
-rw-r--r--src/gpu/effects/GrBicubicEffect.h69
9 files changed, 562 insertions, 199 deletions
diff --git a/gm/tilemodes_scaled.cpp b/gm/tilemodes_scaled.cpp
new file mode 100644
index 0000000000..63a4ef70a8
--- /dev/null
+++ b/gm/tilemodes_scaled.cpp
@@ -0,0 +1,282 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+
+// effects
+#include "SkGradientShader.h"
+#include "SkUnitMappers.h"
+#include "SkBlurDrawLooper.h"
+
+static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h) {
+ bm->setConfig(config, w, h);
+ bm->allocPixels();
+ bm->eraseColor(SK_ColorTRANSPARENT);
+
+ SkCanvas canvas(*bm);
+ SkPoint pts[] = { { 0, 0 }, { SkIntToScalar(w), SkIntToScalar(h)} };
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+ SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
+ SkPaint paint;
+
+ SkUnitMapper* um = NULL;
+
+ um = new SkCosineMapper;
+// um = new SkDiscreteMapper(12);
+
+ SkAutoUnref au(um);
+
+ paint.setDither(true);
+ paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
+ SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
+ canvas.drawPaint(paint);
+}
+
+static void setup(SkPaint* paint, const SkBitmap& bm, SkPaint::FilterLevel filter_level,
+ SkShader::TileMode tmx, SkShader::TileMode tmy) {
+ SkShader* shader = SkShader::CreateBitmapShader(bm, tmx, tmy);
+ paint->setShader(shader)->unref();
+ paint->setFilterLevel(filter_level);
+}
+
+static const SkBitmap::Config gConfigs[] = {
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kRGB_565_Config,
+};
+
+class ScaledTilingGM : public skiagm::GM {
+ SkBlurDrawLooper fLooper;
+public:
+ ScaledTilingGM(bool powerOfTwoSize)
+ : fLooper(SkIntToScalar(1), SkIntToScalar(2), SkIntToScalar(2), 0x88000000)
+ , fPowerOfTwoSize(powerOfTwoSize) {
+ }
+
+ SkBitmap fTexture[SK_ARRAY_COUNT(gConfigs)];
+
+protected:
+
+ enum {
+ kPOTSize = 4,
+ kNPOTSize = 3,
+ };
+
+ SkString onShortName() {
+ SkString name("scaled_tilemodes");
+ if (!fPowerOfTwoSize) {
+ name.append("_npot");
+ }
+ return name;
+ }
+
+ SkISize onISize() { return SkISize::Make(880, 760); }
+
+ virtual void onOnceBeforeDraw() SK_OVERRIDE {
+ int size = fPowerOfTwoSize ? kPOTSize : kNPOTSize;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+ makebm(&fTexture[i], gConfigs[i], size, size);
+ }
+ }
+
+ virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+
+ float scale = 32.f/kPOTSize;
+
+ int size = fPowerOfTwoSize ? kPOTSize : kNPOTSize;
+
+ SkRect r = { 0, 0, SkIntToScalar(size*2), SkIntToScalar(size*2) };
+
+ static const char* gConfigNames[] = { "8888" , "565", "4444" };
+
+ static const SkPaint::FilterLevel gFilterLevels[] =
+ { SkPaint::kNone_FilterLevel,
+ SkPaint::kLow_FilterLevel,
+ SkPaint::kMedium_FilterLevel,
+ SkPaint::kHigh_FilterLevel };
+ static const char* gFilterNames[] = { "None", "Low", "Medium", "High" };
+
+ static const SkShader::TileMode gModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode };
+ static const char* gModeNames[] = { "C", "R", "M" };
+
+ SkScalar y = SkIntToScalar(24);
+ SkScalar x = SkIntToScalar(10)/scale;
+
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+ SkPaint p;
+ SkString str;
+ p.setAntiAlias(true);
+ p.setDither(true);
+ p.setLooper(&fLooper);
+ str.printf("[%s,%s]", gModeNames[kx], gModeNames[ky]);
+
+ p.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawText(str.c_str(), str.size(), scale*(x + r.width()/2), y, p);
+
+ x += r.width() * 4 / 3;
+ }
+ }
+
+ y = SkIntToScalar(40) / scale;
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gFilterLevels); j++) {
+ x = SkIntToScalar(10)/scale;
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+ SkPaint paint;
+#if 1 // Temporary change to regen bitmap before each draw. This may help tracking down an issue
+ // on SGX where resizing NPOT textures to POT textures exhibits a driver bug.
+ if (!fPowerOfTwoSize) {
+ makebm(&fTexture[i], gConfigs[i], size, size);
+ }
+#endif
+ setup(&paint, fTexture[i], gFilterLevels[j], gModes[kx], gModes[ky]);
+ paint.setDither(true);
+
+ canvas->save();
+ canvas->scale(scale,scale);
+ canvas->translate(x, y);
+ canvas->drawRect(r, paint);
+ canvas->restore();
+
+ x += r.width() * 4 / 3;
+ }
+ }
+ {
+ SkPaint p;
+ SkString str;
+ p.setAntiAlias(true);
+ p.setLooper(&fLooper);
+ str.printf("%s, %s", gConfigNames[i], gFilterNames[j]);
+ canvas->drawText(str.c_str(), str.size(), scale*x, scale*(y + r.height() * 2 / 3), p);
+ }
+
+ y += r.height() * 4 / 3;
+ }
+ }
+ }
+
+private:
+ bool fPowerOfTwoSize;
+ typedef skiagm::GM INHERITED;
+};
+
+static const int gWidth = 32;
+static const int gHeight = 32;
+
+static SkShader* make_bm(SkShader::TileMode tx, SkShader::TileMode ty) {
+ SkBitmap bm;
+ makebm(&bm, SkBitmap::kARGB_8888_Config, gWidth, gHeight);
+ return SkShader::CreateBitmapShader(bm, tx, ty);
+}
+
+static SkShader* make_grad(SkShader::TileMode tx, SkShader::TileMode ty) {
+ SkPoint pts[] = { { 0, 0 }, { SkIntToScalar(gWidth), SkIntToScalar(gHeight)} };
+ SkPoint center = { SkIntToScalar(gWidth)/2, SkIntToScalar(gHeight)/2 };
+ SkScalar rad = SkIntToScalar(gWidth)/2;
+ SkColor colors[] = { 0xFFFF0000, 0xFF0044FF };
+
+ int index = (int)ty;
+ switch (index % 3) {
+ case 0:
+ return SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors), tx);
+ case 1:
+ return SkGradientShader::CreateRadial(center, rad, colors, NULL, SK_ARRAY_COUNT(colors), tx);
+ case 2:
+ return SkGradientShader::CreateSweep(center.fX, center.fY, colors, NULL, SK_ARRAY_COUNT(colors));
+ }
+
+ return NULL;
+}
+
+typedef SkShader* (*ShaderProc)(SkShader::TileMode, SkShader::TileMode);
+
+class ScaledTiling2GM : public skiagm::GM {
+ ShaderProc fProc;
+ SkString fName;
+public:
+ ScaledTiling2GM(ShaderProc proc, const char name[]) : fProc(proc) {
+ fName.printf("scaled_tilemode_%s", name);
+ }
+
+protected:
+ SkString onShortName() {
+ return fName;
+ }
+
+ SkISize onISize() { return SkISize::Make(880, 560); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->scale(SkIntToScalar(3)/2, SkIntToScalar(3)/2);
+
+ const SkScalar w = SkIntToScalar(gWidth);
+ const SkScalar h = SkIntToScalar(gHeight);
+ SkRect r = { -w, -h, w*2, h*2 };
+
+ static const SkShader::TileMode gModes[] = {
+ SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode
+ };
+ static const char* gModeNames[] = {
+ "Clamp", "Repeat", "Mirror"
+ };
+
+ SkScalar y = SkIntToScalar(24);
+ SkScalar x = SkIntToScalar(66);
+
+ SkPaint p;
+ p.setAntiAlias(true);
+ p.setTextAlign(SkPaint::kCenter_Align);
+
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ SkString str(gModeNames[kx]);
+ canvas->drawText(str.c_str(), str.size(), x + r.width()/2, y, p);
+ x += r.width() * 4 / 3;
+ }
+
+ y += SkIntToScalar(16) + h;
+ p.setTextAlign(SkPaint::kRight_Align);
+
+ for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+ x = SkIntToScalar(16) + w;
+
+ SkString str(gModeNames[ky]);
+ canvas->drawText(str.c_str(), str.size(), x, y + h/2, p);
+
+ x += SkIntToScalar(50);
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ SkPaint paint;
+ paint.setShader(fProc(gModes[kx], gModes[ky]))->unref();
+
+ canvas->save();
+ canvas->translate(x, y);
+ canvas->drawRect(r, paint);
+ canvas->restore();
+
+ x += r.width() * 4 / 3;
+ }
+ y += r.height() * 4 / 3;
+ }
+ }
+
+private:
+ typedef skiagm::GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM( return new ScaledTilingGM(true); )
+DEF_GM( return new ScaledTilingGM(false); )
+DEF_GM( return new ScaledTiling2GM(make_bm, "bitmap"); )
+DEF_GM( return new ScaledTiling2GM(make_grad, "gradient"); )
diff --git a/gyp/effects.gyp b/gyp/effects.gyp
index d0b8b4d774..d22debb757 100644
--- a/gyp/effects.gyp
+++ b/gyp/effects.gyp
@@ -16,6 +16,7 @@
],
'include_dirs': [
'../include/effects',
+ '../src/effects',
'../src/core',
],
'direct_dependent_settings': {
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index b2afc5ef12..52faae0448 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -122,6 +122,7 @@
'../gm/thinrects.cpp',
'../gm/thinstrokedrects.cpp',
'../gm/tilemodes.cpp',
+ '../gm/tilemodes_scaled.cpp',
'../gm/tinybitmap.cpp',
'../gm/twopointradial.cpp',
'../gm/typeface.cpp',
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 33fbfae637..d50d245ce4 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -134,6 +134,8 @@
'<(skia_src_path)/gpu/effects/GrBezierEffect.h',
'<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp',
'<(skia_src_path)/gpu/effects/GrConvolutionEffect.h',
+ '<(skia_src_path)/gpu/effects/GrBicubicEffect.cpp',
+ '<(skia_src_path)/gpu/effects/GrBicubicEffect.h',
'<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.cpp',
'<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.h',
'<(skia_src_path)/gpu/effects/GrSingleTextureEffect.cpp',
diff --git a/include/core/SkError.h b/include/core/SkError.h
index c5af46065f..f3f22e9aa0 100644
--- a/include/core/SkError.h
+++ b/include/core/SkError.h
@@ -47,7 +47,12 @@ enum SkError {
/** Skia failed while trying to consume some external resource.
*/
- kParseError_SkError
+ kParseError_SkError,
+
+ /** Something went wrong internally; could be resource exhaustion but
+ * will often be a bug.
+ */
+ kInternalError_SkError
};
/** Return the current per-thread error code. Error codes are "sticky"; they
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index 0e7ac6a277..70b5212b95 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -5,11 +5,14 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-#include "SkBitmapProcShader.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkPixelRef.h"
#include "SkErrorInternals.h"
+#include "SkBitmapProcShader.h"
+
+#include "effects/GrSimpleTextureEffect.h"
+#include "effects/GrBicubicEffect.h"
bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
switch (bm.config()) {
@@ -367,11 +370,9 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
break;
case SkPaint::kHigh_FilterLevel:
- SkErrorInternals::SetError( kInvalidPaint_SkError,
- "Sorry, I don't yet support high quality "
- "filtering on the GPU; falling back to "
- "MIPMaps.");
- textureFilterMode = GrTextureParams::kMipMap_FilterMode;
+ // fall back to no filtering here; we will install another
+ // shader that will do the HQ filtering.
+ textureFilterMode = GrTextureParams::kNone_FilterMode;
break;
default:
SkErrorInternals::SetError( kInvalidPaint_SkError,
@@ -386,11 +387,17 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
if (NULL == texture) {
- SkDebugf("Couldn't convert bitmap to texture.\n");
+ SkErrorInternals::SetError( kInternalError_SkError,
+ "Couldn't convert bitmap to texture.");
return NULL;
}
- GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params);
+ GrEffectRef* effect = NULL;
+ if (paintFilterLevel == SkPaint::kHigh_FilterLevel) {
+ effect = GrBicubicEffect::Create(texture, matrix, params);
+ } else {
+ effect = GrSimpleTextureEffect::Create(texture, matrix, params);
+ }
GrUnlockAndUnrefCachedBitmapTexture(texture);
return effect;
}
diff --git a/src/effects/SkBicubicImageFilter.cpp b/src/effects/SkBicubicImageFilter.cpp
index 3b2dd4fe7d..0ffcde6e2e 100644
--- a/src/effects/SkBicubicImageFilter.cpp
+++ b/src/effects/SkBicubicImageFilter.cpp
@@ -14,31 +14,30 @@
#include "SkUnPreMultiply.h"
#if SK_SUPPORT_GPU
-#include "gl/GrGLEffectMatrix.h"
-#include "effects/GrSingleTextureEffect.h"
-#include "GrTBackendEffectFactory.h"
+#include "effects/GrBicubicEffect.h"
#include "GrContext.h"
#include "GrTexture.h"
#include "SkImageFilterUtils.h"
#endif
+#define DS(x) SkDoubleToScalar(x)
+
+static const SkScalar gMitchellCoefficients[16] = {
+ DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0),
+ DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0),
+ DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0),
+ DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS( 7.0 / 18.0),
+};
+
SkBicubicImageFilter::SkBicubicImageFilter(const SkSize& scale, const SkScalar coefficients[16], SkImageFilter* input)
: INHERITED(input),
fScale(scale) {
memcpy(fCoefficients, coefficients, sizeof(fCoefficients));
}
-#define DS(x) SkDoubleToScalar(x)
-
SkBicubicImageFilter* SkBicubicImageFilter::CreateMitchell(const SkSize& scale,
SkImageFilter* input) {
- static const SkScalar coefficients[16] = {
- DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0),
- DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0),
- DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0),
- DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS( 7.0 / 18.0),
- };
- return SkNEW_ARGS(SkBicubicImageFilter, (scale, coefficients, input));
+ return SkNEW_ARGS(SkBicubicImageFilter, (scale, gMitchellCoefficients, input));
}
SkBicubicImageFilter::SkBicubicImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
@@ -157,184 +156,6 @@ bool SkBicubicImageFilter::onFilterImage(Proxy* proxy,
///////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
-class GrGLBicubicEffect;
-
-class GrBicubicEffect : public GrSingleTextureEffect {
-public:
- virtual ~GrBicubicEffect();
-
- static const char* Name() { return "Bicubic"; }
- const float* coefficients() const { return fCoefficients; }
-
- typedef GrGLBicubicEffect GLEffect;
-
- virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
- virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
-
- static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16]) {
- AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients)));
- return CreateEffectRef(effect);
- }
-
-private:
- GrBicubicEffect(GrTexture*, const SkScalar coefficients[16]);
- virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
- float fCoefficients[16];
-
- GR_DECLARE_EFFECT_TEST;
-
- typedef GrSingleTextureEffect INHERITED;
-};
-
-class GrGLBicubicEffect : public GrGLEffect {
-public:
- GrGLBicubicEffect(const GrBackendEffectFactory& factory,
- const GrDrawEffect&);
- virtual void emitCode(GrGLShaderBuilder*,
- const GrDrawEffect&,
- EffectKey,
- const char* outputColor,
- const char* inputColor,
- const TextureSamplerArray&) SK_OVERRIDE;
-
- static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
-
- virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
-
-private:
- typedef GrGLUniformManager::UniformHandle UniformHandle;
-
- UniformHandle fCoefficientsUni;
- UniformHandle fImageIncrementUni;
-
- GrGLEffectMatrix fEffectMatrix;
-
- typedef GrGLEffect INHERITED;
-};
-
-GrGLBicubicEffect::GrGLBicubicEffect(const GrBackendEffectFactory& factory,
- const GrDrawEffect& drawEffect)
- : INHERITED(factory)
- , fEffectMatrix(drawEffect.castEffect<GrBicubicEffect>().coordsType()) {
-}
-
-void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
- const GrDrawEffect&,
- EffectKey key,
- const char* outputColor,
- const char* inputColor,
- const TextureSamplerArray& samplers) {
- SkString coords;
- fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
- fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
- kMat44f_GrSLType, "Coefficients");
- fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
- kVec2f_GrSLType, "ImageIncrement");
-
- const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
- const char* coeff = builder->getUniformCStr(fCoefficientsUni);
-
- SkString cubicBlendName;
-
- static const GrGLShaderVar gCubicBlendArgs[] = {
- GrGLShaderVar("coefficients", kMat44f_GrSLType),
- GrGLShaderVar("t", kFloat_GrSLType),
- GrGLShaderVar("c0", kVec4f_GrSLType),
- GrGLShaderVar("c1", kVec4f_GrSLType),
- GrGLShaderVar("c2", kVec4f_GrSLType),
- GrGLShaderVar("c3", kVec4f_GrSLType),
- };
- builder->fsEmitFunction(kVec4f_GrSLType,
- "cubicBlend",
- SK_ARRAY_COUNT(gCubicBlendArgs),
- gCubicBlendArgs,
- "\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n"
- "\tvec4 c = coefficients * ts;\n"
- "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
- &cubicBlendName);
- builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5, 0.5);\n", coords.c_str(), imgInc);
- builder->fsCodeAppendf("\tvec2 f = fract(coord / %s);\n", imgInc);
- for (int y = 0; y < 4; ++y) {
- for (int x = 0; x < 4; ++x) {
- SkString coord;
- coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1);
- builder->fsCodeAppendf("\tvec4 s%d%d = ", x, y);
- builder->fsAppendTextureLookup(samplers[0], coord.c_str());
- builder->fsCodeAppend(";\n");
- }
- builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, s0%d, s1%d, s2%d, s3%d);\n", y, cubicBlendName.c_str(), coeff, y, y, y, y);
- }
- builder->fsCodeAppendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
-}
-
-GrGLEffect::EffectKey GrGLBicubicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
- const GrBicubicEffect& bicubic = drawEffect.castEffect<GrBicubicEffect>();
- EffectKey matrixKey = GrGLEffectMatrix::GenKey(bicubic.getMatrix(),
- drawEffect,
- bicubic.coordsType(),
- bicubic.texture(0));
- return matrixKey;
-}
-
-void GrGLBicubicEffect::setData(const GrGLUniformManager& uman,
- const GrDrawEffect& drawEffect) {
- const GrBicubicEffect& effect = drawEffect.castEffect<GrBicubicEffect>();
- GrTexture& texture = *effect.texture(0);
- float imageIncrement[2];
- imageIncrement[0] = 1.0f / texture.width();
- imageIncrement[1] = 1.0f / texture.height();
- uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
- uman.setMatrix4f(fCoefficientsUni, effect.coefficients());
- fEffectMatrix.setData(uman,
- effect.getMatrix(),
- drawEffect,
- effect.texture(0));
-}
-
-GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
- const SkScalar coefficients[16])
- : INHERITED(texture, MakeDivByTextureWHMatrix(texture)) {
- for (int y = 0; y < 4; y++) {
- for (int x = 0; x < 4; x++) {
- // Convert from row-major scalars to column-major floats.
- fCoefficients[x * 4 + y] = SkScalarToFloat(coefficients[y * 4 + x]);
- }
- }
-}
-
-GrBicubicEffect::~GrBicubicEffect() {
-}
-
-const GrBackendEffectFactory& GrBicubicEffect::getFactory() const {
- return GrTBackendEffectFactory<GrBicubicEffect>::getInstance();
-}
-
-bool GrBicubicEffect::onIsEqual(const GrEffect& sBase) const {
- const GrBicubicEffect& s = CastEffect<GrBicubicEffect>(sBase);
- return this->texture(0) == s.texture(0) &&
- !memcmp(fCoefficients, s.coefficients(), 16);
-}
-
-void GrBicubicEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
- // FIXME: Perhaps we can do better.
- *validFlags = 0;
- return;
-}
-
-GR_DEFINE_EFFECT_TEST(GrBicubicEffect);
-
-GrEffectRef* GrBicubicEffect::TestCreate(SkMWCRandom* random,
- GrContext* context,
- const GrDrawTargetCaps&,
- GrTexture* textures[]) {
- int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
- GrEffectUnitTest::kAlphaTextureIdx;
- SkScalar coefficients[16];
- for (int i = 0; i < 16; i++) {
- coefficients[i] = random->nextSScalar1();
- }
- return GrBicubicEffect::Create(textures[texIdx], coefficients);
-}
bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
SkBitmap* result, SkIPoint* offset) {
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
new file mode 100644
index 0000000000..9a38f67860
--- /dev/null
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -0,0 +1,175 @@
+#include "GrBicubicEffect.h"
+
+#define DS(x) SkDoubleToScalar(x)
+
+const SkScalar GrBicubicEffect::gMitchellCoefficients[16] = {
+ DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0),
+ DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0),
+ DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0),
+ DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS( 7.0 / 18.0),
+};
+
+
+class GrGLBicubicEffect : public GrGLEffect {
+public:
+ GrGLBicubicEffect(const GrBackendEffectFactory& factory,
+ const GrDrawEffect&);
+ virtual void emitCode(GrGLShaderBuilder*,
+ const GrDrawEffect&,
+ EffectKey,
+ const char* outputColor,
+ const char* inputColor,
+ const TextureSamplerArray&) SK_OVERRIDE;
+
+ static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
+
+ virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
+
+private:
+ typedef GrGLUniformManager::UniformHandle UniformHandle;
+
+ UniformHandle fCoefficientsUni;
+ UniformHandle fImageIncrementUni;
+
+ GrGLEffectMatrix fEffectMatrix;
+
+ typedef GrGLEffect INHERITED;
+};
+
+GrGLBicubicEffect::GrGLBicubicEffect(const GrBackendEffectFactory& factory,
+ const GrDrawEffect& drawEffect)
+ : INHERITED(factory)
+ , fEffectMatrix(drawEffect.castEffect<GrBicubicEffect>().coordsType()) {
+}
+
+void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
+ const GrDrawEffect&,
+ EffectKey key,
+ const char* outputColor,
+ const char* inputColor,
+ const TextureSamplerArray& samplers) {
+ SkString coords;
+ fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
+ fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+ kMat44f_GrSLType, "Coefficients");
+ fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+ kVec2f_GrSLType, "ImageIncrement");
+
+ const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
+ const char* coeff = builder->getUniformCStr(fCoefficientsUni);
+
+ SkString cubicBlendName;
+
+ static const GrGLShaderVar gCubicBlendArgs[] = {
+ GrGLShaderVar("coefficients", kMat44f_GrSLType),
+ GrGLShaderVar("t", kFloat_GrSLType),
+ GrGLShaderVar("c0", kVec4f_GrSLType),
+ GrGLShaderVar("c1", kVec4f_GrSLType),
+ GrGLShaderVar("c2", kVec4f_GrSLType),
+ GrGLShaderVar("c3", kVec4f_GrSLType),
+ };
+ builder->fsEmitFunction(kVec4f_GrSLType,
+ "cubicBlend",
+ SK_ARRAY_COUNT(gCubicBlendArgs),
+ gCubicBlendArgs,
+ "\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n"
+ "\tvec4 c = coefficients * ts;\n"
+ "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
+ &cubicBlendName);
+ builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5, 0.5);\n", coords.c_str(), imgInc);
+ builder->fsCodeAppendf("\tvec2 f = fract(coord / %s);\n", imgInc);
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ SkString coord;
+ coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1);
+ builder->fsCodeAppendf("\tvec4 s%d%d = ", x, y);
+ builder->fsAppendTextureLookup(samplers[0], coord.c_str());
+ builder->fsCodeAppend(";\n");
+ }
+ builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, s0%d, s1%d, s2%d, s3%d);\n", y, cubicBlendName.c_str(), coeff, y, y, y, y);
+ }
+ builder->fsCodeAppendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
+}
+
+GrGLEffect::EffectKey GrGLBicubicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+ const GrBicubicEffect& bicubic = drawEffect.castEffect<GrBicubicEffect>();
+ EffectKey matrixKey = GrGLEffectMatrix::GenKey(bicubic.getMatrix(),
+ drawEffect,
+ bicubic.coordsType(),
+ bicubic.texture(0));
+ return matrixKey;
+}
+
+void GrGLBicubicEffect::setData(const GrGLUniformManager& uman,
+ const GrDrawEffect& drawEffect) {
+ const GrBicubicEffect& effect = drawEffect.castEffect<GrBicubicEffect>();
+ GrTexture& texture = *effect.texture(0);
+ float imageIncrement[2];
+ imageIncrement[0] = 1.0f / texture.width();
+ imageIncrement[1] = 1.0f / texture.height();
+ uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
+ uman.setMatrix4f(fCoefficientsUni, effect.coefficients());
+ fEffectMatrix.setData(uman,
+ effect.getMatrix(),
+ drawEffect,
+ effect.texture(0));
+}
+
+GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
+ const SkScalar coefficients[16])
+ : INHERITED(texture, MakeDivByTextureWHMatrix(texture)) {
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ // Convert from row-major scalars to column-major floats.
+ fCoefficients[x * 4 + y] = SkScalarToFloat(coefficients[y * 4 + x]);
+ }
+ }
+}
+
+GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
+ const SkScalar coefficients[16],
+ const SkMatrix &matrix,
+ const GrTextureParams &params,
+ CoordsType coordsType)
+ : INHERITED(texture, MakeDivByTextureWHMatrix(texture), params, coordsType) {
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ // Convert from row-major scalars to column-major floats.
+ fCoefficients[x * 4 + y] = SkScalarToFloat(coefficients[y * 4 + x]);
+ }
+ }
+}
+
+GrBicubicEffect::~GrBicubicEffect() {
+}
+
+const GrBackendEffectFactory& GrBicubicEffect::getFactory() const {
+ return GrTBackendEffectFactory<GrBicubicEffect>::getInstance();
+}
+
+bool GrBicubicEffect::onIsEqual(const GrEffect& sBase) const {
+ const GrBicubicEffect& s = CastEffect<GrBicubicEffect>(sBase);
+ return this->texture(0) == s.texture(0) &&
+ !memcmp(fCoefficients, s.coefficients(), 16);
+}
+
+void GrBicubicEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
+ // FIXME: Perhaps we can do better.
+ *validFlags = 0;
+ return;
+}
+
+GR_DEFINE_EFFECT_TEST(GrBicubicEffect);
+
+GrEffectRef* GrBicubicEffect::TestCreate(SkMWCRandom* random,
+ GrContext* context,
+ const GrDrawTargetCaps&,
+ GrTexture* textures[]) {
+ int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
+ GrEffectUnitTest::kAlphaTextureIdx;
+ SkScalar coefficients[16];
+ for (int i = 0; i < 16; i++) {
+ coefficients[i] = random->nextSScalar1();
+ }
+ return GrBicubicEffect::Create(textures[texIdx], coefficients);
+}
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
new file mode 100644
index 0000000000..618ef1a779
--- /dev/null
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBicubicTextureEffect_DEFINED
+#define GrBicubicTextureEffect_DEFINED
+
+#include "GrSingleTextureEffect.h"
+#include "GrDrawEffect.h"
+#include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
+#include "GrTBackendEffectFactory.h"
+
+class GrGLBicubicEffect;
+
+class GrBicubicEffect : public GrSingleTextureEffect {
+public:
+ virtual ~GrBicubicEffect();
+
+ static const char* Name() { return "Bicubic"; }
+ const float* coefficients() const { return fCoefficients; }
+
+ typedef GrGLBicubicEffect GLEffect;
+
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+ static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16]) {
+ AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients)));
+ return CreateEffectRef(effect);
+ }
+
+ static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16],
+ const SkMatrix& matrix,
+ const GrTextureParams& p,
+ CoordsType coordsType = kLocal_CoordsType) {
+ AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients, matrix, p, coordsType)));
+ return CreateEffectRef(effect);
+ }
+
+ static GrEffectRef* Create(GrTexture* tex) {
+ return Create(tex, gMitchellCoefficients);
+ }
+
+ static GrEffectRef* Create(GrTexture* tex,
+ const SkMatrix& matrix,
+ const GrTextureParams& p,
+ CoordsType coordsType = kLocal_CoordsType) {
+ return Create(tex, gMitchellCoefficients, matrix, p, coordsType);
+ }
+
+private:
+ GrBicubicEffect(GrTexture*, const SkScalar coefficients[16]);
+ GrBicubicEffect(GrTexture*, const SkScalar coefficients[16],
+ const SkMatrix &matrix, const GrTextureParams &p, CoordsType coordsType);
+ virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
+ float fCoefficients[16];
+
+ GR_DECLARE_EFFECT_TEST;
+
+ static const SkScalar gMitchellCoefficients[16];
+
+ typedef GrSingleTextureEffect INHERITED;
+};
+
+#endif