Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef GrTextureDomainEffect_DEFINED
      9 #define GrTextureDomainEffect_DEFINED
     10 
     11 #include "GrSingleTextureEffect.h"
     12 #include "gl/GrGLProcessor.h"
     13 
     14 class GrGLProgramBuilder;
     15 class GrGLShaderBuilder;
     16 class GrInvariantOutput;
     17 struct SkRect;
     18 
     19 /**
     20  * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped
     21  * the edge of the domain or result in a vec4 of zeros (decal mode). The domain is clipped to
     22  * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the
     23  * domain to affect the read value unless the caller considers this when calculating the domain.
     24  */
     25 class GrTextureDomain {
     26 public:
     27     enum Mode {
     28         // Ignore the texture domain rectangle.
     29         kIgnore_Mode,
     30         // Clamp texture coords to the domain rectangle.
     31         kClamp_Mode,
     32         // Treat the area outside the domain rectangle as fully transparent.
     33         kDecal_Mode,
     34         // Wrap texture coordinates.  NOTE: filtering may not work as expected because Bilerp will
     35         // read texels outside of the domain.  We could perform additional texture reads and filter
     36         // in the shader, but are not currently doing this for performance reasons
     37         kRepeat_Mode,
     38 
     39         kLastMode = kRepeat_Mode
     40     };
     41     static const int kModeCount = kLastMode + 1;
     42 
     43     static const GrTextureDomain& IgnoredDomain() {
     44         static const SkRect gDummyRect = {0, 0, 0, 0};
     45         static const GrTextureDomain gDomain(gDummyRect, kIgnore_Mode);
     46         return gDomain;
     47     }
     48 
     49     /**
     50      * @param index     Pass a value >= 0 if using multiple texture domains in the same effect.
     51      *                  It is used to keep inserted variables from causing name collisions.
     52      */
     53     GrTextureDomain(const SkRect& domain, Mode, int index = -1);
     54 
     55     const SkRect& domain() const { return fDomain; }
     56     Mode mode() const { return fMode; }
     57 
     58     /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
     59        texels neighboring the domain may be read. */
     60     static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) {
     61         SkScalar wInv = SK_Scalar1 / texture->width();
     62         SkScalar hInv = SK_Scalar1 / texture->height();
     63         SkRect result = {
     64             texelRect.fLeft * wInv,
     65             texelRect.fTop * hInv,
     66             texelRect.fRight * wInv,
     67             texelRect.fBottom * hInv
     68         };
     69         return result;
     70     }
     71 
     72     static const SkRect MakeTexelDomainForMode(const GrTexture* texture, const SkIRect& texelRect, Mode mode) {
     73         // For Clamp mode, inset by half a texel.
     74         SkScalar wInv = SK_Scalar1 / texture->width();
     75         SkScalar hInv = SK_Scalar1 / texture->height();
     76         SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0;
     77         return SkRect::MakeLTRB(
     78             (texelRect.fLeft + inset) * wInv,
     79             (texelRect.fTop + inset) * hInv,
     80             (texelRect.fRight - inset) * wInv,
     81             (texelRect.fBottom - inset) * hInv
     82         );
     83     }
     84 
     85     bool operator== (const GrTextureDomain& that) const {
     86         return fMode == that.fMode && (kIgnore_Mode == fMode || fDomain == that.fDomain);
     87     }
     88 
     89     /**
     90      * A GrGLProcessor subclass that corresponds to a GrProcessor subclass that uses GrTextureDomain
     91      * should include this helper. It generates the texture domain GLSL, produces the part of the
     92      * effect key that reflects the texture domain code, and performs the uniform uploads necessary
     93      * for texture domains.
     94      */
     95     class GLDomain {
     96     public:
     97         GLDomain() {
     98             fPrevDomain[0] = SK_FloatNaN;
     99             SkDEBUGCODE(fMode = (Mode) -1;)
    100         }
    101 
    102         /**
    103          * Call this from GrGLProcessor::emitCode() to sample the texture W.R.T. the domain and
    104          * mode.
    105          *
    106          * @param outcolor  name of vec4 variable to hold the sampled color.
    107          * @param inCoords  name of vec2 variable containing the coords to be used with the domain.
    108          *                  It is assumed that this is a variable and not an expression.
    109          * @param inModulateColor   if non-NULL the sampled color will be modulated with this
    110          *                          expression before being written to outColor.
    111          */
    112         void sampleTexture(GrGLShaderBuilder* builder,
    113                            const GrTextureDomain& textureDomain,
    114                            const char* outColor,
    115                            const SkString& inCoords,
    116                            const GrGLProcessor::TextureSampler sampler,
    117                            const char* inModulateColor = NULL);
    118 
    119         /**
    120          * Call this from GrGLProcessor::setData() to upload uniforms necessary for the texture
    121          * domain. The rectangle is automatically adjusted to account for the texture's origin.
    122          */
    123         void setData(const GrGLProgramDataManager& pdman, const GrTextureDomain& textureDomain,
    124                      GrSurfaceOrigin textureOrigin);
    125 
    126         enum {
    127             kDomainKeyBits = 2, // See DomainKey().
    128         };
    129 
    130         /**
    131          * GrGLProcessor::GenKey() must call this and include the returned value in it's computed
    132          * key. The returned will be limited to the lower kDomainKeyBits bits.
    133          */
    134         static uint32_t DomainKey(const GrTextureDomain& domain) {
    135             GR_STATIC_ASSERT(kModeCount <= 4);
    136             return domain.mode();
    137         }
    138 
    139     private:
    140         SkDEBUGCODE(Mode                      fMode;)
    141         GrGLProgramDataManager::UniformHandle fDomainUni;
    142         SkString                              fDomainName;
    143         GrGLfloat                             fPrevDomain[4];
    144     };
    145 
    146 protected:
    147     Mode    fMode;
    148     SkRect  fDomain;
    149     int     fIndex;
    150 
    151     typedef GrSingleTextureEffect INHERITED;
    152 };
    153 
    154 /**
    155  * A basic texture effect that uses GrTextureDomain.
    156  */
    157 class GrTextureDomainEffect : public GrSingleTextureEffect {
    158 
    159 public:
    160     static GrFragmentProcessor* Create(GrTexture*,
    161                                        const SkMatrix&,
    162                                        const SkRect& domain,
    163                                        GrTextureDomain::Mode,
    164                                        GrTextureParams::FilterMode filterMode,
    165                                        GrCoordSet = kLocal_GrCoordSet);
    166 
    167     virtual ~GrTextureDomainEffect();
    168 
    169     const char* name() const override { return "TextureDomain"; }
    170 
    171     void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
    172 
    173     GrGLFragmentProcessor* createGLInstance() const override;
    174 
    175     const GrTextureDomain& textureDomain() const { return fTextureDomain; }
    176 
    177 protected:
    178     GrTextureDomain fTextureDomain;
    179 
    180 private:
    181     GrTextureDomainEffect(GrTexture*,
    182                           const SkMatrix&,
    183                           const SkRect& domain,
    184                           GrTextureDomain::Mode,
    185                           GrTextureParams::FilterMode,
    186                           GrCoordSet);
    187 
    188     bool onIsEqual(const GrFragmentProcessor&) const override;
    189 
    190     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
    191 
    192     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
    193 
    194     typedef GrSingleTextureEffect INHERITED;
    195 };
    196 
    197 #endif
    198