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
This commit is contained in:
parent
f0595b39a9
commit
3aad3b01af
282
gm/tilemodes_scaled.cpp
Normal file
282
gm/tilemodes_scaled.cpp
Normal file
@ -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"); )
|
@ -16,6 +16,7 @@
|
||||
],
|
||||
'include_dirs': [
|
||||
'../include/effects',
|
||||
'../src/effects',
|
||||
'../src/core',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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, ¶ms);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
175
src/gpu/effects/GrBicubicEffect.cpp
Normal file
175
src/gpu/effects/GrBicubicEffect.cpp
Normal file
@ -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 ¶ms,
|
||||
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);
|
||||
}
|
69
src/gpu/effects/GrBicubicEffect.h
Normal file
69
src/gpu/effects/GrBicubicEffect.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user