Home | History | Annotate | Download | only in gpu
      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 GrEffect_DEFINED
      9 #define GrEffect_DEFINED
     10 
     11 #include "GrColor.h"
     12 #include "GrEffectUnitTest.h"
     13 #include "GrTexture.h"
     14 #include "GrTextureAccess.h"
     15 #include "GrTypesPriv.h"
     16 
     17 class GrBackendEffectFactory;
     18 class GrContext;
     19 class GrCoordTransform;
     20 class GrEffect;
     21 class GrVertexEffect;
     22 class SkString;
     23 
     24 /**
     25  * A Wrapper class for GrEffect. Its ref-count will track owners that may use effects to enqueue
     26  * new draw operations separately from ownership within a deferred drawing queue. When the
     27  * GrEffectRef ref count reaches zero the scratch GrResources owned by the effect can be recycled
     28  * in service of later draws. However, the deferred draw queue may still own direct references to
     29  * the underlying GrEffect.
     30  *
     31  * GrEffectRefs created by new are placed in a per-thread managed pool. The pool is destroyed when
     32  * the thread ends. Therefore, all dynamically allocated GrEffectRefs must be unreffed before thread
     33  * termination.
     34  */
     35 class GrEffectRef : public SkRefCnt {
     36 public:
     37     SK_DECLARE_INST_COUNT(GrEffectRef);
     38     virtual ~GrEffectRef();
     39 
     40     GrEffect* get() { return fEffect; }
     41     const GrEffect* get() const { return fEffect; }
     42 
     43     const GrEffect* operator-> () { return fEffect; }
     44     const GrEffect* operator-> () const { return fEffect; }
     45 
     46     void* operator new(size_t size);
     47     void operator delete(void* target);
     48 
     49     void* operator new(size_t size, void* placement) {
     50         return ::operator new(size, placement);
     51     }
     52     void operator delete(void* target, void* placement) {
     53         ::operator delete(target, placement);
     54     }
     55 
     56 private:
     57     friend class GrEffect; // to construct these
     58 
     59     explicit GrEffectRef(GrEffect* effect);
     60 
     61     GrEffect* fEffect;
     62 
     63     typedef SkRefCnt INHERITED;
     64 };
     65 
     66 /** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
     67     Ganesh shading pipeline.
     68     Subclasses must have a function that produces a human-readable name:
     69         static const char* Name();
     70     GrEffect objects *must* be immutable: after being constructed, their fields may not change.
     71 
     72     GrEffect subclass objects should be created by factory functions that return GrEffectRef.
     73     There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static
     74     member function of a GrEffect subclass.
     75 
     76     Because almost no code should ever handle a GrEffect directly outside of a GrEffectRef, we
     77     privately inherit from SkRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
     78 
     79     Dynamically allocated GrEffects and their corresponding GrEffectRefs are managed by a per-thread
     80     memory pool. The ref count of an effect must reach 0 before the thread terminates and the pool
     81     is destroyed. To create a static effect use the macro GR_CREATE_STATIC_EFFECT declared below.
     82   */
     83 class GrEffect : private SkRefCnt {
     84 public:
     85     SK_DECLARE_INST_COUNT(GrEffect)
     86 
     87     virtual ~GrEffect();
     88 
     89     /**
     90      * This function is used to perform optimizations. When called the color and validFlags params
     91      * indicate whether the input components to this effect in the FS will have known values.
     92      * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to
     93      * indicate known values of its output. A component of the color param only has meaning if the
     94      * corresponding bit in validFlags is set.
     95      */
     96     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
     97 
     98     /** Will this effect read the source color value? */
     99     bool willUseInputColor() const { return fWillUseInputColor; }
    100 
    101     /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
    102         identification. The factory should be an instance of templated class,
    103         GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
    104         a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
    105         by the factory.
    106 
    107         Example:
    108         class MyCustomEffect : public GrEffect {
    109         ...
    110             virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
    111                 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
    112             }
    113         ...
    114         };
    115      */
    116     virtual const GrBackendEffectFactory& getFactory() const = 0;
    117 
    118     /** Returns true if this and other effect conservatively draw identically. It can only return
    119         true when the two effects are of the same subclass (i.e. they return the same object from
    120         from getFactory()).
    121 
    122         A return value of true from isEqual() should not be used to test whether the effects would
    123         generate the same shader code. To test for identical code generation use the EffectKey
    124         computed by the GrBackendEffectFactory:
    125             effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB).
    126      */
    127     bool isEqual(const GrEffectRef& other) const {
    128         return this->isEqual(*other.get());
    129     }
    130 
    131     /** Human-meaningful string to identify this effect; may be embedded
    132         in generated shader code. */
    133     const char* name() const;
    134 
    135     int numTransforms() const { return fCoordTransforms.count(); }
    136 
    137     /** Returns the coordinate transformation at index. index must be valid according to
    138         numTransforms(). */
    139     const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; }
    140 
    141     int numTextures() const { return fTextureAccesses.count(); }
    142 
    143     /** Returns the access pattern for the texture at index. index must be valid according to
    144         numTextures(). */
    145     const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
    146 
    147     /** Shortcut for textureAccess(index).texture(); */
    148     GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
    149 
    150     /** Will this effect read the destination pixel value? */
    151     bool willReadDstColor() const { return fWillReadDstColor; }
    152 
    153     /** Will this effect read the fragment position? */
    154     bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
    155 
    156     /** Will this effect emit custom vertex shader code?
    157         (To set this value the effect must inherit from GrVertexEffect.) */
    158     bool hasVertexCode() const { return fHasVertexCode; }
    159 
    160     int numVertexAttribs() const {
    161         SkASSERT(0 == fVertexAttribTypes.count() || fHasVertexCode);
    162         return fVertexAttribTypes.count();
    163     }
    164 
    165     GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
    166 
    167     static const int kMaxVertexAttribs = 2;
    168 
    169     /** Useful for effects that want to insert a texture matrix that is implied by the texture
    170         dimensions */
    171     static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) {
    172         SkASSERT(NULL != texture);
    173         SkMatrix mat;
    174         mat.setIDiv(texture->width(), texture->height());
    175         return mat;
    176     }
    177 
    178     void* operator new(size_t size);
    179     void operator delete(void* target);
    180 
    181     void* operator new(size_t size, void* placement) {
    182         return ::operator new(size, placement);
    183     }
    184     void operator delete(void* target, void* placement) {
    185         ::operator delete(target, placement);
    186     }
    187 
    188     /** These functions are used when recording effects into a deferred drawing queue. The inc call
    189         keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
    190         effect to be returned to the cache for reuse. The dec call must balance the inc call. */
    191     void incDeferredRefCounts() const {
    192         this->ref();
    193         int count = fTextureAccesses.count();
    194         for (int t = 0; t < count; ++t) {
    195             fTextureAccesses[t]->getTexture()->incDeferredRefCount();
    196         }
    197     }
    198     void decDeferredRefCounts() const {
    199         int count = fTextureAccesses.count();
    200         for (int t = 0; t < count; ++t) {
    201             fTextureAccesses[t]->getTexture()->decDeferredRefCount();
    202         }
    203         this->unref();
    204     }
    205 
    206 protected:
    207     /**
    208      * Subclasses call this from their constructor to register coordinate transformations. The
    209      * effect subclass manages the lifetime of the transformations (this function only stores a
    210      * pointer). The GrCoordTransform is typically a member field of the GrEffect subclass. When the
    211      * matrix has perspective, the transformed coordinates will have 3 components. Otherwise they'll
    212      * have 2. This must only be called from the constructor because GrEffects are immutable.
    213      */
    214     void addCoordTransform(const GrCoordTransform* coordTransform);
    215 
    216     /**
    217      * Subclasses call this from their constructor to register GrTextureAccesses. The effect
    218      * subclass manages the lifetime of the accesses (this function only stores a pointer). The
    219      * GrTextureAccess is typically a member field of the GrEffect subclass. This must only be
    220      * called from the constructor because GrEffects are immutable.
    221      */
    222     void addTextureAccess(const GrTextureAccess* textureAccess);
    223 
    224     GrEffect()
    225         : fWillReadDstColor(false)
    226         , fWillReadFragmentPosition(false)
    227         , fWillUseInputColor(true)
    228         , fHasVertexCode(false)
    229         , fEffectRef(NULL) {}
    230 
    231     /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
    232         an example factory function. */
    233     static GrEffectRef* CreateEffectRef(GrEffect* effect) {
    234         if (NULL == effect->fEffectRef) {
    235             effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
    236         } else {
    237             effect->fEffectRef->ref();
    238         }
    239         return effect->fEffectRef;
    240     }
    241 
    242     static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
    243         return CreateEffectRef(const_cast<GrEffect*>(effect));
    244     }
    245 
    246     /** Used by GR_CREATE_STATIC_EFFECT below */
    247     static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
    248         SkASSERT(NULL == effect->fEffectRef);
    249         effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
    250         return effect->fEffectRef;
    251     }
    252 
    253 
    254     /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
    255         GrEffectRef. E.g.:
    256 
    257         class EffectSubclass : public GrEffect {
    258         public:
    259             GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
    260                 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
    261                 return CreateEffectRef(effect);
    262             }
    263      */
    264     class AutoEffectUnref {
    265     public:
    266         AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
    267         ~AutoEffectUnref() { fEffect->unref(); }
    268         operator GrEffect*() { return fEffect; }
    269     private:
    270         GrEffect* fEffect;
    271     };
    272 
    273     /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
    274       */
    275     template <typename T>
    276     static const T& CastEffect(const GrEffect& effectRef) {
    277         return *static_cast<const T*>(&effectRef);
    278     }
    279 
    280     /**
    281      * If the effect subclass will read the destination pixel value then it must call this function
    282      * from its constructor. Otherwise, when its generated backend-specific effect class attempts
    283      * to generate code that reads the destination pixel it will fail.
    284      */
    285     void setWillReadDstColor() { fWillReadDstColor = true; }
    286 
    287     /**
    288      * If the effect will generate a backend-specific effect that will read the fragment position
    289      * in the FS then it must call this method from its constructor. Otherwise, the request to
    290      * access the fragment position will be denied.
    291      */
    292     void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
    293 
    294     /**
    295      * If the effect will generate a result that does not depend on the input color value then it must
    296      * call this function from its constructor. Otherwise, when its generated backend-specific code
    297      * might fail during variable binding due to unused variables.
    298      */
    299     void setWillNotUseInputColor() { fWillUseInputColor = false; }
    300 
    301 private:
    302     bool isEqual(const GrEffect& other) const {
    303         if (&this->getFactory() != &other.getFactory()) {
    304             return false;
    305         }
    306         bool result = this->onIsEqual(other);
    307 #ifdef SK_DEBUG
    308         if (result) {
    309             this->assertEquality(other);
    310         }
    311 #endif
    312         return result;
    313     }
    314 
    315     SkDEBUGCODE(void assertEquality(const GrEffect& other) const;)
    316 
    317     /** Subclass implements this to support isEqual(). It will only be called if it is known that
    318         the two effects are of the same subclass (i.e. they return the same object from
    319         getFactory()).*/
    320     virtual bool onIsEqual(const GrEffect& other) const = 0;
    321 
    322     void EffectRefDestroyed() { fEffectRef = NULL; }
    323 
    324     friend class GrEffectRef;    // to call EffectRefDestroyed()
    325     friend class GrEffectStage;  // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
    326                                  // from deferred state, to call isEqual on naked GrEffects, and
    327                                  // to inc/dec deferred ref counts.
    328     friend class GrVertexEffect; // to set fHasVertexCode and build fVertexAttribTypes.
    329 
    330     SkSTArray<4, const GrCoordTransform*, true>  fCoordTransforms;
    331     SkSTArray<4, const GrTextureAccess*, true>   fTextureAccesses;
    332     SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
    333     bool                                         fWillReadDstColor;
    334     bool                                         fWillReadFragmentPosition;
    335     bool                                         fWillUseInputColor;
    336     bool                                         fHasVertexCode;
    337     GrEffectRef*                                 fEffectRef;
    338 
    339     typedef SkRefCnt INHERITED;
    340 };
    341 
    342 inline GrEffectRef::GrEffectRef(GrEffect* effect) {
    343     SkASSERT(NULL != effect);
    344     effect->ref();
    345     fEffect = effect;
    346 }
    347 
    348 /**
    349  * This creates an effect outside of the effect memory pool. The effect's destructor will be called
    350  * at global destruction time. NAME will be the name of the created GrEffectRef.
    351  */
    352 #define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS)                                         \
    353 enum {                                                                                            \
    354     k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8),                         \
    355     k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef)                     \
    356 };                                                                                                \
    357 static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage;                              \
    358 static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset;   \
    359 static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
    360 static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect);                                         \
    361 static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect));     \
    362 static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
    363 
    364 
    365 #endif
    366