Registry-based unit test for custom effects
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 3 Aug 2012 14:34:46 +0000 (14:34 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 3 Aug 2012 14:34:46 +0000 (14:34 +0000)
Review URL: http://codereview.appspot.com/6447085/

git-svn-id: http://skia.googlecode.com/svn/trunk@4946 2bbb7eff-a529-9590-31e7-b0007b416f81

18 files changed:
gyp/gpu.gyp
include/core/SkRandom.h
include/gpu/GrCustomStage.h
include/gpu/GrCustomStageUnitTest.h [new file with mode: 0644]
src/effects/gradients/SkGradientShader.cpp
src/effects/gradients/SkGradientShaderPriv.h
src/effects/gradients/SkLinearGradient.cpp
src/effects/gradients/SkRadialGradient.cpp
src/effects/gradients/SkSweepGradient.cpp
src/effects/gradients/SkTwoPointConicalGradient.cpp
src/effects/gradients/SkTwoPointRadialGradient.cpp
src/gpu/GrCustomStage.cpp
src/gpu/effects/GrColorTableEffect.cpp
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgram.h
src/gpu/gl/GrGLProgramStage.h
src/gpu/gl/GrGLShaderBuilder.cpp
tests/GLProgramsTest.cpp

index 177a728..652708f 100644 (file)
         '../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',
index b850df3..b1b7564 100644 (file)
@@ -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) {
index a13ecd4..0ac7a76 100644 (file)
@@ -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 (file)
index 0000000..9cbadf3
--- /dev/null
@@ -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
index e415c62..f61f8d5 100644 (file)
@@ -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
index 9e80fd3..807bf32 100644 (file)
@@ -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;
 
index d88540e..ef39768 100644 (file)
@@ -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,
index f3978a5..dbde95a 100644 (file)
@@ -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,
index 0dee9b5..89ebba2 100644 (file)
@@ -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,
index 8902573..528291b 100644 (file)
@@ -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(
index 84ae91d..441f5a8 100644 (file)
@@ -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)
index bea07cf..6d7bfad 100644 (file)
 
 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() {
index f1ce664..94eb8fd 100644 (file)
@@ -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);
index ebbd267..b04d924 100644 (file)
@@ -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(),
index 62c70e5..989b7c6 100644 (file)
@@ -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],
index 8e3a4b1..69095b6 100644 (file)
@@ -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
index fb70556..3ca4086 100644 (file)
@@ -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();
index d7aea98..a43ad83 100644 (file)
@@ -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());