robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 1 | |
| 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.com | 8d033a1 | 2012-04-27 15:52:53 +0000 | [diff] [blame] | 13 | #include "SkPath.h" |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 14 | #include "GrNoncopyable.h" |
| 15 | #include "GrClip.h" |
| 16 | #include "SkRefCnt.h" |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 17 | #include "GrTexture.h" |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 18 | #include "SkDeque.h" |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 19 | #include "GrContext.h" |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 20 | |
| 21 | class GrGpu; |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 22 | class GrPathRenderer; |
| 23 | class GrPathRendererChain; |
| 24 | class SkPath; |
robertphillips@google.com | f294b77 | 2012-04-27 14:29:26 +0000 | [diff] [blame] | 25 | class GrTexture; |
| 26 | class GrDrawState; |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 27 | |
| 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 | */ |
| 34 | struct ScissoringSettings { |
| 35 | bool fEnableScissoring; |
| 36 | GrIRect fScissorRect; |
| 37 | |
| 38 | void setupScissoring(GrGpu* gpu); |
| 39 | }; |
| 40 | |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 41 | /** |
| 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 | */ |
| 45 | class GrClipMaskCache : public GrNoncopyable { |
| 46 | public: |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 47 | GrClipMaskCache() |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 48 | : fContext(NULL) |
| 49 | , fStack(sizeof(GrClipStackFrame)) { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 50 | // We need an initial frame to capture the clip state prior to |
| 51 | // any pushes |
| 52 | new (fStack.push_back()) GrClipStackFrame(); |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 53 | } |
| 54 | |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 55 | ~GrClipMaskCache() { |
| 56 | |
| 57 | while (!fStack.empty()) { |
| 58 | GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back(); |
| 59 | temp->~GrClipStackFrame(); |
| 60 | fStack.pop_back(); |
| 61 | } |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 62 | } |
| 63 | |
| 64 | bool canReuse(const GrClip& clip, int width, int height) { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 65 | |
| 66 | if (fStack.empty()) { |
| 67 | GrAssert(false); |
| 68 | return false; |
| 69 | } |
| 70 | |
| 71 | GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); |
| 72 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 73 | if (back->fLastMask.texture() && |
| 74 | back->fLastMask.texture()->width() >= width && |
| 75 | back->fLastMask.texture()->height() >= height && |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 76 | clip == back->fLastClip) { |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 77 | return true; |
| 78 | } |
| 79 | |
| 80 | return false; |
| 81 | } |
| 82 | |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 83 | 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.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 113 | } |
| 114 | |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 115 | 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.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | GrTexture* getLastMask() { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 129 | |
| 130 | if (fStack.empty()) { |
| 131 | GrAssert(false); |
| 132 | return NULL; |
| 133 | } |
| 134 | |
| 135 | GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); |
| 136 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 137 | return back->fLastMask.texture(); |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 138 | } |
| 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.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 149 | return back->fLastMask.texture(); |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 150 | } |
| 151 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 152 | void acquireMask(const GrClip& clip, |
| 153 | const GrTextureDesc& desc, |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 154 | const GrIRect& bound) { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 155 | |
| 156 | if (fStack.empty()) { |
| 157 | GrAssert(false); |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 158 | return; |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); |
| 162 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 163 | back->acquireMask(fContext, clip, desc, bound); |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 164 | } |
| 165 | |
| 166 | int getLastMaskWidth() const { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 167 | |
| 168 | if (fStack.empty()) { |
| 169 | GrAssert(false); |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 170 | return -1; |
| 171 | } |
| 172 | |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 173 | GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); |
| 174 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 175 | if (NULL == back->fLastMask.texture()) { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 176 | return -1; |
| 177 | } |
| 178 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 179 | return back->fLastMask.texture()->width(); |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | int getLastMaskHeight() const { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 183 | |
| 184 | if (fStack.empty()) { |
| 185 | GrAssert(false); |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 186 | return -1; |
| 187 | } |
| 188 | |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 189 | GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); |
| 190 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 191 | if (NULL == back->fLastMask.texture()) { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 192 | return -1; |
| 193 | } |
| 194 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 195 | return back->fLastMask.texture()->height(); |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 196 | } |
| 197 | |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 198 | void getLastBound(GrIRect* bound) const { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 199 | |
| 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.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 209 | } |
| 210 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 211 | 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.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 229 | protected: |
| 230 | private: |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 231 | struct GrClipStackFrame { |
| 232 | |
| 233 | GrClipStackFrame() { |
| 234 | reset(); |
| 235 | } |
| 236 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 237 | void acquireMask(GrContext* context, |
| 238 | const GrClip& clip, |
| 239 | const GrTextureDesc& desc, |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 240 | const GrIRect& bound) { |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 241 | |
| 242 | fLastClip = clip; |
| 243 | |
| 244 | fLastMask.set(context, desc); |
| 245 | |
| 246 | fLastBound = bound; |
| 247 | } |
| 248 | |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 249 | void reset () { |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 250 | fLastClip.setEmpty(); |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 251 | |
| 252 | const GrTextureDesc desc = { kNone_GrTextureFlags, 0, 0, |
| 253 | kUnknown_GrPixelConfig, 0 }; |
| 254 | |
| 255 | fLastMask.set(NULL, desc); |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 256 | fLastBound.setEmpty(); |
| 257 | } |
| 258 | |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 259 | 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.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 262 | GrAutoScratchTexture fLastMask; |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 263 | // 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.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 266 | GrIRect fLastBound; |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 267 | }; |
| 268 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 269 | GrContext* fContext; |
robertphillips@google.com | beeb97c | 2012-05-09 21:15:28 +0000 | [diff] [blame] | 270 | SkDeque fStack; |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 271 | |
| 272 | typedef GrNoncopyable INHERITED; |
| 273 | }; |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 274 | |
| 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.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 283 | class GrClipMaskManager : public GrNoncopyable { |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 284 | public: |
| 285 | GrClipMaskManager() |
| 286 | : fClipMaskInStencil(false) |
robertphillips@google.com | 2c75681 | 2012-05-22 20:28:23 +0000 | [diff] [blame^] | 287 | , fClipMaskInAlpha(false) { |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 288 | } |
| 289 | |
| 290 | bool createClipMask(GrGpu* gpu, |
| 291 | const GrClip& clip, |
| 292 | ScissoringSettings* scissorSettings); |
| 293 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 294 | void releaseResources(); |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 295 | |
| 296 | bool isClipInStencil() const { return fClipMaskInStencil; } |
robertphillips@google.com | f294b77 | 2012-04-27 14:29:26 +0000 | [diff] [blame] | 297 | bool isClipInAlpha() const { return fClipMaskInAlpha; } |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 298 | |
| 299 | void resetMask() { |
| 300 | fClipMaskInStencil = false; |
| 301 | } |
| 302 | |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 303 | void setContext(GrContext* context) { |
| 304 | fAACache.setContext(context); |
| 305 | } |
| 306 | |
robertphillips@google.com | 2c75681 | 2012-05-22 20:28:23 +0000 | [diff] [blame^] | 307 | GrContext* getContext() { |
| 308 | return fAACache.getContext(); |
| 309 | } |
| 310 | |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 311 | protected: |
| 312 | private: |
| 313 | bool fClipMaskInStencil; // is the clip mask in the stencil buffer? |
robertphillips@google.com | f294b77 | 2012-04-27 14:29:26 +0000 | [diff] [blame] | 314 | bool fClipMaskInAlpha; // is the clip mask in an alpha texture? |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 315 | GrClipMaskCache fAACache; // cache for the AA path |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 316 | |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 317 | bool createStencilClipMask(GrGpu* gpu, |
| 318 | const GrClip& clip, |
| 319 | const GrRect& bounds, |
| 320 | ScissoringSettings* scissorSettings); |
robertphillips@google.com | a72eef3 | 2012-05-01 17:22:59 +0000 | [diff] [blame] | 321 | bool createAlphaClipMask(GrGpu* gpu, |
| 322 | const GrClip& clipIn, |
| 323 | GrTexture** result, |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 324 | GrIRect *resultBounds); |
robertphillips@google.com | 6b70a7b | 2012-05-11 15:32:48 +0000 | [diff] [blame] | 325 | bool createSoftwareClipMask(GrGpu* gpu, |
| 326 | const GrClip& clipIn, |
| 327 | GrTexture** result, |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 328 | GrIRect *resultBounds); |
robertphillips@google.com | 6b70a7b | 2012-05-11 15:32:48 +0000 | [diff] [blame] | 329 | bool clipMaskPreamble(GrGpu* gpu, |
| 330 | const GrClip& clipIn, |
| 331 | GrTexture** result, |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 332 | GrIRect *resultBounds); |
robertphillips@google.com | f294b77 | 2012-04-27 14:29:26 +0000 | [diff] [blame] | 333 | |
robertphillips@google.com | fa66294 | 2012-05-17 12:20:22 +0000 | [diff] [blame] | 334 | bool useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn); |
| 335 | |
robertphillips@google.com | f294b77 | 2012-04-27 14:29:26 +0000 | [diff] [blame] | 336 | bool drawClipShape(GrGpu* gpu, |
| 337 | GrTexture* target, |
| 338 | const GrClip& clipIn, |
| 339 | int index); |
| 340 | |
| 341 | void drawTexture(GrGpu* gpu, |
| 342 | GrTexture* target, |
robertphillips@google.com | f294b77 | 2012-04-27 14:29:26 +0000 | [diff] [blame] | 343 | GrTexture* texture); |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 344 | |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 345 | void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp); |
robertphillips@google.com | f105b10 | 2012-05-14 12:18:26 +0000 | [diff] [blame] | 346 | |
| 347 | void setupCache(const GrClip& clip, |
robertphillips@google.com | 6623fcd | 2012-05-15 16:47:23 +0000 | [diff] [blame] | 348 | const GrIRect& bounds); |
robertphillips@google.com | 6d62df4 | 2012-05-07 18:07:36 +0000 | [diff] [blame] | 349 | |
robertphillips@google.com | fd6daf5 | 2012-05-02 19:32:32 +0000 | [diff] [blame] | 350 | typedef GrNoncopyable INHERITED; |
robertphillips@google.com | 1e945b7 | 2012-04-16 18:03:03 +0000 | [diff] [blame] | 351 | }; |
| 352 | |
| 353 | #endif // GrClipMaskManager_DEFINED |