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