diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-12-09 17:03:02 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-12-09 17:03:02 +0000 |
commit | 907fbd53c5e5dd4cbde7b72f9242b51febd7ef95 (patch) | |
tree | 03bb985d1f109953370ab218f7cbfef7788a8b00 /src/gpu | |
parent | 2a7d4ddb17e496de6425267fe56653806da07878 (diff) |
Make texture domain a helper so that it can be incorporated into other effects.
R=robertphillips@google.com, jvanverth@google.com
Author: bsalomon@google.com
Review URL: https://codereview.chromium.org/98893006
git-svn-id: http://skia.googlecode.com/svn/trunk@12569 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 10 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 4 | ||||
-rw-r--r-- | src/gpu/effects/GrTextureDomain.cpp (renamed from src/gpu/effects/GrTextureDomainEffect.cpp) | 241 | ||||
-rw-r--r-- | src/gpu/effects/GrTextureDomain.h | 169 | ||||
-rw-r--r-- | src/gpu/effects/GrTextureDomainEffect.h | 89 | ||||
-rw-r--r-- | src/gpu/gl/GrGLEffect.h | 1 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.h | 19 |
7 files changed, 346 insertions, 187 deletions
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 3aef3dee67..4fd746f3fa 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -17,7 +17,7 @@ #include "GrRenderTarget.h" #include "GrStencilBuffer.h" #include "GrSWMaskHelper.h" -#include "effects/GrTextureDomainEffect.h" +#include "effects/GrTextureDomain.h" #include "SkRasterClip.h" #include "SkStrokeRec.h" #include "SkTLazy.h" @@ -52,8 +52,8 @@ void setup_drawstate_aaclip(GrGpu* gpu, drawState->addCoverageEffect( GrTextureDomainEffect::Create(result, mat, - GrTextureDomainEffect::MakeTexelDomain(result, domainTexels), - GrTextureDomainEffect::kDecal_WrapMode, + GrTextureDomain::MakeTexelDomain(result, domainTexels), + GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode, kPosition_GrCoordSet))->unref(); } @@ -365,8 +365,8 @@ void GrClipMaskManager::mergeMask(GrTexture* dstMask, drawState->addColorEffect( GrTextureDomainEffect::Create(srcMask, sampleM, - GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound), - GrTextureDomainEffect::kDecal_WrapMode, + GrTextureDomain::MakeTexelDomain(srcMask, srcBound), + GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode))->unref(); fGpu->drawSimpleRect(SkRect::Make(dstBound), NULL); } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 9580d22b06..2555b41c51 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -8,7 +8,7 @@ #include "SkGpuDevice.h" #include "effects/GrBicubicEffect.h" -#include "effects/GrTextureDomainEffect.h" +#include "effects/GrTextureDomain.h" #include "effects/GrSimpleTextureEffect.h" #include "GrContext.h" @@ -1420,7 +1420,7 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, effect.reset(GrTextureDomainEffect::Create(texture, SkMatrix::I(), textureDomain, - GrTextureDomainEffect::kClamp_WrapMode, + GrTextureDomain::kClamp_Mode, params.filterMode())); } else if (bicubic) { effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), params)); diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomain.cpp index 699aa729fd..517eb6dce1 100644 --- a/src/gpu/effects/GrTextureDomainEffect.cpp +++ b/src/gpu/effects/GrTextureDomain.cpp @@ -5,12 +5,141 @@ * found in the LICENSE file. */ -#include "GrTextureDomainEffect.h" +#include "GrTextureDomain.h" #include "GrSimpleTextureEffect.h" #include "GrTBackendEffectFactory.h" #include "gl/GrGLEffect.h" #include "SkFloatingPoint.h" + +GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode mode, int index) + : fIndex(index) { + + static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1}; + if (domain.contains(kFullRect)) { + fMode = kIgnore_Mode; + } else { + fMode = mode; + } + + if (fMode != kIgnore_Mode) { + // We don't currently handle domains that are empty or don't intersect the texture. + // It is OK if the domain rect is a line or point, but it should not be inverted. We do not + // handle rects that do not intersect the [0..1]x[0..1] rect. + SkASSERT(domain.fLeft <= domain.fRight); + SkASSERT(domain.fTop <= domain.fBottom); + fDomain.fLeft = SkMaxScalar(domain.fLeft, kFullRect.fLeft); + fDomain.fRight = SkMinScalar(domain.fRight, kFullRect.fRight); + fDomain.fTop = SkMaxScalar(domain.fTop, kFullRect.fTop); + fDomain.fBottom = SkMinScalar(domain.fBottom, kFullRect.fBottom); + SkASSERT(fDomain.fLeft <= fDomain.fRight); + SkASSERT(fDomain.fTop <= fDomain.fBottom); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void GrTextureDomain::GLDomain::sampleTexture(GrGLShaderBuilder* builder, + const GrTextureDomain& textureDomain, + const char* outColor, + const SkString& inCoords, + const GrGLEffect::TextureSampler sampler, + const char* inModulateColor) { + SkASSERT(-1 == fMode || textureDomain.mode() == fMode); + SkDEBUGCODE(fMode = textureDomain.mode();) + + if (kIgnore_Mode == textureDomain.mode()) { + builder->fsCodeAppendf("\t%s = ", outColor); + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, + inCoords.c_str()); + builder->fsCodeAppend(";\n"); + return; + } + + if (!fDomainUni.isValid()) { + const char* name; + SkString uniName("TexDom"); + if (textureDomain.fIndex >= 0) { + uniName.appendS32(textureDomain.fIndex); + } + fDomainUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec4f_GrSLType, uniName.c_str(), &name); + fDomainName = name; + } + if (kClamp_Mode == textureDomain.mode()) { + SkString clampedCoords; + clampedCoords.appendf("\tclamp(%s, %s.xy, %s.zw)", + inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str()); + + builder->fsCodeAppendf("\t%s = ", outColor); + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str()); + builder->fsCodeAppend(";\n"); + } else { + SkASSERT(GrTextureDomain::kDecal_Mode == textureDomain.mode()); + // Add a block since we're going to declare variables. + GrGLShaderBuilder::FSBlock block(builder); + + const char* domain = fDomainName.c_str(); + if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) { + // On the NexusS and GalaxyNexus, the other path (with the 'any' + // call) causes the compilation error "Calls to any function that + // may require a gradient calculation inside a conditional block + // may return undefined results". This appears to be an issue with + // the 'any' call since even the simple "result=black; if (any()) + // result=white;" code fails to compile. + builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n"); + builder->fsCodeAppend("\tvec4 inside = "); + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str()); + builder->fsCodeAppend(";\n"); + + builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n", + inCoords.c_str(), domain, domain, domain); + builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n", + inCoords.c_str(), domain, domain, domain); + builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n"); + builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outColor); + } else { + builder->fsCodeAppend("\tbvec4 outside;\n"); + builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", inCoords.c_str(), + domain); + builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", inCoords.c_str(), + domain); + builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outColor); + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str()); + builder->fsCodeAppend(";\n"); + } + } +} + +void GrTextureDomain::GLDomain::setData(const GrGLUniformManager& uman, + const GrTextureDomain& textureDomain, + GrSurfaceOrigin textureOrigin) { + SkASSERT(textureDomain.mode() == fMode); + if (kIgnore_Mode != textureDomain.mode()) { + GrGLfloat values[4] = { + SkScalarToFloat(textureDomain.domain().left()), + SkScalarToFloat(textureDomain.domain().top()), + SkScalarToFloat(textureDomain.domain().right()), + SkScalarToFloat(textureDomain.domain().bottom()) + }; + // vertical flip if necessary + if (kBottomLeft_GrSurfaceOrigin == textureOrigin) { + values[1] = 1.0f - values[1]; + values[3] = 1.0f - values[3]; + // The top and bottom were just flipped, so correct the ordering + // of elements so that values = (l, t, r, b). + SkTSwap(values[1], values[3]); + } + if (0 != memcmp(values, fPrevDomain, 4 * sizeof(GrGLfloat))) { + uman.set4fv(fDomainUni, 1, values); + memcpy(fPrevDomain, values, 4 * sizeof(GrGLfloat)); + } + } +} + + +////////////////////////////////////////////////////////////////////////////// + class GrGLTextureDomainEffect : public GrGLEffect { public: GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrDrawEffect&); @@ -28,16 +157,13 @@ public: static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); private: - GrGLUniformManager::UniformHandle fNameUni; - GrGLfloat fPrevDomain[4]; - + GrTextureDomain::GLDomain fGLDomain; typedef GrGLEffect INHERITED; }; GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) : INHERITED(factory) { - fPrevDomain[0] = SK_FloatNaN; } void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder, @@ -47,80 +173,24 @@ void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) { - const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>(); + const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>(); + const GrTextureDomain& domain = effect.textureDomain(); SkString coords2D = builder->ensureFSCoords2D(coords, 0); - const char* domain; - fNameUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, - kVec4f_GrSLType, "TexDom", &domain); - if (GrTextureDomainEffect::kClamp_WrapMode == texDom.wrapMode()) { - - builder->fsCodeAppendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n", - coords2D.c_str(), domain, domain); - - builder->fsCodeAppendf("\t%s = ", outputColor); - builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], "clampCoord"); - builder->fsCodeAppend(";\n"); - } else { - SkASSERT(GrTextureDomainEffect::kDecal_WrapMode == texDom.wrapMode()); - - if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) { - // On the NexusS and GalaxyNexus, the other path (with the 'any' - // call) causes the compilation error "Calls to any function that - // may require a gradient calculation inside a conditional block - // may return undefined results". This appears to be an issue with - // the 'any' call since even the simple "result=black; if (any()) - // result=white;" code fails to compile. - builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n"); - builder->fsCodeAppend("\tvec4 inside = "); - builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], coords2D.c_str()); - builder->fsCodeAppend(";\n"); - - builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n", - coords2D.c_str(), domain, domain, domain); - builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n", - coords2D.c_str(), domain, domain, domain); - builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n"); - builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outputColor); - } else { - builder->fsCodeAppend("\tbvec4 outside;\n"); - builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", coords2D.c_str(), domain); - builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", coords2D.c_str(), domain); - builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outputColor); - builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], coords2D.c_str()); - builder->fsCodeAppend(";\n"); - } - } + fGLDomain.sampleTexture(builder, domain, outputColor, coords2D, samplers[0], inputColor); } void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { - const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>(); - const SkRect& domain = texDom.domain(); - - float values[4] = { - SkScalarToFloat(domain.left()), - SkScalarToFloat(domain.top()), - SkScalarToFloat(domain.right()), - SkScalarToFloat(domain.bottom()) - }; - // vertical flip if necessary - if (kBottomLeft_GrSurfaceOrigin == texDom.texture(0)->origin()) { - values[1] = 1.0f - values[1]; - values[3] = 1.0f - values[3]; - // The top and bottom were just flipped, so correct the ordering - // of elements so that values = (l, t, r, b). - SkTSwap(values[1], values[3]); - } - if (0 != memcmp(values, fPrevDomain, 4 * sizeof(GrGLfloat))) { - uman.set4fv(fNameUni, 1, values); - memcpy(fPrevDomain, values, 4 * sizeof(GrGLfloat)); - } + const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>(); + const GrTextureDomain& domain = effect.textureDomain(); + fGLDomain.setData(uman, domain, effect.texture(0)->origin()); } GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { - return drawEffect.castEffect<GrTextureDomainEffect>().wrapMode(); + const GrTextureDomain& domain = drawEffect.castEffect<GrTextureDomainEffect>().textureDomain(); + return GrTextureDomain::GLDomain::DomainKey(domain); } @@ -129,30 +199,19 @@ GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEf GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture, const SkMatrix& matrix, const SkRect& domain, - WrapMode wrapMode, + GrTextureDomain::Mode mode, GrTextureParams::FilterMode filterMode, GrCoordSet coordSet) { static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1}; - if (kClamp_WrapMode == wrapMode && domain.contains(kFullRect)) { + if (GrTextureDomain::kIgnore_Mode == mode || + (GrTextureDomain::kClamp_Mode == mode && domain.contains(kFullRect))) { return GrSimpleTextureEffect::Create(texture, matrix, filterMode); } else { - SkRect clippedDomain; - // We don't currently handle domains that are empty or don't intersect the texture. - // It is OK if the domain rect is a line or point, but it should not be inverted. We do not - // handle rects that do not intersect the [0..1]x[0..1] rect. - SkASSERT(domain.fLeft <= domain.fRight); - SkASSERT(domain.fTop <= domain.fBottom); - clippedDomain.fLeft = SkMaxScalar(domain.fLeft, kFullRect.fLeft); - clippedDomain.fRight = SkMinScalar(domain.fRight, kFullRect.fRight); - clippedDomain.fTop = SkMaxScalar(domain.fTop, kFullRect.fTop); - clippedDomain.fBottom = SkMinScalar(domain.fBottom, kFullRect.fBottom); - SkASSERT(clippedDomain.fLeft <= clippedDomain.fRight); - SkASSERT(clippedDomain.fTop <= clippedDomain.fBottom); AutoEffectUnref effect(SkNEW_ARGS(GrTextureDomainEffect, (texture, matrix, - clippedDomain, - wrapMode, + domain, + mode, filterMode, coordSet))); return CreateEffectRef(effect); @@ -163,12 +222,11 @@ GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture, GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture, const SkMatrix& matrix, const SkRect& domain, - WrapMode wrapMode, + GrTextureDomain::Mode mode, GrTextureParams::FilterMode filterMode, GrCoordSet coordSet) : GrSingleTextureEffect(texture, matrix, filterMode, coordSet) - , fWrapMode(wrapMode) - , fTextureDomain(domain) { + , fTextureDomain(domain, mode) { } GrTextureDomainEffect::~GrTextureDomainEffect() { @@ -186,7 +244,7 @@ bool GrTextureDomainEffect::onIsEqual(const GrEffect& sBase) const { } void GrTextureDomainEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { - if (kDecal_WrapMode == fWrapMode) { + if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { // TODO: helper *validFlags = 0; } else { this->updateConstantColorComponentsForModulation(color, validFlags); @@ -208,14 +266,15 @@ GrEffectRef* GrTextureDomainEffect::TestCreate(SkRandom* random, domain.fRight = random->nextRangeScalar(domain.fLeft, SK_Scalar1); domain.fTop = random->nextUScalar1(); domain.fBottom = random->nextRangeScalar(domain.fTop, SK_Scalar1); - WrapMode wrapMode = random->nextBool() ? kClamp_WrapMode : kDecal_WrapMode; + GrTextureDomain::Mode mode = + (GrTextureDomain::Mode) random->nextULessThan(GrTextureDomain::kModeCount); const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random); bool bilerp = random->nextBool(); GrCoordSet coords = random->nextBool() ? kLocal_GrCoordSet : kPosition_GrCoordSet; return GrTextureDomainEffect::Create(textures[texIdx], matrix, domain, - wrapMode, + mode, bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode, coords); } diff --git a/src/gpu/effects/GrTextureDomain.h b/src/gpu/effects/GrTextureDomain.h new file mode 100644 index 0000000000..f64d5c3cf5 --- /dev/null +++ b/src/gpu/effects/GrTextureDomain.h @@ -0,0 +1,169 @@ +/* + * 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 GrTextureDomainEffect_DEFINED +#define GrTextureDomainEffect_DEFINED + +#include "GrSingleTextureEffect.h" +#include "gl/GrGLEffect.h" + +class GrGLShaderBuilder; +struct SkRect; + +/** + * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped + * the edge of the domain or result in a vec4 of zeros (decal mode). The domain is clipped to + * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the + * domain to affect the read value unless the caller considers this when calculating the domain. + */ +class GrTextureDomain { +public: + enum Mode { + kIgnore_Mode, // Ignore the texture domain rectangle. + kClamp_Mode, // Clamp texture coords to the domain rectangle. + kDecal_Mode, // Treat the area outside the domain rectangle as fully transparent. + + kLastMode = kDecal_Mode + }; + static const int kModeCount = kLastMode + 1; + + /** + * @param index Pass a value >= 0 if using multiple texture domains in the same effect. + * It is used to keep inserted variables from causing name collisions. + */ + GrTextureDomain(const SkRect& domain, Mode, int index = -1); + + const SkRect& domain() const { return fDomain; } + Mode mode() const { return fMode; } + + /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled + texels neighboring the domain may be read. */ + static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) { + SkScalar wInv = SK_Scalar1 / texture->width(); + SkScalar hInv = SK_Scalar1 / texture->height(); + SkRect result = { + texelRect.fLeft * wInv, + texelRect.fTop * hInv, + texelRect.fRight * wInv, + texelRect.fBottom * hInv + }; + return result; + } + + bool operator== (const GrTextureDomain& that) const { + return fMode == that.fMode && fDomain == that.fDomain; + } + + /** + * A GrGLEffect subclass that corresponds to a GrEffect subclass that uses GrTextureDomain + * should include this helper. It generates the texture domain GLSL, produces the part of the + * effect key that reflects the texture domain code, and performs the uniform uploads necessary + * for texture domains. + */ + class GLDomain { + public: + GLDomain() { + fPrevDomain[0] = SK_FloatNaN; + SkDEBUGCODE(fMode = (Mode) -1;) + } + + /** + * Call this from GrGLEffect::emitCode() to sample the texture W.R.T. the domain and mode. + * + * @param outcolor name of vec4 variable to hold the sampled color. + * @param inCoords name of vec2 variable containing the coords to be used with the domain. + * It is assumed that this is a variable and not an expression. + * @param inModulateColor if non-NULL the sampled color will be modulated with this + * expression before being written to outColor. + */ + void sampleTexture(GrGLShaderBuilder* builder, + const GrTextureDomain& textureDomain, + const char* outColor, + const SkString& inCoords, + const GrGLEffect::TextureSampler sampler, + const char* inModulateColor = NULL); + + /** + * Call this from GrGLEffect::setData() to upload uniforms necessary for the texture domain. + * The rectangle is automatically adjusted to account for the texture's origin. + */ + void setData(const GrGLUniformManager& uman, const GrTextureDomain& textureDomain, + GrSurfaceOrigin textureOrigin); + + enum { + kDomainKeyBits = 2, // See DomainKey(). + }; + + /** + * GrGLEffect::GenKey() must call this and include the returned value in it's computed key. + * The returned will be limited to the lower kDomainKeyBits bits. + */ + static GrGLEffect::EffectKey DomainKey(const GrTextureDomain& domain) { + GR_STATIC_ASSERT(kModeCount <= 4); + return domain.mode(); + } + + private: + SkDEBUGCODE(Mode fMode;) + GrGLUniformManager::UniformHandle fDomainUni; + SkString fDomainName; + GrGLfloat fPrevDomain[4]; + }; + +protected: + Mode fMode; + SkRect fDomain; + int fIndex; + + typedef GrSingleTextureEffect INHERITED; +}; + +class GrGLTextureDomainEffect; + +/** + * A basic texture effect that uses GrTextureDomain. + */ +class GrTextureDomainEffect : public GrSingleTextureEffect { + +public: + static GrEffectRef* Create(GrTexture*, + const SkMatrix&, + const SkRect& domain, + GrTextureDomain::Mode, + GrTextureParams::FilterMode filterMode, + GrCoordSet = kLocal_GrCoordSet); + + virtual ~GrTextureDomainEffect(); + + static const char* Name() { return "TextureDomain"; } + + typedef GrGLTextureDomainEffect GLEffect; + + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; + + const GrTextureDomain& textureDomain() const { return fTextureDomain; } + +protected: + GrTextureDomain fTextureDomain; + +private: + GrTextureDomainEffect(GrTexture*, + const SkMatrix&, + const SkRect& domain, + GrTextureDomain::Mode, + GrTextureParams::FilterMode, + GrCoordSet); + + virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; + + GR_DECLARE_EFFECT_TEST; + + typedef GrSingleTextureEffect INHERITED; +}; + +#endif diff --git a/src/gpu/effects/GrTextureDomainEffect.h b/src/gpu/effects/GrTextureDomainEffect.h deleted file mode 100644 index 46ee2a6506..0000000000 --- a/src/gpu/effects/GrTextureDomainEffect.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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 GrTextureDomainEffect_DEFINED -#define GrTextureDomainEffect_DEFINED - -#include "GrSingleTextureEffect.h" - -class GrGLTextureDomainEffect; -struct SkRect; - -/** - * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped - * the edge of the domain or result in a vec4 of zeros. The domain is clipped to normalized texture - * coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the domain to affect the - * read value unless the caller considers this when calculating the domain. TODO: This should be a - * helper that can assist an effect rather than effect unto itself. - */ -class GrTextureDomainEffect : public GrSingleTextureEffect { - -public: - /** - * If SkShader::kDecal_TileMode sticks then this enum could be replaced by SkShader::TileMode. - * We could also consider replacing/augmenting Decal mode with Border mode where the color - * outside of the domain is user-specifiable. Decal mode currently has a hard (non-lerped) - * transition between the border and the interior. - */ - enum WrapMode { - kClamp_WrapMode, - kDecal_WrapMode, - }; - - static GrEffectRef* Create(GrTexture*, - const SkMatrix&, - const SkRect& domain, - WrapMode, - GrTextureParams::FilterMode filterMode, - GrCoordSet = kLocal_GrCoordSet); - - virtual ~GrTextureDomainEffect(); - - static const char* Name() { return "TextureDomain"; } - - typedef GrGLTextureDomainEffect GLEffect; - - virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; - virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; - - const SkRect& domain() const { return fTextureDomain; } - WrapMode wrapMode() const { return fWrapMode; } - - /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled - texels neighboring the domain may be read. */ - static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) { - SkScalar wInv = SK_Scalar1 / texture->width(); - SkScalar hInv = SK_Scalar1 / texture->height(); - SkRect result = { - texelRect.fLeft * wInv, - texelRect.fTop * hInv, - texelRect.fRight * wInv, - texelRect.fBottom * hInv - }; - return result; - } - -protected: - WrapMode fWrapMode; - SkRect fTextureDomain; - -private: - GrTextureDomainEffect(GrTexture*, - const SkMatrix&, - const SkRect& domain, - WrapMode, - GrTextureParams::FilterMode filterMode, - GrCoordSet); - - virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; - - GR_DECLARE_EFFECT_TEST; - - typedef GrSingleTextureEffect INHERITED; -}; - -#endif diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h index b6807383e6..1cc3df24b0 100644 --- a/src/gpu/gl/GrGLEffect.h +++ b/src/gpu/gl/GrGLEffect.h @@ -40,6 +40,7 @@ class GrGLEffect { public: typedef GrBackendEffectFactory::EffectKey EffectKey; typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray; + typedef GrGLProgramEffects::TextureSampler TextureSampler; typedef GrGLProgramEffects::TextureSamplerArray TextureSamplerArray; enum { diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h index 52c24ae3ac..103efa5aab 100644 --- a/src/gpu/gl/GrGLShaderBuilder.h +++ b/src/gpu/gl/GrGLShaderBuilder.h @@ -208,6 +208,25 @@ public: const GrGLContextInfo& ctxInfo() const; + /** + * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder + * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that + * our shaders print pretty without effect writers tracking indentation. + */ + class FSBlock { + public: + FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) { + SkASSERT(NULL != builder); + fBuilder->fsCodeAppend("\t{\n"); + } + + ~FSBlock() { + fBuilder->fsCodeAppend("\t}\n"); + } + private: + GrGLShaderBuilder* fBuilder; + }; + protected: GrGpuGL* gpu() const { return fGpu; } |