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