blob: 1ceee16becf4aa54fa33234b80e42d57ece1e918 [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)
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000288 , fCurrClipMaskType(kNone_ClipMaskType) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000289 }
290
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000291 bool createClipMask(const GrClip& clip,
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000292 ScissoringSettings* scissorSettings);
293
robertphillips@google.comf105b102012-05-14 12:18:26 +0000294 void releaseResources();
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000295
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000296 bool isClipInStencil() const {
297 return kStencil_ClipMaskType == fCurrClipMaskType;
298 }
299 bool isClipInAlpha() const {
300 return kAlpha_ClipMaskType == fCurrClipMaskType;
301 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000302
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000303 void invalidateStencilMask() {
304 if (kStencil_ClipMaskType == fCurrClipMaskType) {
305 fCurrClipMaskType = kNone_ClipMaskType;
306 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000307 }
308
robertphillips@google.com49d9fd52012-05-23 11:44:08 +0000309 void postClipPush() {
310 // TODO: make sure that, if the clip stack is unaltered, the
311 // prior clip mask is reused (i.e., a push w/ no change to the
312 // clip stack)
313 fAACache.push();
314 }
315
316 void preClipPop() {
317 fAACache.pop();
318 }
319
robertphillips@google.comf105b102012-05-14 12:18:26 +0000320 void setContext(GrContext* context) {
321 fAACache.setContext(context);
322 }
323
robertphillips@google.com2c756812012-05-22 20:28:23 +0000324 GrContext* getContext() {
325 return fAACache.getContext();
326 }
327
bsalomon@google.com411dad02012-06-05 20:24:20 +0000328 /**
329 * Informs the helper function adjustStencilParams() about how the stencil
330 * buffer clip is being used.
331 */
332 enum StencilClipMode {
333 // Draw to the clip bit of the stencil buffer
334 kModifyClip_StencilClipMode,
335 // Clip against the existing representation of the clip in the high bit
336 // of the stencil buffer.
337 kRespectClip_StencilClipMode,
338 // Neither writing to nor clipping against the clip bit.
339 kIgnoreClip_StencilClipMode,
340 };
341
342 /**
343 * The stencil func, mask, and reference value are specified by GrGpu's
344 * caller but the actual values passed to the API may have to be adjusted
345 * due to the stencil buffer simultaneously being used for clipping. This
346 * function should be called even when clipping is disabled in order to
347 * prevent the clip from being accidentally overwritten.
348 */
349 GrStencilFunc adjustStencilParams(GrStencilFunc,
350 StencilClipMode mode,
351 unsigned int stencilBitCnt,
352 unsigned int* ref,
353 unsigned int* mask,
354 unsigned int* writeMask);
355
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000356private:
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000357 GrGpu* fGpu;
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000358
359 /**
360 * We may represent the clip as a mask in the stencil buffer or as an alpha
361 * texture. It may be neither because the scissor rect suffices or we
362 * haven't yet examined the clip.
363 */
364 enum ClipMaskType {
365 kNone_ClipMaskType,
366 kStencil_ClipMaskType,
367 kAlpha_ClipMaskType,
368 } fCurrClipMaskType;
369
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000370 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000371
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000372 bool createStencilClipMask(const GrClip& clip,
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000373 const GrRect& bounds,
374 ScissoringSettings* scissorSettings);
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000375 bool createAlphaClipMask(const GrClip& clipIn,
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000376 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000377 GrIRect *resultBounds);
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000378 bool createSoftwareClipMask(const GrClip& clipIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000379 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000380 GrIRect *resultBounds);
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000381 bool clipMaskPreamble(const GrClip& clipIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000382 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000383 GrIRect *resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000384
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000385 bool useSWOnlyPath(const GrClip& clipIn);
robertphillips@google.comfa662942012-05-17 12:20:22 +0000386
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000387 bool drawClipShape(GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000388 const GrClip& clipIn,
389 int index);
390
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000391 void drawTexture(GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000392 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000393
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000394 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000395
396 void setupCache(const GrClip& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000397 const GrIRect& bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000398
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000399 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000400};
401
402#endif // GrClipMaskManager_DEFINED