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 GrClipMaskCache_DEFINED
9#define GrClipMaskCache_DEFINED
10
11#include "GrContext.h"
12#include "GrNoncopyable.h"
13#include "SkClipStack.h"
14
15class GrTexture;
16
17/**
18 * The stencil buffer stores the last clip path - providing a single entry
19 * "cache". This class provides similar functionality for AA clip paths
20 */
21class GrClipMaskCache : public GrNoncopyable {
22public:
23    GrClipMaskCache();
24
25    ~GrClipMaskCache() {
26
27        while (!fStack.empty()) {
28            GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
29            temp->~GrClipStackFrame();
30            fStack.pop_back();
31        }
32    }
33
34    bool canReuse(int32_t clipGenID, const SkIRect& bounds) {
35
36        SkASSERT(clipGenID != SkClipStack::kWideOpenGenID);
37        SkASSERT(clipGenID != SkClipStack::kEmptyGenID);
38
39        if (SkClipStack::kInvalidGenID == clipGenID) {
40            return false;
41        }
42
43        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
44
45        // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
46        // an offset to the caller.
47        if (back->fLastMask.texture() &&
48            back->fLastBound == bounds &&
49            back->fLastClipGenID == clipGenID) {
50            return true;
51        }
52
53        return false;
54    }
55
56    void reset() {
57        if (fStack.empty()) {
58//            GrAssert(false);
59            return;
60        }
61
62        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
63
64        back->reset();
65    }
66
67    /**
68     * After a "push" the clip state is entirely open. Currently, the
69     * entire clip stack will be re-rendered into a new clip mask.
70     * TODO: can we take advantage of the nested nature of the clips to
71     * reduce the mask creation cost?
72     */
73    void push();
74
75    void pop() {
76        //GrAssert(!fStack.empty());
77
78        if (!fStack.empty()) {
79            GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
80
81            back->~GrClipStackFrame();
82            fStack.pop_back();
83        }
84    }
85
86    int32_t getLastClipGenID() const {
87
88        if (fStack.empty()) {
89            return SkClipStack::kInvalidGenID;
90        }
91
92        return ((GrClipStackFrame*) fStack.back())->fLastClipGenID;
93    }
94
95    GrTexture* getLastMask() {
96
97        if (fStack.empty()) {
98            GrAssert(false);
99            return NULL;
100        }
101
102        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
103
104        return back->fLastMask.texture();
105    }
106
107    const GrTexture* getLastMask() const {
108
109        if (fStack.empty()) {
110            GrAssert(false);
111            return NULL;
112        }
113
114        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
115
116        return back->fLastMask.texture();
117    }
118
119    void acquireMask(int32_t clipGenID,
120                     const GrTextureDesc& desc,
121                     const SkIRect& bound) {
122
123        if (fStack.empty()) {
124            GrAssert(false);
125            return;
126        }
127
128        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
129
130        back->acquireMask(fContext, clipGenID, desc, bound);
131    }
132
133    int getLastMaskWidth() const {
134
135        if (fStack.empty()) {
136            GrAssert(false);
137            return -1;
138        }
139
140        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
141
142        if (NULL == back->fLastMask.texture()) {
143            return -1;
144        }
145
146        return back->fLastMask.texture()->width();
147    }
148
149    int getLastMaskHeight() const {
150
151        if (fStack.empty()) {
152            GrAssert(false);
153            return -1;
154        }
155
156        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
157
158        if (NULL == back->fLastMask.texture()) {
159            return -1;
160        }
161
162        return back->fLastMask.texture()->height();
163    }
164
165    void getLastBound(SkIRect* bound) const {
166
167        if (fStack.empty()) {
168            GrAssert(false);
169            bound->setEmpty();
170            return;
171        }
172
173        GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
174
175        *bound = back->fLastBound;
176    }
177
178    void setContext(GrContext* context) {
179        fContext = context;
180    }
181
182    GrContext* getContext() {
183        return fContext;
184    }
185
186    void releaseResources() {
187
188        SkDeque::F2BIter iter(fStack);
189        for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
190                frame != NULL;
191                frame = (GrClipStackFrame*) iter.next()) {
192            frame->reset();
193        }
194    }
195
196private:
197    struct GrClipStackFrame {
198
199        GrClipStackFrame() {
200            this->reset();
201        }
202
203        void acquireMask(GrContext* context,
204                         int32_t clipGenID,
205                         const GrTextureDesc& desc,
206                         const SkIRect& bound) {
207
208            fLastClipGenID = clipGenID;
209
210            fLastMask.set(context, desc);
211
212            fLastBound = bound;
213        }
214
215        void reset () {
216            fLastClipGenID = SkClipStack::kInvalidGenID;
217
218            GrTextureDesc desc;
219
220            fLastMask.set(NULL, desc);
221            fLastBound.setEmpty();
222        }
223
224        int32_t                 fLastClipGenID;
225        // The mask's width & height values are used by GrClipMaskManager to correctly scale the
226        // texture coords for the geometry drawn with this mask.
227        GrAutoScratchTexture    fLastMask;
228        // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is
229        // used by GrClipMaskManager to position a rect and compute texture coords for the mask.
230        SkIRect                 fLastBound;
231    };
232
233    GrContext*   fContext;
234    SkDeque      fStack;
235
236    typedef GrNoncopyable INHERITED;
237};
238
239#endif // GrClipMaskCache_DEFINED
240