aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-08-03 14:34:46 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-08-03 14:34:46 +0000
commitd472620458e2383e6dd949f4e1aaf61160717ffe (patch)
tree2822ac4f1c55d6eaa9ed4ac6dc2b7014de5410ff
parentdea8e252e1259f5bdd15e16a21646402058b939d (diff)
Registry-based unit test for custom effects
Review URL: http://codereview.appspot.com/6447085/ git-svn-id: http://skia.googlecode.com/svn/trunk@4946 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gyp/gpu.gyp1
-rw-r--r--include/core/SkRandom.h12
-rw-r--r--include/gpu/GrCustomStage.h1
-rw-r--r--include/gpu/GrCustomStageUnitTest.h73
-rw-r--r--src/effects/gradients/SkGradientShader.cpp24
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h16
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp25
-rw-r--r--src/effects/gradients/SkRadialGradient.cpp25
-rw-r--r--src/effects/gradients/SkSweepGradient.cpp25
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp32
-rw-r--r--src/effects/gradients/SkTwoPointRadialGradient.cpp33
-rw-r--r--src/gpu/GrCustomStage.cpp7
-rw-r--r--src/gpu/effects/GrColorTableEffect.cpp19
-rw-r--r--src/gpu/gl/GrGLProgram.cpp18
-rw-r--r--src/gpu/gl/GrGLProgram.h6
-rw-r--r--src/gpu/gl/GrGLProgramStage.h7
-rw-r--r--src/gpu/gl/GrGLShaderBuilder.cpp12
-rw-r--r--tests/GLProgramsTest.cpp173
18 files changed, 366 insertions, 143 deletions
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp
index 177a728513..652708fb7e 100644
--- a/gyp/gpu.gyp
+++ b/gyp/gpu.gyp
@@ -205,6 +205,7 @@
'../include/gpu/GrContext.h',
'../include/gpu/GrContextFactory.h',
'../include/gpu/GrCustomStage.h',
+ '../include/gpu/GrCustomStageUnitTest.h',
'../include/gpu/GrFontScaler.h',
'../include/gpu/GrGlyph.h',
'../include/gpu/GrInstanceCounter.h',
diff --git a/include/core/SkRandom.h b/include/core/SkRandom.h
index b850df3cc3..b1b7564b1f 100644
--- a/include/core/SkRandom.h
+++ b/include/core/SkRandom.h
@@ -57,6 +57,14 @@ public:
return min + this->nextU() % (max - min + 1);
}
+ /** Return the next pseudo random unsigned number, mapped to lie within
+ [0, count).
+ */
+ uint32_t nextULessThan(uint32_t count) {
+ SkASSERT(count > 0);
+ return this->nextRangeU(0, count - 1);
+ }
+
/** Return the next pseudo random number expressed as an unsigned SkFixed
in the range [0..SK_Fixed1).
*/
@@ -77,6 +85,10 @@ public:
*/
SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
+ /** Return the next pseudo random number as a bool.
+ */
+ bool nextBool() { return this->nextU() >= 0x80000000; }
+
/** Return the next pseudo random number as a signed 64bit value.
*/
void next64(Sk64* a) {
diff --git a/include/gpu/GrCustomStage.h b/include/gpu/GrCustomStage.h
index a13ecd469e..0ac7a76205 100644
--- a/include/gpu/GrCustomStage.h
+++ b/include/gpu/GrCustomStage.h
@@ -11,6 +11,7 @@
#include "GrRefCnt.h"
#include "GrNoncopyable.h"
#include "GrProgramStageFactory.h"
+#include "GrCustomStageUnitTest.h"
class GrContext;
class GrTexture;
diff --git a/include/gpu/GrCustomStageUnitTest.h b/include/gpu/GrCustomStageUnitTest.h
new file mode 100644
index 0000000000..9cbadf3a5b
--- /dev/null
+++ b/include/gpu/GrCustomStageUnitTest.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrCustomStageUnitTest_DEFINED
+#define GrCustomStageUnitTest_DEFINED
+
+#include "SkRandom.h"
+
+#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+class GrCustomStage;
+class GrContext;
+class GrTexture;
+
+class GrCustomStageTestFactory : GrNoncopyable {
+public:
+ // Used to access the dummy textures in TestCreate procs.
+ enum {
+ kSkiaPMTextureIdx = 0,
+ kAlphaTextureIdx = 1,
+ };
+
+ typedef GrCustomStage* (*CreateProc)(SkRandom*, GrContext*, GrTexture* dummyTextures[]);
+
+ GrCustomStageTestFactory(CreateProc createProc) {
+ fCreateProc = createProc;
+ GetFactories()->push_back(this);
+ }
+
+ static GrCustomStage* CreateStage(SkRandom* random,
+ GrContext* context,
+ GrTexture* dummyTextures[]) {
+ uint32_t idx = random->nextRangeU(0, GetFactories()->count() - 1);
+ GrCustomStageTestFactory* factory = (*GetFactories())[idx];
+ return factory->fCreateProc(random, context, dummyTextures);
+ }
+
+private:
+ CreateProc fCreateProc;
+ static SkTArray<GrCustomStageTestFactory*, true>* GetFactories();
+};
+
+/** GrCustomStage subclasses should insert this macro in their declaration to be included in the
+ * program generation unit test.
+ */
+#define GR_DECLARE_CUSTOM_STAGE_TEST \
+ static GrCustomStageTestFactory gTestFactory; \
+ static GrCustomStage* TestCreate(SkRandom*, GrContext*, GrTexture* dummyTextures[2])
+
+/** GrCustomStage subclasses should insert this macro in their implemenation file. They must then
+ * also implement this static function:
+ * GrCustomStage* CreateStage(SkRandom*, GrContext*, GrTexture* dummyTextures[2]);
+ * dummyTextures[] are valied textures that they can optionally use for their texture accesses. The
+ * first texture has config kSkia8888_PM_GrPixelConfig and the second has kAlpha_8_GrPixelConfig.
+ * TestCreate functions are also free to create additional textures using the GrContext.
+ */
+#define GR_DEFINE_CUSTOM_STAGE_TEST(CustomStage) \
+ GrCustomStageTestFactory CustomStage :: gTestFactory(CustomStage :: TestCreate)
+
+#else // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+// The unit test relies on static initializers. Just declare the TestCreate function so that
+// its definitions will compile.
+#define GR_DECLARE_CUSTOM_STAGE_TEST \
+ static GrCustomStage* TestCreate(SkRandom*, GrContext*, GrTexture* dummyTextures[2])
+#define GR_DEFINE_CUSTOM_STAGE_TEST(X)
+
+#endif // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+#endif \ No newline at end of file
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index e415c62c36..f61f8d53b0 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -732,4 +732,28 @@ GrTexture* GrGradientEffect::texture(unsigned int index)
return fTexture;
}
+int GrGradientEffect::RandomGradientParams(SkRandom* random,
+ SkColor colors[],
+ SkScalar** stops,
+ SkShader::TileMode* tm) {
+ int outColors = random->nextRangeU(1, kMaxRandomGradientColors);
+
+ // if one color, omit stops, otherwise randomly decide whether or not to
+ if (outColors == 1 || (outColors >= 2 && random->nextBool())) {
+ *stops = NULL;
+ }
+
+ GrScalar stop = 0.f;
+ for (int i = 0; i < outColors; ++i) {
+ colors[i] = random->nextU();
+ if (NULL != *stops) {
+ (*stops)[i] = stop;
+ stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
+ }
+ }
+ *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
+
+ return outColors;
+}
+
#endif
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 9e80fd3467..807bf324ad 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -233,8 +233,22 @@ public:
bool useTexture() const { return fUseTexture; }
-private:
+protected:
+ /** Populates a pair of arrays with colors and stop info to construct a random gradient.
+ The function decides whether stop values should be used or not. The return value indicates
+ the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
+ sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
+ size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be
+ passed to the gradient factory rather than the array.
+ */
+ static const int kMaxRandomGradientColors = 4;
+ static int RandomGradientParams(SkRandom* r,
+ SkColor colors[kMaxRandomGradientColors],
+ SkScalar** stops,
+ SkShader::TileMode* tm);
+
+private:
GrTexture* fTexture;
bool fUseTexture;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index d88540e244..ef397682d9 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -516,12 +516,37 @@ public:
typedef GrGLLinearGradient GLProgramStage;
private:
+ GR_DECLARE_CUSTOM_STAGE_TEST;
typedef GrGradientEffect INHERITED;
};
/////////////////////////////////////////////////////////////////////
+GR_DEFINE_CUSTOM_STAGE_TEST(GrLinearGradient);
+
+GrCustomStage* GrLinearGradient::TestCreate(SkRandom* random,
+ GrContext* context,
+ GrTexture**) {
+ SkPoint points[] = {{random->nextUScalar1(), random->nextUScalar1()},
+ {random->nextUScalar1(), random->nextUScalar1()}};
+
+ SkColor colors[kMaxRandomGradientColors];
+ SkScalar stopsArray[kMaxRandomGradientColors];
+ SkScalar* stops = stopsArray;
+ SkShader::TileMode tm;
+ int colorCount = RandomGradientParams(random, colors, &stops, &tm);
+ SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points,
+ colors, stops, colorCount,
+ tm));
+ GrSamplerState sampler;
+ GrCustomStage* stage = shader->asNewCustomStage(context, &sampler);
+ GrAssert(NULL != stage);
+ return stage;
+}
+
+/////////////////////////////////////////////////////////////////////
+
void GrGLLinearGradient::emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index f3978a5951..dbde95a17e 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -516,12 +516,37 @@ public:
typedef GrGLRadialGradient GLProgramStage;
private:
+ GR_DECLARE_CUSTOM_STAGE_TEST;
typedef GrGradientEffect INHERITED;
};
/////////////////////////////////////////////////////////////////////
+GR_DEFINE_CUSTOM_STAGE_TEST(GrRadialGradient);
+
+GrCustomStage* GrRadialGradient::TestCreate(SkRandom* random,
+ GrContext* context,
+ GrTexture**) {
+ SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
+ SkScalar radius = random->nextUScalar1();
+
+ SkColor colors[kMaxRandomGradientColors];
+ SkScalar stopsArray[kMaxRandomGradientColors];
+ SkScalar* stops = stopsArray;
+ SkShader::TileMode tm;
+ int colorCount = RandomGradientParams(random, colors, &stops, &tm);
+ SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center, radius,
+ colors, stops, colorCount,
+ tm));
+ GrSamplerState sampler;
+ GrCustomStage* stage = shader->asNewCustomStage(context, &sampler);
+ GrAssert(NULL != stage);
+ return stage;
+}
+
+/////////////////////////////////////////////////////////////////////
+
void GrGLRadialGradient::emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 0dee9b5303..89ebba2563 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -422,13 +422,36 @@ public:
typedef GrGLSweepGradient GLProgramStage;
-protected:
+private:
+ GR_DECLARE_CUSTOM_STAGE_TEST;
typedef GrGradientEffect INHERITED;
};
/////////////////////////////////////////////////////////////////////
+GR_DEFINE_CUSTOM_STAGE_TEST(GrSweepGradient);
+
+GrCustomStage* GrSweepGradient::TestCreate(SkRandom* random,
+ GrContext* context,
+ GrTexture**) {
+ SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
+
+ SkColor colors[kMaxRandomGradientColors];
+ SkScalar stopsArray[kMaxRandomGradientColors];
+ SkScalar* stops = stopsArray;
+ SkShader::TileMode tmIgnored;
+ int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored);
+ SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
+ colors, stops, colorCount));
+ GrSamplerState sampler;
+ GrCustomStage* stage = shader->asNewCustomStage(context, &sampler);
+ GrAssert(NULL != stage);
+ return stage;
+}
+
+/////////////////////////////////////////////////////////////////////
+
void GrGLSweepGradient::emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index 89025733c2..528291bdc1 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -402,6 +402,7 @@ public:
typedef GrGLConical2Gradient GLProgramStage;
private:
+ GR_DECLARE_CUSTOM_STAGE_TEST;
// @{
// Cache of values - these can change arbitrarily, EXCEPT
@@ -416,6 +417,37 @@ private:
typedef GrGradientEffect INHERITED;
};
+GR_DEFINE_CUSTOM_STAGE_TEST(GrConical2Gradient);
+
+GrCustomStage* GrConical2Gradient::TestCreate(SkRandom* random,
+ GrContext* context,
+ GrTexture**) {
+ SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
+ SkScalar radius1 = random->nextUScalar1();
+ SkPoint center2;
+ SkScalar radius2;
+ do {
+ center1.set(random->nextUScalar1(), random->nextUScalar1());
+ radius2 = random->nextUScalar1 ();
+ // If the circles are identical the factory will give us an empty shader.
+ } while (radius1 == radius2 && center1 == center2);
+
+ SkColor colors[kMaxRandomGradientColors];
+ SkScalar stopsArray[kMaxRandomGradientColors];
+ SkScalar* stops = stopsArray;
+ SkShader::TileMode tm;
+ int colorCount = RandomGradientParams(random, colors, &stops, &tm);
+ SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
+ center2, radius2,
+ colors, stops, colorCount,
+ tm));
+ GrSamplerState sampler;
+ GrCustomStage* stage = shader->asNewCustomStage(context, &sampler);
+ GrAssert(NULL != stage);
+ return stage;
+}
+
+
/////////////////////////////////////////////////////////////////////
GrGLConical2Gradient::GrGLConical2Gradient(
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 84ae91dafa..441f5a8d09 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -434,6 +434,7 @@ public:
typedef GrGLRadial2Gradient GLProgramStage;
private:
+ GR_DECLARE_CUSTOM_STAGE_TEST;
// @{
// Cache of values - these can change arbitrarily, EXCEPT
@@ -450,6 +451,38 @@ private:
/////////////////////////////////////////////////////////////////////
+GR_DEFINE_CUSTOM_STAGE_TEST(GrRadial2Gradient);
+
+GrCustomStage* GrRadial2Gradient::TestCreate(SkRandom* random,
+ GrContext* context,
+ GrTexture**) {
+ SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
+ SkScalar radius1 = random->nextUScalar1();
+ SkPoint center2;
+ SkScalar radius2;
+ do {
+ center1.set(random->nextUScalar1(), random->nextUScalar1());
+ radius2 = random->nextUScalar1 ();
+ // There is a bug in two point radial gradients with idenitical radii
+ } while (radius1 == radius2);
+
+ SkColor colors[kMaxRandomGradientColors];
+ SkScalar stopsArray[kMaxRandomGradientColors];
+ SkScalar* stops = stopsArray;
+ SkShader::TileMode tm;
+ int colorCount = RandomGradientParams(random, colors, &stops, &tm);
+ SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointRadial(center1, radius1,
+ center2, radius2,
+ colors, stops, colorCount,
+ tm));
+ GrSamplerState sampler;
+ GrCustomStage* stage = shader->asNewCustomStage(context, &sampler);
+ GrAssert(NULL != stage);
+ return stage;
+}
+
+/////////////////////////////////////////////////////////////////////
+
GrGLRadial2Gradient::GrGLRadial2Gradient(
const GrProgramStageFactory& factory,
const GrCustomStage& baseData)
diff --git a/src/gpu/GrCustomStage.cpp b/src/gpu/GrCustomStage.cpp
index bea07cfab4..6d7bfad272 100644
--- a/src/gpu/GrCustomStage.cpp
+++ b/src/gpu/GrCustomStage.cpp
@@ -13,6 +13,13 @@
SK_DEFINE_INST_COUNT(GrCustomStage)
+#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+SkTArray<GrCustomStageTestFactory*, true>* GrCustomStageTestFactory::GetFactories() {
+ static SkTArray<GrCustomStageTestFactory*, true> gFactories;
+ return &gFactories;
+}
+#endif
+
class GrCustomStage_Globals {
public:
static GrMemoryPool* GetTLS() {
diff --git a/src/gpu/effects/GrColorTableEffect.cpp b/src/gpu/effects/GrColorTableEffect.cpp
index f1ce664826..94eb8fdd74 100644
--- a/src/gpu/effects/GrColorTableEffect.cpp
+++ b/src/gpu/effects/GrColorTableEffect.cpp
@@ -52,11 +52,20 @@ void GrGLColorTableEffect::emitFS(GrGLShaderBuilder* builder,
static const float kColorScaleFactor = 255.0f / 256.0f;
static const float kColorOffsetFactor = 1.0f / 512.0f;
SkString* code = &builder->fFSCode;
- code->appendf("\t\tvec4 coord = vec4(%s.rgb / %s.a, %s.a);\n",
- inputColor, inputColor, inputColor);
- code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
- kColorScaleFactor,
- kColorOffsetFactor, kColorOffsetFactor, kColorOffsetFactor, kColorOffsetFactor);
+ if (NULL == inputColor) {
+ // the input color is solid white (all ones).
+ static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
+ code->appendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
+ kMaxValue, kMaxValue, kMaxValue, kMaxValue);
+
+ } else {
+ code->appendf("\t\tvec4 coord = vec4(%s.rgb / %s.a, %s.a);\n",
+ inputColor, inputColor, inputColor);
+ code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
+ kColorScaleFactor,
+ kColorOffsetFactor, kColorOffsetFactor,
+ kColorOffsetFactor, kColorOffsetFactor);
+ }
const GrTextureAccess& access = *fCustomStage.textureAccess(0);
code->appendf("\t\t%s.a = ", outputColor);
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index ebbd267fae..b04d924eb5 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -301,7 +301,7 @@ static void addColorFilter(SkString* fsCode, const char * outputVar,
add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
}
-void GrGLProgram::genEdgeCoverage(SkString* coverageVar,
+bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
GrGLShaderBuilder* segments) const {
if (fDesc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit) {
const char *vsName, *fsName;
@@ -358,8 +358,10 @@ void GrGLProgram::genEdgeCoverage(SkString* coverageVar,
break;
}
*coverageVar = "edgeAlpha";
+ return true;
} else {
coverageVar->reset();
+ return false;
}
}
@@ -770,7 +772,7 @@ bool GrGLProgram::genProgram(const GrCustomStage** customStages) {
if (!wroteFragColorZero || Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) {
if (!coverageIsZero) {
- this->genEdgeCoverage(&inCoverage, &builder);
+ bool inCoverageIsScalar = this->genEdgeCoverage(&inCoverage, &builder);
switch (fDesc.fCoverageInput) {
case Desc::kSolidWhite_ColorInput:
@@ -778,9 +780,11 @@ bool GrGLProgram::genProgram(const GrCustomStage** customStages) {
break;
case Desc::kAttribute_ColorInput:
gen_attribute_coverage(&builder, &inCoverage);
+ inCoverageIsScalar = false;
break;
case Desc::kUniform_ColorInput:
this->genUniformCoverage(&builder, &inCoverage);
+ inCoverageIsScalar = false;
break;
default:
GrCrash("Unexpected input coverage.");
@@ -793,8 +797,7 @@ bool GrGLProgram::genProgram(const GrCustomStage** customStages) {
// create var to hold stage output
outCoverage = "coverage";
outCoverage.appendS32(s);
- builder.fFSCode.appendf("\tvec4 %s;\n",
- outCoverage.c_str());
+ builder.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
const char* inCoords;
// figure out what our input coords are
@@ -813,6 +816,13 @@ bool GrGLProgram::genProgram(const GrCustomStage** customStages) {
const GrProgramStageFactory& factory = customStages[s]->getFactory();
fProgramStage[s] = factory.createGLInstance(*customStages[s]);
}
+ // stages don't know how to deal with a scalar input. (Maybe they should. We
+ // could pass a GrGLShaderVar)
+ if (inCoverageIsScalar) {
+ builder.fFSCode.appendf("\tvec4 %s4 = vec4(%s);\n",
+ inCoverage.c_str(), inCoverage.c_str());
+ inCoverage.append("4");
+ }
this->genStageCode(s,
inCoverage.size() ? inCoverage.c_str() : NULL,
outCoverage.c_str(),
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 62c70e54bc..989b7c67b4 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -259,8 +259,10 @@ private:
void genUniformCoverage(GrGLShaderBuilder* segments, SkString* inOutCoverage);
- // generates code to compute coverage based on edge AA.
- void genEdgeCoverage(SkString* coverageVar, GrGLShaderBuilder* builder) const;
+ // generates code to compute coverage based on edge AA. Returns true if edge coverage was
+ // inserted in which case coverageVar will be updated to refer to a scalar. Otherwise,
+ // coverageVar is set to an empty string.
+ bool genEdgeCoverage(SkString* coverageVar, GrGLShaderBuilder* builder) const;
// Creates a GL program ID, binds shader attributes to GL vertex attrs, and links the program
bool bindOutputsAttribsAndLinkProgram(SkString texCoordAttrNames[GrDrawState::kMaxTexCoords],
diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h
index 8e3a4b1584..69095b6f4a 100644
--- a/src/gpu/gl/GrGLProgramStage.h
+++ b/src/gpu/gl/GrGLProgramStage.h
@@ -57,7 +57,12 @@ public:
on the state.
The code will be inside an otherwise-empty block.
Fragment shader inputs are a vec2 of coordinates, one texture,
- and a color; output is a color. */
+ and a color; output is a color. The input color may be NULL which
+ indicates that the input color is solid white. TODO: Better system
+ for communicating optimization info (e.g. input color is solid white,
+ trans black, known to be opaque, etc.) that allows the custom stage
+ to communicate back similar known info about its output.
+ */
/* TODO: don't give them the samplerName, just a handle; then give
a function here for them to call into that'll apply any texture
domain - but do we force them to be honest about texture domain
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index fb70556709..3ca408618c 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -184,11 +184,7 @@ void GrGLShaderBuilder::emitCustomTextureLookup(SamplerMode samplerMode,
GrCustomStage::StageKey GrGLShaderBuilder::KeyForTextureAccess(const GrTextureAccess& access,
const GrGLCaps& caps) {
GrCustomStage::StageKey key = 0;
-
- if (!access.getTexture()) {
- return key;
- }
-
+
// Assume that swizzle support implies that we never have to modify a shader to adjust
// for texture format/swizzle settings.
if (caps.textureSwizzleSupport()) {
@@ -277,7 +273,11 @@ void GrGLShaderBuilder::addVarying(GrSLType type,
fGSOutputs.push_back();
fGSOutputs.back().setType(type);
fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
- fGSOutputs.back().accessName()->printf("g%s", name);
+ if (kNonStageIdx == fCurrentStage) {
+ fGSOutputs.back().accessName()->printf("g%s", name);
+ } else {
+ fGSOutputs.back().accessName()->printf("g%s%d", name, fCurrentStage);
+ }
fsName = fGSOutputs.back().accessName();
} else {
fsName = fVSOutputs.back().accessName();
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index d7aea981c7..a43ad834ef 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -6,23 +6,19 @@
* found in the LICENSE file.
*/
-// This is a GPU-backend specific test
-#if SK_SUPPORT_GPU
+// This is a GPU-backend specific test. It relies on static intializers to work
#include "gl/GrGpuGL.h"
#include "effects/GrColorTableEffect.h"
#include "effects/GrConvolutionEffect.h"
-#include "../effects/gradients/SkLinearGradient.h"
-#include "../effects/gradients/SkRadialGradient.h"
-#include "../effects/gradients/SkTwoPointRadialGradient.h"
-#include "../effects/gradients/SkTwoPointConicalGradient.h"
-#include "../effects/gradients/SkSweepGradient.h"
#include "effects/GrMorphologyEffect.h"
#include "SkLightingImageFilter.h"
#include "GrProgramStageFactory.h"
#include "GrRandom.h"
#include "Test.h"
+#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
namespace {
// GrRandoms nextU() values have patterns in the low bits
@@ -44,47 +40,32 @@ SkPoint3 random_point3(GrRandom* r) {
return SkPoint3(r->nextF(), r->nextF(), r->nextF());
}
-// populate a pair of arrays with colors and stop info, colorCount indicates
-// the max number of colors, and is set to the actual number on return
-void random_gradient(GrRandom* r, int* colorCount, SkColor* colors,
- SkScalar** stops) {
- int outColors = random_int(r, 1, *colorCount);
-
- // if one color, omit stops, if two colors, randomly decide whether or not to
- if (outColors == 1 || (outColors == 2 && random_bool(r))) *stops = NULL;
-
- GrScalar stop = 0.f;
- for (int i = 0; i < outColors; ++i) {
- colors[i] = static_cast<SkColor>(r->nextF() * 0xffffffff);
- if (*stops) {
- (*stops)[i] = stop;
- stop = i < outColors - 1 ? stop + r->nextF() * (1.f - stop) : 1.f;
- }
- }
-
- *colorCount = outColors;
-}
-
typedef GrGLProgram::StageDesc StageDesc;
// TODO: Effects should be able to register themselves for inclusion in the
// randomly generated shaders. They should be able to configure themselves
// randomly.
-const GrCustomStage* create_random_effect(StageDesc* stageDesc, GrRandom* random,
- GrContext* context) {
+const GrCustomStage* create_random_effect(StageDesc* stageDesc,
+ GrRandom* random,
+ GrContext* context,
+ GrTexture* dummyTextures[]) {
enum EffectType {
kConvolution_EffectType,
kErode_EffectType,
kDilate_EffectType,
- kRadialGradient_EffectType,
- kRadial2Gradient_EffectType,
- kConical2Gradient_EffectType,
+ /**
+ * Lighting effects don't work in unit test because they assume they insert functions and
+ * assume the names are unique. This breaks when there are two light effects in the same
+ * shader.
+ */
+ /*
kDiffuseDistant_EffectType,
kDiffusePoint_EffectType,
kDiffuseSpot_EffectType,
kSpecularDistant_EffectType,
kSpecularPoint_EffectType,
kSpecularSpot_EffectType,
- kSweepGradient_EffectType,
+ */
+
kColorTable_EffectType,
kEffectCount
@@ -101,7 +82,20 @@ const GrCustomStage* create_random_effect(StageDesc* stageDesc, GrRandom* random
Gr1DKernelEffect::kY_Direction
};
- static const int kMaxGradientStops = 4;
+ // The new code uses SkRandom not GrRandom.
+ // TODO: Remove GrRandom.
+ SkRandom sk_random;
+ sk_random.setSeed(random->nextU());
+
+ bool useFactory = random_bool(random);
+ if (useFactory) {
+ GrCustomStage* stage = GrCustomStageTestFactory::CreateStage(&sk_random,
+ context,
+ dummyTextures);
+ GrAssert(stage);
+ return stage;
+ }
+
// TODO: When matrices are property of the custom-stage then remove the
// no-persp flag code below.
@@ -147,89 +141,7 @@ const GrCustomStage* create_random_effect(StageDesc* stageDesc, GrRandom* random
kernelRadius,
GrContext::kDilate_MorphologyType));
}
- case kRadialGradient_EffectType: {
- SkPoint center = {random->nextF(), random->nextF()};
- SkScalar radius = random->nextF();
- int colorCount = kMaxGradientStops;
- SkColor colors[kMaxGradientStops];
- SkScalar stops[kMaxGradientStops];
- SkScalar* stopsPtr = stops;
- random_gradient(random, &colorCount, colors, &stopsPtr);
- SkShader::TileMode tileMode = static_cast<SkShader::TileMode>(
- random_int(random, SkShader::kTileModeCount));
- SkAutoTUnref<SkGradientShaderBase> gradient(
- static_cast<SkGradientShaderBase*>(SkGradientShader::CreateRadial(
- center, radius, colors, stopsPtr, colorCount, tileMode, NULL)));
- GrSamplerState sampler;
- GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
- GrAssert(NULL != stage);
- return stage;
- }
- case kRadial2Gradient_EffectType: {
- SkPoint center1 = {random->nextF(), random->nextF()};
- SkPoint center2 = {random->nextF(), random->nextF()};
- SkScalar radius1 = random->nextF();
- SkScalar radius2;
- do {
- radius2 = random->nextF();
- } while (radius1 == radius2);
- int colorCount = kMaxGradientStops;
- SkColor colors[kMaxGradientStops];
- SkScalar stops[kMaxGradientStops];
- SkScalar* stopsPtr = stops;
- random_gradient(random, &colorCount, colors, &stopsPtr);
- SkShader::TileMode tileMode = static_cast<SkShader::TileMode>(
- random_int(random, SkShader::kTileModeCount));
- SkAutoTUnref<SkGradientShaderBase> gradient(
- static_cast<SkGradientShaderBase*>(SkGradientShader::
- CreateTwoPointRadial(center1, radius1, center2, radius2,
- colors, stopsPtr, colorCount, tileMode, NULL)));
- GrSamplerState sampler;
- GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
- GrAssert(NULL != stage);
- return stage;
- }
- case kConical2Gradient_EffectType: {
- SkPoint center1 = {random->nextF(), random->nextF()};
- SkScalar radius1 = random->nextF();
- SkPoint center2;
- SkScalar radius2;
- do {
- center1.set(random->nextF(), random->nextF());
- radius2 = random->nextF();
- } while (radius1 == radius2 && center1 == center2);
- int colorCount = kMaxGradientStops;
- SkColor colors[kMaxGradientStops];
- SkScalar stops[kMaxGradientStops];
- SkScalar* stopsPtr = stops;
- random_gradient(random, &colorCount, colors, &stopsPtr);
- SkShader::TileMode tileMode = static_cast<SkShader::TileMode>(
- random_int(random, SkShader::kTileModeCount));
- SkAutoTUnref<SkGradientShaderBase> gradient(
- static_cast<SkGradientShaderBase*>(SkGradientShader::
- CreateTwoPointConical(center1, radius1, center2, radius2,
- colors, stopsPtr, colorCount, tileMode, NULL)));
- GrSamplerState sampler;
- GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
- GrAssert(NULL != stage);
- return stage;
- }
- case kSweepGradient_EffectType: {
- SkPoint center = {random->nextF(), random->nextF()};
- SkScalar radius = random->nextF();
- int colorCount = kMaxGradientStops;
- SkColor colors[kMaxGradientStops];
- SkScalar stops[kMaxGradientStops];
- SkScalar* stopsPtr = stops;
- random_gradient(random, &colorCount, colors, &stopsPtr);
- SkAutoTUnref<SkGradientShaderBase> gradient(
- static_cast<SkGradientShaderBase*>(SkGradientShader::CreateSweep(
- center.fX, center.fY, colors, stopsPtr, colorCount, NULL)));
- GrSamplerState sampler;
- GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
- GrAssert(NULL != stage);
- return stage;
- }
+ /*
case kDiffuseDistant_EffectType: {
SkPoint3 direction = random_point3(random);
direction.normalize();
@@ -316,8 +228,10 @@ const GrCustomStage* create_random_effect(StageDesc* stageDesc, GrRandom* random
SkASSERT(ok);
return stage;
}
+ */
case kColorTable_EffectType: {
- return SkNEW_ARGS(GrColorTableEffect, (NULL));
+ GrTexture* alphaTexture = dummyTextures[GrCustomStageTestFactory::kAlphaTextureIdx];
+ return SkNEW_ARGS(GrColorTableEffect, (alphaTexture));
}
default:
GrCrash("Unexpected custom effect type");
@@ -328,6 +242,16 @@ const GrCustomStage* create_random_effect(StageDesc* stageDesc, GrRandom* random
bool GrGpuGL::programUnitTest() {
+ GrTextureDesc dummyDesc;
+ dummyDesc.fConfig = kSkia8888_PM_GrPixelConfig;
+ dummyDesc.fWidth = 34;
+ dummyDesc.fHeight = 18;
+ SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
+ dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
+ dummyDesc.fWidth = 16;
+ dummyDesc.fHeight = 22;
+ SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
+
// GrGLSLGeneration glslGeneration =
GrGetGLSLGeneration(this->glBinding(), this->glInterface());
static const int STAGE_OPTS[] = {
@@ -416,12 +340,15 @@ bool GrGpuGL::programUnitTest() {
stage.fCustomStageKey = 0;
- stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
+ stage.fOptFlags |= STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
- bool useCustomEffect = random_bool(&random);
- if (useCustomEffect) {
- customStages[s].reset(create_random_effect(&stage, &random, getContext()));
+ if (stage.isEnabled()) {
+ GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
+ customStages[s].reset(create_random_effect(&stage,
+ &random,
+ getContext(),
+ dummyTextures));
if (NULL != customStages[s]) {
stage.fCustomStageKey =
customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps());