blob: 02fc875f833507852615ebeb971fe4de4b5e57ed [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
12#include "GrRect.h"
bsalomon@google.com8d033a12012-04-27 15:52:53 +000013#include "SkPath.h"
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000014#include "GrNoncopyable.h"
15#include "GrClip.h"
16#include "SkRefCnt.h"
robertphillips@google.com6d62df42012-05-07 18:07:36 +000017#include "GrTexture.h"
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000018#include "SkDeque.h"
robertphillips@google.comf105b102012-05-14 12:18:26 +000019#include "GrContext.h"
robertphillips@google.com1e945b72012-04-16 18:03:03 +000020
21class GrGpu;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000022class GrPathRenderer;
23class GrPathRendererChain;
24class SkPath;
robertphillips@google.comf294b772012-04-27 14:29:26 +000025class GrTexture;
26class GrDrawState;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000027
28/**
29 * Scissoring needs special handling during stencil clip mask creation
30 * since the creation process re-entrantly invokes setupClipAndFlushState.
31 * During this process the call stack is used to keep
32 * track of (and apply to the GPU) the current scissor settings.
33 */
34struct ScissoringSettings {
35 bool fEnableScissoring;
36 GrIRect fScissorRect;
37
38 void setupScissoring(GrGpu* gpu);
39};
40
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000041/**
42 * The stencil buffer stores the last clip path - providing a single entry
43 * "cache". This class provides similar functionality for AA clip paths
44 */
45class GrClipMaskCache : public GrNoncopyable {
46public:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000047 GrClipMaskCache()
robertphillips@google.comf105b102012-05-14 12:18:26 +000048 : fContext(NULL)
49 , fStack(sizeof(GrClipStackFrame)) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000050 // We need an initial frame to capture the clip state prior to
51 // any pushes
52 new (fStack.push_back()) GrClipStackFrame();
robertphillips@google.com6d62df42012-05-07 18:07:36 +000053 }
54
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000055 ~GrClipMaskCache() {
56
57 while (!fStack.empty()) {
58 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
59 temp->~GrClipStackFrame();
60 fStack.pop_back();
61 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000062 }
63
64 bool canReuse(const GrClip& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000065
66 if (fStack.empty()) {
67 GrAssert(false);
68 return false;
69 }
70
71 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
72
robertphillips@google.comf105b102012-05-14 12:18:26 +000073 if (back->fLastMask.texture() &&
74 back->fLastMask.texture()->width() >= width &&
75 back->fLastMask.texture()->height() >= height &&
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000076 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000077 return true;
78 }
79
80 return false;
81 }
82
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000083 void reset() {
84 if (fStack.empty()) {
85 GrAssert(false);
86 return;
87 }
88
89 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
90
91 back->reset();
92 }
93
94 /**
95 * After a "push" the clip state is entirely open. Currently, the
96 * entire clip stack will be re-rendered into a new clip mask.
97 * TODO: can we take advantage of the nested nature of the clips to
98 * reduce the mask creation cost?
99 */
100 void push() {
101 new (fStack.push_back()) GrClipStackFrame();
102 }
103
104 void pop() {
105 GrAssert(!fStack.empty());
106
107 if (!fStack.empty()) {
108 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
109
110 back->~GrClipStackFrame();
111 fStack.pop_back();
112 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000113 }
114
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000115 void getLastClip(GrClip* clip) const {
116
117 if (fStack.empty()) {
118 GrAssert(false);
119 clip->setEmpty();
120 return;
121 }
122
123 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
124
125 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000126 }
127
128 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000129
130 if (fStack.empty()) {
131 GrAssert(false);
132 return NULL;
133 }
134
135 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
136
robertphillips@google.comf105b102012-05-14 12:18:26 +0000137 return back->fLastMask.texture();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000138 }
139
140 const GrTexture* getLastMask() const {
141
142 if (fStack.empty()) {
143 GrAssert(false);
144 return NULL;
145 }
146
147 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
148
robertphillips@google.comf105b102012-05-14 12:18:26 +0000149 return back->fLastMask.texture();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000150 }
151
robertphillips@google.comf105b102012-05-14 12:18:26 +0000152 void acquireMask(const GrClip& clip,
153 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000154 const GrIRect& bound) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000155
156 if (fStack.empty()) {
157 GrAssert(false);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000158 return;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000159 }
160
161 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
162
robertphillips@google.comf105b102012-05-14 12:18:26 +0000163 back->acquireMask(fContext, clip, desc, bound);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000164 }
165
166 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000167
168 if (fStack.empty()) {
169 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000170 return -1;
171 }
172
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000173 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
174
robertphillips@google.comf105b102012-05-14 12:18:26 +0000175 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000176 return -1;
177 }
178
robertphillips@google.comf105b102012-05-14 12:18:26 +0000179 return back->fLastMask.texture()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000180 }
181
182 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000183
184 if (fStack.empty()) {
185 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000186 return -1;
187 }
188
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000189 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
190
robertphillips@google.comf105b102012-05-14 12:18:26 +0000191 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000192 return -1;
193 }
194
robertphillips@google.comf105b102012-05-14 12:18:26 +0000195 return back->fLastMask.texture()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000196 }
197
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000198 void getLastBound(GrIRect* bound) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000199
200 if (fStack.empty()) {
201 GrAssert(false);
202 bound->setEmpty();
203 return;
204 }
205
206 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
207
208 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000209 }
210
robertphillips@google.comf105b102012-05-14 12:18:26 +0000211 void setContext(GrContext* context) {
212 fContext = context;
213 }
214
215 GrContext* getContext() {
216 return fContext;
217 }
218
219 void releaseResources() {
220
221 SkDeque::F2BIter iter(fStack);
222 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
223 frame != NULL;
224 frame = (GrClipStackFrame*) iter.next()) {
225 frame->reset();
226 }
227 }
228
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000229protected:
230private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000231 struct GrClipStackFrame {
232
233 GrClipStackFrame() {
234 reset();
235 }
236
robertphillips@google.comf105b102012-05-14 12:18:26 +0000237 void acquireMask(GrContext* context,
238 const GrClip& clip,
239 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000240 const GrIRect& bound) {
robertphillips@google.comf105b102012-05-14 12:18:26 +0000241
242 fLastClip = clip;
243
244 fLastMask.set(context, desc);
245
246 fLastBound = bound;
247 }
248
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000249 void reset () {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000250 fLastClip.setEmpty();
robertphillips@google.comf105b102012-05-14 12:18:26 +0000251
252 const GrTextureDesc desc = { kNone_GrTextureFlags, 0, 0,
253 kUnknown_GrPixelConfig, 0 };
254
255 fLastMask.set(NULL, desc);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000256 fLastBound.setEmpty();
257 }
258
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000259 GrClip fLastClip;
260 // The mask's width & height values are used in setupDrawStateAAClip to
261 // correctly scale the uvs for geometry drawn with this mask
robertphillips@google.comf105b102012-05-14 12:18:26 +0000262 GrAutoScratchTexture fLastMask;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000263 // fLastBound stores the bounding box of the clip mask in canvas
264 // space. The left and top fields are used to offset the uvs for
265 // geometry drawn with this mask (in setupDrawStateAAClip)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000266 GrIRect fLastBound;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000267 };
268
robertphillips@google.comf105b102012-05-14 12:18:26 +0000269 GrContext* fContext;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000270 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000271
272 typedef GrNoncopyable INHERITED;
273};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000274
275/**
276 * The clip mask creator handles the generation of the clip mask. If anti
277 * aliasing is requested it will (in the future) generate a single channel
278 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
279 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
280 * mask can be represented as a rectangle then scissoring is used. In all
281 * cases scissoring is used to bound the range of the clip mask.
282 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000283class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000284public:
285 GrClipMaskManager()
286 : fClipMaskInStencil(false)
robertphillips@google.comf294b772012-04-27 14:29:26 +0000287 , fClipMaskInAlpha(false)
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000288 , fPathRendererChain(NULL) {
289 }
290
291 bool createClipMask(GrGpu* gpu,
292 const GrClip& clip,
293 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.comf105b102012-05-14 12:18:26 +0000304 void setContext(GrContext* context) {
305 fAACache.setContext(context);
306 }
307
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000308protected:
309private:
310 bool fClipMaskInStencil; // is the clip mask in the stencil buffer?
robertphillips@google.comf294b772012-04-27 14:29:26 +0000311 bool fClipMaskInAlpha; // is the clip mask in an alpha texture?
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000312 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000313
314 // must be instantiated after GrGpu object has been given its owning
315 // GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
316 GrPathRendererChain* fPathRendererChain;
317
318 bool createStencilClipMask(GrGpu* gpu,
319 const GrClip& clip,
320 const GrRect& bounds,
321 ScissoringSettings* scissorSettings);
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000322 bool createAlphaClipMask(GrGpu* gpu,
323 const GrClip& clipIn,
324 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000325 GrIRect *resultBounds);
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000326 bool createSoftwareClipMask(GrGpu* gpu,
327 const GrClip& clipIn,
328 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000329 GrIRect *resultBounds);
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000330 bool clipMaskPreamble(GrGpu* gpu,
331 const GrClip& clipIn,
332 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000333 GrIRect *resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000334
335 bool drawPath(GrGpu* gpu,
bsalomon@google.com8d033a12012-04-27 15:52:53 +0000336 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000337 GrPathFill fill,
338 bool doAA);
339
340 bool drawClipShape(GrGpu* gpu,
341 GrTexture* target,
342 const GrClip& clipIn,
343 int index);
344
345 void drawTexture(GrGpu* gpu,
346 GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000347 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000348
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000349 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000350
351 void setupCache(const GrClip& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000352 const GrIRect& bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000353
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000354 // determines the path renderer used to draw a clip path element.
355 GrPathRenderer* getClipPathRenderer(GrGpu* gpu,
356 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000357 GrPathFill fill,
358 bool antiAlias);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000359
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000360 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000361};
362
363#endif // GrClipMaskManager_DEFINED