gfx/skia/trunk/src/gpu/effects/GrTextureDomain.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/gpu/effects/GrTextureDomain.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,280 @@
     1.4 +/*
     1.5 + * Copyright 2012 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "GrTextureDomain.h"
    1.12 +#include "GrSimpleTextureEffect.h"
    1.13 +#include "GrTBackendEffectFactory.h"
    1.14 +#include "gl/GrGLEffect.h"
    1.15 +#include "SkFloatingPoint.h"
    1.16 +
    1.17 +
    1.18 +GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode mode, int index)
    1.19 +    : fIndex(index) {
    1.20 +
    1.21 +    static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
    1.22 +    if (domain.contains(kFullRect)) {
    1.23 +        fMode = kIgnore_Mode;
    1.24 +    } else {
    1.25 +        fMode = mode;
    1.26 +    }
    1.27 +
    1.28 +    if (fMode != kIgnore_Mode) {
    1.29 +        // We don't currently handle domains that are empty or don't intersect the texture.
    1.30 +        // It is OK if the domain rect is a line or point, but it should not be inverted. We do not
    1.31 +        // handle rects that do not intersect the [0..1]x[0..1] rect.
    1.32 +        SkASSERT(domain.fLeft <= domain.fRight);
    1.33 +        SkASSERT(domain.fTop <= domain.fBottom);
    1.34 +        fDomain.fLeft = SkMaxScalar(domain.fLeft, kFullRect.fLeft);
    1.35 +        fDomain.fRight = SkMinScalar(domain.fRight, kFullRect.fRight);
    1.36 +        fDomain.fTop = SkMaxScalar(domain.fTop, kFullRect.fTop);
    1.37 +        fDomain.fBottom = SkMinScalar(domain.fBottom, kFullRect.fBottom);
    1.38 +        SkASSERT(fDomain.fLeft <= fDomain.fRight);
    1.39 +        SkASSERT(fDomain.fTop <= fDomain.fBottom);
    1.40 +    }
    1.41 +}
    1.42 +
    1.43 +//////////////////////////////////////////////////////////////////////////////
    1.44 +
    1.45 +void GrTextureDomain::GLDomain::sampleTexture(GrGLShaderBuilder* builder,
    1.46 +                                              const GrTextureDomain& textureDomain,
    1.47 +                                              const char* outColor,
    1.48 +                                              const SkString& inCoords,
    1.49 +                                              const GrGLEffect::TextureSampler sampler,
    1.50 +                                              const char* inModulateColor) {
    1.51 +    SkASSERT((Mode)-1 == fMode || textureDomain.mode() == fMode);
    1.52 +    SkDEBUGCODE(fMode = textureDomain.mode();)
    1.53 +
    1.54 +    if (kIgnore_Mode == textureDomain.mode()) {
    1.55 +        builder->fsCodeAppendf("\t%s = ", outColor);
    1.56 +        builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler,
    1.57 +                                                    inCoords.c_str());
    1.58 +        builder->fsCodeAppend(";\n");
    1.59 +        return;
    1.60 +    }
    1.61 +
    1.62 +    if (!fDomainUni.isValid()) {
    1.63 +        const char* name;
    1.64 +        SkString uniName("TexDom");
    1.65 +        if (textureDomain.fIndex >= 0) {
    1.66 +            uniName.appendS32(textureDomain.fIndex);
    1.67 +        }
    1.68 +        fDomainUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
    1.69 +                                            kVec4f_GrSLType, uniName.c_str(), &name);
    1.70 +        fDomainName = name;
    1.71 +    }
    1.72 +    if (kClamp_Mode == textureDomain.mode()) {
    1.73 +        SkString clampedCoords;
    1.74 +        clampedCoords.appendf("\tclamp(%s, %s.xy, %s.zw)",
    1.75 +                                inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str());
    1.76 +
    1.77 +        builder->fsCodeAppendf("\t%s = ", outColor);
    1.78 +        builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str());
    1.79 +        builder->fsCodeAppend(";\n");
    1.80 +    } else {
    1.81 +        SkASSERT(GrTextureDomain::kDecal_Mode == textureDomain.mode());
    1.82 +        // Add a block since we're going to declare variables.
    1.83 +        GrGLShaderBuilder::FSBlock block(builder);
    1.84 +
    1.85 +        const char* domain = fDomainName.c_str();
    1.86 +        if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) {
    1.87 +            // On the NexusS and GalaxyNexus, the other path (with the 'any'
    1.88 +            // call) causes the compilation error "Calls to any function that
    1.89 +            // may require a gradient calculation inside a conditional block
    1.90 +            // may return undefined results". This appears to be an issue with
    1.91 +            // the 'any' call since even the simple "result=black; if (any())
    1.92 +            // result=white;" code fails to compile.
    1.93 +            builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
    1.94 +            builder->fsCodeAppend("\tvec4 inside = ");
    1.95 +            builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str());
    1.96 +            builder->fsCodeAppend(";\n");
    1.97 +
    1.98 +            builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n",
    1.99 +                                    inCoords.c_str(), domain, domain, domain);
   1.100 +            builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n",
   1.101 +                                    inCoords.c_str(), domain, domain, domain);
   1.102 +            builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n");
   1.103 +            builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outColor);
   1.104 +        } else {
   1.105 +            builder->fsCodeAppend("\tbvec4 outside;\n");
   1.106 +            builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", inCoords.c_str(),
   1.107 +                                   domain);
   1.108 +            builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", inCoords.c_str(),
   1.109 +                                   domain);
   1.110 +            builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outColor);
   1.111 +            builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str());
   1.112 +            builder->fsCodeAppend(";\n");
   1.113 +        }
   1.114 +    }
   1.115 +}
   1.116 +
   1.117 +void GrTextureDomain::GLDomain::setData(const GrGLUniformManager& uman,
   1.118 +                                        const GrTextureDomain& textureDomain,
   1.119 +                                        GrSurfaceOrigin textureOrigin) {
   1.120 +    SkASSERT(textureDomain.mode() == fMode);
   1.121 +    if (kIgnore_Mode != textureDomain.mode()) {
   1.122 +        GrGLfloat values[4] = {
   1.123 +            SkScalarToFloat(textureDomain.domain().left()),
   1.124 +            SkScalarToFloat(textureDomain.domain().top()),
   1.125 +            SkScalarToFloat(textureDomain.domain().right()),
   1.126 +            SkScalarToFloat(textureDomain.domain().bottom())
   1.127 +        };
   1.128 +        // vertical flip if necessary
   1.129 +        if (kBottomLeft_GrSurfaceOrigin == textureOrigin) {
   1.130 +            values[1] = 1.0f - values[1];
   1.131 +            values[3] = 1.0f - values[3];
   1.132 +            // The top and bottom were just flipped, so correct the ordering
   1.133 +            // of elements so that values = (l, t, r, b).
   1.134 +            SkTSwap(values[1], values[3]);
   1.135 +        }
   1.136 +        if (0 != memcmp(values, fPrevDomain, 4 * sizeof(GrGLfloat))) {
   1.137 +            uman.set4fv(fDomainUni, 1, values);
   1.138 +            memcpy(fPrevDomain, values, 4 * sizeof(GrGLfloat));
   1.139 +        }
   1.140 +    }
   1.141 +}
   1.142 +
   1.143 +
   1.144 +//////////////////////////////////////////////////////////////////////////////
   1.145 +
   1.146 +class GrGLTextureDomainEffect : public GrGLEffect {
   1.147 +public:
   1.148 +    GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
   1.149 +
   1.150 +    virtual void emitCode(GrGLShaderBuilder*,
   1.151 +                          const GrDrawEffect&,
   1.152 +                          EffectKey,
   1.153 +                          const char* outputColor,
   1.154 +                          const char* inputColor,
   1.155 +                          const TransformedCoordsArray&,
   1.156 +                          const TextureSamplerArray&) SK_OVERRIDE;
   1.157 +
   1.158 +    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
   1.159 +
   1.160 +    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
   1.161 +
   1.162 +private:
   1.163 +    GrTextureDomain::GLDomain         fGLDomain;
   1.164 +    typedef GrGLEffect INHERITED;
   1.165 +};
   1.166 +
   1.167 +GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrBackendEffectFactory& factory,
   1.168 +                                                 const GrDrawEffect&)
   1.169 +    : INHERITED(factory) {
   1.170 +}
   1.171 +
   1.172 +void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder,
   1.173 +                                       const GrDrawEffect& drawEffect,
   1.174 +                                       EffectKey key,
   1.175 +                                       const char* outputColor,
   1.176 +                                       const char* inputColor,
   1.177 +                                       const TransformedCoordsArray& coords,
   1.178 +                                       const TextureSamplerArray& samplers) {
   1.179 +    const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>();
   1.180 +    const GrTextureDomain& domain = effect.textureDomain();
   1.181 +
   1.182 +    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
   1.183 +    fGLDomain.sampleTexture(builder, domain, outputColor, coords2D, samplers[0], inputColor);
   1.184 +}
   1.185 +
   1.186 +void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman,
   1.187 +                                      const GrDrawEffect& drawEffect) {
   1.188 +    const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>();
   1.189 +    const GrTextureDomain& domain = effect.textureDomain();
   1.190 +    fGLDomain.setData(uman, domain, effect.texture(0)->origin());
   1.191 +}
   1.192 +
   1.193 +GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEffect,
   1.194 +                                                      const GrGLCaps&) {
   1.195 +    const GrTextureDomain& domain = drawEffect.castEffect<GrTextureDomainEffect>().textureDomain();
   1.196 +    return GrTextureDomain::GLDomain::DomainKey(domain);
   1.197 +}
   1.198 +
   1.199 +
   1.200 +///////////////////////////////////////////////////////////////////////////////
   1.201 +
   1.202 +GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture,
   1.203 +                                           const SkMatrix& matrix,
   1.204 +                                           const SkRect& domain,
   1.205 +                                           GrTextureDomain::Mode mode,
   1.206 +                                           GrTextureParams::FilterMode filterMode,
   1.207 +                                           GrCoordSet coordSet) {
   1.208 +    static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
   1.209 +    if (GrTextureDomain::kIgnore_Mode == mode ||
   1.210 +        (GrTextureDomain::kClamp_Mode == mode && domain.contains(kFullRect))) {
   1.211 +        return GrSimpleTextureEffect::Create(texture, matrix, filterMode);
   1.212 +    } else {
   1.213 +
   1.214 +        AutoEffectUnref effect(SkNEW_ARGS(GrTextureDomainEffect, (texture,
   1.215 +                                                                  matrix,
   1.216 +                                                                  domain,
   1.217 +                                                                  mode,
   1.218 +                                                                  filterMode,
   1.219 +                                                                  coordSet)));
   1.220 +        return CreateEffectRef(effect);
   1.221 +
   1.222 +    }
   1.223 +}
   1.224 +
   1.225 +GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture,
   1.226 +                                             const SkMatrix& matrix,
   1.227 +                                             const SkRect& domain,
   1.228 +                                             GrTextureDomain::Mode mode,
   1.229 +                                             GrTextureParams::FilterMode filterMode,
   1.230 +                                             GrCoordSet coordSet)
   1.231 +    : GrSingleTextureEffect(texture, matrix, filterMode, coordSet)
   1.232 +    , fTextureDomain(domain, mode) {
   1.233 +}
   1.234 +
   1.235 +GrTextureDomainEffect::~GrTextureDomainEffect() {
   1.236 +
   1.237 +}
   1.238 +
   1.239 +const GrBackendEffectFactory& GrTextureDomainEffect::getFactory() const {
   1.240 +    return GrTBackendEffectFactory<GrTextureDomainEffect>::getInstance();
   1.241 +}
   1.242 +
   1.243 +bool GrTextureDomainEffect::onIsEqual(const GrEffect& sBase) const {
   1.244 +    const GrTextureDomainEffect& s = CastEffect<GrTextureDomainEffect>(sBase);
   1.245 +    return this->hasSameTextureParamsMatrixAndSourceCoords(s) &&
   1.246 +           this->fTextureDomain == s.fTextureDomain;
   1.247 +}
   1.248 +
   1.249 +void GrTextureDomainEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
   1.250 +    if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { // TODO: helper
   1.251 +        *validFlags = 0;
   1.252 +    } else {
   1.253 +        this->updateConstantColorComponentsForModulation(color, validFlags);
   1.254 +    }
   1.255 +}
   1.256 +
   1.257 +///////////////////////////////////////////////////////////////////////////////
   1.258 +
   1.259 +GR_DEFINE_EFFECT_TEST(GrTextureDomainEffect);
   1.260 +
   1.261 +GrEffectRef* GrTextureDomainEffect::TestCreate(SkRandom* random,
   1.262 +                                               GrContext*,
   1.263 +                                               const GrDrawTargetCaps&,
   1.264 +                                               GrTexture* textures[]) {
   1.265 +    int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
   1.266 +                                      GrEffectUnitTest::kAlphaTextureIdx;
   1.267 +    SkRect domain;
   1.268 +    domain.fLeft = random->nextUScalar1();
   1.269 +    domain.fRight = random->nextRangeScalar(domain.fLeft, SK_Scalar1);
   1.270 +    domain.fTop = random->nextUScalar1();
   1.271 +    domain.fBottom = random->nextRangeScalar(domain.fTop, SK_Scalar1);
   1.272 +    GrTextureDomain::Mode mode =
   1.273 +        (GrTextureDomain::Mode) random->nextULessThan(GrTextureDomain::kModeCount);
   1.274 +    const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
   1.275 +    bool bilerp = random->nextBool();
   1.276 +    GrCoordSet coords = random->nextBool() ? kLocal_GrCoordSet : kPosition_GrCoordSet;
   1.277 +    return GrTextureDomainEffect::Create(textures[texIdx],
   1.278 +                                         matrix,
   1.279 +                                         domain,
   1.280 +                                         mode,
   1.281 +                                         bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode,
   1.282 +                                         coords);
   1.283 +}

mercurial