diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-08-03 14:34:46 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-08-03 14:34:46 +0000 |
commit | d472620458e2383e6dd949f4e1aaf61160717ffe (patch) | |
tree | 2822ac4f1c55d6eaa9ed4ac6dc2b7014de5410ff | |
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
-rw-r--r-- | gyp/gpu.gyp | 1 | ||||
-rw-r--r-- | include/core/SkRandom.h | 12 | ||||
-rw-r--r-- | include/gpu/GrCustomStage.h | 1 | ||||
-rw-r--r-- | include/gpu/GrCustomStageUnitTest.h | 73 | ||||
-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 | ||||
-rw-r--r-- | tests/GLProgramsTest.cpp | 173 |
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()); |