GrClipMaskManager.h revision d6176b0dcacb124539e0cfd051e6d93a9782f020
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 "GrContext.h" 13#include "GrNoncopyable.h" 14#include "GrRect.h" 15#include "GrStencil.h" 16#include "GrTexture.h" 17 18#include "SkClipStack.h" 19#include "SkDeque.h" 20#include "SkPath.h" 21#include "SkRefCnt.h" 22 23class GrGpu; 24class GrPathRenderer; 25class GrPathRendererChain; 26class SkPath; 27class GrTexture; 28class GrDrawState; 29 30/** 31 * The stencil buffer stores the last clip path - providing a single entry 32 * "cache". This class provides similar functionality for AA clip paths 33 */ 34class GrClipMaskCache : public GrNoncopyable { 35public: 36 GrClipMaskCache(); 37 38 ~GrClipMaskCache() { 39 40 while (!fStack.empty()) { 41 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back(); 42 temp->~GrClipStackFrame(); 43 fStack.pop_back(); 44 } 45 } 46 47 bool canReuse(const SkClipStack& clip, int width, int height) { 48 49 if (fStack.empty()) { 50 GrAssert(false); 51 return false; 52 } 53 54 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 55 56 if (back->fLastMask.texture() && 57 back->fLastMask.texture()->width() >= width && 58 back->fLastMask.texture()->height() >= height && 59 clip == back->fLastClip) { 60 return true; 61 } 62 63 return false; 64 } 65 66 void reset() { 67 if (fStack.empty()) { 68// GrAssert(false); 69 return; 70 } 71 72 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 73 74 back->reset(); 75 } 76 77 /** 78 * After a "push" the clip state is entirely open. Currently, the 79 * entire clip stack will be re-rendered into a new clip mask. 80 * TODO: can we take advantage of the nested nature of the clips to 81 * reduce the mask creation cost? 82 */ 83 void push(); 84 85 void pop() { 86 //GrAssert(!fStack.empty()); 87 88 if (!fStack.empty()) { 89 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 90 91 back->~GrClipStackFrame(); 92 fStack.pop_back(); 93 } 94 } 95 96 void getLastClip(SkClipStack* clip) const { 97 98 if (fStack.empty()) { 99 GrAssert(false); 100 clip->reset(); 101 return; 102 } 103 104 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 105 106 *clip = back->fLastClip; 107 } 108 109 GrTexture* getLastMask() { 110 111 if (fStack.empty()) { 112 GrAssert(false); 113 return NULL; 114 } 115 116 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 117 118 return back->fLastMask.texture(); 119 } 120 121 const GrTexture* getLastMask() const { 122 123 if (fStack.empty()) { 124 GrAssert(false); 125 return NULL; 126 } 127 128 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 129 130 return back->fLastMask.texture(); 131 } 132 133 void acquireMask(const SkClipStack& clip, 134 const GrTextureDesc& desc, 135 const GrIRect& bound) { 136 137 if (fStack.empty()) { 138 GrAssert(false); 139 return; 140 } 141 142 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 143 144 back->acquireMask(fContext, clip, desc, bound); 145 } 146 147 int getLastMaskWidth() const { 148 149 if (fStack.empty()) { 150 GrAssert(false); 151 return -1; 152 } 153 154 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 155 156 if (NULL == back->fLastMask.texture()) { 157 return -1; 158 } 159 160 return back->fLastMask.texture()->width(); 161 } 162 163 int getLastMaskHeight() const { 164 165 if (fStack.empty()) { 166 GrAssert(false); 167 return -1; 168 } 169 170 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 171 172 if (NULL == back->fLastMask.texture()) { 173 return -1; 174 } 175 176 return back->fLastMask.texture()->height(); 177 } 178 179 void getLastBound(GrIRect* bound) const { 180 181 if (fStack.empty()) { 182 GrAssert(false); 183 bound->setEmpty(); 184 return; 185 } 186 187 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 188 189 *bound = back->fLastBound; 190 } 191 192 void setContext(GrContext* context) { 193 fContext = context; 194 } 195 196 GrContext* getContext() { 197 return fContext; 198 } 199 200 void releaseResources() { 201 202 SkDeque::F2BIter iter(fStack); 203 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next(); 204 frame != NULL; 205 frame = (GrClipStackFrame*) iter.next()) { 206 frame->reset(); 207 } 208 } 209 210protected: 211private: 212 struct GrClipStackFrame { 213 214 GrClipStackFrame() { 215 reset(); 216 } 217 218 void acquireMask(GrContext* context, 219 const SkClipStack& clip, 220 const GrTextureDesc& desc, 221 const GrIRect& bound) { 222 223 fLastClip = clip; 224 225 fLastMask.set(context, desc); 226 227 fLastBound = bound; 228 } 229 230 void reset () { 231 fLastClip.reset(); 232 233 GrTextureDesc desc; 234 235 fLastMask.set(NULL, desc); 236 fLastBound.setEmpty(); 237 } 238 239 SkClipStack fLastClip; 240 // The mask's width & height values are used in setupDrawStateAAClip to 241 // correctly scale the uvs for geometry drawn with this mask 242 GrAutoScratchTexture fLastMask; 243 // fLastBound stores the bounding box of the clip mask in canvas 244 // space. The left and top fields are used to offset the uvs for 245 // geometry drawn with this mask (in setupDrawStateAAClip) 246 GrIRect fLastBound; 247 }; 248 249 GrContext* fContext; 250 SkDeque fStack; 251 252 typedef GrNoncopyable INHERITED; 253}; 254 255/** 256 * The clip mask creator handles the generation of the clip mask. If anti 257 * aliasing is requested it will (in the future) generate a single channel 258 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit 259 * mask in the stencil buffer. In the non anti-aliasing case, if the clip 260 * mask can be represented as a rectangle then scissoring is used. In all 261 * cases scissoring is used to bound the range of the clip mask. 262 */ 263class GrClipMaskManager : public GrNoncopyable { 264public: 265 GR_DECLARE_RESOURCE_CACHE_DOMAIN(GetAlphaMaskDomain) 266 267 GrClipMaskManager() 268 : fGpu(NULL) 269 , fCurrClipMaskType(kNone_ClipMaskType) { 270 } 271 272 /** 273 * Creates a clip mask if necessary as a stencil buffer or alpha texture 274 * and sets the GrGpu's scissor and stencil state. If the return is false 275 * then the draw can be skipped. 276 */ 277 bool setupClipping(const GrClipData* clipDataIn); 278 279 void releaseResources(); 280 281 bool isClipInStencil() const { 282 return kStencil_ClipMaskType == fCurrClipMaskType; 283 } 284 bool isClipInAlpha() const { 285 return kAlpha_ClipMaskType == fCurrClipMaskType; 286 } 287 288 void invalidateStencilMask() { 289 if (kStencil_ClipMaskType == fCurrClipMaskType) { 290 fCurrClipMaskType = kNone_ClipMaskType; 291 } 292 } 293 294 void setContext(GrContext* context) { 295 fAACache.setContext(context); 296 } 297 298 GrContext* getContext() { 299 return fAACache.getContext(); 300 } 301 302 void setGpu(GrGpu* gpu) { 303 fGpu = gpu; 304 } 305 306private: 307 /** 308 * Informs the helper function adjustStencilParams() about how the stencil 309 * buffer clip is being used. 310 */ 311 enum StencilClipMode { 312 // Draw to the clip bit of the stencil buffer 313 kModifyClip_StencilClipMode, 314 // Clip against the existing representation of the clip in the high bit 315 // of the stencil buffer. 316 kRespectClip_StencilClipMode, 317 // Neither writing to nor clipping against the clip bit. 318 kIgnoreClip_StencilClipMode, 319 }; 320 321 GrGpu* fGpu; 322 323 /** 324 * We may represent the clip as a mask in the stencil buffer or as an alpha 325 * texture. It may be neither because the scissor rect suffices or we 326 * haven't yet examined the clip. 327 */ 328 enum ClipMaskType { 329 kNone_ClipMaskType, 330 kStencil_ClipMaskType, 331 kAlpha_ClipMaskType, 332 } fCurrClipMaskType; 333 334 GrClipMaskCache fAACache; // cache for the AA path 335 336 bool createStencilClipMask(const GrClipData& clipDataIn, 337 const GrIRect& devClipBounds); 338 bool createAlphaClipMask(const GrClipData& clipDataIn, 339 GrTexture** result, 340 GrIRect *devResultBounds); 341 bool createSoftwareClipMask(const GrClipData& clipDataIn, 342 GrTexture** result, 343 GrIRect *devResultBounds); 344 bool clipMaskPreamble(const GrClipData& clipDataIn, 345 GrTexture** result, 346 GrIRect *devResultBounds); 347 348 bool useSWOnlyPath(const SkClipStack& clipIn); 349 350 bool drawClipShape(GrTexture* target, 351 const SkClipStack::Iter::Clip* clip, 352 const GrIRect& resultBounds); 353 354 void drawTexture(GrTexture* target, 355 GrTexture* texture); 356 357 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp); 358 359 void setupCache(const SkClipStack& clip, 360 const GrIRect& bounds); 361 362 /** 363 * Called prior to return control back the GrGpu in setupClipping. It 364 * updates the GrGpu with stencil settings that account stencil-based 365 * clipping. 366 */ 367 void setGpuStencil(); 368 369 /** 370 * Adjusts the stencil settings to account for interaction with stencil 371 * clipping. 372 */ 373 void adjustStencilParams(GrStencilSettings* settings, 374 StencilClipMode mode, 375 int stencilBitCnt); 376 377 typedef GrNoncopyable INHERITED; 378}; 379 380#endif // GrClipMaskManager_DEFINED 381