diff options
author | 2012-08-03 14:34:46 +0000 | |
---|---|---|
committer | 2012-08-03 14:34:46 +0000 | |
commit | d472620458e2383e6dd949f4e1aaf61160717ffe (patch) | |
tree | 2822ac4f1c55d6eaa9ed4ac6dc2b7014de5410ff /src | |
parent | dea8e252e1259f5bdd15e16a21646402058b939d (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
Diffstat (limited to 'src')
-rw-r--r-- | src/effects/gradients/SkGradientShader.cpp | 24 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShaderPriv.h | 16 | ||||
-rw-r--r-- | src/effects/gradients/SkLinearGradient.cpp | 25 | ||||
-rw-r--r-- | src/effects/gradients/SkRadialGradient.cpp | 25 | ||||
-rw-r--r-- | src/effects/gradients/SkSweepGradient.cpp | 25 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointConicalGradient.cpp | 32 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointRadialGradient.cpp | 33 | ||||
-rw-r--r-- | src/gpu/GrCustomStage.cpp | 7 | ||||
-rw-r--r-- | src/gpu/effects/GrColorTableEffect.cpp | 19 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 18 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 6 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramStage.h | 7 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.cpp | 12 |
13 files changed, 229 insertions, 20 deletions
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(); |