1
2/*
3 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10
11#ifndef GrEffectStage_DEFINED
12#define GrEffectStage_DEFINED
13
14#include "GrBackendEffectFactory.h"
15#include "GrEffect.h"
16#include "SkMatrix.h"
17#include "GrTypes.h"
18
19#include "SkShader.h"
20
21class GrEffectStage {
22public:
23    explicit GrEffectStage(const GrEffectRef* effectRef, int attrIndex0 = -1, int attrIndex1 = -1)
24    : fEffectRef(SkRef(effectRef)) {
25        fCoordChangeMatrixSet = false;
26        fVertexAttribIndices[0] = attrIndex0;
27        fVertexAttribIndices[1] = attrIndex1;
28    }
29
30    GrEffectStage(const GrEffectStage& other) {
31        *this = other;
32    }
33
34    class DeferredStage;
35    // This constructor balances DeferredStage::saveFrom().
36    explicit GrEffectStage(const DeferredStage& deferredStage) {
37        deferredStage.restoreTo(this);
38    }
39
40    GrEffectStage& operator= (const GrEffectStage& other) {
41        fCoordChangeMatrixSet = other.fCoordChangeMatrixSet;
42        if (other.fCoordChangeMatrixSet) {
43            fCoordChangeMatrix = other.fCoordChangeMatrix;
44        }
45        fEffectRef.reset(SkRef(other.fEffectRef.get()));
46        memcpy(fVertexAttribIndices, other.fVertexAttribIndices, sizeof(fVertexAttribIndices));
47        return *this;
48    }
49
50    bool operator== (const GrEffectStage& other) const {
51        SkASSERT(NULL != fEffectRef.get());
52        SkASSERT(NULL != other.fEffectRef.get());
53
54        if (!(*this->getEffect())->isEqual(*other.getEffect())) {
55            return false;
56        }
57
58        if (fCoordChangeMatrixSet != other.fCoordChangeMatrixSet) {
59            return false;
60        }
61
62        if (!fCoordChangeMatrixSet) {
63            return true;
64        }
65
66        return fCoordChangeMatrix == other.fCoordChangeMatrix;
67    }
68
69    bool operator!= (const GrEffectStage& s) const { return !(*this == s); }
70
71    /**
72     * This is called when the coordinate system in which the geometry is specified will change.
73     *
74     * @param matrix    The transformation from the old coord system in which geometry is specified
75     *                  to the new one from which it will actually be drawn.
76     */
77    void localCoordChange(const SkMatrix& matrix) {
78        if (fCoordChangeMatrixSet) {
79            fCoordChangeMatrix.preConcat(matrix);
80        } else {
81            fCoordChangeMatrixSet = true;
82            fCoordChangeMatrix = matrix;
83        }
84    }
85
86    class SavedCoordChange {
87    private:
88        bool fCoordChangeMatrixSet;
89        SkMatrix fCoordChangeMatrix;
90        SkDEBUGCODE(mutable SkAutoTUnref<const GrEffectRef> fEffectRef;)
91
92        friend class GrEffectStage;
93    };
94
95    /**
96     * This gets the current coordinate system change. It is the accumulation of
97     * localCoordChange calls since the effect was installed. It is used when then caller
98     * wants to temporarily change the source geometry coord system, draw something, and then
99     * restore the previous coord system (e.g. temporarily draw in device coords).
100     */
101    void saveCoordChange(SavedCoordChange* savedCoordChange) const {
102        savedCoordChange->fCoordChangeMatrixSet = fCoordChangeMatrixSet;
103        if (fCoordChangeMatrixSet) {
104            savedCoordChange->fCoordChangeMatrix = fCoordChangeMatrix;
105        }
106        SkASSERT(NULL == savedCoordChange->fEffectRef.get());
107        SkDEBUGCODE(SkRef(fEffectRef.get());)
108        SkDEBUGCODE(savedCoordChange->fEffectRef.reset(fEffectRef.get());)
109    }
110
111    /**
112     * This balances the saveCoordChange call.
113     */
114    void restoreCoordChange(const SavedCoordChange& savedCoordChange) {
115        fCoordChangeMatrixSet = savedCoordChange.fCoordChangeMatrixSet;
116        if (fCoordChangeMatrixSet) {
117            fCoordChangeMatrix = savedCoordChange.fCoordChangeMatrix;
118        }
119        SkASSERT(savedCoordChange.fEffectRef.get() == fEffectRef);
120        SkDEBUGCODE(savedCoordChange.fEffectRef.reset(NULL);)
121    }
122
123    /**
124     * Used when storing a deferred GrDrawState. The DeferredStage allows resources owned by its
125     * GrEffect to be recycled through the cache.
126     */
127    class DeferredStage {
128    public:
129        DeferredStage() : fEffect(NULL) {
130            SkDEBUGCODE(fInitialized = false;)
131        }
132
133        ~DeferredStage() {
134            if (NULL != fEffect) {
135                fEffect->decDeferredRefCounts();
136            }
137        }
138
139        void saveFrom(const GrEffectStage& stage) {
140            SkASSERT(!fInitialized);
141            SkASSERT(NULL != stage.fEffectRef.get());
142            stage.fEffectRef->get()->incDeferredRefCounts();
143            fEffect = stage.fEffectRef->get();
144            fCoordChangeMatrixSet = stage.fCoordChangeMatrixSet;
145            if (fCoordChangeMatrixSet) {
146                fCoordChangeMatrix = stage.fCoordChangeMatrix;
147            }
148            fVertexAttribIndices[0] = stage.fVertexAttribIndices[0];
149            fVertexAttribIndices[1] = stage.fVertexAttribIndices[1];
150            SkDEBUGCODE(fInitialized = true;)
151        }
152
153        void restoreTo(GrEffectStage* stage) const {
154            SkASSERT(fInitialized);
155            stage->fEffectRef.reset(GrEffect::CreateEffectRef(fEffect));
156            stage->fCoordChangeMatrixSet = fCoordChangeMatrixSet;
157            if (fCoordChangeMatrixSet) {
158                stage->fCoordChangeMatrix = fCoordChangeMatrix;
159            }
160            stage->fVertexAttribIndices[0] = fVertexAttribIndices[0];
161            stage->fVertexAttribIndices[1] = fVertexAttribIndices[1];
162        }
163
164        bool isEqual(const GrEffectStage& stage, bool ignoreCoordChange) const {
165            if (fVertexAttribIndices[0] != stage.fVertexAttribIndices[0] ||
166                fVertexAttribIndices[1] != stage.fVertexAttribIndices[1]) {
167                return false;
168            }
169
170            if (!(*stage.getEffect())->isEqual(*fEffect)) {
171                return false;
172            }
173
174            if (ignoreCoordChange) {
175                // ignore the coordinate change matrix since there are
176                // explicit uv coordinates
177                return true;
178            }
179
180            if (fCoordChangeMatrixSet != stage.fCoordChangeMatrixSet) {
181                return false;
182            }
183
184            if (!fCoordChangeMatrixSet) {
185                return true;
186            }
187
188            return fCoordChangeMatrix == stage.fCoordChangeMatrix;
189        }
190
191    private:
192        const GrEffect*               fEffect;
193        bool                          fCoordChangeMatrixSet;
194        SkMatrix                      fCoordChangeMatrix;
195        int                           fVertexAttribIndices[2];
196        SkDEBUGCODE(bool fInitialized;)
197    };
198
199    /**
200     * Gets the matrix representing all changes of coordinate system since the GrEffect was
201     * installed in the stage.
202     */
203    const SkMatrix& getCoordChangeMatrix() const {
204        if (fCoordChangeMatrixSet) {
205            return fCoordChangeMatrix;
206        } else {
207            return SkMatrix::I();
208        }
209    }
210
211    const GrEffectRef* getEffect() const { return fEffectRef.get(); }
212
213    const int* getVertexAttribIndices() const { return fVertexAttribIndices; }
214    int getVertexAttribIndexCount() const { return fEffectRef->get()->numVertexAttribs(); }
215
216private:
217    bool                                fCoordChangeMatrixSet;
218    SkMatrix                            fCoordChangeMatrix;
219    SkAutoTUnref<const GrEffectRef>     fEffectRef;
220    int                                 fVertexAttribIndices[2];
221};
222
223#endif
224