aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-12-09 17:03:02 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-12-09 17:03:02 +0000
commit907fbd53c5e5dd4cbde7b72f9242b51febd7ef95 (patch)
tree03bb985d1f109953370ab218f7cbfef7788a8b00 /src/gpu
parent2a7d4ddb17e496de6425267fe56653806da07878 (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.cpp10
-rw-r--r--src/gpu/SkGpuDevice.cpp4
-rw-r--r--src/gpu/effects/GrTextureDomain.cpp (renamed from src/gpu/effects/GrTextureDomainEffect.cpp)241
-rw-r--r--src/gpu/effects/GrTextureDomain.h169
-rw-r--r--src/gpu/effects/GrTextureDomainEffect.h89
-rw-r--r--src/gpu/gl/GrGLEffect.h1
-rw-r--r--src/gpu/gl/GrGLShaderBuilder.h19
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; }