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
17class GrBackendEffectFactory;
18class GrContext;
19class GrCoordTransform;
20class GrEffect;
21class GrVertexEffect;
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 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  */
83class GrEffect : private SkRefCnt {
84public:
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
206protected:
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
301private:
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
342inline 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)                                         \
353enum {                                                                                            \
354    k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8),                         \
355    k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef)                     \
356};                                                                                                \
357static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage;                              \
358static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset;   \
359static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
360static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect);                                         \
361static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect));     \
362static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
363
364
365#endif
366