blob: 9a091c4b3a408a80bbb5d58e69fce7e9d47b64bf [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
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000034 bool canReuse(int32_t clipGenID, const SkIRect& bounds) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000035
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000036 SkASSERT(clipGenID != SkClipStack::kWideOpenGenID);
37 SkASSERT(clipGenID != SkClipStack::kEmptyGenID);
38
39 if (SkClipStack::kInvalidGenID == clipGenID) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000040 return false;
41 }
42
43 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
44
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000045 // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
46 // an offset to the caller.
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000047 if (back->fLastMask.texture() &&
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000048 back->fLastBound == bounds &&
49 back->fLastClipGenID == clipGenID) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000050 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
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000086 int32_t getLastClipGenID() const {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000087
88 if (fStack.empty()) {
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000089 return SkClipStack::kInvalidGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000090 }
91
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000092 return ((GrClipStackFrame*) fStack.back())->fLastClipGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000093 }
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
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000119 void acquireMask(int32_t clipGenID,
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000120 const GrTextureDesc& desc,
121 const GrIRect& bound) {
122
123 if (fStack.empty()) {
124 GrAssert(false);
125 return;
126 }
127
128 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
129
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000130 back->acquireMask(fContext, clipGenID, desc, bound);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000131 }
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(GrIRect* 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
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000196private:
197 struct GrClipStackFrame {
198
199 GrClipStackFrame() {
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000200 this->reset();
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000201 }
202
203 void acquireMask(GrContext* context,
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000204 int32_t clipGenID,
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000205 const GrTextureDesc& desc,
206 const GrIRect& bound) {
207
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000208 fLastClipGenID = clipGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000209
210 fLastMask.set(context, desc);
211
212 fLastBound = bound;
213 }
214
215 void reset () {
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000216 fLastClipGenID = SkClipStack::kInvalidGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000217
218 GrTextureDesc desc;
219
220 fLastMask.set(NULL, desc);
221 fLastBound.setEmpty();
222 }
223
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000224 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.
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000227 GrAutoScratchTexture fLastMask;
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000228 // 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.
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000230 GrIRect fLastBound;
231 };
232
233 GrContext* fContext;
234 SkDeque fStack;
235
236 typedef GrNoncopyable INHERITED;
237};
238
239#endif // GrClipMaskCache_DEFINED