New subclasses for both Gr and GrGL gradient effect classes.

This replaces GrSingleTextureEffect as the base for gradient effects (so we'll be able to do gradient effects without textures), and adds a base class to the GL gradient custom stage implementations (which will soon handle generating the appropriate code to pass colors in and lerp instead of using a cached texture for simpler gradient cases).

Also added a custom stage for linear gradients.
Review URL: https://codereview.appspot.com/6426049

git-svn-id: http://skia.googlecode.com/svn/trunk@4674 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
rileya@google.com 2012-07-19 15:16:19 +00:00
parent d4cf366473
commit 22e57f9916
5 changed files with 203 additions and 54 deletions

View File

@ -222,8 +222,10 @@ public:
// to first.
// 1: radius of first circle
// 2: the second radius minus the first radius
kLinear_BitmapType, //<! Access bitmap using local coords transformed
// by matrix. No extras
kLast_BitmapType = kTwoPointConical_BitmapType
kLast_BitmapType = kLinear_BitmapType
};
/** Optional methods for shaders that can pretend to be a bitmap/texture
to play along with opengl. Default just returns kNone_BitmapType and

View File

@ -1026,14 +1026,13 @@ SkShader::BitmapType Linear_Gradient::asABitmap(SkBitmap* bitmap,
this->commonAsABitmap(bitmap);
}
if (matrix) {
matrix->setScale(SkIntToScalar(kGradient32Length), SK_Scalar1);
matrix->preConcat(fPtsToUnit);
}
if (xy) {
xy[0] = fTileMode;
xy[1] = kClamp_TileMode;
}
return kDefault_BitmapType;
return kLinear_BitmapType;
}
SkShader::GradientType Linear_Gradient::asAGradient(GradientInfo* info) const {

View File

@ -441,7 +441,8 @@ SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5,
shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 5, shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch);
namespace {
@ -607,6 +608,14 @@ inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
twoPointParams[2])))->unref();
sampler->setFilter(GrSamplerState::kBilinear_Filter);
break;
case SkShader::kLinear_BitmapType:
sampler->setCustomStage(SkNEW_ARGS(GrLinearGradient, (texture)))->unref();
if (skPaint.isFilterBitmap()) {
sampler->setFilter(GrSamplerState::kBilinear_Filter);
} else {
sampler->setFilter(GrSamplerState::kNearest_Filter);
}
break;
default:
if (skPaint.isFilterBitmap()) {
sampler->setFilter(GrSamplerState::kBilinear_Filter);

View File

@ -9,9 +9,117 @@
#include "gl/GrGLProgramStage.h"
#include "GrProgramStageFactory.h"
// Base class for GL gradient custom stages
class GrGLGradientStage : public GrGLProgramStage {
public:
GrGLGradientStage(const GrProgramStageFactory& factory);
virtual ~GrGLGradientStage();
// emit code that gets a fragment's color from an expression for t; for now
// this always uses the texture, but for simpler cases we'll be able to lerp
void emitColorLookup(GrGLShaderBuilder* builder, const char* t,
const char* outputColor, const char* samplerName);
private:
typedef GrGLProgramStage INHERITED;
};
GrGLGradientStage::GrGLGradientStage(const GrProgramStageFactory& factory)
: INHERITED(factory) { }
GrGLGradientStage::~GrGLGradientStage() { }
void GrGLGradientStage::emitColorLookup(GrGLShaderBuilder* builder,
const char* tName,
const char* outputColor,
const char* samplerName) {
// Texture is effectively 1D so the y coordinate is 0.5, if we pack multiple
// gradients into a texture, we could instead pick the appropriate row here
builder->fSampleCoords.printf("vec2(%s, 0.5)", tName);
builder->fComplexCoord = true;
builder->emitDefaultFetch(outputColor, samplerName);
}
/////////////////////////////////////////////////////////////////////
class GrGLRadialGradient : public GrGLProgramStage {
GrGradientEffect::GrGradientEffect(GrTexture* texture)
: fTexture (texture)
, fUseTexture(true) {
SkSafeRef(fTexture);
}
GrGradientEffect::~GrGradientEffect() {
if (fTexture) {
SkSafeUnref(fTexture);
}
}
unsigned int GrGradientEffect::numTextures() const {
return fUseTexture ? 1 : 0;
}
GrTexture* GrGradientEffect::texture(unsigned int index)
const {
GrAssert(fUseTexture && 0 == index);
return fTexture;
}
/////////////////////////////////////////////////////////////////////
class GrGLLinearGradient : public GrGLGradientStage {
public:
GrGLLinearGradient(const GrProgramStageFactory& factory,
const GrCustomStage&)
: INHERITED (factory) { }
virtual ~GrGLLinearGradient() { }
virtual void emitVS(GrGLShaderBuilder* builder,
const char* vertexCoords) SK_OVERRIDE { }
virtual void emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
const char* samplerName) SK_OVERRIDE;
static StageKey GenKey(const GrCustomStage& s) { return 0; }
private:
typedef GrGLGradientStage INHERITED;
};
void GrGLLinearGradient::emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
const char* samplerName) {
SkString t;
t.printf("%s.x", builder->fSampleCoords.c_str());
this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
}
/////////////////////////////////////////////////////////////////////
GrLinearGradient::GrLinearGradient(GrTexture* texture)
: INHERITED(texture) {
}
GrLinearGradient::~GrLinearGradient() {
}
const GrProgramStageFactory& GrLinearGradient::getFactory() const {
return GrTProgramStageFactory<GrLinearGradient>::getInstance();
}
bool GrLinearGradient::isEqual(const GrCustomStage& sBase) const {
return INHERITED::isEqual(sBase);
}
/////////////////////////////////////////////////////////////////////
class GrGLRadialGradient : public GrGLGradientStage {
public:
@ -30,7 +138,7 @@ public:
private:
typedef GrGLProgramStage INHERITED;
typedef GrGLGradientStage INHERITED;
};
@ -38,11 +146,9 @@ void GrGLRadialGradient::emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
const char* samplerName) {
builder->fSampleCoords.printf("vec2(length(%s.xy), 0.5)",
builder->fSampleCoords.c_str());
builder->fComplexCoord = true;
builder->emitDefaultFetch(outputColor, samplerName);
SkString t;
t.printf("length(%s.xy)", builder->fSampleCoords.c_str());
this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
}
@ -50,7 +156,7 @@ void GrGLRadialGradient::emitFS(GrGLShaderBuilder* builder,
GrRadialGradient::GrRadialGradient(GrTexture* texture)
: GrSingleTextureEffect(texture) {
: INHERITED(texture) {
}
@ -73,7 +179,7 @@ bool GrRadialGradient::isEqual(const GrCustomStage& sBase) const {
typedef GrGLShaderBuilder::UniformHandle UniformHandle;
static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
class GrGLRadial2Gradient : public GrGLProgramStage {
class GrGLRadial2Gradient : public GrGLGradientStage {
public:
@ -124,7 +230,7 @@ protected:
private:
typedef GrGLProgramStage INHERITED;
typedef GrGLGradientStage INHERITED;
};
@ -191,6 +297,7 @@ void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* builder,
SkString cName("c");
SkString ac4Name("ac4");
SkString rootName("root");
SkString t;
SkString p0;
SkString p1;
SkString p2;
@ -240,20 +347,15 @@ void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* builder,
rootName.c_str(), bVar.c_str(), bVar.c_str(),
ac4Name.c_str());
// x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
// y coord is 0.5 (texture is effectively 1D)
builder->fSampleCoords.printf("vec2((-%s + %s * %s) * %s, 0.5)",
bVar.c_str(), p5.c_str(),
rootName.c_str(), p1.c_str());
// t is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
t.printf("(-%s + %s * %s) * %s", bVar.c_str(), p5.c_str(),
rootName.c_str(), p1.c_str());
} else {
// x coord is: -c/b
// y coord is 0.5 (texture is effectively 1D)
builder->fSampleCoords.printf("vec2((-%s / %s), 0.5)",
cName.c_str(), bVar.c_str());
// t is: -c/b
t.printf("-%s / %s", cName.c_str(), bVar.c_str());
}
builder->fComplexCoord = true;
builder->emitDefaultFetch(outputColor, samplerName);
this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
}
void GrGLRadial2Gradient::initUniforms(const GrGLShaderBuilder* builder,
@ -309,7 +411,7 @@ GrRadial2Gradient::GrRadial2Gradient(GrTexture* texture,
GrScalar center,
GrScalar radius,
bool posRoot)
: GrSingleTextureEffect(texture)
: INHERITED(texture)
, fCenterX1 (center)
, fRadius0 (radius)
, fPosRoot (posRoot) {
@ -335,7 +437,7 @@ bool GrRadial2Gradient::isEqual(const GrCustomStage& sBase) const {
/////////////////////////////////////////////////////////////////////
class GrGLConical2Gradient : public GrGLProgramStage {
class GrGLConical2Gradient : public GrGLGradientStage {
public:
@ -386,7 +488,7 @@ protected:
private:
typedef GrGLProgramStage INHERITED;
typedef GrGLGradientStage INHERITED;
};
@ -536,10 +638,8 @@ void GrGLConical2Gradient::emitFS(GrGLShaderBuilder* builder,
code->appendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
p5.c_str(), p3.c_str());
// y coord is 0.5 (texture is effectively 1D)
code->appendf("\t\t");
builder->fSampleCoords.printf("vec2(%s, 0.5)", tName.c_str());
builder->emitDefaultFetch(outputColor, samplerName);
this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
// otherwise, if r(t) for the larger root was <= 0, try the other root
code->appendf("\t\t} else {\n");
@ -550,10 +650,8 @@ void GrGLConical2Gradient::emitFS(GrGLShaderBuilder* builder,
code->appendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
tName.c_str(), p5.c_str(), p3.c_str());
// y coord is 0.5 (texture is effectively 1D)
code->appendf("\t\t\t");
builder->fSampleCoords.printf("vec2(%s, 0.5)", tName.c_str());
builder->emitDefaultFetch(outputColor, samplerName);
this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
// end if (r(t) > 0) for smaller root
code->appendf("\t\t\t}\n");
@ -571,11 +669,9 @@ void GrGLConical2Gradient::emitFS(GrGLShaderBuilder* builder,
code->appendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
p5.c_str(), p3.c_str());
code->appendf("\t");
builder->fSampleCoords.printf("vec2(%s, 0.5)", tName.c_str());
builder->emitDefaultFetch(outputColor, samplerName);
this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
code->appendf("\t}\n");
}
builder->fComplexCoord = true;
}
void GrGLConical2Gradient::initUniforms(const GrGLShaderBuilder* builder,
@ -633,7 +729,7 @@ GrConical2Gradient::GrConical2Gradient(GrTexture* texture,
GrScalar center,
GrScalar radius,
GrScalar diffRadius)
: GrSingleTextureEffect (texture)
: INHERITED (texture)
, fCenterX1 (center)
, fRadius0 (radius)
, fDiffRadius (diffRadius) {
@ -660,7 +756,7 @@ bool GrConical2Gradient::isEqual(const GrCustomStage& sBase) const {
/////////////////////////////////////////////////////////////////////
class GrGLSweepGradient : public GrGLProgramStage {
class GrGLSweepGradient : public GrGLGradientStage {
public:
@ -679,7 +775,7 @@ public:
private:
typedef GrGLProgramStage INHERITED;
typedef GrGLGradientStage INHERITED;
};
@ -687,18 +783,16 @@ void GrGLSweepGradient::emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
const char* samplerName) {
builder->fSampleCoords.printf(
"vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)",
SkString t;
t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
builder->fSampleCoords.c_str(), builder->fSampleCoords.c_str());
builder->fComplexCoord = true;
builder->emitDefaultFetch(outputColor, samplerName);
this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
}
/////////////////////////////////////////////////////////////////////
GrSweepGradient::GrSweepGradient(GrTexture* texture)
: GrSingleTextureEffect(texture) {
: INHERITED(texture) {
}

View File

@ -35,9 +35,54 @@
* determines the gradient value.
*/
// Base class for Gr gradient effects
class GrGradientEffect : public GrCustomStage {
public:
GrGradientEffect(GrTexture* texture);
// TODO: Look at a GradientInfo and make the texture only if necessary
// GrGradientEffect(GrContext* ctx, GradientInfo* info);
virtual ~GrGradientEffect();
unsigned int numTextures() const;
GrTexture* texture(unsigned int index) const;
bool useTexture() const { return fUseTexture; }
private:
GrTexture* fTexture;
bool fUseTexture;
typedef GrCustomStage INHERITED;
};
class GrGLLinearGradient;
class GrLinearGradient : public GrGradientEffect {
public:
GrLinearGradient(GrTexture* texture);
virtual ~GrLinearGradient();
static const char* Name() { return "Linear Gradient"; }
virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
typedef GrGLLinearGradient GLProgramStage;
private:
typedef GrGradientEffect INHERITED;
};
class GrGLRadialGradient;
class GrRadialGradient : public GrSingleTextureEffect {
class GrRadialGradient : public GrGradientEffect {
public:
@ -52,12 +97,12 @@ public:
private:
typedef GrSingleTextureEffect INHERITED;
typedef GrGradientEffect INHERITED;
};
class GrGLRadial2Gradient;
class GrRadial2Gradient : public GrSingleTextureEffect {
class GrRadial2Gradient : public GrGradientEffect {
public:
@ -88,12 +133,12 @@ private:
// @}
typedef GrSingleTextureEffect INHERITED;
typedef GrGradientEffect INHERITED;
};
class GrGLConical2Gradient;
class GrConical2Gradient : public GrSingleTextureEffect {
class GrConical2Gradient : public GrGradientEffect {
public:
@ -124,12 +169,12 @@ private:
// @}
typedef GrSingleTextureEffect INHERITED;
typedef GrGradientEffect INHERITED;
};
class GrGLSweepGradient;
class GrSweepGradient : public GrSingleTextureEffect {
class GrSweepGradient : public GrGradientEffect {
public:
@ -144,7 +189,7 @@ public:
protected:
typedef GrSingleTextureEffect INHERITED;
typedef GrGradientEffect INHERITED;
};
#endif