Index: src/gpu/effects/GrTextureDomain.cpp |
diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomain.cpp |
similarity index 56% |
rename from src/gpu/effects/GrTextureDomainEffect.cpp |
rename to src/gpu/effects/GrTextureDomain.cpp |
index 699aa729fd9f04052b0e6b3a77d320b93264cb16..517eb6dce1aa3df4a02a5740ba056ac01c00e2e5 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); |
} |