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
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 3eb60d2..cddabe3 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -140,8 +140,8 @@
'<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.cpp',
'<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.h',
'<(skia_src_path)/gpu/effects/GrSingleTextureEffect.cpp',
- '<(skia_src_path)/gpu/effects/GrSingleTextureEffect.h',
- '<(skia_src_path)/gpu/effects/GrTextureDomainEffect.cpp',
+ '<(skia_src_path)/gpu/effects/GrSingleTexture.h',
+ '<(skia_src_path)/gpu/effects/GrTextureDomain.cpp',
'<(skia_src_path)/gpu/effects/GrTextureDomainEffect.h',
'<(skia_src_path)/gpu/effects/GrTextureStripAtlas.cpp',
'<(skia_src_path)/gpu/effects/GrTextureStripAtlas.h',
diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp
index 02fdf48..6133db1 100644
--- a/src/effects/SkGpuBlurUtils.cpp
+++ b/src/effects/SkGpuBlurUtils.cpp
@@ -11,7 +11,7 @@
#if SK_SUPPORT_GPU
#include "effects/GrConvolutionEffect.h"
-#include "effects/GrTextureDomainEffect.h"
+#include "effects/GrTextureDomain.h"
#include "GrContext.h"
#endif
@@ -173,7 +173,7 @@
srcTexture,
matrix,
domain,
- GrTextureDomainEffect::kDecal_WrapMode,
+ GrTextureDomain::kDecal_Mode,
GrTextureParams::kBilerp_FilterMode));
paint.addColorEffect(effect);
} else {
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 3aef3de..4fd746f 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 @@
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 @@
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 9580d22..2555b41 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 @@
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/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
new file mode 100644
index 0000000..517eb6d
--- /dev/null
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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 "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&);
+
+ virtual void emitCode(GrGLShaderBuilder*,
+ const GrDrawEffect&,
+ EffectKey,
+ const char* outputColor,
+ const char* inputColor,
+ const TransformedCoordsArray&,
+ const TextureSamplerArray&) SK_OVERRIDE;
+
+ virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
+
+ static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
+
+private:
+ GrTextureDomain::GLDomain fGLDomain;
+ typedef GrGLEffect INHERITED;
+};
+
+GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrBackendEffectFactory& factory,
+ const GrDrawEffect&)
+ : INHERITED(factory) {
+}
+
+void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder,
+ const GrDrawEffect& drawEffect,
+ EffectKey key,
+ const char* outputColor,
+ const char* inputColor,
+ const TransformedCoordsArray& coords,
+ const TextureSamplerArray& samplers) {
+ const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>();
+ const GrTextureDomain& domain = effect.textureDomain();
+
+ SkString coords2D = builder->ensureFSCoords2D(coords, 0);
+ fGLDomain.sampleTexture(builder, domain, outputColor, coords2D, samplers[0], inputColor);
+}
+
+void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman,
+ const GrDrawEffect& drawEffect) {
+ 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&) {
+ const GrTextureDomain& domain = drawEffect.castEffect<GrTextureDomainEffect>().textureDomain();
+ return GrTextureDomain::GLDomain::DomainKey(domain);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture,
+ const SkMatrix& matrix,
+ const SkRect& domain,
+ GrTextureDomain::Mode mode,
+ GrTextureParams::FilterMode filterMode,
+ GrCoordSet coordSet) {
+ static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
+ if (GrTextureDomain::kIgnore_Mode == mode ||
+ (GrTextureDomain::kClamp_Mode == mode && domain.contains(kFullRect))) {
+ return GrSimpleTextureEffect::Create(texture, matrix, filterMode);
+ } else {
+
+ AutoEffectUnref effect(SkNEW_ARGS(GrTextureDomainEffect, (texture,
+ matrix,
+ domain,
+ mode,
+ filterMode,
+ coordSet)));
+ return CreateEffectRef(effect);
+
+ }
+}
+
+GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture,
+ const SkMatrix& matrix,
+ const SkRect& domain,
+ GrTextureDomain::Mode mode,
+ GrTextureParams::FilterMode filterMode,
+ GrCoordSet coordSet)
+ : GrSingleTextureEffect(texture, matrix, filterMode, coordSet)
+ , fTextureDomain(domain, mode) {
+}
+
+GrTextureDomainEffect::~GrTextureDomainEffect() {
+
+}
+
+const GrBackendEffectFactory& GrTextureDomainEffect::getFactory() const {
+ return GrTBackendEffectFactory<GrTextureDomainEffect>::getInstance();
+}
+
+bool GrTextureDomainEffect::onIsEqual(const GrEffect& sBase) const {
+ const GrTextureDomainEffect& s = CastEffect<GrTextureDomainEffect>(sBase);
+ return this->hasSameTextureParamsMatrixAndSourceCoords(s) &&
+ this->fTextureDomain == s.fTextureDomain;
+}
+
+void GrTextureDomainEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
+ if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { // TODO: helper
+ *validFlags = 0;
+ } else {
+ this->updateConstantColorComponentsForModulation(color, validFlags);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrTextureDomainEffect);
+
+GrEffectRef* GrTextureDomainEffect::TestCreate(SkRandom* random,
+ GrContext*,
+ const GrDrawTargetCaps&,
+ GrTexture* textures[]) {
+ int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
+ GrEffectUnitTest::kAlphaTextureIdx;
+ SkRect domain;
+ domain.fLeft = random->nextUScalar1();
+ domain.fRight = random->nextRangeScalar(domain.fLeft, SK_Scalar1);
+ domain.fTop = random->nextUScalar1();
+ domain.fBottom = random->nextRangeScalar(domain.fTop, SK_Scalar1);
+ 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,
+ 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 0000000..f64d5c3
--- /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.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp
deleted file mode 100644
index 699aa72..0000000
--- a/src/gpu/effects/GrTextureDomainEffect.cpp
+++ /dev/null
@@ -1,221 +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.
- */
-
-#include "GrTextureDomainEffect.h"
-#include "GrSimpleTextureEffect.h"
-#include "GrTBackendEffectFactory.h"
-#include "gl/GrGLEffect.h"
-#include "SkFloatingPoint.h"
-
-class GrGLTextureDomainEffect : public GrGLEffect {
-public:
- GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
-
- virtual void emitCode(GrGLShaderBuilder*,
- const GrDrawEffect&,
- EffectKey,
- const char* outputColor,
- const char* inputColor,
- const TransformedCoordsArray&,
- const TextureSamplerArray&) SK_OVERRIDE;
-
- virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
-
- static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
-
-private:
- GrGLUniformManager::UniformHandle fNameUni;
- GrGLfloat fPrevDomain[4];
-
- typedef GrGLEffect INHERITED;
-};
-
-GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrBackendEffectFactory& factory,
- const GrDrawEffect&)
- : INHERITED(factory) {
- fPrevDomain[0] = SK_FloatNaN;
-}
-
-void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder,
- const GrDrawEffect& drawEffect,
- EffectKey key,
- const char* outputColor,
- const char* inputColor,
- const TransformedCoordsArray& coords,
- const TextureSamplerArray& samplers) {
- const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>();
-
- 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");
- }
- }
-}
-
-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));
- }
-}
-
-GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEffect,
- const GrGLCaps&) {
- return drawEffect.castEffect<GrTextureDomainEffect>().wrapMode();
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture,
- const SkMatrix& matrix,
- const SkRect& domain,
- WrapMode wrapMode,
- GrTextureParams::FilterMode filterMode,
- GrCoordSet coordSet) {
- static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
- if (kClamp_WrapMode == wrapMode && 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,
- filterMode,
- coordSet)));
- return CreateEffectRef(effect);
-
- }
-}
-
-GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture,
- const SkMatrix& matrix,
- const SkRect& domain,
- WrapMode wrapMode,
- GrTextureParams::FilterMode filterMode,
- GrCoordSet coordSet)
- : GrSingleTextureEffect(texture, matrix, filterMode, coordSet)
- , fWrapMode(wrapMode)
- , fTextureDomain(domain) {
-}
-
-GrTextureDomainEffect::~GrTextureDomainEffect() {
-
-}
-
-const GrBackendEffectFactory& GrTextureDomainEffect::getFactory() const {
- return GrTBackendEffectFactory<GrTextureDomainEffect>::getInstance();
-}
-
-bool GrTextureDomainEffect::onIsEqual(const GrEffect& sBase) const {
- const GrTextureDomainEffect& s = CastEffect<GrTextureDomainEffect>(sBase);
- return this->hasSameTextureParamsMatrixAndSourceCoords(s) &&
- this->fTextureDomain == s.fTextureDomain;
-}
-
-void GrTextureDomainEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
- if (kDecal_WrapMode == fWrapMode) {
- *validFlags = 0;
- } else {
- this->updateConstantColorComponentsForModulation(color, validFlags);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-GR_DEFINE_EFFECT_TEST(GrTextureDomainEffect);
-
-GrEffectRef* GrTextureDomainEffect::TestCreate(SkRandom* random,
- GrContext*,
- const GrDrawTargetCaps&,
- GrTexture* textures[]) {
- int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
- GrEffectUnitTest::kAlphaTextureIdx;
- SkRect domain;
- domain.fLeft = random->nextUScalar1();
- 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;
- 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,
- bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode,
- coords);
-}
diff --git a/src/gpu/effects/GrTextureDomainEffect.h b/src/gpu/effects/GrTextureDomainEffect.h
deleted file mode 100644
index 46ee2a6..0000000
--- 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 b680738..1cc3df2 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -40,6 +40,7 @@
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 52c24ae..103efa5 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -208,6 +208,25 @@
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; }