From ce49e16d3b4a5b554d75a609e4ac8973c23c17e2 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Thu, 1 Nov 2012 13:50:50 +0000 Subject: Checkpoint in moving texture matrices out of GrGLProgram and into GrGLEffect. Review URL: https://codereview.appspot.com/6818064 git-svn-id: http://skia.googlecode.com/svn/trunk@6233 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gm/texdata.cpp | 2 +- gyp/gpu.gypi | 2 + include/gpu/GrEffectUnitTest.h | 17 +- src/effects/SkBlendImageFilter.cpp | 40 ++-- src/effects/SkColorMatrixFilter.cpp | 2 + src/effects/gradients/SkGradientShader.cpp | 33 +++- src/effects/gradients/SkGradientShaderPriv.h | 39 +++- src/effects/gradients/SkLinearGradient.cpp | 22 ++- src/effects/gradients/SkRadialGradient.cpp | 24 ++- src/effects/gradients/SkSweepGradient.cpp | 20 +- .../gradients/SkTwoPointConicalGradient.cpp | 36 ++-- src/effects/gradients/SkTwoPointRadialGradient.cpp | 46 +++-- src/gpu/GrContext.cpp | 6 +- src/gpu/GrDrawState.h | 8 +- src/gpu/GrEffect.cpp | 20 ++ src/gpu/SkGpuDevice.cpp | 8 +- src/gpu/effects/GrSingleTextureEffect.cpp | 55 +++++- src/gpu/effects/GrSingleTextureEffect.h | 22 ++- src/gpu/gl/GrGLEffect.cpp | 2 + src/gpu/gl/GrGLEffect.h | 11 +- src/gpu/gl/GrGLEffectMatrix.cpp | 213 +++++++++++++++++++++ src/gpu/gl/GrGLEffectMatrix.h | 97 ++++++++++ src/gpu/gl/GrGLProgram.cpp | 71 +++---- src/gpu/gl/GrGLUniformManager.cpp | 18 ++ src/gpu/gl/GrGLUniformManager.h | 4 + 25 files changed, 692 insertions(+), 126 deletions(-) create mode 100644 src/gpu/gl/GrGLEffectMatrix.cpp create mode 100644 src/gpu/gl/GrGLEffectMatrix.h diff --git a/gm/texdata.cpp b/gm/texdata.cpp index cc3476d1f6..18c600f722 100644 --- a/gm/texdata.cpp +++ b/gm/texdata.cpp @@ -114,7 +114,7 @@ protected: tm = vm; tm.postIDiv(2*S, 2*S); paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, - (texture)), tm)->unref(); + (texture, tm)))->unref(); ctx->drawRect(paint, GrRect::MakeWH(2*S, 2*S)); diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 2febe4dd2f..fae91c245e 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -147,6 +147,8 @@ '<(skia_src_path)/gpu/gl/GrGLDefines.h', '<(skia_src_path)/gpu/gl/GrGLEffect.cpp', '<(skia_src_path)/gpu/gl/GrGLEffect.h', + '<(skia_src_path)/gpu/gl/GrGLEffectMatrix.cpp', + '<(skia_src_path)/gpu/gl/GrGLEffectMatrix.h', '<(skia_src_path)/gpu/gl/GrGLIndexBuffer.cpp', '<(skia_src_path)/gpu/gl/GrGLIndexBuffer.h', '<(skia_src_path)/gpu/gl/GrGLInterface.cpp', diff --git a/include/gpu/GrEffectUnitTest.h b/include/gpu/GrEffectUnitTest.h index 427260c664..8cc2689d91 100644 --- a/include/gpu/GrEffectUnitTest.h +++ b/include/gpu/GrEffectUnitTest.h @@ -12,12 +12,20 @@ #include "GrNoncopyable.h" #include "SkTArray.h" +class SkMatrix; + namespace GrEffectUnitTest { // Used to access the dummy textures in TestCreate procs. enum { kSkiaPMTextureIdx = 0, kAlphaTextureIdx = 1, }; + +/** + * A helper for use in GrEffect::TestCreate functions. + */ +const SkMatrix& TestMatrix(SkRandom*); + } #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS @@ -56,12 +64,13 @@ private: static GrEffectTestFactory gTestFactory; \ static GrEffect* TestCreate(SkRandom*, GrContext*, GrTexture* dummyTextures[2]) -/** GrEffect subclasses should insert this macro in their implemenation file. They must then +/** GrEffect subclasses should insert this macro in their implementation file. They must then * also implement this static function: * GrEffect* TestCreate(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. + * dummyTextures[] are valid textures that can optionally be used to construct GrTextureAccesses. + * 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_EFFECT_TEST(Effect) \ GrEffectTestFactory Effect :: gTestFactory(Effect :: TestCreate) diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp index fb0e4d089a..9ce5726892 100644 --- a/src/effects/SkBlendImageFilter.cpp +++ b/src/effects/SkBlendImageFilter.cpp @@ -13,6 +13,7 @@ #include "SkGr.h" #include "SkGrPixelRef.h" #include "gl/GrGLEffect.h" +#include "gl/GrGLEffectMatrix.h" #include "GrTBackendEffectFactory.h" #endif @@ -127,16 +128,19 @@ public: static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&); + virtual void setData(const GrGLUniformManager&, const GrEffectStage&); + private: typedef GrGLEffect INHERITED; SkBlendImageFilter::Mode fMode; + GrGLEffectMatrix fEffectMatrix; }; /////////////////////////////////////////////////////////////////////////////// class GrBlendEffect : public GrSingleTextureEffect { public: - GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground); + GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground, const SkMatrix&); virtual ~GrBlendEffect(); virtual bool isEqual(const GrEffect&) const SK_OVERRIDE; @@ -209,17 +213,19 @@ GrTexture* SkBlendImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* src, co foregroundTexMatrix.setIDiv(foreground->width(), foreground->height()); GrPaint paint; paint.colorStage(0)->setEffect( - SkNEW_ARGS(GrSingleTextureEffect, (background.get())), backgroundTexMatrix)->unref(); + SkNEW_ARGS(GrSingleTextureEffect, (background.get(), backgroundTexMatrix)))->unref(); paint.colorStage(1)->setEffect( - SkNEW_ARGS(GrBlendEffect, (fMode, foreground.get())), foregroundTexMatrix)->unref(); + SkNEW_ARGS(GrBlendEffect, (fMode, foreground.get(), foregroundTexMatrix)))->unref(); context->drawRect(paint, rect); return dst; } /////////////////////////////////////////////////////////////////////////////// -GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground) - : INHERITED(foreground), fMode(mode) { +GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode, + GrTexture* foreground, + const SkMatrix& matrix) + : INHERITED(foreground, matrix), fMode(mode) { } GrBlendEffect::~GrBlendEffect() { @@ -227,8 +233,7 @@ GrBlendEffect::~GrBlendEffect() { bool GrBlendEffect::isEqual(const GrEffect& sBase) const { const GrBlendEffect& s = static_cast(sBase); - return INHERITED::isEqual(sBase) && - fMode == s.fMode; + return INHERITED::isEqual(sBase) && fMode == s.fMode; } const GrBackendEffectFactory& GrBlendEffect::getFactory() const { @@ -241,6 +246,7 @@ GrGLBlendEffect::GrGLBlendEffect(const GrBackendEffectFactory& factory, const GrEffect& effect) : INHERITED(factory), fMode(static_cast(effect).mode()) { + fRequiresTextureMatrix = false; } GrGLBlendEffect::~GrGLBlendEffect() { @@ -248,16 +254,19 @@ GrGLBlendEffect::~GrGLBlendEffect() { void GrGLBlendEffect::emitCode(GrGLShaderBuilder* builder, const GrEffectStage&, - EffectKey, + EffectKey key, const char* vertexCoords, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { + const char* coords; + GrSLType coordsType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coords); + SkString* code = &builder->fFSCode; const char* bgColor = inputColor; const char* fgColor = "fgColor"; code->appendf("\t\tvec4 %s = ", fgColor); - builder->appendTextureLookup(code, samplers[0]); + builder->appendTextureLookup(code, samplers[0], coords, coordsType); code->append(";\n"); code->appendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", outputColor, bgColor, fgColor); switch (fMode) { @@ -279,7 +288,16 @@ void GrGLBlendEffect::emitCode(GrGLShaderBuilder* builder, } } -GrGLEffect::EffectKey GrGLBlendEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) { - return static_cast(*s.getEffect()).mode(); +void GrGLBlendEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) { + const GrBlendEffect& blend = static_cast(*stage.getEffect()); + fEffectMatrix.setData(uman, blend.getMatrix(), stage.getCoordChangeMatrix(), blend.texture(0)); +} + +GrGLEffect::EffectKey GrGLBlendEffect::GenKey(const GrEffectStage& stage, const GrGLCaps&) { + const GrBlendEffect& blend = static_cast(*stage.getEffect()); + EffectKey key = + GrGLEffectMatrix::GenKey(blend.getMatrix(), stage.getCoordChangeMatrix(), blend.texture(0)); + key |= (blend.mode() << GrGLEffectMatrix::kKeyBits); + return key; } #endif diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp index 58d26735a1..fa724cad11 100644 --- a/src/effects/SkColorMatrixFilter.cpp +++ b/src/effects/SkColorMatrixFilter.cpp @@ -350,6 +350,8 @@ public: : INHERITED(factory) , fMatrixHandle(GrGLUniformManager::kInvalidUniformHandle) , fVectorHandle(GrGLUniformManager::kInvalidUniformHandle) { + // no texture + fRequiresTextureMatrix = false; } virtual void emitCode(GrGLShaderBuilder* builder, diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp index 60eff91d65..78c7e34a74 100644 --- a/src/effects/gradients/SkGradientShader.cpp +++ b/src/effects/gradients/SkGradientShader.cpp @@ -678,7 +678,9 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory) : INHERITED(factory) , fCachedYCoord(GR_ScalarMax) - , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) { } + , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) { + fRequiresTextureMatrix = false; +} GrGLGradientEffect::~GrGLGradientEffect() { } @@ -688,13 +690,37 @@ void GrGLGradientEffect::emitYCoordUniform(GrGLShaderBuilder* builder) { } void GrGLGradientEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) { - GrScalar yCoord = static_cast(*stage.getEffect()).getYCoord(); + const GrGradientEffect& e = static_cast(*stage.getEffect()); + const GrTexture* texture = e.texture(0); + fEffectMatrix.setData(uman, e.getMatrix(), stage.getCoordChangeMatrix(), texture); + + GrScalar yCoord = e.getYCoord(); if (yCoord != fCachedYCoord) { uman.set1f(fFSYUni, yCoord); fCachedYCoord = yCoord; } } +GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrEffectStage& s) { + const GrGradientEffect& e = static_cast(*s.getEffect()); + const GrTexture* texture = e.texture(0); + return GrGLEffectMatrix::GenKey(e.getMatrix(), s.getCoordChangeMatrix(), texture); +} + +void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder, + EffectKey key, + const char* vertexCoords, + const char** fsCoordName, + const char** vsVaryingName, + GrSLType* vsVaryingType) { + fEffectMatrix.emitCodeMakeFSCoords2D(builder, + key & kMatrixKeyMask, + vertexCoords, + fsCoordName, + vsVaryingName, + vsVaryingType); +} + void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder, const char* gradientTValue, const char* outputColor, @@ -714,6 +740,7 @@ void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder, GrGradientEffect::GrGradientEffect(GrContext* ctx, const SkGradientShaderBase& shader, + const SkMatrix& matrix, SkShader::TileMode tileMode) : INHERITED(1) { // TODO: check for simple cases where we don't need a texture: @@ -721,6 +748,8 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx, //shader.asAGradient(&info); //if (info.fColorCount == 2) { ... + fMatrix = matrix; + SkBitmap bitmap; shader.getGradientTableBitmap(&bitmap); diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h index 9f14e7f727..24379110ee 100644 --- a/src/effects/gradients/SkGradientShaderPriv.h +++ b/src/effects/gradients/SkGradientShaderPriv.h @@ -193,12 +193,13 @@ private: #if SK_SUPPORT_GPU #include "gl/GrGLEffect.h" +#include "gl/GrGLEffectMatrix.h" class GrEffectStage; class GrBackendEffectFactory; /* - * The intepretation of the texture matrix depends on the sample mode. The + * The interpretation of the texture matrix depends on the sample mode. The * texture matrix is applied both when the texture coordinates are explicit * and when vertex positions are used as texture coordinates. In the latter * case the texture matrix is applied to the pre-view-matrix position @@ -228,6 +229,7 @@ public: GrGradientEffect(GrContext* ctx, const SkGradientShaderBase& shader, + const SkMatrix& matrix, SkShader::TileMode tileMode); virtual ~GrGradientEffect(); @@ -236,11 +238,12 @@ public: bool useAtlas() const { return SkToBool(-1 != fRow); } GrScalar getYCoord() const { return fYCoord; }; + const SkMatrix& getMatrix() const { return fMatrix;} virtual bool isEqual(const GrEffect& effect) const SK_OVERRIDE { const GrGradientEffect& s = static_cast(effect); return INHERITED::isEqual(effect) && this->useAtlas() == s.useAtlas() && - fYCoord == s.getYCoord(); + fYCoord == s.getYCoord() && fMatrix.cheapEqualTo(s.getMatrix()); } protected: @@ -263,6 +266,7 @@ private: GrScalar fYCoord; GrTextureStripAtlas* fAtlas; int fRow; + SkMatrix fMatrix; typedef GrEffect INHERITED; @@ -279,6 +283,36 @@ public: virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE; protected: + /** + * Subclasses must reserve the lower kMatrixKeyBitCnt of their key for use by + * GrGLGradientEffect. + */ + enum { + kMatrixKeyBitCnt = GrGLEffectMatrix::kKeyBits, + kMatrixKeyMask = (1 << kMatrixKeyBitCnt) - 1, + }; + + /** + * Subclasses must call this. It will return a value restricted to the lower kMatrixKeyBitCnt + * bits. + */ + static EffectKey GenMatrixKey(const GrEffectStage& s); + + /** + * Inserts code to implement the GrGradientEffect's matrix. This should be called before a + * subclass emits its own code. The name of the 2D coords is output via fsCoordName and already + * incorporates any perspective division. The caller can also optionally retrieve the name of + * the varying inserted in the VS and its type, which may be either vec2f or vec3f depending + * upon whether the matrix has perspective or not. It is not necessary to mask the key before + * calling. + */ + void setupMatrix(GrGLShaderBuilder* builder, + EffectKey key, + const char* vertexCoords, + const char** fsCoordName, + const char** vsVaryingName = NULL, + GrSLType* vsVaryingType = NULL); + // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses // should call this method from their emitCode(). void emitYCoordUniform(GrGLShaderBuilder* builder); @@ -295,6 +329,7 @@ protected: private: GrScalar fCachedYCoord; GrGLUniformManager::UniformHandle fFSYUni; + GrGLEffectMatrix fEffectMatrix; typedef GrGLEffect INHERITED; }; diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp index d9576565b5..71614505a1 100644 --- a/src/effects/gradients/SkLinearGradient.cpp +++ b/src/effects/gradients/SkLinearGradient.cpp @@ -495,7 +495,9 @@ public: const char* inputColor, const TextureSamplerArray&) SK_OVERRIDE; - static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps) { return 0; } + static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) { + return GenMatrixKey(stage); + } private: @@ -507,8 +509,11 @@ private: class GrLinearGradient : public GrGradientEffect { public: - GrLinearGradient(GrContext* ctx, const SkLinearGradient& shader, SkShader::TileMode tm) - : INHERITED(ctx, shader, tm) { } + GrLinearGradient(GrContext* ctx, + const SkLinearGradient& shader, + const SkMatrix& matrix, + SkShader::TileMode tm) + : INHERITED(ctx, shader, matrix, tm) { } virtual ~GrLinearGradient() { } static const char* Name() { return "Linear Gradient"; } @@ -553,15 +558,18 @@ GrEffect* GrLinearGradient::TestCreate(SkRandom* random, ///////////////////////////////////////////////////////////////////// void GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder, - const GrEffectStage&, - EffectKey, + const GrEffectStage& stage, + EffectKey key, const char* vertexCoords, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { this->emitYCoordUniform(builder); + const char* coords; + this->setupMatrix(builder, key, vertexCoords, &coords); SkString t; - t.printf("%s.x", builder->defaultTexCoordsName()); + t.append(coords); + t.append(".x"); this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); } @@ -574,7 +582,7 @@ bool SkLinearGradient::asNewEffect(GrContext* context, GrEffectStage* stage) con return false; } matrix.postConcat(fPtsToUnit); - stage->setEffect(SkNEW_ARGS(GrLinearGradient, (context, *this, fTileMode)), matrix)->unref(); + stage->setEffect(SkNEW_ARGS(GrLinearGradient, (context, *this, matrix, fTileMode)))->unref(); return true; } diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp index a20ea35a1a..02a56da588 100644 --- a/src/effects/gradients/SkRadialGradient.cpp +++ b/src/effects/gradients/SkRadialGradient.cpp @@ -490,7 +490,9 @@ public: const char* inputColor, const TextureSamplerArray&) SK_OVERRIDE; - static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps) { return 0; } + static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) { + return GenMatrixKey(stage); + } private: @@ -503,8 +505,11 @@ private: class GrRadialGradient : public GrGradientEffect { public: - GrRadialGradient(GrContext* ctx, const SkRadialGradient& shader, SkShader::TileMode tm) - : INHERITED(ctx, shader, tm) { + GrRadialGradient(GrContext* ctx, + const SkRadialGradient& shader, + const SkMatrix& matrix, + SkShader::TileMode tm) + : INHERITED(ctx, shader, matrix, tm) { } virtual ~GrRadialGradient() { } @@ -551,15 +556,18 @@ GrEffect* GrRadialGradient::TestCreate(SkRandom* random, ///////////////////////////////////////////////////////////////////// void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder, - const GrEffectStage&, - EffectKey, + const GrEffectStage& stage, + EffectKey key, const char* vertexCoords, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { this->emitYCoordUniform(builder); - SkString t; - t.printf("length(%s.xy)", builder->defaultTexCoordsName()); + const char* coords; + this->setupMatrix(builder, key, vertexCoords, &coords); + SkString t("length("); + t.append(coords); + t.append(")"); this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); } @@ -573,7 +581,7 @@ bool SkRadialGradient::asNewEffect(GrContext* context, GrEffectStage* stage) con return false; } matrix.postConcat(fPtsToUnit); - stage->setEffect(SkNEW_ARGS(GrRadialGradient, (context, *this, fTileMode)), matrix)->unref(); + stage->setEffect(SkNEW_ARGS(GrRadialGradient, (context, *this, matrix, fTileMode)))->unref(); return true; } diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp index a783e3757c..589cf4ad14 100644 --- a/src/effects/gradients/SkSweepGradient.cpp +++ b/src/effects/gradients/SkSweepGradient.cpp @@ -399,7 +399,9 @@ public: const char* inputColor, const TextureSamplerArray&) SK_OVERRIDE; - static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps) { return 0; } + static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) { + return GenMatrixKey(stage); + } private: @@ -413,8 +415,9 @@ class GrSweepGradient : public GrGradientEffect { public: GrSweepGradient(GrContext* ctx, - const SkSweepGradient& shader) - : INHERITED(ctx, shader, SkShader::kClamp_TileMode) { } + const SkSweepGradient& shader, + const SkMatrix& matrix) + : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { } virtual ~GrSweepGradient() { } static const char* Name() { return "Sweep Gradient"; } @@ -457,16 +460,17 @@ GrEffect* GrSweepGradient::TestCreate(SkRandom* random, ///////////////////////////////////////////////////////////////////// void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder, - const GrEffectStage&, - EffectKey, + const GrEffectStage& stage, + EffectKey key, const char* vertexCoords, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { this->emitYCoordUniform(builder); + const char* coords; + this->setupMatrix(builder, key, vertexCoords, &coords); SkString t; - t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", - builder->defaultTexCoordsName(), builder->defaultTexCoordsName()); + t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords, coords); this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); } @@ -478,7 +482,7 @@ bool SkSweepGradient::asNewEffect(GrContext* context, GrEffectStage* stage) cons return false; } matrix.postConcat(fPtsToUnit); - stage->setEffect(SkNEW_ARGS(GrSweepGradient, (context, *this)), matrix)->unref(); + stage->setEffect(SkNEW_ARGS(GrSweepGradient, (context, *this, matrix)))->unref(); return true; } diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp index f93f660837..41292bb43a 100644 --- a/src/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp @@ -371,8 +371,9 @@ public: GrConical2Gradient(GrContext* ctx, const SkTwoPointConicalGradient& shader, + const SkMatrix& matrix, SkShader::TileMode tm) - : INHERITED(ctx, shader, tm) + : INHERITED(ctx, shader, matrix, tm) , fCenterX1(shader.getCenterX1()) , fRadius0(shader.getStartRadius()) , fDiffRadius(shader.getDiffRadius()) { } @@ -468,12 +469,17 @@ GrGLConical2Gradient::GrGLConical2Gradient( } void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, - const GrEffectStage&, - EffectKey, + const GrEffectStage& stage, + EffectKey key, const char* vertexCoords, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { + const char* fsCoords; + const char* vsCoordsVarying; + GrSLType coordsVaryingType; + this->setupMatrix(builder, key, vertexCoords, &fsCoords, &vsCoordsVarying, &coordsVaryingType); + this->emitYCoordUniform(builder); // 2 copies of uniform array, 1 for each of vertex & fragment shader, // to work around Xoom bug. Doesn't seem to cause performance decrease @@ -485,7 +491,7 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, // For radial gradients without perspective we can pass the linear // part of the quadratic as a varying. - if (!builder->defaultTextureMatrixIsPerspective()) { + if (kVec2f_GrSLType == coordsVaryingType) { builder->addVarying(kFloat_GrSLType, "Conical2BCoeff", &fVSVaryingName, &fFSVaryingName); } @@ -502,11 +508,11 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, // For radial gradients without perspective we can pass the linear // part of the quadratic as a varying. - if (!builder->defaultTextureMatrixIsPerspective()) { + if (kVec2f_GrSLType == coordsVaryingType) { // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5]) code->appendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n", fVSVaryingName, p2.c_str(), - vertexCoords, p3.c_str(), p5.c_str()); + vsCoordsVarying, p3.c_str(), p5.c_str()); } } @@ -538,12 +544,12 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, // If we we're able to interpolate the linear component, // bVar is the varying; otherwise compute it SkString bVar; - if (!builder->defaultTextureMatrixIsPerspective()) { + if (kVec2f_GrSLType == coordsVaryingType) { bVar = fFSVaryingName; } else { bVar = "b"; code->appendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n", - bVar.c_str(), p2.c_str(), builder->defaultTexCoordsName(), + bVar.c_str(), p2.c_str(), fsCoords, p3.c_str(), p5.c_str()); } @@ -553,7 +559,7 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, // c = (x^2)+(y^2) - params[4] code->appendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(), - builder->defaultTexCoordsName(), builder->defaultTexCoordsName(), + fsCoords, fsCoords, p4.c_str()); // Non-degenerate case (quadratic) @@ -669,7 +675,15 @@ void GrGLConical2Gradient::setData(const GrGLUniformManager& uman, const GrEffec } GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrEffectStage& s, const GrGLCaps&) { - return (static_cast(*s.getEffect()).isDegenerate()); + enum { + kIsDegenerate = 1 << kMatrixKeyBitCnt, + }; + + EffectKey key = GenMatrixKey(s); + if (static_cast(*s.getEffect()).isDegenerate()) { + key |= kIsDegenerate; + } + return key; } ///////////////////////////////////////////////////////////////////// @@ -695,7 +709,7 @@ bool SkTwoPointConicalGradient::asNewEffect(GrContext* context, matrix.postConcat(rot); } - stage->setEffect(SkNEW_ARGS(GrConical2Gradient, (context, *this, fTileMode)), matrix)->unref(); + stage->setEffect(SkNEW_ARGS(GrConical2Gradient, (context, *this, matrix, fTileMode)))->unref(); return true; } diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp index 659bce0099..d0186291f2 100644 --- a/src/effects/gradients/SkTwoPointRadialGradient.cpp +++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp @@ -404,8 +404,11 @@ private: class GrRadial2Gradient : public GrGradientEffect { public: - GrRadial2Gradient(GrContext* ctx, const SkTwoPointRadialGradient& shader, SkShader::TileMode tm) - : INHERITED(ctx, shader, tm) + GrRadial2Gradient(GrContext* ctx, + const SkTwoPointRadialGradient& shader, + const SkMatrix& matrix, + SkShader::TileMode tm) + : INHERITED(ctx, shader, matrix, tm) , fCenterX1(shader.getCenterX1()) , fRadius0(shader.getStartRadius()) , fPosRoot(shader.getDiffRadius() < 0) { } @@ -501,14 +504,19 @@ GrGLRadial2Gradient::GrGLRadial2Gradient( } void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder, - const GrEffectStage&, - EffectKey, + const GrEffectStage& stage, + EffectKey key, const char* vertexCoords, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { this->emitYCoordUniform(builder); + const char* fsCoords; + const char* vsCoordsVarying; + GrSLType coordsVaryingType; + this->setupMatrix(builder, key, vertexCoords, &fsCoords, &vsCoordsVarying, &coordsVaryingType); + // 2 copies of uniform array, 1 for each of vertex & fragment shader, // to work around Xoom bug. Doesn't seem to cause performance decrease // in test apps, but need to keep an eye on it. @@ -519,9 +527,8 @@ void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder, // For radial gradients without perspective we can pass the linear // part of the quadratic as a varying. - if (!builder->defaultTextureMatrixIsPerspective()) { - builder->addVarying(kFloat_GrSLType, "Radial2BCoeff", - &fVSVaryingName, &fFSVaryingName); + if (kVec2f_GrSLType == coordsVaryingType) { + builder->addVarying(kFloat_GrSLType, "Radial2BCoeff", &fVSVaryingName, &fFSVaryingName); } // VS @@ -534,11 +541,11 @@ void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder, // For radial gradients without perspective we can pass the linear // part of the quadratic as a varying. - if (!builder->defaultTextureMatrixIsPerspective()) { + if (kVec2f_GrSLType == coordsVaryingType) { // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3]) code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n", fVSVaryingName, p2.c_str(), - vertexCoords, p3.c_str()); + vsCoordsVarying, p3.c_str()); } } @@ -565,20 +572,19 @@ void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder, // If we we're able to interpolate the linear component, // bVar is the varying; otherwise compute it SkString bVar; - if (!builder->defaultTextureMatrixIsPerspective()) { + if (kVec2f_GrSLType == coordsVaryingType) { bVar = fFSVaryingName; } else { bVar = "b"; code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n", - bVar.c_str(), p2.c_str(), - builder->defaultTexCoordsName(), p3.c_str()); + bVar.c_str(), p2.c_str(), fsCoords, p3.c_str()); } // c = (x^2)+(y^2) - params[4] code->appendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(), - builder->defaultTexCoordsName(), - builder->defaultTexCoordsName(), + fsCoords, + fsCoords, p4.c_str()); // If we aren't degenerate, emit some extra code, and accept a slightly @@ -643,7 +649,15 @@ void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman, const GrEffect } GrGLEffect::EffectKey GrGLRadial2Gradient::GenKey(const GrEffectStage& s, const GrGLCaps&) { - return (static_cast(*s.getEffect()).isDegenerate()); + enum { + kIsDegenerate = 1 << kMatrixKeyBitCnt, + }; + + EffectKey key = GenMatrixKey(s); + if (static_cast(*s.getEffect()).isDegenerate()) { + key |= kIsDegenerate; + } + return key; } ///////////////////////////////////////////////////////////////////// @@ -667,7 +681,7 @@ bool SkTwoPointRadialGradient::asNewEffect(GrContext* context, matrix.postConcat(rot); } - stage->setEffect(SkNEW_ARGS(GrRadial2Gradient, (context, *this, fTileMode)), matrix)->unref(); + stage->setEffect(SkNEW_ARGS(GrRadial2Gradient, (context, *this, matrix, fTileMode)))->unref(); return true; } diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index f7f6b0c0b7..b9b2a827a5 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -1808,7 +1808,7 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture, i < scaleFactorY ? 0.5f : 1.0f); paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, - (srcTexture, true)), matrix)->unref(); + (srcTexture, matrix, true)))->unref(); this->drawRectToRect(paint, dstRect, srcRect); srcRect = dstRect; srcTexture = dstTexture; @@ -1865,8 +1865,8 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture, // FIXME: This should be mitchell, not bilinear. matrix.setIDiv(srcTexture->width(), srcTexture->height()); this->setRenderTarget(dstTexture->asRenderTarget()); - paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect,(srcTexture, true)), - matrix)->unref(); + paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect,(srcTexture, + matrix, true)))->unref(); SkRect dstRect(srcRect); scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); this->drawRectToRect(paint, dstRect, srcRect); diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index 3c6c3a371a..b53944189a 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -198,16 +198,16 @@ public: } void createTextureEffect(int stageIdx, GrTexture* texture, const GrMatrix& matrix) { GrAssert(!this->getStage(stageIdx).getEffect()); - GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture)); - this->stage(stageIdx)->setEffect(effect, matrix)->unref(); + GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix)); + this->stage(stageIdx)->setEffect(effect)->unref(); } void createTextureEffect(int stageIdx, GrTexture* texture, const GrMatrix& matrix, const GrTextureParams& params) { GrAssert(!this->getStage(stageIdx).getEffect()); - GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, params)); - this->stage(stageIdx)->setEffect(effect, matrix)->unref(); + GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params)); + this->stage(stageIdx)->setEffect(effect)->unref(); } diff --git a/src/gpu/GrEffect.cpp b/src/gpu/GrEffect.cpp index 09032bf0f9..d470c9cc5f 100644 --- a/src/gpu/GrEffect.cpp +++ b/src/gpu/GrEffect.cpp @@ -20,6 +20,26 @@ SkTArray* GrEffectTestFactory::GetFactories() { } #endif +namespace GrEffectUnitTest { +const SkMatrix& TestMatrix(SkRandom* random) { + static SkMatrix gMatrices[5]; + static bool gOnce; + if (!gOnce) { + gMatrices[0].reset(); + gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100)); + gMatrices[2].setRotate(SkIntToScalar(17)); + gMatrices[3].setRotate(SkIntToScalar(185)); + gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33)); + gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf); + gMatrices[4].setRotate(SkIntToScalar(215)); + gMatrices[4].set(SkMatrix::kMPersp0, SkFloatToScalar(0.00013f)); + gMatrices[4].set(SkMatrix::kMPersp1, SkFloatToScalar(-0.000039f)); + gOnce = true; + } + return gMatrices[random->nextULessThan(static_cast(SK_ARRAY_COUNT(gMatrices)))]; +} +} + class GrEffect_Globals { public: static GrMemoryPool* GetTLS() { diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index cdccbcd049..946d54dcc8 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -608,7 +608,7 @@ inline bool skPaint2GrPaintShader(SkGpuDevice* dev, GrScalar sy = SkFloatToScalar(1.f / bitmap.height()); matrix.postScale(sx, sy); } - stage->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture, params)), matrix)->unref(); + stage->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params)))->unref(); return true; } @@ -875,7 +875,7 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath, matrix.setIDiv(pathTexture->width(), pathTexture->height()); // Blend pathTexture over blurTexture. context->setRenderTarget(blurTexture->asRenderTarget()); - paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (pathTexture)), matrix)->unref(); + paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (pathTexture, matrix)))->unref(); if (SkMaskFilter::kInner_BlurType == blurType) { // inner: dst = dst * src paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); @@ -906,7 +906,7 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath, matrix.postIDiv(blurTexture->width(), blurTexture->height()); grp->coverageStage(MASK_IDX)->reset(); - grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (blurTexture)), matrix)->unref(); + grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (blurTexture, matrix)))->unref(); context->drawRect(*grp, finalRect); return true; } @@ -962,7 +962,7 @@ bool drawWithMaskFilter(GrContext* context, const SkPath& devPath, m.setTranslate(-dstM.fBounds.fLeft*SK_Scalar1, -dstM.fBounds.fTop*SK_Scalar1); m.postIDiv(texture->width(), texture->height()); - grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture)), m)->unref(); + grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture, m)))->unref(); GrRect d; d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft), GrIntToScalar(dstM.fBounds.fTop), diff --git a/src/gpu/effects/GrSingleTextureEffect.cpp b/src/gpu/effects/GrSingleTextureEffect.cpp index 8866153962..0f3b614dd7 100644 --- a/src/gpu/effects/GrSingleTextureEffect.cpp +++ b/src/gpu/effects/GrSingleTextureEffect.cpp @@ -7,6 +7,7 @@ #include "effects/GrSingleTextureEffect.h" #include "gl/GrGLEffect.h" +#include "gl/GrGLEffectMatrix.h" #include "gl/GrGLSL.h" #include "gl/GrGLTexture.h" #include "GrTBackendEffectFactory.h" @@ -16,25 +17,43 @@ class GrGLSingleTextureEffect : public GrGLEffect { public: GrGLSingleTextureEffect(const GrBackendEffectFactory& factory, const GrEffect&) : INHERITED (factory) { + fRequiresTextureMatrix = false; } virtual void emitCode(GrGLShaderBuilder* builder, const GrEffectStage&, - EffectKey, + EffectKey key, const char* vertexCoords, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) SK_OVERRIDE { - + const char* coordName; + GrSLType coordType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coordName); builder->fFSCode.appendf("\t%s = ", outputColor); - builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplers[0]); + builder->appendTextureLookupAndModulate(&builder->fFSCode, + inputColor, + samplers[0], + coordName, + coordType); builder->fFSCode.append(";\n"); } - static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&) { return 0; } + static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) { + const GrSingleTextureEffect& ste = + static_cast(*stage.getEffect()); + return GrGLEffectMatrix::GenKey(ste.getMatrix(), + stage.getCoordChangeMatrix(), + ste.texture(0)); + } -private: + virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE { + const GrSingleTextureEffect& ste = + static_cast(*stage.getEffect()); + fEffectMatrix.setData(uman, ste.getMatrix(), stage.getCoordChangeMatrix(), ste.texture(0)); + } +private: + GrGLEffectMatrix fEffectMatrix; typedef GrGLEffect INHERITED; }; @@ -43,16 +62,39 @@ private: GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture) : INHERITED(1) , fTextureAccess(texture) { + fMatrix.reset(); } GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, bool bilerp) : INHERITED(1) , fTextureAccess(texture, bilerp) { + fMatrix.reset(); } GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const GrTextureParams& params) : INHERITED(1) , fTextureAccess(texture, params) { + fMatrix.reset(); +} + +GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const GrMatrix& m) + : INHERITED(1) + , fTextureAccess(texture) + , fMatrix(m) { +} + +GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const GrMatrix& m, bool bilerp) + : INHERITED(1) + , fTextureAccess(texture, bilerp) + , fMatrix(m) { +} + +GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, + const GrMatrix& m, + const GrTextureParams& params) + : INHERITED(1) + , fTextureAccess(texture, params) + , fMatrix(m) { } GrSingleTextureEffect::~GrSingleTextureEffect() { @@ -76,5 +118,6 @@ GrEffect* GrSingleTextureEffect::TestCreate(SkRandom* random, GrTexture* textures[]) { int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : GrEffectUnitTest::kAlphaTextureIdx; - return SkNEW_ARGS(GrSingleTextureEffect, (textures[texIdx])); + const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random); + return SkNEW_ARGS(GrSingleTextureEffect, (textures[texIdx], matrix)); } diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h index 346a6f48d8..23b416d3b3 100644 --- a/src/gpu/effects/GrSingleTextureEffect.h +++ b/src/gpu/effects/GrSingleTextureEffect.h @@ -9,6 +9,7 @@ #define GrSingleTextureEffect_DEFINED #include "GrEffect.h" +#include "GrMatrix.h" class GrGLSingleTextureEffect; @@ -18,28 +19,37 @@ class GrGLSingleTextureEffect; class GrSingleTextureEffect : public GrEffect { public: - /** Uses default texture params (unfiltered, clamp) */ - GrSingleTextureEffect(GrTexture* texture); - - /** Uses default tile mode (clamp) */ - GrSingleTextureEffect(GrTexture* texture, bool bilerp); - + /** These three constructors assume an identity matrix */ + GrSingleTextureEffect(GrTexture* texture); /* unfiltered, clamp mode */ + GrSingleTextureEffect(GrTexture* texture, bool bilerp); /* clamp mode */ GrSingleTextureEffect(GrTexture* texture, const GrTextureParams&); + /** These three constructors take an explicit matrix */ + GrSingleTextureEffect(GrTexture*, const GrMatrix&); /* unfiltered, clamp mode */ + GrSingleTextureEffect(GrTexture*, const GrMatrix&, bool bilerp); /* clamp mode */ + GrSingleTextureEffect(GrTexture*, const GrMatrix&, const GrTextureParams&); + virtual ~GrSingleTextureEffect(); virtual const GrTextureAccess& textureAccess(int index) const SK_OVERRIDE; static const char* Name() { return "Single Texture"; } + const GrMatrix& getMatrix() const { return fMatrix; } + typedef GrGLSingleTextureEffect GLEffect; virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; + virtual bool isEqual(const GrEffect& effect) const SK_OVERRIDE { + const GrSingleTextureEffect& ste = static_cast(effect); + return INHERITED::isEqual(effect) && fMatrix.cheapEqualTo(ste.getMatrix()); + } private: GR_DECLARE_EFFECT_TEST; GrTextureAccess fTextureAccess; + GrMatrix fMatrix; typedef GrEffect INHERITED; }; diff --git a/src/gpu/gl/GrGLEffect.cpp b/src/gpu/gl/GrGLEffect.cpp index 0bbf1f7ccb..5e0875b71c 100644 --- a/src/gpu/gl/GrGLEffect.cpp +++ b/src/gpu/gl/GrGLEffect.cpp @@ -10,6 +10,8 @@ GrGLEffect::GrGLEffect(const GrBackendEffectFactory& factory) : fFactory(factory) { + + fRequiresTextureMatrix = true; } GrGLEffect::~GrGLEffect() { diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h index 30b8455a68..0fd5722cb8 100644 --- a/src/gpu/gl/GrGLEffect.h +++ b/src/gpu/gl/GrGLEffect.h @@ -51,7 +51,9 @@ public: @param builder Interface used to emit code in the shaders. @param stage The effect stage that generated this program stage. - @param key The key that was computed by EffectKey() from the generating GrEffect. + @param key The key that was computed by GenKey() from the generating GrEffect. + Only the bits indicated by GrBackendEffectFactory::kEffectKeyBits are + guaranteed to match the value produced by GenKey(); @param vertexCoords A vec2 of texture coordinates in the VS, which may be altered. This will be removed soon and stages will be responsible for computing their own coords. @@ -85,7 +87,14 @@ public: static EffectKey GenTextureKey(const GrEffect&, const GrGLCaps&); + bool requiresTextureMatrix() const { return fRequiresTextureMatrix; } + + protected: + // HACK: This is a temporary field that allows GrGLEffect subclasses to opt into the new + // shader gen where a texture matrix is not automatically inserted. It defaults to true and is + // set to false in a subclass to opt into the new behavior. + bool fRequiresTextureMatrix; const GrBackendEffectFactory& fFactory; }; diff --git a/src/gpu/gl/GrGLEffectMatrix.cpp b/src/gpu/gl/GrGLEffectMatrix.cpp new file mode 100644 index 0000000000..0db87f9773 --- /dev/null +++ b/src/gpu/gl/GrGLEffectMatrix.cpp @@ -0,0 +1,213 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrGLEffectMatrix.h" +#include "GrTexture.h" + +GrGLEffect::EffectKey GrGLEffectMatrix::GenKey(const SkMatrix& effectMatrix, + const SkMatrix& coordChangeMatrix, + const GrTexture* texture) { + SkMatrix::TypeMask type0 = effectMatrix.getType(); + SkMatrix::TypeMask type1 = coordChangeMatrix.getType(); + + static const int kNonTransMask = SkMatrix::kAffine_Mask | + SkMatrix::kScale_Mask | + SkMatrix::kPerspective_Mask; + int combinedTypes = type0 | type1; + + bool reverseY = (NULL != texture) && GrSurface::kBottomLeft_Origin == texture->origin(); + + if (SkMatrix::kPerspective_Mask & combinedTypes) { + return kGeneral_Key; + } else if ((kNonTransMask & combinedTypes) || reverseY) { + return kNoPersp_Key; + } else if (kTrans_Key & combinedTypes) { + return kTrans_Key; + } else { + GrAssert(effectMatrix.isIdentity() && coordChangeMatrix.isIdentity()); + return kIdentity_Key; + } +} + +GrSLType GrGLEffectMatrix::emitCode(GrGLShaderBuilder* builder, + EffectKey key, + const char* vertexCoords, + const char** fsCoordName, + const char** vsCoordName, + const char* suffix) { + GrSLType varyingType; + const char* uniName; + key &= kKeyMask; + switch (key) { + case kIdentity_Key: + fUniType = kVoid_GrSLType; + varyingType = kVec2f_GrSLType; + break; + case kTrans_Key: + fUniType = kVec2f_GrSLType; + uniName = "StageTranslate"; + varyingType = kVec2f_GrSLType; + break; + case kNoPersp_Key: + fUniType = kMat33f_GrSLType; + uniName = "StageMatrix"; + varyingType = kVec2f_GrSLType; + break; + case kGeneral_Key: + fUniType = kMat33f_GrSLType; + uniName = "StageMatrix"; + varyingType = kVec3f_GrSLType; + break; + default: + GrCrash("Unexpected key."); + } + SkString suffixedUniName; + if (NULL != suffix) { + suffixedUniName.append(uniName); + suffixedUniName.append(suffix); + uniName = suffixedUniName.c_str(); + } + if (kVoid_GrSLType != fUniType) { + fUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType, + fUniType, + uniName, + &uniName); + } + + const char* varyingName = "StageCoord"; + SkString suffixedVaryingName; + if (NULL != suffix) { + suffixedVaryingName.append(varyingName); + suffixedVaryingName.append(suffix); + varyingName = suffixedVaryingName.c_str(); + } + const char* vsVaryingName; + const char* fsVaryingName; + builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName); + + // varying = matrix * vertex-coords (logically) + switch (fUniType) { + case kVoid_GrSLType: + GrAssert(kVec2f_GrSLType == varyingType); + builder->fVSCode.appendf("\t%s = %s;\n", vsVaryingName, vertexCoords); + break; + case kVec2f_GrSLType: + GrAssert(kVec2f_GrSLType == varyingType); + builder->fVSCode.appendf("\t%s = %s + %s;\n", vsVaryingName, uniName, vertexCoords); + break; + case kMat33f_GrSLType: { + GrAssert(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType); + if (kVec2f_GrSLType == varyingType) { + builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1)).xy;\n", + vsVaryingName, uniName, vertexCoords); + } else { + builder->fVSCode.appendf("\t%s = %s * vec3(%s, 1);\n", + vsVaryingName, uniName, vertexCoords); + } + break; + } + default: + GrCrash("Unexpected uniform type."); + } + if (NULL != vsCoordName) { + *vsCoordName = vsVaryingName; + } + if (NULL != fsCoordName) { + *fsCoordName = fsVaryingName; + } + return varyingType; +} + +/** + * This is similar to emitCode except that it performs perspective division in the FS if the + * texture coordinates have a w coordinate. The fsCoordName always refers to a vec2f. + */ +void GrGLEffectMatrix::emitCodeMakeFSCoords2D(GrGLShaderBuilder* builder, + EffectKey key, + const char* vertexCoords, + const char** fsCoordName, + const char** vsVaryingName, + GrSLType* vsVaryingType, + const char* suffix) { + const char* fsVaryingName; + + GrSLType varyingType = this->emitCode(builder, + key, + vertexCoords, + &fsVaryingName, + vsVaryingName, + suffix); + if (kVec3f_GrSLType == varyingType) { + + const char* coordName = "coords2D"; + SkString suffixedCoordName; + if (NULL != suffix) { + suffixedCoordName.append(coordName); + suffixedCoordName.append(suffix); + coordName = suffixedCoordName.c_str(); + } + builder->fFSCode.appendf("\tvec2 %s = %s.xy / %s.z;", + coordName, fsVaryingName, fsVaryingName); + if (NULL != fsCoordName) { + *fsCoordName = coordName; + } + } else if(NULL != fsCoordName) { + *fsCoordName = fsVaryingName; + } + if (NULL != vsVaryingType) { + *vsVaryingType = varyingType; + } +} + +void GrGLEffectMatrix::setData(const GrGLUniformManager& uniformManager, + const SkMatrix& matrix, + const SkMatrix& coordChangeMatrix, + const GrTexture* texture) { + GrAssert((GrGLUniformManager::kInvalidUniformHandle == fUni) == + (kVoid_GrSLType == fUniType)); + switch (fUniType) { + case kVoid_GrSLType: + GrAssert(matrix.isIdentity()); + GrAssert(coordChangeMatrix.isIdentity()); + GrAssert(NULL == texture || GrSurface::kTopLeft_Origin == texture->origin()); + return; + case kVec2f_GrSLType: { + GrAssert(SkMatrix::kTranslate_Mask == (matrix.getType() | coordChangeMatrix.getType())); + GrAssert(NULL == texture || GrSurface::kTopLeft_Origin == texture->origin()); + SkScalar tx = matrix[SkMatrix::kMTransX] + coordChangeMatrix[SkMatrix::kMTransX]; + SkScalar ty = matrix[SkMatrix::kMTransY] + coordChangeMatrix[SkMatrix::kMTransY]; + if (fPrevMatrix.get(SkMatrix::kMTransX) != tx || + fPrevMatrix.get(SkMatrix::kMTransY) != ty) { + uniformManager.set2f(fUni, tx, ty); + fPrevMatrix.set(SkMatrix::kMTransX, tx); + fPrevMatrix.set(SkMatrix::kMTransY, ty); + } + break; + } + case kMat33f_GrSLType: { + SkMatrix combined; + combined.setConcat(matrix, coordChangeMatrix); + if (NULL != texture && GrSurface::kBottomLeft_Origin == texture->origin()) { + // combined.postScale(1,-1); + // combined.postTranslate(0,1); + combined.set(SkMatrix::kMSkewY, + combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]); + combined.set(SkMatrix::kMScaleY, + combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]); + combined.set(SkMatrix::kMTransY, + combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]); + } + if (!fPrevMatrix.cheapEqualTo(combined)) { + uniformManager.setSkMatrix(fUni, combined); + fPrevMatrix = combined; + } + break; + } + default: + GrCrash("Unexpected uniform type."); + } +} diff --git a/src/gpu/gl/GrGLEffectMatrix.h b/src/gpu/gl/GrGLEffectMatrix.h new file mode 100644 index 0000000000..9e45f3ef82 --- /dev/null +++ b/src/gpu/gl/GrGLEffectMatrix.h @@ -0,0 +1,97 @@ +/* + * 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 GrGLEffectMatrix_DEFINED +#define GrGLEffectMatrix_DEFINED + +#include "GrGLEffect.h" +#include "SkMatrix.h" + +class GrTexture; +class SkRandom; + +/** + * This is a helper to implement a texture matrix in a GrGLEffect. + */ +class GrGLEffectMatrix { +public: + typedef GrGLEffect::EffectKey EffectKey; + /** + * The matrix uses kKeyBits of the effect's EffectKey. A GrGLEffect may place these bits at an + * arbitrary shift in its final key. However, when GrGLEffectMatrix::emitCode*() code is called + * the relevant bits must be in the lower kKeyBits of the key parameter. + */ + enum { + kKeyBits = 2, + kKeyMask = (1 << kKeyBits) - 1, + }; + + GrGLEffectMatrix() : fUni(GrGLUniformManager::kInvalidUniformHandle) { + fPrevMatrix = SkMatrix::InvalidMatrix(); + } + + /** + * Generates the key for the portion of the code emitted by this class's emitCode() function. + * Pass a texture to make GrGLEffectMatrix automatically adjust for the texture's origin. Pass + * NULL when not using the EffectMatrix for a texture lookups, or if the GrGLEffect subclass + * wants to handle origin adjustments in some other manner. coordChangeMatrix is the matrix + * from GrEffectStage. + */ + static EffectKey GenKey(const SkMatrix& effectMatrix, + const SkMatrix& coordChangeMatrix, + const GrTexture*); + + /** + * Emits code to implement the matrix in the VS. A varying is added as an output of the VS and + * input to the FS. The varying may be either a vec2f or vec3f depending upon whether + * perspective interpolation is required or not. The names of the varying in the VS and FS are + * are returned as output parameters and the type of the varying is the return value. The suffix + * is an optional parameter that can be used to make all variables emitted by the object + * unique within a stage. It is only necessary if multiple GrGLEffectMatrix objects are used by + * a GrGLEffect. + */ + GrSLType emitCode(GrGLShaderBuilder*, + EffectKey, + const char* vertexCoords, + const char** fsCoordName, /* optional */ + const char** vsCoordName = NULL, + const char* suffix = NULL); + + /** + * This is similar to emitCode except that it performs perspective division in the FS if the + * texture coordinates have a w coordinate. The fsCoordName always refers to a vec2f. + */ + void emitCodeMakeFSCoords2D(GrGLShaderBuilder*, + EffectKey, + const char* vertexCoords, + const char** fsCoordName, /* optional */ + const char** vsVaryingName = NULL, + GrSLType* vsVaryingType = NULL, + const char* suffix = NULL); + /** + * Call from a GrGLEffect's subclass to update the texture matrix. The matrix, + * coordChangeMatrix, and texture params should match those used with GenKey. + */ + void setData(const GrGLUniformManager& uniformManager, + const SkMatrix& effectMatrix, + const SkMatrix& coordChangeMatrix, + const GrTexture*); + +private: + enum { + kIdentity_Key = 0, + kTrans_Key = 1, + kNoPersp_Key = 2, + kGeneral_Key = 3, + }; + + GrGLUniformManager::UniformHandle fUni; + GrSLType fUniType; + SkMatrix fPrevMatrix; +}; + +#endif \ No newline at end of file diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index cd16d9e24f..120bd1e3ad 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -909,57 +909,64 @@ GrGLEffect* GrGLProgram::GenStageCode(const GrEffectStage& stage, /// Vertex Shader Stuff - // decide whether we need a matrix to transform texture coords and whether the varying needs a - // perspective coord. - const char* matName = NULL; - GrSLType texCoordVaryingType; - if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { - texCoordVaryingType = kVec2f_GrSLType; - } else { - uniforms->fTextureMatrixUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType, - kMat33f_GrSLType, "TexM", &matName); - builder->getUniformVariable(uniforms->fTextureMatrixUni); - - if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) { + const char* vertexCoords; + + // Has the effect not yet been updated to insert its own texture matrix if necessary. + if (glEffect->requiresTextureMatrix()) { + // Decide whether we need a matrix to transform texture coords and whether the varying needs + // a perspective coord. + const char* matName = NULL; + GrSLType texCoordVaryingType; + if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { texCoordVaryingType = kVec2f_GrSLType; } else { - texCoordVaryingType = kVec3f_GrSLType; + uniforms->fTextureMatrixUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType, + kMat33f_GrSLType, "TexM", &matName); + builder->getUniformVariable(uniforms->fTextureMatrixUni); + + if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) { + texCoordVaryingType = kVec2f_GrSLType; + } else { + texCoordVaryingType = kVec3f_GrSLType; + } + } + const char *varyingVSName, *varyingFSName; + builder->addVarying(texCoordVaryingType, + "Stage", + &varyingVSName, + &varyingFSName); + builder->setupTextureAccess(varyingFSName, texCoordVaryingType); + + if (!matName) { + GrAssert(kVec2f_GrSLType == texCoordVaryingType); + builder->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord); + } else { + // varying = texMatrix * texCoord + builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n", + varyingVSName, matName, vsInCoord, + vector_all_coords(GrSLTypeToVecLength(texCoordVaryingType))); } + vertexCoords = varyingVSName; + } else { + vertexCoords = vsInCoord; } - const char *varyingVSName, *varyingFSName; - builder->addVarying(texCoordVaryingType, - "Stage", - &varyingVSName, - &varyingFSName); - builder->setupTextureAccess(varyingFSName, texCoordVaryingType); + // setup texture samplers for gl effect int numTextures = effect->numTextures(); SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers; - textureSamplers.push_back_n(numTextures); - for (int i = 0; i < numTextures; ++i) { textureSamplers[i].init(builder, &effect->textureAccess(i)); uniforms->fSamplerUniforms.push_back(textureSamplers[i].fSamplerUniform); } - if (!matName) { - GrAssert(kVec2f_GrSLType == texCoordVaryingType); - builder->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord); - } else { - // varying = texMatrix * texCoord - builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n", - varyingVSName, matName, vsInCoord, - vector_all_coords(GrSLTypeToVecLength(texCoordVaryingType))); - } - // Enclose custom code in a block to avoid namespace conflicts builder->fVSCode.appendf("\t{ // %s\n", glEffect->name()); builder->fFSCode.appendf("\t{ // %s \n", glEffect->name()); glEffect->emitCode(builder, stage, desc.fEffectKey, - varyingVSName, + vertexCoords, fsOutColor, fsInColor, textureSamplers); diff --git a/src/gpu/gl/GrGLUniformManager.cpp b/src/gpu/gl/GrGLUniformManager.cpp index 684ef8c37e..7a92d25b28 100644 --- a/src/gpu/gl/GrGLUniformManager.cpp +++ b/src/gpu/gl/GrGLUniformManager.cpp @@ -8,6 +8,7 @@ #include "gl/GrGLShaderBuilder.h" #include "gl/GrGLProgram.h" #include "gl/GrGLUniformHandle.h" +#include "SkMatrix.h" #define ASSERT_ARRAY_UPLOAD_IN_BOUNDS(UNI, OFFSET, COUNT) \ GrAssert(offset + arrayCount <= uni.fArrayCount || \ @@ -231,6 +232,23 @@ void GrGLUniformManager::setMatrix4fv(UniformHandle u, } } +void GrGLUniformManager::setSkMatrix(UniformHandle u, const SkMatrix& matrix) const { + GR_STATIC_ASSERT(SK_SCALAR_IS_FLOAT); + GrGLfloat mt[] = { + matrix.get(SkMatrix::kMScaleX), + matrix.get(SkMatrix::kMSkewY), + matrix.get(SkMatrix::kMPersp0), + matrix.get(SkMatrix::kMSkewX), + matrix.get(SkMatrix::kMScaleY), + matrix.get(SkMatrix::kMPersp1), + matrix.get(SkMatrix::kMTransX), + matrix.get(SkMatrix::kMTransY), + matrix.get(SkMatrix::kMPersp2), + }; + this->setMatrix3f(u, mt); +} + + void GrGLUniformManager::getUniformLocations(GrGLuint programID, const BuilderUniformArray& uniforms) { GrAssert(uniforms.count() == fUniforms.count()); int count = fUniforms.count(); diff --git a/src/gpu/gl/GrGLUniformManager.h b/src/gpu/gl/GrGLUniformManager.h index e9856c6ea3..8f435d3037 100644 --- a/src/gpu/gl/GrGLUniformManager.h +++ b/src/gpu/gl/GrGLUniformManager.h @@ -15,6 +15,7 @@ #include "SkTArray.h" class GrGLContextInfo; +class SkMatrix; /** Manages a program's uniforms. */ @@ -47,6 +48,9 @@ public: void setMatrix3fv(UniformHandle, int offset, int arrayCount, const GrGLfloat matrices[]) const; void setMatrix4fv(UniformHandle, int offset, int arrayCount, const GrGLfloat matrices[]) const; + // convenience method for uploading a SkMatrix to a 3x3 matrix uniform + void setSkMatrix(UniformHandle, const SkMatrix&) const; + struct BuilderUniform { GrGLShaderVar fVariable; uint32_t fVisibility; -- cgit v1.2.3