GrEffect.h revision 7839ce1af63bf12fe7b3caa866970bbbb3afb13d
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
19class GrBackendEffectFactory;
20class GrContext;
21class GrEffect;
22class 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 */
35class GrEffectRef : public SkRefCnt {
36public:
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
56private:
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  */
83class GrEffect : private GrRefCnt {
84public:
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
204protected:
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
284private:
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
322inline 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)                                         \
333enum {                                                                                            \
334    k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8),                         \
335    k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef)                     \
336};                                                                                                \
337static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage;                              \
338static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset;   \
339static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
340static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect);                                         \
341static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect));     \
342static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
343
344
345#endif
346