blob: d22838e6e79e32e92e3b024ed8b79d4b2ddd80b0 [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
robertphillips@google.com641f8b12012-07-31 19:15:58 +000019#include "SkClipStack.h"
bsalomon@google.com411dad02012-06-05 20:24:20 +000020#include "SkDeque.h"
21#include "SkPath.h"
22#include "SkRefCnt.h"
robertphillips@google.com1e945b72012-04-16 18:03:03 +000023
24class GrGpu;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000025class GrPathRenderer;
26class GrPathRendererChain;
27class SkPath;
robertphillips@google.comf294b772012-04-27 14:29:26 +000028class GrTexture;
29class GrDrawState;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000030
31/**
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000032 * The stencil buffer stores the last clip path - providing a single entry
33 * "cache". This class provides similar functionality for AA clip paths
34 */
35class GrClipMaskCache : public GrNoncopyable {
36public:
robertphillips@google.comf8d904a2012-07-31 12:18:16 +000037 GrClipMaskCache();
robertphillips@google.com6d62df42012-05-07 18:07:36 +000038
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000039 ~GrClipMaskCache() {
40
41 while (!fStack.empty()) {
42 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
43 temp->~GrClipStackFrame();
44 fStack.pop_back();
45 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000046 }
47
robertphillips@google.com641f8b12012-07-31 19:15:58 +000048 bool canReuse(const SkClipStack& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000049
50 if (fStack.empty()) {
51 GrAssert(false);
52 return false;
53 }
54
55 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
56
robertphillips@google.comf105b102012-05-14 12:18:26 +000057 if (back->fLastMask.texture() &&
58 back->fLastMask.texture()->width() >= width &&
59 back->fLastMask.texture()->height() >= height &&
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000060 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000061 return true;
62 }
63
64 return false;
65 }
66
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000067 void reset() {
68 if (fStack.empty()) {
robertphillips@google.com87baf892012-05-23 12:02:21 +000069// GrAssert(false);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000070 return;
71 }
72
73 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
74
75 back->reset();
76 }
77
78 /**
79 * After a "push" the clip state is entirely open. Currently, the
80 * entire clip stack will be re-rendered into a new clip mask.
81 * TODO: can we take advantage of the nested nature of the clips to
82 * reduce the mask creation cost?
83 */
robertphillips@google.comf8d904a2012-07-31 12:18:16 +000084 void push();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000085
86 void pop() {
robertphillips@google.com87baf892012-05-23 12:02:21 +000087 //GrAssert(!fStack.empty());
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000088
89 if (!fStack.empty()) {
90 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
91
92 back->~GrClipStackFrame();
93 fStack.pop_back();
94 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000095 }
96
robertphillips@google.com641f8b12012-07-31 19:15:58 +000097 void getLastClip(SkClipStack* clip) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000098
99 if (fStack.empty()) {
100 GrAssert(false);
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000101 clip->reset();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000102 return;
103 }
104
105 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
106
107 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000108 }
109
110 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000111
112 if (fStack.empty()) {
113 GrAssert(false);
114 return NULL;
115 }
116
117 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
118
robertphillips@google.comf105b102012-05-14 12:18:26 +0000119 return back->fLastMask.texture();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000120 }
121
122 const GrTexture* getLastMask() const {
123
124 if (fStack.empty()) {
125 GrAssert(false);
126 return NULL;
127 }
128
129 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
130
robertphillips@google.comf105b102012-05-14 12:18:26 +0000131 return back->fLastMask.texture();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000132 }
133
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000134 void acquireMask(const SkClipStack& clip,
robertphillips@google.comf105b102012-05-14 12:18:26 +0000135 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000136 const GrIRect& bound) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000137
138 if (fStack.empty()) {
139 GrAssert(false);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000140 return;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000141 }
142
143 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
144
robertphillips@google.comf105b102012-05-14 12:18:26 +0000145 back->acquireMask(fContext, clip, desc, bound);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000146 }
147
148 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000149
150 if (fStack.empty()) {
151 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000152 return -1;
153 }
154
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000155 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
156
robertphillips@google.comf105b102012-05-14 12:18:26 +0000157 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000158 return -1;
159 }
160
robertphillips@google.comf105b102012-05-14 12:18:26 +0000161 return back->fLastMask.texture()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000162 }
163
164 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000165
166 if (fStack.empty()) {
167 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000168 return -1;
169 }
170
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000171 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
172
robertphillips@google.comf105b102012-05-14 12:18:26 +0000173 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000174 return -1;
175 }
176
robertphillips@google.comf105b102012-05-14 12:18:26 +0000177 return back->fLastMask.texture()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000178 }
179
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000180 void getLastBound(GrIRect* bound) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000181
182 if (fStack.empty()) {
183 GrAssert(false);
184 bound->setEmpty();
185 return;
186 }
187
188 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
189
190 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000191 }
192
robertphillips@google.comf105b102012-05-14 12:18:26 +0000193 void setContext(GrContext* context) {
194 fContext = context;
195 }
196
197 GrContext* getContext() {
198 return fContext;
199 }
200
201 void releaseResources() {
202
203 SkDeque::F2BIter iter(fStack);
204 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
205 frame != NULL;
206 frame = (GrClipStackFrame*) iter.next()) {
207 frame->reset();
208 }
209 }
210
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000211protected:
212private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000213 struct GrClipStackFrame {
214
215 GrClipStackFrame() {
216 reset();
217 }
218
robertphillips@google.comf105b102012-05-14 12:18:26 +0000219 void acquireMask(GrContext* context,
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000220 const SkClipStack& clip,
robertphillips@google.comf105b102012-05-14 12:18:26 +0000221 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000222 const GrIRect& bound) {
robertphillips@google.comf105b102012-05-14 12:18:26 +0000223
224 fLastClip = clip;
225
226 fLastMask.set(context, desc);
227
228 fLastBound = bound;
229 }
230
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000231 void reset () {
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000232 fLastClip.reset();
robertphillips@google.comf105b102012-05-14 12:18:26 +0000233
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000234 GrTextureDesc desc;
robertphillips@google.comf105b102012-05-14 12:18:26 +0000235
236 fLastMask.set(NULL, desc);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000237 fLastBound.setEmpty();
238 }
239
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000240 SkClipStack fLastClip;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000241 // The mask's width & height values are used in setupDrawStateAAClip to
242 // correctly scale the uvs for geometry drawn with this mask
robertphillips@google.comf105b102012-05-14 12:18:26 +0000243 GrAutoScratchTexture fLastMask;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000244 // fLastBound stores the bounding box of the clip mask in canvas
245 // space. The left and top fields are used to offset the uvs for
246 // geometry drawn with this mask (in setupDrawStateAAClip)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000247 GrIRect fLastBound;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000248 };
249
robertphillips@google.comf105b102012-05-14 12:18:26 +0000250 GrContext* fContext;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000251 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000252
253 typedef GrNoncopyable INHERITED;
254};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000255
256/**
257 * The clip mask creator handles the generation of the clip mask. If anti
258 * aliasing is requested it will (in the future) generate a single channel
259 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
260 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
261 * mask can be represented as a rectangle then scissoring is used. In all
262 * cases scissoring is used to bound the range of the clip mask.
263 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000264class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000265public:
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000266 GrClipMaskManager(GrGpu* gpu)
267 : fGpu(gpu)
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000268 , fCurrClipMaskType(kNone_ClipMaskType) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000269 }
270
bsalomon@google.coma3201942012-06-21 19:58:20 +0000271 /**
272 * Creates a clip mask if necessary as a stencil buffer or alpha texture
273 * and sets the GrGpu's scissor and stencil state. If the return is false
274 * then the draw can be skipped.
275 */
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000276 bool setupClipping(const GrClipData* clipDataIn);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000277
robertphillips@google.comf105b102012-05-14 12:18:26 +0000278 void releaseResources();
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000279
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000280 bool isClipInStencil() const {
281 return kStencil_ClipMaskType == fCurrClipMaskType;
282 }
283 bool isClipInAlpha() const {
284 return kAlpha_ClipMaskType == fCurrClipMaskType;
285 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000286
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000287 void invalidateStencilMask() {
288 if (kStencil_ClipMaskType == fCurrClipMaskType) {
289 fCurrClipMaskType = kNone_ClipMaskType;
290 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000291 }
292
robertphillips@google.comf105b102012-05-14 12:18:26 +0000293 void setContext(GrContext* context) {
294 fAACache.setContext(context);
295 }
296
robertphillips@google.com2c756812012-05-22 20:28:23 +0000297 GrContext* getContext() {
298 return fAACache.getContext();
299 }
300
bsalomon@google.coma3201942012-06-21 19:58:20 +0000301private:
bsalomon@google.com411dad02012-06-05 20:24:20 +0000302 /**
303 * Informs the helper function adjustStencilParams() about how the stencil
304 * buffer clip is being used.
305 */
306 enum StencilClipMode {
307 // Draw to the clip bit of the stencil buffer
308 kModifyClip_StencilClipMode,
309 // Clip against the existing representation of the clip in the high bit
310 // of the stencil buffer.
311 kRespectClip_StencilClipMode,
312 // Neither writing to nor clipping against the clip bit.
313 kIgnoreClip_StencilClipMode,
314 };
315
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000316 GrGpu* fGpu;
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000317
318 /**
319 * We may represent the clip as a mask in the stencil buffer or as an alpha
320 * texture. It may be neither because the scissor rect suffices or we
321 * haven't yet examined the clip.
322 */
323 enum ClipMaskType {
324 kNone_ClipMaskType,
325 kStencil_ClipMaskType,
326 kAlpha_ClipMaskType,
327 } fCurrClipMaskType;
328
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000329 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000330
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000331 bool createStencilClipMask(const GrClipData& clipDataIn,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000332 const GrIRect& devClipBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000333 bool createAlphaClipMask(const GrClipData& clipDataIn,
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000334 GrTexture** result,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000335 GrIRect *devResultBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000336 bool createSoftwareClipMask(const GrClipData& clipDataIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000337 GrTexture** result,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000338 GrIRect *devResultBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000339 bool clipMaskPreamble(const GrClipData& clipDataIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000340 GrTexture** result,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000341 GrIRect *devResultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000342
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000343 bool useSWOnlyPath(const SkClipStack& clipIn);
robertphillips@google.comfa662942012-05-17 12:20:22 +0000344
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000345 bool drawClipShape(GrTexture* target,
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000346 const SkClipStack::Iter::Clip* clip,
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000347 const GrIRect& resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000348
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000349 void drawTexture(GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000350 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000351
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000352 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000353
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000354 void setupCache(const SkClipStack& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000355 const GrIRect& bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000356
bsalomon@google.coma3201942012-06-21 19:58:20 +0000357 /**
358 * Called prior to return control back the GrGpu in setupClipping. It
359 * updates the GrGpu with stencil settings that account stencil-based
360 * clipping.
361 */
362 void setGpuStencil();
363
364 /**
365 * Adjusts the stencil settings to account for interaction with stencil
366 * clipping.
367 */
368 void adjustStencilParams(GrStencilSettings* settings,
369 StencilClipMode mode,
370 int stencilBitCnt);
371
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000372 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000373};
374
375#endif // GrClipMaskManager_DEFINED