GrClipMaskManager.h revision d6176b0dcacb124539e0cfd051e6d93a9782f020
1
2/*
3 * Copyright 2012 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#ifndef GrClipMaskManager_DEFINED
10#define GrClipMaskManager_DEFINED
11
12#include "GrContext.h"
13#include "GrNoncopyable.h"
14#include "GrRect.h"
15#include "GrStencil.h"
16#include "GrTexture.h"
17
18#include "SkClipStack.h"
19#include "SkDeque.h"
20#include "SkPath.h"
21#include "SkRefCnt.h"
22
23class GrGpu;
24class GrPathRenderer;
25class GrPathRendererChain;
26class SkPath;
27class GrTexture;
28class GrDrawState;
29
30/**
31 * The stencil buffer stores the last clip path - providing a single entry
32 * "cache". This class provides similar functionality for AA clip paths
33 */
34class GrClipMaskCache : public GrNoncopyable {
35public:
36    GrClipMaskCache();
37
38    ~GrClipMaskCache() {
39
40        while (!fStack.empty()) {
41            GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
42            temp->~GrClipStackFrame();
43            fStack.pop_back();
44        }
45    }
46
47    bool canReuse(const SkClipStack& clip, int width, int height) {
48
49        if (fStack.empty()) {
50            GrAssert(false);
51            return false;
52        }
53
54        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
55
56        if (back->fLastMask.texture() &&
57            back->fLastMask.texture()->width() >= width &&
58            back->fLastMask.texture()->height() >= height &&
59            clip == back->fLastClip) {
60            return true;
61        }
62
63        return false;
64    }
65
66    void reset() {
67        if (fStack.empty()) {
68//            GrAssert(false);
69            return;
70        }
71
72        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
73
74        back->reset();
75    }
76
77    /**
78     * After a "push" the clip state is entirely open. Currently, the
79     * entire clip stack will be re-rendered into a new clip mask.
80     * TODO: can we take advantage of the nested nature of the clips to
81     * reduce the mask creation cost?
82     */
83    void push();
84
85    void pop() {
86        //GrAssert(!fStack.empty());
87
88        if (!fStack.empty()) {
89            GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
90
91            back->~GrClipStackFrame();
92            fStack.pop_back();
93        }
94    }
95
96    void getLastClip(SkClipStack* clip) const {
97
98        if (fStack.empty()) {
99            GrAssert(false);
100            clip->reset();
101            return;
102        }
103
104        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
105
106        *clip = back->fLastClip;
107    }
108
109    GrTexture* getLastMask() {
110
111        if (fStack.empty()) {
112            GrAssert(false);
113            return NULL;
114        }
115
116        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
117
118        return back->fLastMask.texture();
119    }
120
121    const GrTexture* getLastMask() const {
122
123        if (fStack.empty()) {
124            GrAssert(false);
125            return NULL;
126        }
127
128        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
129
130        return back->fLastMask.texture();
131    }
132
133    void acquireMask(const SkClipStack& clip,
134                     const GrTextureDesc& desc,
135                     const GrIRect& bound) {
136
137        if (fStack.empty()) {
138            GrAssert(false);
139            return;
140        }
141
142        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
143
144        back->acquireMask(fContext, clip, desc, bound);
145    }
146
147    int getLastMaskWidth() const {
148
149        if (fStack.empty()) {
150            GrAssert(false);
151            return -1;
152        }
153
154        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
155
156        if (NULL == back->fLastMask.texture()) {
157            return -1;
158        }
159
160        return back->fLastMask.texture()->width();
161    }
162
163    int getLastMaskHeight() const {
164
165        if (fStack.empty()) {
166            GrAssert(false);
167            return -1;
168        }
169
170        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
171
172        if (NULL == back->fLastMask.texture()) {
173            return -1;
174        }
175
176        return back->fLastMask.texture()->height();
177    }
178
179    void getLastBound(GrIRect* bound) const {
180
181        if (fStack.empty()) {
182            GrAssert(false);
183            bound->setEmpty();
184            return;
185        }
186
187        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
188
189        *bound = back->fLastBound;
190    }
191
192    void setContext(GrContext* context) {
193        fContext = context;
194    }
195
196    GrContext* getContext() {
197        return fContext;
198    }
199
200    void releaseResources() {
201
202        SkDeque::F2BIter iter(fStack);
203        for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
204                frame != NULL;
205                frame = (GrClipStackFrame*) iter.next()) {
206            frame->reset();
207        }
208    }
209
210protected:
211private:
212    struct GrClipStackFrame {
213
214        GrClipStackFrame() {
215            reset();
216        }
217
218        void acquireMask(GrContext* context,
219                         const SkClipStack& clip,
220                         const GrTextureDesc& desc,
221                         const GrIRect& bound) {
222
223            fLastClip = clip;
224
225            fLastMask.set(context, desc);
226
227            fLastBound = bound;
228        }
229
230        void reset () {
231            fLastClip.reset();
232
233            GrTextureDesc desc;
234
235            fLastMask.set(NULL, desc);
236            fLastBound.setEmpty();
237        }
238
239        SkClipStack             fLastClip;
240        // The mask's width & height values are used in setupDrawStateAAClip to
241        // correctly scale the uvs for geometry drawn with this mask
242        GrAutoScratchTexture    fLastMask;
243        // fLastBound stores the bounding box of the clip mask in canvas
244        // space. The left and top fields are used to offset the uvs for
245        // geometry drawn with this mask (in setupDrawStateAAClip)
246        GrIRect                 fLastBound;
247    };
248
249    GrContext*   fContext;
250    SkDeque      fStack;
251
252    typedef GrNoncopyable INHERITED;
253};
254
255/**
256 * The clip mask creator handles the generation of the clip mask. If anti
257 * aliasing is requested it will (in the future) generate a single channel
258 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
259 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
260 * mask can be represented as a rectangle then scissoring is used. In all
261 * cases scissoring is used to bound the range of the clip mask.
262 */
263class GrClipMaskManager : public GrNoncopyable {
264public:
265    GR_DECLARE_RESOURCE_CACHE_DOMAIN(GetAlphaMaskDomain)
266
267    GrClipMaskManager()
268        : fGpu(NULL)
269        , fCurrClipMaskType(kNone_ClipMaskType) {
270    }
271
272    /**
273     * Creates a clip mask if necessary as a stencil buffer or alpha texture
274     * and sets the GrGpu's scissor and stencil state. If the return is false
275     * then the draw can be skipped.
276     */
277    bool setupClipping(const GrClipData* clipDataIn);
278
279    void releaseResources();
280
281    bool isClipInStencil() const {
282        return kStencil_ClipMaskType == fCurrClipMaskType;
283    }
284    bool isClipInAlpha() const {
285        return kAlpha_ClipMaskType == fCurrClipMaskType;
286    }
287
288    void invalidateStencilMask() {
289        if (kStencil_ClipMaskType == fCurrClipMaskType) {
290            fCurrClipMaskType = kNone_ClipMaskType;
291        }
292    }
293
294    void setContext(GrContext* context) {
295        fAACache.setContext(context);
296    }
297
298    GrContext* getContext() {
299        return fAACache.getContext();
300    }
301
302    void setGpu(GrGpu* gpu) {
303        fGpu = gpu;
304    }
305
306private:
307    /**
308     * Informs the helper function adjustStencilParams() about how the stencil
309     * buffer clip is being used.
310     */
311    enum StencilClipMode {
312        // Draw to the clip bit of the stencil buffer
313        kModifyClip_StencilClipMode,
314        // Clip against the existing representation of the clip in the high bit
315        // of the stencil buffer.
316        kRespectClip_StencilClipMode,
317        // Neither writing to nor clipping against the clip bit.
318        kIgnoreClip_StencilClipMode,
319    };
320
321    GrGpu* fGpu;
322
323    /**
324     * We may represent the clip as a mask in the stencil buffer or as an alpha
325     * texture. It may be neither because the scissor rect suffices or we
326     * haven't yet examined the clip.
327     */
328    enum ClipMaskType {
329        kNone_ClipMaskType,
330        kStencil_ClipMaskType,
331        kAlpha_ClipMaskType,
332    } fCurrClipMaskType;
333
334    GrClipMaskCache fAACache;       // cache for the AA path
335
336    bool createStencilClipMask(const GrClipData& clipDataIn,
337                               const GrIRect& devClipBounds);
338    bool createAlphaClipMask(const GrClipData& clipDataIn,
339                             GrTexture** result,
340                             GrIRect *devResultBounds);
341    bool createSoftwareClipMask(const GrClipData& clipDataIn,
342                                GrTexture** result,
343                                GrIRect *devResultBounds);
344    bool clipMaskPreamble(const GrClipData& clipDataIn,
345                          GrTexture** result,
346                          GrIRect *devResultBounds);
347
348    bool useSWOnlyPath(const SkClipStack& clipIn);
349
350    bool drawClipShape(GrTexture* target,
351                       const SkClipStack::Iter::Clip* clip,
352                       const GrIRect& resultBounds);
353
354    void drawTexture(GrTexture* target,
355                     GrTexture* texture);
356
357    void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
358
359    void setupCache(const SkClipStack& clip,
360                    const GrIRect& bounds);
361
362    /**
363     * Called prior to return control back the GrGpu in setupClipping. It
364     * updates the GrGpu with stencil settings that account stencil-based
365     * clipping.
366     */
367    void setGpuStencil();
368
369    /**
370     * Adjusts the stencil settings to account for interaction with stencil
371     * clipping.
372     */
373    void adjustStencilParams(GrStencilSettings* settings,
374                             StencilClipMode mode,
375                             int stencilBitCnt);
376
377    typedef GrNoncopyable INHERITED;
378};
379
380#endif // GrClipMaskManager_DEFINED
381