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
diff --git a/src/effects/SkGradientShader.cpp b/src/effects/SkGradientShader.cpp
index 559e711..b86c4e2 100644
--- a/src/effects/SkGradientShader.cpp
+++ b/src/effects/SkGradientShader.cpp
@@ -1026,14 +1026,13 @@
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 {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 605b640..4e3baa3 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -441,7 +441,8 @@
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 @@
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);
diff --git a/src/gpu/effects/GrGradientEffects.cpp b/src/gpu/effects/GrGradientEffects.cpp
index 988717a..ec465b8 100644
--- a/src/gpu/effects/GrGradientEffects.cpp
+++ b/src/gpu/effects/GrGradientEffects.cpp
@@ -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 @@
private:
- typedef GrGLProgramStage INHERITED;
+ typedef GrGLGradientStage INHERITED;
};
@@ -38,11 +146,9 @@
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 @@
GrRadialGradient::GrRadialGradient(GrTexture* texture)
- : GrSingleTextureEffect(texture) {
+ : INHERITED(texture) {
}
@@ -73,7 +179,7 @@
typedef GrGLShaderBuilder::UniformHandle UniformHandle;
static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
-class GrGLRadial2Gradient : public GrGLProgramStage {
+class GrGLRadial2Gradient : public GrGLGradientStage {
public:
@@ -124,7 +230,7 @@
private:
- typedef GrGLProgramStage INHERITED;
+ typedef GrGLGradientStage INHERITED;
};
@@ -191,6 +297,7 @@
SkString cName("c");
SkString ac4Name("ac4");
SkString rootName("root");
+ SkString t;
SkString p0;
SkString p1;
SkString p2;
@@ -240,20 +347,15 @@
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 @@
GrScalar center,
GrScalar radius,
bool posRoot)
- : GrSingleTextureEffect(texture)
+ : INHERITED(texture)
, fCenterX1 (center)
, fRadius0 (radius)
, fPosRoot (posRoot) {
@@ -335,7 +437,7 @@
/////////////////////////////////////////////////////////////////////
-class GrGLConical2Gradient : public GrGLProgramStage {
+class GrGLConical2Gradient : public GrGLGradientStage {
public:
@@ -386,7 +488,7 @@
private:
- typedef GrGLProgramStage INHERITED;
+ typedef GrGLGradientStage INHERITED;
};
@@ -536,10 +638,8 @@
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 @@
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 @@
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 @@
GrScalar center,
GrScalar radius,
GrScalar diffRadius)
- : GrSingleTextureEffect (texture)
+ : INHERITED (texture)
, fCenterX1 (center)
, fRadius0 (radius)
, fDiffRadius (diffRadius) {
@@ -660,7 +756,7 @@
/////////////////////////////////////////////////////////////////////
-class GrGLSweepGradient : public GrGLProgramStage {
+class GrGLSweepGradient : public GrGLGradientStage {
public:
@@ -679,7 +775,7 @@
private:
- typedef GrGLProgramStage INHERITED;
+ typedef GrGLGradientStage INHERITED;
};
@@ -687,18 +783,16 @@
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) {
}
diff --git a/src/gpu/effects/GrGradientEffects.h b/src/gpu/effects/GrGradientEffects.h
index 37e4642..eb1a8f2 100644
--- a/src/gpu/effects/GrGradientEffects.h
+++ b/src/gpu/effects/GrGradientEffects.h
@@ -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 @@
private:
- typedef GrSingleTextureEffect INHERITED;
+ typedef GrGradientEffect INHERITED;
};
class GrGLRadial2Gradient;
-class GrRadial2Gradient : public GrSingleTextureEffect {
+class GrRadial2Gradient : public GrGradientEffect {
public:
@@ -88,12 +133,12 @@
// @}
- typedef GrSingleTextureEffect INHERITED;
+ typedef GrGradientEffect INHERITED;
};
class GrGLConical2Gradient;
-class GrConical2Gradient : public GrSingleTextureEffect {
+class GrConical2Gradient : public GrGradientEffect {
public:
@@ -124,12 +169,12 @@
// @}
- typedef GrSingleTextureEffect INHERITED;
+ typedef GrGradientEffect INHERITED;
};
class GrGLSweepGradient;
-class GrSweepGradient : public GrSingleTextureEffect {
+class GrSweepGradient : public GrGradientEffect {
public:
@@ -144,7 +189,7 @@
protected:
- typedef GrSingleTextureEffect INHERITED;
+ typedef GrGradientEffect INHERITED;
};
#endif