blob: 9c72552cf19f299a11c6456da4ce1ef79b926051 [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.com1e945b72012-04-16 18:03:03 +000019
20class GrGpu;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000021class GrPathRenderer;
22class GrPathRendererChain;
23class SkPath;
robertphillips@google.comf294b772012-04-27 14:29:26 +000024class GrTexture;
25class GrDrawState;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000026
27/**
28 * Scissoring needs special handling during stencil clip mask creation
29 * since the creation process re-entrantly invokes setupClipAndFlushState.
30 * During this process the call stack is used to keep
31 * track of (and apply to the GPU) the current scissor settings.
32 */
33struct ScissoringSettings {
34 bool fEnableScissoring;
35 GrIRect fScissorRect;
36
37 void setupScissoring(GrGpu* gpu);
38};
39
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000040/**
41 * The stencil buffer stores the last clip path - providing a single entry
42 * "cache". This class provides similar functionality for AA clip paths
43 */
44class GrClipMaskCache : public GrNoncopyable {
45public:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000046 GrClipMaskCache()
47 : fStack(sizeof(GrClipStackFrame)) {
48 // We need an initial frame to capture the clip state prior to
49 // any pushes
50 new (fStack.push_back()) GrClipStackFrame();
robertphillips@google.com6d62df42012-05-07 18:07:36 +000051 }
52
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000053 ~GrClipMaskCache() {
54
55 while (!fStack.empty()) {
56 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
57 temp->~GrClipStackFrame();
58 fStack.pop_back();
59 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000060 }
61
62 bool canReuse(const GrClip& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000063
64 if (fStack.empty()) {
65 GrAssert(false);
66 return false;
67 }
68
69 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
70
robertphillips@google.com8fff3562012-05-11 12:53:50 +000071 if (back->fLastMask &&
72 back->fLastMask->width() >= width &&
73 back->fLastMask->height() >= height &&
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000074 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000075 return true;
76 }
77
78 return false;
79 }
80
robertphillips@google.com8fff3562012-05-11 12:53:50 +000081 void set(const GrClip& clip, GrTexture* mask, const GrRect& bound) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000082
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000083 if (fStack.empty()) {
84 GrAssert(false);
85 return;
86 }
87
88 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
89
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000090 back->fLastClip = clip;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000091 SkSafeRef(mask);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000092 back->fLastMask.reset(mask);
93 back->fLastBound = bound;
94 }
95
96 void reset() {
97 if (fStack.empty()) {
98 GrAssert(false);
99 return;
100 }
101
102 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
103
104 back->reset();
105 }
106
107 /**
108 * After a "push" the clip state is entirely open. Currently, the
109 * entire clip stack will be re-rendered into a new clip mask.
110 * TODO: can we take advantage of the nested nature of the clips to
111 * reduce the mask creation cost?
112 */
113 void push() {
114 new (fStack.push_back()) GrClipStackFrame();
115 }
116
117 void pop() {
118 GrAssert(!fStack.empty());
119
120 if (!fStack.empty()) {
121 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
122
123 back->~GrClipStackFrame();
124 fStack.pop_back();
125 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000126 }
127
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000128 void getLastClip(GrClip* clip) const {
129
130 if (fStack.empty()) {
131 GrAssert(false);
132 clip->setEmpty();
133 return;
134 }
135
136 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
137
138 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000139 }
140
141 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000142
143 if (fStack.empty()) {
144 GrAssert(false);
145 return NULL;
146 }
147
148 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
149
150 return back->fLastMask.get();
151 }
152
153 const GrTexture* getLastMask() const {
154
155 if (fStack.empty()) {
156 GrAssert(false);
157 return NULL;
158 }
159
160 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
161
162 return back->fLastMask.get();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000163 }
164
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000165 GrTexture* detachLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000166
167 if (fStack.empty()) {
168 GrAssert(false);
169 return NULL;
170 }
171
172 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
173
174 return back->fLastMask.detach();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000175 }
176
177 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000178
179 if (fStack.empty()) {
180 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000181 return -1;
182 }
183
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000184 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
185
186 if (NULL == back->fLastMask.get()) {
187 return -1;
188 }
189
190 return back->fLastMask.get()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000191 }
192
193 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000194
195 if (fStack.empty()) {
196 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000197 return -1;
198 }
199
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000200 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
201
202 if (NULL == back->fLastMask.get()) {
203 return -1;
204 }
205
206 return back->fLastMask.get()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000207 }
208
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000209 void getLastBound(GrRect* bound) const {
210
211 if (fStack.empty()) {
212 GrAssert(false);
213 bound->setEmpty();
214 return;
215 }
216
217 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
218
219 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000220 }
221
222protected:
223private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000224 struct GrClipStackFrame {
225
226 GrClipStackFrame() {
227 reset();
228 }
229
230 void reset () {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000231 fLastClip.setEmpty();
232 fLastMask.reset(NULL);
233 fLastBound.setEmpty();
234 }
235
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000236 GrClip fLastClip;
237 // The mask's width & height values are used in setupDrawStateAAClip to
238 // correctly scale the uvs for geometry drawn with this mask
239 SkAutoTUnref<GrTexture> fLastMask;
240 // fLastBound stores the bounding box of the clip mask in canvas
241 // space. The left and top fields are used to offset the uvs for
242 // geometry drawn with this mask (in setupDrawStateAAClip)
243 GrRect fLastBound;
244 };
245
246 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000247
248 typedef GrNoncopyable INHERITED;
249};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000250
251/**
252 * The clip mask creator handles the generation of the clip mask. If anti
253 * aliasing is requested it will (in the future) generate a single channel
254 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
255 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
256 * mask can be represented as a rectangle then scissoring is used. In all
257 * cases scissoring is used to bound the range of the clip mask.
258 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000259class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000260public:
261 GrClipMaskManager()
262 : fClipMaskInStencil(false)
robertphillips@google.comf294b772012-04-27 14:29:26 +0000263 , fClipMaskInAlpha(false)
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000264 , fPathRendererChain(NULL) {
265 }
266
267 bool createClipMask(GrGpu* gpu,
268 const GrClip& clip,
269 ScissoringSettings* scissorSettings);
270
271 void freeResources();
272
273 bool isClipInStencil() const { return fClipMaskInStencil; }
robertphillips@google.comf294b772012-04-27 14:29:26 +0000274 bool isClipInAlpha() const { return fClipMaskInAlpha; }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000275
276 void resetMask() {
277 fClipMaskInStencil = false;
278 }
279
280protected:
281private:
282 bool fClipMaskInStencil; // is the clip mask in the stencil buffer?
robertphillips@google.comf294b772012-04-27 14:29:26 +0000283 bool fClipMaskInAlpha; // is the clip mask in an alpha texture?
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000284 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000285
286 // must be instantiated after GrGpu object has been given its owning
287 // GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
288 GrPathRendererChain* fPathRendererChain;
289
290 bool createStencilClipMask(GrGpu* gpu,
291 const GrClip& clip,
292 const GrRect& bounds,
293 ScissoringSettings* scissorSettings);
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000294 bool createAlphaClipMask(GrGpu* gpu,
295 const GrClip& clipIn,
296 GrTexture** result,
297 GrRect *resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000298
299 bool drawPath(GrGpu* gpu,
bsalomon@google.com8d033a12012-04-27 15:52:53 +0000300 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000301 GrPathFill fill,
302 bool doAA);
303
304 bool drawClipShape(GrGpu* gpu,
305 GrTexture* target,
306 const GrClip& clipIn,
307 int index);
308
309 void drawTexture(GrGpu* gpu,
310 GrTexture* target,
311 const GrRect& rect,
312 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000313
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000314 void getAccum(GrGpu* gpu,
315 const GrTextureDesc& desc,
316 GrTexture** accum);
317
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000318 // determines the path renderer used to draw a clip path element.
319 GrPathRenderer* getClipPathRenderer(GrGpu* gpu,
320 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000321 GrPathFill fill,
322 bool antiAlias);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000323
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000324 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000325};
326
327#endif // GrClipMaskManager_DEFINED