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/effects/GrTextureDomain.cpp | |
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/effects/GrTextureDomain.cpp')
-rw-r--r-- | src/gpu/effects/GrTextureDomain.cpp | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp new file mode 100644 index 0000000000..517eb6dce1 --- /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); +} |