blob: 2e46c083b6760b73a428036af6b273a0d7a691e0 [file] [log] [blame]
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001
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
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000012#include "GrClip.h"
robertphillips@google.comf105b102012-05-14 12:18:26 +000013#include "GrContext.h"
bsalomon@google.com411dad02012-06-05 20:24:20 +000014#include "GrNoncopyable.h"
15#include "GrRect.h"
16#include "GrStencil.h"
17#include "GrTexture.h"
18
19#include "SkDeque.h"
20#include "SkPath.h"
21#include "SkRefCnt.h"
robertphillips@google.com1e945b72012-04-16 18:03:03 +000022
23class GrGpu;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000024class GrPathRenderer;
25class GrPathRendererChain;
26class SkPath;
robertphillips@google.comf294b772012-04-27 14:29:26 +000027class GrTexture;
28class GrDrawState;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000029
30/**
31 * Scissoring needs special handling during stencil clip mask creation
32 * since the creation process re-entrantly invokes setupClipAndFlushState.
33 * During this process the call stack is used to keep
34 * track of (and apply to the GPU) the current scissor settings.
35 */
36struct ScissoringSettings {
37 bool fEnableScissoring;
38 GrIRect fScissorRect;
39
40 void setupScissoring(GrGpu* gpu);
41};
42
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000043/**
44 * The stencil buffer stores the last clip path - providing a single entry
45 * "cache". This class provides similar functionality for AA clip paths
46 */
47class GrClipMaskCache : public GrNoncopyable {
48public:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000049 GrClipMaskCache()
robertphillips@google.comf105b102012-05-14 12:18:26 +000050 : fContext(NULL)
51 , fStack(sizeof(GrClipStackFrame)) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000052 // We need an initial frame to capture the clip state prior to
53 // any pushes
54 new (fStack.push_back()) GrClipStackFrame();
robertphillips@google.com6d62df42012-05-07 18:07:36 +000055 }
56
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000057 ~GrClipMaskCache() {
58
59 while (!fStack.empty()) {
60 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
61 temp->~GrClipStackFrame();
62 fStack.pop_back();
63 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000064 }
65
66 bool canReuse(const GrClip& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000067
68 if (fStack.empty()) {
69 GrAssert(false);
70 return false;
71 }
72
73 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
74
robertphillips@google.comf105b102012-05-14 12:18:26 +000075 if (back->fLastMask.texture() &&
76 back->fLastMask.texture()->width() >= width &&
77 back->fLastMask.texture()->height() >= height &&
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000078 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000079 return true;
80 }
81
82 return false;
83 }
84
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000085 void reset() {
86 if (fStack.empty()) {
robertphillips@google.com87baf892012-05-23 12:02:21 +000087// GrAssert(false);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000088 return;
89 }
90
91 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
92
93 back->reset();
94 }
95
96 /**
97 * After a "push" the clip state is entirely open. Currently, the
98 * entire clip stack will be re-rendered into a new clip mask.
99 * TODO: can we take advantage of the nested nature of the clips to
100 * reduce the mask creation cost?
101 */
102 void push() {
103 new (fStack.push_back()) GrClipStackFrame();
104 }
105
106 void pop() {
robertphillips@google.com87baf892012-05-23 12:02:21 +0000107 //GrAssert(!fStack.empty());
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000108
109 if (!fStack.empty()) {
110 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
111
112 back->~GrClipStackFrame();
113 fStack.pop_back();
114 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000115 }
116
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000117 void getLastClip(GrClip* clip) const {
118
119 if (fStack.empty()) {
120 GrAssert(false);
121 clip->setEmpty();
122 return;
123 }
124
125 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
126
127 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000128 }
129
130 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000131
132 if (fStack.empty()) {
133 GrAssert(false);
134 return NULL;
135 }
136
137 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
138
robertphillips@google.comf105b102012-05-14 12:18:26 +0000139 return back->fLastMask.texture();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000140 }
141
142 const GrTexture* getLastMask() const {
143
144 if (fStack.empty()) {
145 GrAssert(false);
146 return NULL;
147 }
148
149 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
150
robertphillips@google.comf105b102012-05-14 12:18:26 +0000151 return back->fLastMask.texture();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000152 }
153
robertphillips@google.comf105b102012-05-14 12:18:26 +0000154 void acquireMask(const GrClip& clip,
155 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000156 const GrIRect& bound) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000157
158 if (fStack.empty()) {
159 GrAssert(false);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000160 return;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000161 }
162
163 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
164
robertphillips@google.comf105b102012-05-14 12:18:26 +0000165 back->acquireMask(fContext, clip, desc, bound);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000166 }
167
168 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000169
170 if (fStack.empty()) {
171 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000172 return -1;
173 }
174
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000175 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
176
robertphillips@google.comf105b102012-05-14 12:18:26 +0000177 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000178 return -1;
179 }
180
robertphillips@google.comf105b102012-05-14 12:18:26 +0000181 return back->fLastMask.texture()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000182 }
183
184 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000185
186 if (fStack.empty()) {
187 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000188 return -1;
189 }
190
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000191 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
192
robertphillips@google.comf105b102012-05-14 12:18:26 +0000193 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000194 return -1;
195 }
196
robertphillips@google.comf105b102012-05-14 12:18:26 +0000197 return back->fLastMask.texture()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000198 }
199
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000200 void getLastBound(GrIRect* bound) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000201
202 if (fStack.empty()) {
203 GrAssert(false);
204 bound->setEmpty();
205 return;
206 }
207
208 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
209
210 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000211 }
212
robertphillips@google.comf105b102012-05-14 12:18:26 +0000213 void setContext(GrContext* context) {
214 fContext = context;
215 }
216
217 GrContext* getContext() {
218 return fContext;
219 }
220
221 void releaseResources() {
222
223 SkDeque::F2BIter iter(fStack);
224 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
225 frame != NULL;
226 frame = (GrClipStackFrame*) iter.next()) {
227 frame->reset();
228 }
229 }
230
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000231protected:
232private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000233 struct GrClipStackFrame {
234
235 GrClipStackFrame() {
236 reset();
237 }
238
robertphillips@google.comf105b102012-05-14 12:18:26 +0000239 void acquireMask(GrContext* context,
240 const GrClip& clip,
241 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000242 const GrIRect& bound) {
robertphillips@google.comf105b102012-05-14 12:18:26 +0000243
244 fLastClip = clip;
245
246 fLastMask.set(context, desc);
247
248 fLastBound = bound;
249 }
250
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000251 void reset () {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000252 fLastClip.setEmpty();
robertphillips@google.comf105b102012-05-14 12:18:26 +0000253
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000254 GrTextureDesc desc;
robertphillips@google.comf105b102012-05-14 12:18:26 +0000255
256 fLastMask.set(NULL, desc);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000257 fLastBound.setEmpty();
258 }
259
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000260 GrClip fLastClip;
261 // The mask's width & height values are used in setupDrawStateAAClip to
262 // correctly scale the uvs for geometry drawn with this mask
robertphillips@google.comf105b102012-05-14 12:18:26 +0000263 GrAutoScratchTexture fLastMask;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000264 // fLastBound stores the bounding box of the clip mask in canvas
265 // space. The left and top fields are used to offset the uvs for
266 // geometry drawn with this mask (in setupDrawStateAAClip)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000267 GrIRect fLastBound;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000268 };
269
robertphillips@google.comf105b102012-05-14 12:18:26 +0000270 GrContext* fContext;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000271 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000272
273 typedef GrNoncopyable INHERITED;
274};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000275
276/**
277 * The clip mask creator handles the generation of the clip mask. If anti
278 * aliasing is requested it will (in the future) generate a single channel
279 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
280 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
281 * mask can be represented as a rectangle then scissoring is used. In all
282 * cases scissoring is used to bound the range of the clip mask.
283 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000284class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000285public:
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000286 GrClipMaskManager(GrGpu* gpu)
287 : fGpu(gpu)
288 , fClipMaskInStencil(false)
robertphillips@google.com2c756812012-05-22 20:28:23 +0000289 , fClipMaskInAlpha(false) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000290 }
291
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000292 bool createClipMask(const GrClip& clip,
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000293 ScissoringSettings* scissorSettings);
294
robertphillips@google.comf105b102012-05-14 12:18:26 +0000295 void releaseResources();
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000296
297 bool isClipInStencil() const { return fClipMaskInStencil; }
robertphillips@google.comf294b772012-04-27 14:29:26 +0000298 bool isClipInAlpha() const { return fClipMaskInAlpha; }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000299
300 void resetMask() {
301 fClipMaskInStencil = false;
302 }
303
robertphillips@google.com49d9fd52012-05-23 11:44:08 +0000304 void postClipPush() {
305 // TODO: make sure that, if the clip stack is unaltered, the
306 // prior clip mask is reused (i.e., a push w/ no change to the
307 // clip stack)
308 fAACache.push();
309 }
310
311 void preClipPop() {
312 fAACache.pop();
313 }
314
robertphillips@google.comf105b102012-05-14 12:18:26 +0000315 void setContext(GrContext* context) {
316 fAACache.setContext(context);
317 }
318
robertphillips@google.com2c756812012-05-22 20:28:23 +0000319 GrContext* getContext() {
320 return fAACache.getContext();
321 }
322
bsalomon@google.com411dad02012-06-05 20:24:20 +0000323 /**
324 * Informs the helper function adjustStencilParams() about how the stencil
325 * buffer clip is being used.
326 */
327 enum StencilClipMode {
328 // Draw to the clip bit of the stencil buffer
329 kModifyClip_StencilClipMode,
330 // Clip against the existing representation of the clip in the high bit
331 // of the stencil buffer.
332 kRespectClip_StencilClipMode,
333 // Neither writing to nor clipping against the clip bit.
334 kIgnoreClip_StencilClipMode,
335 };
336
337 /**
338 * The stencil func, mask, and reference value are specified by GrGpu's
339 * caller but the actual values passed to the API may have to be adjusted
340 * due to the stencil buffer simultaneously being used for clipping. This
341 * function should be called even when clipping is disabled in order to
342 * prevent the clip from being accidentally overwritten.
343 */
344 GrStencilFunc adjustStencilParams(GrStencilFunc,
345 StencilClipMode mode,
346 unsigned int stencilBitCnt,
347 unsigned int* ref,
348 unsigned int* mask,
349 unsigned int* writeMask);
350
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000351private:
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000352 GrGpu* fGpu;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000353 bool fClipMaskInStencil; // is the clip mask in the stencil buffer?
robertphillips@google.comf294b772012-04-27 14:29:26 +0000354 bool fClipMaskInAlpha; // is the clip mask in an alpha texture?
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000355 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000356
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000357 bool createStencilClipMask(const GrClip& clip,
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000358 const GrRect& bounds,
359 ScissoringSettings* scissorSettings);
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000360 bool createAlphaClipMask(const GrClip& clipIn,
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000361 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000362 GrIRect *resultBounds);
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000363 bool createSoftwareClipMask(const GrClip& clipIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000364 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000365 GrIRect *resultBounds);
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000366 bool clipMaskPreamble(const GrClip& clipIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000367 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000368 GrIRect *resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000369
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000370 bool useSWOnlyPath(const GrClip& clipIn);
robertphillips@google.comfa662942012-05-17 12:20:22 +0000371
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000372 bool drawClipShape(GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000373 const GrClip& clipIn,
374 int index);
375
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000376 void drawTexture(GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000377 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000378
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000379 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000380
381 void setupCache(const GrClip& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000382 const GrIRect& bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000383
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000384 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000385};
386
387#endif // GrClipMaskManager_DEFINED