From a5e65ec434fed44dc616e4f64950b835b541181b Mon Sep 17 00:00:00 2001 From: "twiz@google.com" Date: Thu, 2 Aug 2012 15:15:16 +0000 Subject: [PATCH] Introduction of set of functions to manage generation of texture fetch shader code. A new set of routines have been added to GrGLShaderBuilder to emit texture fetches, taking into consideration the format of the texture to be accessed, and the channel swizzle. Review URL: https://codereview.appspot.com/6446072 git-svn-id: http://skia.googlecode.com/svn/trunk@4919 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/gpu/GrCustomStage.h | 29 +++++++- include/gpu/GrProgramStageFactory.h | 27 ++++--- src/effects/SkLightingImageFilter.cpp | 6 +- src/effects/gradients/SkLinearGradient.cpp | 2 +- src/effects/gradients/SkRadialGradient.cpp | 2 +- src/effects/gradients/SkSweepGradient.cpp | 2 +- .../gradients/SkTwoPointConicalGradient.cpp | 6 +- .../gradients/SkTwoPointRadialGradient.cpp | 4 +- src/gpu/GrCustomStage.cpp | 17 ++++- src/gpu/effects/GrColorTableEffect.cpp | 60 +++++++++++---- src/gpu/effects/GrColorTableEffect.h | 4 + src/gpu/effects/GrConvolutionEffect.cpp | 7 +- src/gpu/effects/GrMorphologyEffect.cpp | 6 +- src/gpu/effects/GrSingleTextureEffect.cpp | 4 +- src/gpu/effects/GrTextureDomainEffect.cpp | 4 +- src/gpu/gl/GrGLProgram.h | 2 +- src/gpu/gl/GrGLProgramStage.cpp | 11 +++ src/gpu/gl/GrGLProgramStage.h | 2 + src/gpu/gl/GrGLShaderBuilder.cpp | 73 +++++++++++++++++++ src/gpu/gl/GrGLShaderBuilder.h | 17 +++++ src/gpu/gl/GrGpuGL_program.cpp | 6 +- src/gpu/gl/GrGpuGL_unittest.cpp | 2 +- 22 files changed, 238 insertions(+), 55 deletions(-) diff --git a/include/gpu/GrCustomStage.h b/include/gpu/GrCustomStage.h index 906076656a..a13ecd469e 100644 --- a/include/gpu/GrCustomStage.h +++ b/include/gpu/GrCustomStage.h @@ -14,6 +14,27 @@ class GrContext; class GrTexture; +class SkString; + +/** A class representing the swizzle access pattern for a texture. + */ +class GrTextureAccess { +public: + typedef char Swizzle[4]; + + GrTextureAccess(const GrTexture* texture, const SkString& swizzle); + + const GrTexture* getTexture() const { return fTexture; } + const Swizzle& getSwizzle() const { return fSwizzle; } + + bool referencesAlpha() const { + return fSwizzle[0] == 'a' || fSwizzle[1] == 'a' || fSwizzle[2] == 'a' || fSwizzle[3] == 'a'; + } + +private: + const GrTexture* fTexture; + Swizzle fSwizzle; +}; /** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the Ganesh shading pipeline. @@ -74,13 +95,17 @@ public: */ virtual bool isEqual(const GrCustomStage&) const; - /** Human-meaningful string to identify this effect; may be embedded - in generated shader code. */ + /** Human-meaningful string to identify this effect; may be embedded + in generated shader code. */ const char* name() const { return this->getFactory().name(); } virtual unsigned int numTextures() const; virtual GrTexture* texture(unsigned int index) const; + /** Returns the access pattern for the texture at index. Returns NULL if index is + unused. */ + virtual const GrTextureAccess* textureAccess(unsigned int index) const; + void* operator new(size_t size); void operator delete(void* target); diff --git a/include/gpu/GrProgramStageFactory.h b/include/gpu/GrProgramStageFactory.h index f2b4f5fc90..90f6b32851 100644 --- a/include/gpu/GrProgramStageFactory.h +++ b/include/gpu/GrProgramStageFactory.h @@ -19,15 +19,18 @@ class GrCustomStage; class GrGLProgramStage; +class GrGLCaps; class GrProgramStageFactory : public GrNoncopyable { public: - typedef uint16_t StageKey; + typedef uint32_t StageKey; enum { kProgramStageKeyBits = 10, + kTexturingStageKeyBits = 6 }; - virtual StageKey glStageKey(const GrCustomStage& stage) const = 0; + virtual StageKey glStageKey(const GrCustomStage& stage, + const GrGLCaps& caps ) const = 0; virtual GrGLProgramStage* createGLInstance( const GrCustomStage& stage) const = 0; @@ -68,7 +71,7 @@ template class GrTProgramStageFactory : public GrProgramStageFactory { public: - typedef typename StageClass::GLProgramStage GLProgramStage; + typedef typename StageClass::GLProgramStage GLProgramStage; /** Returns a human-readable name that is accessible via GrCustomStage or GrGLProgramStage and is consistent between the two of them. @@ -80,20 +83,26 @@ public: id identifies the GrCustomShader subclass. The remainder is based on the aspects of the GrCustomStage object's configuration that affect GLSL code generation. */ - virtual StageKey glStageKey(const GrCustomStage& stage) const SK_OVERRIDE { + virtual StageKey glStageKey(const GrCustomStage& stage, + const GrGLCaps& caps) const SK_OVERRIDE { GrAssert(kIllegalStageClassID != fStageClassID); - StageKey stageID = GLProgramStage::GenKey(stage); + StageKey stageID = GLProgramStage::GenKey(stage, caps); + StageKey textureKey = GLProgramStage::GenTextureKey(stage, caps); #if GR_DEBUG static const StageKey kIllegalIDMask = (uint16_t) (~((1U << kProgramStageKeyBits) - 1)); GrAssert(!(kIllegalIDMask & stageID)); + + static const StageKey kIllegalTextureKeyMask = + (uint16_t) (~((1U << kTexturingStageKeyBits) - 1)); + GrAssert(!(kIllegalTextureKeyMask & textureKey)); #endif - return fStageClassID | stageID; + return fStageClassID | (textureKey << kProgramStageKeyBits) | stageID; } /** Returns a new instance of the appropriate *GL* implementation class - for the given GrCustomStage; caller is responsible for deleting - the object. */ + for the given GrCustomStage; caller is responsible for deleting + the object. */ virtual GLProgramStage* createGLInstance( const GrCustomStage& stage) const SK_OVERRIDE { return SkNEW_ARGS(GLProgramStage, (*this, stage)); @@ -113,7 +122,7 @@ public: protected: GrTProgramStageFactory() { - fStageClassID = GenID() << kProgramStageKeyBits; + fStageClassID = GenID() << (kProgramStageKeyBits + kTexturingStageKeyBits) ; } }; diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp index 98c294c60c..b6532aa292 100644 --- a/src/effects/SkLightingImageFilter.cpp +++ b/src/effects/SkLightingImageFilter.cpp @@ -918,7 +918,7 @@ public: virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0; - static inline StageKey GenKey(const GrCustomStage& s); + static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps); virtual void setData(const GrGLUniformManager&, const GrCustomStage&, @@ -1086,8 +1086,8 @@ vec3 interiorNormal(float m[9], float surfaceScale) {\n\ code->appendf(")%s;\n", builder->fModulate.c_str()); } -GrGLProgramStage::StageKey GrGLLightingEffect::GenKey( - const GrCustomStage& s) { +GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(const GrCustomStage& s, + const GrGLCaps& caps) { return static_cast(s).light()->type(); } diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp index cd44d3f14e..d88540e244 100644 --- a/src/effects/gradients/SkLinearGradient.cpp +++ b/src/effects/gradients/SkLinearGradient.cpp @@ -491,7 +491,7 @@ public: const char* outputColor, const char* inputColor, const char* samplerName) SK_OVERRIDE; - static StageKey GenKey(const GrCustomStage& s) { return 0; } + static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; } private: diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp index 32083dc1da..f3978a5951 100644 --- a/src/effects/gradients/SkRadialGradient.cpp +++ b/src/effects/gradients/SkRadialGradient.cpp @@ -487,7 +487,7 @@ public: const char* inputColor, const char* samplerName) SK_OVERRIDE; - static StageKey GenKey(const GrCustomStage& s) { return 0; } + static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; } private: diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp index 1daaa7d231..0dee9b5303 100644 --- a/src/effects/gradients/SkSweepGradient.cpp +++ b/src/effects/gradients/SkSweepGradient.cpp @@ -396,7 +396,7 @@ public: const char* inputColor, const char* samplerName) SK_OVERRIDE; - static StageKey GenKey(const GrCustomStage& s) { return 0; } + static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; } private: diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp index 9fe180a3c9..89025733c2 100644 --- a/src/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp @@ -340,7 +340,7 @@ public: const GrRenderTarget*, int stageNum) SK_OVERRIDE; - static StageKey GenKey(const GrCustomStage& s); + static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps); protected: @@ -636,7 +636,7 @@ void GrGLConical2Gradient::setData(const GrGLUniformManager& uman, } } -GrCustomStage::StageKey GrGLConical2Gradient::GenKey(const GrCustomStage& s) { +GrCustomStage::StageKey GrGLConical2Gradient::GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return (static_cast(s).isDegenerate()); } @@ -669,4 +669,4 @@ GrCustomStage* SkTwoPointConicalGradient::asNewCustomStage( return NULL; } -#endif \ No newline at end of file +#endif diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp index 06e27fe17a..84ae91dafa 100644 --- a/src/effects/gradients/SkTwoPointRadialGradient.cpp +++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp @@ -373,7 +373,7 @@ public: const GrRenderTarget*, int stageNum) SK_OVERRIDE; - static StageKey GenKey(const GrCustomStage& s); + static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps); protected: @@ -608,7 +608,7 @@ void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman, } } -GrCustomStage::StageKey GrGLRadial2Gradient::GenKey(const GrCustomStage& s) { +GrCustomStage::StageKey GrGLRadial2Gradient::GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return (static_cast(s).isDegenerate()); } diff --git a/src/gpu/GrCustomStage.cpp b/src/gpu/GrCustomStage.cpp index 43de5ae271..bea07cfab4 100644 --- a/src/gpu/GrCustomStage.cpp +++ b/src/gpu/GrCustomStage.cpp @@ -8,6 +8,7 @@ #include "GrContext.h" #include "GrCustomStage.h" #include "GrMemoryPool.h" +#include "SkString.h" #include "SkTLS.h" SK_DEFINE_INST_COUNT(GrCustomStage) @@ -31,6 +32,17 @@ private: int32_t GrProgramStageFactory::fCurrStageClassID = GrProgramStageFactory::kIllegalStageClassID; +GrTextureAccess::GrTextureAccess(const GrTexture* texture, const SkString& swizzle) + : fTexture(texture) { + GrAssert(swizzle.size() <= 4); + for (unsigned int offset = 0; offset < swizzle.size(); ++offset) { + fSwizzle[offset] = swizzle[offset]; + } + if (swizzle.size() < 4) { + fSwizzle[swizzle.size()] = 0; + } +} + GrCustomStage::GrCustomStage() { } @@ -63,6 +75,10 @@ GrTexture* GrCustomStage::texture(unsigned int index) const { return NULL; } +const GrTextureAccess* GrCustomStage::textureAccess(unsigned int index) const { + return NULL; +} + void * GrCustomStage::operator new(size_t size) { return GrCustomStage_Globals::GetTLS()->allocate(size); } @@ -70,4 +86,3 @@ void * GrCustomStage::operator new(size_t size) { void GrCustomStage::operator delete(void* target) { GrCustomStage_Globals::GetTLS()->release(target); } - diff --git a/src/gpu/effects/GrColorTableEffect.cpp b/src/gpu/effects/GrColorTableEffect.cpp index 2075c22fbb..f1ce664826 100644 --- a/src/gpu/effects/GrColorTableEffect.cpp +++ b/src/gpu/effects/GrColorTableEffect.cpp @@ -30,49 +30,72 @@ public: const GrRenderTarget*, int stageNum) SK_OVERRIDE {} - static inline StageKey GenKey(const GrCustomStage&); + static StageKey GenKey(const GrCustomStage&, const GrGLCaps&); private: + + const GrCustomStage& fCustomStage; + typedef GrGLProgramStage INHERITED; }; GrGLColorTableEffect::GrGLColorTableEffect( const GrProgramStageFactory& factory, const GrCustomStage& stage) - : INHERITED(factory) { + : INHERITED(factory) + , fCustomStage(stage) { } -void GrGLColorTableEffect::emitFS(GrGLShaderBuilder* state, +void GrGLColorTableEffect::emitFS(GrGLShaderBuilder* builder, const char* outputColor, const char* inputColor, const char* samplerName) { static const float kColorScaleFactor = 255.0f / 256.0f; static const float kColorOffsetFactor = 1.0f / 512.0f; - SkString* code = &state->fFSCode; + 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); - code->appendf("\t\t%s.a = texture2D(%s, vec2(coord.a, 0.125)).a;\n", - outputColor, samplerName); - code->appendf("\t\t%s.r = texture2D(%s, vec2(coord.r, 0.375)).a;\n", - outputColor, samplerName); - code->appendf("\t\t%s.g = texture2D(%s, vec2(coord.g, 0.625)).a;\n", - outputColor, samplerName); - code->appendf("\t\t%s.b = texture2D(%s, vec2(coord.b, 0.875)).a;\n", - outputColor, samplerName); + + const GrTextureAccess& access = *fCustomStage.textureAccess(0); + code->appendf("\t\t%s.a = ", outputColor); + builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode, + access, + samplerName, + "vec2(coord.a, 0.125)"); + + code->appendf("\t\t%s.r = ", outputColor); + builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode, + access, + samplerName, + "vec2(coord.r, 0.375)"); + + code->appendf("\t\t%s.g = ", outputColor); + builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode, + access, + samplerName, + "vec2(coord.g, 0.625)"); + + code->appendf("\t\t%s.b = ", outputColor); + builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode, + access, + samplerName, + "vec2(coord.b, 0.875)"); + code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); } -GrGLProgramStage::StageKey GrGLColorTableEffect::GenKey( - const GrCustomStage& s) { +GrGLProgramStage::StageKey GrGLColorTableEffect::GenKey(const GrCustomStage& s, + const GrGLCaps& caps) { return 0; } /////////////////////////////////////////////////////////////////////////////// GrColorTableEffect::GrColorTableEffect(GrTexture* texture) - : INHERITED(texture) { + : INHERITED(texture) + , fTextureAccess(texture, SkString("a")) { } GrColorTableEffect::~GrColorTableEffect() { @@ -85,3 +108,10 @@ const GrProgramStageFactory& GrColorTableEffect::getFactory() const { bool GrColorTableEffect::isEqual(const GrCustomStage& sBase) const { return INHERITED::isEqual(sBase); } + +const GrTextureAccess* GrColorTableEffect::textureAccess(unsigned int index) const { + if (0 == index) + return &fTextureAccess; + + return NULL; +} diff --git a/src/gpu/effects/GrColorTableEffect.h b/src/gpu/effects/GrColorTableEffect.h index ee7a630469..16d76ade7f 100644 --- a/src/gpu/effects/GrColorTableEffect.h +++ b/src/gpu/effects/GrColorTableEffect.h @@ -29,10 +29,14 @@ public: virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE; virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE; + virtual const GrTextureAccess* textureAccess(unsigned int index) const SK_OVERRIDE; + typedef GrGLColorTableEffect GLProgramStage; private: + GrTextureAccess fTextureAccess; + typedef GrSingleTextureEffect INHERITED; }; #endif diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp index 6af891b098..5cce800b51 100644 --- a/src/gpu/effects/GrConvolutionEffect.cpp +++ b/src/gpu/effects/GrConvolutionEffect.cpp @@ -33,7 +33,7 @@ public: const GrRenderTarget*, int stageNum) SK_OVERRIDE; - static inline StageKey GenKey(const GrCustomStage&); + static inline StageKey GenKey(const GrCustomStage&, const GrGLCaps&); private: int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); } @@ -125,8 +125,8 @@ void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman, uman.set1fv(fKernelUni, 0, this->width(), conv.kernel()); } -GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey( - const GrCustomStage& s) { +GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(const GrCustomStage& s, + const GrGLCaps& caps) { return static_cast(s).radius(); } @@ -185,4 +185,3 @@ bool GrConvolutionEffect::isEqual(const GrCustomStage& sBase) const { this->direction() == s.direction() && 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); } - diff --git a/src/gpu/effects/GrMorphologyEffect.cpp b/src/gpu/effects/GrMorphologyEffect.cpp index f8b268dae6..be8485e554 100644 --- a/src/gpu/effects/GrMorphologyEffect.cpp +++ b/src/gpu/effects/GrMorphologyEffect.cpp @@ -26,7 +26,7 @@ public: const char* inputColor, const char* samplerName) SK_OVERRIDE; - static inline StageKey GenKey(const GrCustomStage& s); + static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps); virtual void setData(const GrGLUniformManager&, const GrCustomStage&, @@ -98,8 +98,8 @@ void GrGLMorphologyEffect ::emitFS(GrGLShaderBuilder* builder, code->appendf("\t\t%s = value%s;\n", outputColor, builder->fModulate.c_str()); } -GrGLProgramStage::StageKey GrGLMorphologyEffect::GenKey( - const GrCustomStage& s) { +GrGLProgramStage::StageKey GrGLMorphologyEffect::GenKey(const GrCustomStage& s, + const GrGLCaps& caps) { const GrMorphologyEffect& m = static_cast(s); StageKey key = static_cast(m.radius()); key |= (m.type() << 8); diff --git a/src/gpu/effects/GrSingleTextureEffect.cpp b/src/gpu/effects/GrSingleTextureEffect.cpp index 350d9e6bc5..5f66e09805 100644 --- a/src/gpu/effects/GrSingleTextureEffect.cpp +++ b/src/gpu/effects/GrSingleTextureEffect.cpp @@ -26,7 +26,7 @@ public: builder->emitDefaultFetch(outputColor, samplerName); } - static inline StageKey GenKey(const GrCustomStage&) { return 0; } + static inline StageKey GenKey(const GrCustomStage&, const GrGLCaps&) { return 0; } private: @@ -56,5 +56,3 @@ GrTexture* GrSingleTextureEffect::texture(unsigned int index) const { const GrProgramStageFactory& GrSingleTextureEffect::getFactory() const { return GrTProgramStageFactory::getInstance(); } - - diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp index 1bf0512da7..e76d0c916b 100644 --- a/src/gpu/effects/GrTextureDomainEffect.cpp +++ b/src/gpu/effects/GrTextureDomainEffect.cpp @@ -27,7 +27,7 @@ public: const GrRenderTarget*, int stageNum) SK_OVERRIDE; - static inline StageKey GenKey(const GrCustomStage&) { return 0; } + static inline StageKey GenKey(const GrCustomStage&, const GrGLCaps&) { return 0; } private: GrGLUniformManager::UniformHandle fNameUni; @@ -107,5 +107,3 @@ bool GrTextureDomainEffect::isEqual(const GrCustomStage& sBase) const { const GrTextureDomainEffect& s = static_cast(sBase); return (INHERITED::isEqual(sBase) && this->fTextureDomain == s.fTextureDomain); } - - diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 18d97d5652..62c70e54bc 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -164,7 +164,7 @@ public: /** Non-zero if user-supplied code will write the stage's contribution to the fragment shader. */ - uint16_t fCustomStageKey; + GrProgramStageFactory::StageKey fCustomStageKey; GR_STATIC_ASSERT((InConfigFlags)(uint8_t)kInConfigBitMask == kInConfigBitMask); diff --git a/src/gpu/gl/GrGLProgramStage.cpp b/src/gpu/gl/GrGLProgramStage.cpp index 12c3894131..b1a37fe374 100644 --- a/src/gpu/gl/GrGLProgramStage.cpp +++ b/src/gpu/gl/GrGLProgramStage.cpp @@ -27,3 +27,14 @@ void GrGLProgramStage::setData(const GrGLUniformManager&, int stageNum) { } +GrGLProgramStage::StageKey GrGLProgramStage::GenTextureKey(const GrCustomStage& stage, + const GrGLCaps& caps) { + StageKey key = 0; + for (unsigned int index = 0; index < stage.numTextures(); ++index) { + if (stage.textureAccess(index)) { + key = (key << index) | + GrGLShaderBuilder::KeyForTextureAccess(*stage.textureAccess(index), caps); + } + } + return key; +} diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h index 12163f8917..8e3a4b1584 100644 --- a/src/gpu/gl/GrGLProgramStage.h +++ b/src/gpu/gl/GrGLProgramStage.h @@ -78,6 +78,8 @@ public: const char* name() const { return fFactory.name(); } + static StageKey GenTextureKey(const GrCustomStage&, const GrGLCaps&); + protected: const GrProgramStageFactory& fFactory; diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp index 28449537e7..0d2a1ecf44 100644 --- a/src/gpu/gl/GrGLShaderBuilder.cpp +++ b/src/gpu/gl/GrGLShaderBuilder.cpp @@ -8,6 +8,7 @@ #include "gl/GrGLShaderBuilder.h" #include "gl/GrGLProgram.h" #include "gl/GrGLUniformHandle.h" +#include "GrTexture.h" // number of each input/output type in a single allocation block static const int kVarsPerBlock = 8; @@ -21,6 +22,50 @@ static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar: typedef GrGLUniformManager::UniformHandle UniformHandle; /////////////////////////////////////////////////////////////////////////////// +static SkString build_sampler_string(GrGLShaderBuilder::SamplerMode samplerMode) { + SkString sampler("texture2D"); + switch (samplerMode) { + case GrGLShaderBuilder::kDefault_SamplerMode: + break; + case GrGLShaderBuilder::kProj_SamplerMode: + sampler.append("Proj"); + break; + case GrGLShaderBuilder::kExplicitDivide_SamplerMode: + GrAssert(false); // Not Implemented + break; + } + + return sampler; +} + +static bool texture_requires_alpha_to_red_swizzle(const GrGLCaps& caps, + const GrTextureAccess& access) { + return GrPixelConfigIsAlphaOnly(access.getTexture()->config()) && caps.textureRedSupport() && + access.referencesAlpha(); +} + +static SkString build_swizzle_string(const GrTextureAccess& textureAccess, + const GrGLCaps& caps) { + const GrTextureAccess::Swizzle& swizzle = textureAccess.getSwizzle(); + if (0 == swizzle[0]) { + return SkString(""); + } + + SkString swizzleOut("."); + bool alphaIsRed = texture_requires_alpha_to_red_swizzle(caps, textureAccess); + for (int offset = 0; offset < 4 && swizzle[offset]; ++offset) { + if (alphaIsRed && 'a' == swizzle[offset]) { + swizzleOut.appendf("r"); + } else { + swizzleOut.appendf("%c", swizzle[offset]); + } + } + + return swizzleOut; +} + +/////////////////////////////////////////////////////////////////////////////// + // Architectural assumption: always 2-d input coords. // Likely to become non-constant and non-static, perhaps even // varying by stage, if we use 1D textures for gradients! @@ -120,6 +165,34 @@ void GrGLShaderBuilder::emitDefaultFetch(const char* outColor, fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str()); } +void GrGLShaderBuilder::emitCustomTextureLookup(SamplerMode samplerMode, + const GrTextureAccess& textureAccess, + const char* samplerName, + const char* coordName) { + GrAssert(samplerName && coordName); + SkString sampler = build_sampler_string(samplerMode); + SkString swizzle = build_swizzle_string(textureAccess, fContext.caps()); + + fFSCode.appendf("%s( %s, %s)%s;\n", sampler.c_str(), samplerName, + coordName, swizzle.c_str()); +} + +GrCustomStage::StageKey GrGLShaderBuilder::KeyForTextureAccess(const GrTextureAccess& access, + const GrGLCaps& caps) { + GrCustomStage::StageKey key = 0; + // Assume that swizzle support implies that we never have to modify a shader to adjust + // for texture format/swizzle settings. + if (caps.textureSwizzleSupport()) { + return key; + } + + if (texture_requires_alpha_to_red_swizzle(caps, access)) { + key = 1; + } + + return key; +} + GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility, GrSLType type, const char* name, diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h index f110628627..16a11e29a0 100644 --- a/src/gpu/gl/GrGLShaderBuilder.h +++ b/src/gpu/gl/GrGLShaderBuilder.h @@ -9,6 +9,7 @@ #define GrGLShaderBuilder_DEFINED #include "GrAllocator.h" +#include "GrCustomStage.h" #include "gl/GrGLShaderVar.h" #include "gl/GrGLSL.h" #include "gl/GrGLUniformManager.h" @@ -55,6 +56,22 @@ public: void emitDefaultFetch(const char* outColor, const char* samplerName); + /** Emits a texture lookup to the shader code with the form: + texture2D{Proj}(samplerName, coordName).swizzle + The routine selects the type of texturing based on samplerMode. + The generated swizzle state is built based on the format of the texture and the requested + swizzle access pattern. */ + void emitCustomTextureLookup(SamplerMode samplerMode, + const GrTextureAccess& textureAccess, + const char* samplerName, + const char* coordName); + + /** Generates a StageKey for the shader code based on the texture access parameters and the + capabilities of the GL context. This is useful for keying the shader programs that may + have multiple representations, based on the type/format of textures used. */ + static GrCustomStage::StageKey KeyForTextureAccess(const GrTextureAccess& access, + const GrGLCaps& caps); + /** Add a uniform variable to the current program, that has visibilty in one or more shaders. visibility is a bitfield of ShaderType values indicating from which shaders the uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index 6d6d9167af..c959f66b9a 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -596,12 +596,13 @@ namespace { void setup_custom_stage(GrGLProgram::Desc::StageDesc* stage, const GrSamplerState& sampler, + const GrGLCaps& caps, const GrCustomStage** customStages, GrGLProgram* program, int index) { const GrCustomStage* customStage = sampler.getCustomStage(); if (customStage) { const GrProgramStageFactory& factory = customStage->getFactory(); - stage->fCustomStageKey = factory.glStageKey(*customStage); + stage->fCustomStageKey = factory.glStageKey(*customStage, caps); customStages[index] = customStage; } else { stage->fCustomStageKey = 0; @@ -746,7 +747,8 @@ void GrGpuGL::buildProgram(bool isPoints, } } - setup_custom_stage(&stage, sampler, customStages, fCurrentProgram.get(), s); + setup_custom_stage(&stage, sampler, this->glCaps(), customStages, + fCurrentProgram.get(), s); } else { stage.fOptFlags = 0; diff --git a/src/gpu/gl/GrGpuGL_unittest.cpp b/src/gpu/gl/GrGpuGL_unittest.cpp index 1a28b9811f..7fd61d9f88 100644 --- a/src/gpu/gl/GrGpuGL_unittest.cpp +++ b/src/gpu/gl/GrGpuGL_unittest.cpp @@ -413,7 +413,7 @@ bool GrGpuGL::programUnitTest() { customStages[s].reset(create_random_effect(&stage, &random, getContext())); if (NULL != customStages[s]) { stage.fCustomStageKey = - customStages[s]->getFactory().glStageKey(*customStages[s]); + customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps()); } } }