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 "GrNoncopyable.h"
     14 #include "GrRefCnt.h"
     15 #include "GrTexture.h"
     16 #include "GrTextureAccess.h"
     17 #include "GrTypesPriv.h"
     18 
     19 class GrBackendEffectFactory;
     20 class GrContext;
     21 class GrEffect;
     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 GrRefCnt 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 GrRefCnt {
     84 public:
     85     SK_DECLARE_INST_COUNT(GrEffect)
     86 
     87     /**
     88      * The types of vertex coordinates available to an effect in the vertex shader. Effects can
     89      * require their own vertex attribute but these coordinates are made available by the framework
     90      * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords
     91      * is used (usually an explicit vertex attribute) but its meaning is determined by the effect
     92      * subclass.
     93      */
     94     enum CoordsType {
     95         kLocal_CoordsType,
     96         kPosition_CoordsType,
     97 
     98         kCustom_CoordsType,
     99     };
    100 
    101     virtual ~GrEffect();
    102 
    103     /**
    104      * This function is used to perform optimizations. When called the color and validFlags params
    105      * indicate whether the input components to this effect in the FS will have known values.
    106      * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to
    107      * indicate known values of its output. A component of the color param only has meaning if the
    108      * corresponding bit in validFlags is set.
    109      */
    110     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0;
    111 
    112     /** This object, besides creating back-end-specific helper objects, is used for run-time-type-
    113         identification. The factory should be an instance of templated class,
    114         GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have
    115         a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created
    116         by the factory.
    117 
    118         Example:
    119         class MyCustomEffect : public GrEffect {
    120         ...
    121             virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
    122                 return GrTBackendEffectFactory<MyCustomEffect>::getInstance();
    123             }
    124         ...
    125         };
    126      */
    127     virtual const GrBackendEffectFactory& getFactory() const = 0;
    128 
    129     /** Returns true if this and other effect conservatively draw identically. It can only return
    130         true when the two effects are of the same subclass (i.e. they return the same object from
    131         from getFactory()).
    132 
    133         A return value of true from isEqual() should not be used to test whether the effects would
    134         generate the same shader code. To test for identical code generation use the EffectKey
    135         computed by the GrBackendEffectFactory:
    136             effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB).
    137      */
    138     bool isEqual(const GrEffectRef& other) const {
    139         return this->isEqual(*other.get());
    140     }
    141 
    142     /** Human-meaningful string to identify this effect; may be embedded
    143         in generated shader code. */
    144     const char* name() const;
    145 
    146     int numTextures() const { return fTextureAccesses.count(); }
    147 
    148     /** Returns the access pattern for the texture at index. index must be valid according to
    149         numTextures(). */
    150     const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; }
    151 
    152     /** Shortcut for textureAccess(index).texture(); */
    153     GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
    154 
    155     /** Will this effect read the destination pixel value? */
    156     bool willReadDstColor() const { return fWillReadDstColor; }
    157 
    158     /** Will this effect read the fragment position? */
    159     bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
    160 
    161     int numVertexAttribs() const { return fVertexAttribTypes.count(); }
    162 
    163     GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
    164 
    165     static const int kMaxVertexAttribs = 2;
    166 
    167     /** Useful for effects that want to insert a texture matrix that is implied by the texture
    168         dimensions */
    169     static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) {
    170         GrAssert(NULL != texture);
    171         SkMatrix mat;
    172         mat.setIDiv(texture->width(), texture->height());
    173         return mat;
    174     }
    175 
    176     void* operator new(size_t size);
    177     void operator delete(void* target);
    178 
    179     void* operator new(size_t size, void* placement) {
    180         return ::operator new(size, placement);
    181     }
    182     void operator delete(void* target, void* placement) {
    183         ::operator delete(target, placement);
    184     }
    185 
    186     /** These functions are used when recording effects into a deferred drawing queue. The inc call
    187         keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
    188         effect to be returned to the cache for reuse. The dec call must balance the inc call. */
    189     void incDeferredRefCounts() const {
    190         this->ref();
    191         int count = fTextureAccesses.count();
    192         for (int t = 0; t < count; ++t) {
    193             fTextureAccesses[t]->getTexture()->incDeferredRefCount();
    194         }
    195     }
    196     void decDeferredRefCounts() const {
    197         int count = fTextureAccesses.count();
    198         for (int t = 0; t < count; ++t) {
    199             fTextureAccesses[t]->getTexture()->decDeferredRefCount();
    200         }
    201         this->unref();
    202     }
    203 
    204 protected:
    205     /**
    206      * Subclasses call this from their constructor to register GrTextureAccesses. The effect
    207      * subclass manages the lifetime of the accesses (this function only stores a pointer). This
    208      * must only be called from the constructor because GrEffects are immutable.
    209      */
    210     void addTextureAccess(const GrTextureAccess* textureAccess);
    211 
    212     /**
    213      * Subclasses call this from their constructor to register vertex attributes (at most
    214      * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
    215      * immutable.
    216      */
    217     void addVertexAttrib(GrSLType type);
    218 
    219     GrEffect() : fWillReadDstColor(false), fWillReadFragmentPosition(false), fEffectRef(NULL) {}
    220 
    221     /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
    222         an example factory function. */
    223     static GrEffectRef* CreateEffectRef(GrEffect* effect) {
    224         if (NULL == effect->fEffectRef) {
    225             effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect));
    226         } else {
    227             effect->fEffectRef->ref();
    228         }
    229         return effect->fEffectRef;
    230     }
    231 
    232     static const GrEffectRef* CreateEffectRef(const GrEffect* effect) {
    233         return CreateEffectRef(const_cast<GrEffect*>(effect));
    234     }
    235 
    236     /** Used by GR_CREATE_STATIC_EFFECT below */
    237     static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
    238         GrAssert(NULL == effect->fEffectRef);
    239         effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
    240         return effect->fEffectRef;
    241     }
    242 
    243 
    244     /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
    245         GrEffectRef. E.g.:
    246 
    247         class EffectSubclass : public GrEffect {
    248         public:
    249             GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) {
    250                 AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...)));
    251                 return CreateEffectRef(effect);
    252             }
    253      */
    254     class AutoEffectUnref {
    255     public:
    256         AutoEffectUnref(GrEffect* effect) : fEffect(effect) { }
    257         ~AutoEffectUnref() { fEffect->unref(); }
    258         operator GrEffect*() { return fEffect; }
    259     private:
    260         GrEffect* fEffect;
    261     };
    262 
    263     /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass
    264       */
    265     template <typename T>
    266     static const T& CastEffect(const GrEffect& effectRef) {
    267         return *static_cast<const T*>(&effectRef);
    268     }
    269 
    270     /**
    271      * If the effect subclass will read the destination pixel value then it must call this function
    272      * from its constructor. Otherwise, when its generated backend-specific effect class attempts
    273      * to generate code that reads the destination pixel it will fail.
    274      */
    275     void setWillReadDstColor() { fWillReadDstColor = true; }
    276 
    277     /**
    278      * If the effect will generate a backend-specific effect that will read the fragment position
    279      * in the FS then it must call this method from its constructor. Otherwise, the request to
    280      * access the fragment position will be denied.
    281      */
    282     void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; }
    283 
    284 private:
    285     bool isEqual(const GrEffect& other) const {
    286         if (&this->getFactory() != &other.getFactory()) {
    287             return false;
    288         }
    289         bool result = this->onIsEqual(other);
    290 #if GR_DEBUG
    291         if (result) {
    292             GrAssert(this->numTextures() == other.numTextures());
    293             for (int i = 0; i < this->numTextures(); ++i) {
    294                 GrAssert(*fTextureAccesses[i] == *other.fTextureAccesses[i]);
    295             }
    296         }
    297 #endif
    298         return result;
    299     }
    300 
    301     /** Subclass implements this to support isEqual(). It will only be called if it is known that
    302         the two effects are of the same subclass (i.e. they return the same object from
    303         getFactory()).*/
    304     virtual bool onIsEqual(const GrEffect& other) const = 0;
    305 
    306     void EffectRefDestroyed() { fEffectRef = NULL; }
    307 
    308     friend class GrEffectRef;   // to call EffectRefDestroyed()
    309     friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
    310                                 // from deferred state, to call isEqual on naked GrEffects, and
    311                                 // to inc/dec deferred ref counts.
    312 
    313     SkSTArray<4, const GrTextureAccess*, true>   fTextureAccesses;
    314     SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
    315     bool                                         fWillReadDstColor;
    316     bool                                         fWillReadFragmentPosition;
    317     GrEffectRef*                                 fEffectRef;
    318 
    319     typedef GrRefCnt INHERITED;
    320 };
    321 
    322 inline GrEffectRef::GrEffectRef(GrEffect* effect) {
    323     GrAssert(NULL != effect);
    324     effect->ref();
    325     fEffect = effect;
    326 }
    327 
    328 /**
    329  * This creates an effect outside of the effect memory pool. The effect's destructor will be called
    330  * at global destruction time. NAME will be the name of the created GrEffectRef.
    331  */
    332 #define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS)                                         \
    333 enum {                                                                                            \
    334     k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8),                         \
    335     k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef)                     \
    336 };                                                                                                \
    337 static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage;                              \
    338 static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset;   \
    339 static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
    340 static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect);                                         \
    341 static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect));     \
    342 static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
    343 
    344 
    345 #endif
    346