1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrClipMaskCache_DEFINED 9 #define GrClipMaskCache_DEFINED 10 11 #include "GrContext.h" 12 #include "GrNoncopyable.h" 13 #include "SkClipStack.h" 14 15 class GrTexture; 16 17 /** 18 * The stencil buffer stores the last clip path - providing a single entry 19 * "cache". This class provides similar functionality for AA clip paths 20 */ 21 class GrClipMaskCache : public GrNoncopyable { 22 public: 23 GrClipMaskCache(); 24 ~GrClipMaskCache()25 ~GrClipMaskCache() { 26 27 while (!fStack.empty()) { 28 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back(); 29 temp->~GrClipStackFrame(); 30 fStack.pop_back(); 31 } 32 } 33 canReuse(int32_t clipGenID,const SkIRect & bounds)34 bool canReuse(int32_t clipGenID, const SkIRect& bounds) { 35 36 SkASSERT(clipGenID != SkClipStack::kWideOpenGenID); 37 SkASSERT(clipGenID != SkClipStack::kEmptyGenID); 38 39 if (SkClipStack::kInvalidGenID == clipGenID) { 40 return false; 41 } 42 43 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 44 45 // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate 46 // an offset to the caller. 47 if (back->fLastMask.texture() && 48 back->fLastBound == bounds && 49 back->fLastClipGenID == clipGenID) { 50 return true; 51 } 52 53 return false; 54 } 55 reset()56 void reset() { 57 if (fStack.empty()) { 58 // GrAssert(false); 59 return; 60 } 61 62 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 63 64 back->reset(); 65 } 66 67 /** 68 * After a "push" the clip state is entirely open. Currently, the 69 * entire clip stack will be re-rendered into a new clip mask. 70 * TODO: can we take advantage of the nested nature of the clips to 71 * reduce the mask creation cost? 72 */ 73 void push(); 74 pop()75 void pop() { 76 //GrAssert(!fStack.empty()); 77 78 if (!fStack.empty()) { 79 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 80 81 back->~GrClipStackFrame(); 82 fStack.pop_back(); 83 } 84 } 85 getLastClipGenID()86 int32_t getLastClipGenID() const { 87 88 if (fStack.empty()) { 89 return SkClipStack::kInvalidGenID; 90 } 91 92 return ((GrClipStackFrame*) fStack.back())->fLastClipGenID; 93 } 94 getLastMask()95 GrTexture* getLastMask() { 96 97 if (fStack.empty()) { 98 GrAssert(false); 99 return NULL; 100 } 101 102 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 103 104 return back->fLastMask.texture(); 105 } 106 getLastMask()107 const GrTexture* getLastMask() const { 108 109 if (fStack.empty()) { 110 GrAssert(false); 111 return NULL; 112 } 113 114 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 115 116 return back->fLastMask.texture(); 117 } 118 acquireMask(int32_t clipGenID,const GrTextureDesc & desc,const GrIRect & bound)119 void acquireMask(int32_t clipGenID, 120 const GrTextureDesc& desc, 121 const GrIRect& bound) { 122 123 if (fStack.empty()) { 124 GrAssert(false); 125 return; 126 } 127 128 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 129 130 back->acquireMask(fContext, clipGenID, desc, bound); 131 } 132 getLastMaskWidth()133 int getLastMaskWidth() const { 134 135 if (fStack.empty()) { 136 GrAssert(false); 137 return -1; 138 } 139 140 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 141 142 if (NULL == back->fLastMask.texture()) { 143 return -1; 144 } 145 146 return back->fLastMask.texture()->width(); 147 } 148 getLastMaskHeight()149 int getLastMaskHeight() const { 150 151 if (fStack.empty()) { 152 GrAssert(false); 153 return -1; 154 } 155 156 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 157 158 if (NULL == back->fLastMask.texture()) { 159 return -1; 160 } 161 162 return back->fLastMask.texture()->height(); 163 } 164 getLastBound(GrIRect * bound)165 void getLastBound(GrIRect* bound) const { 166 167 if (fStack.empty()) { 168 GrAssert(false); 169 bound->setEmpty(); 170 return; 171 } 172 173 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 174 175 *bound = back->fLastBound; 176 } 177 setContext(GrContext * context)178 void setContext(GrContext* context) { 179 fContext = context; 180 } 181 getContext()182 GrContext* getContext() { 183 return fContext; 184 } 185 releaseResources()186 void releaseResources() { 187 188 SkDeque::F2BIter iter(fStack); 189 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next(); 190 frame != NULL; 191 frame = (GrClipStackFrame*) iter.next()) { 192 frame->reset(); 193 } 194 } 195 196 private: 197 struct GrClipStackFrame { 198 GrClipStackFrameGrClipStackFrame199 GrClipStackFrame() { 200 this->reset(); 201 } 202 acquireMaskGrClipStackFrame203 void acquireMask(GrContext* context, 204 int32_t clipGenID, 205 const GrTextureDesc& desc, 206 const GrIRect& bound) { 207 208 fLastClipGenID = clipGenID; 209 210 fLastMask.set(context, desc); 211 212 fLastBound = bound; 213 } 214 resetGrClipStackFrame215 void reset () { 216 fLastClipGenID = SkClipStack::kInvalidGenID; 217 218 GrTextureDesc desc; 219 220 fLastMask.set(NULL, desc); 221 fLastBound.setEmpty(); 222 } 223 224 int32_t fLastClipGenID; 225 // The mask's width & height values are used by GrClipMaskManager to correctly scale the 226 // texture coords for the geometry drawn with this mask. 227 GrAutoScratchTexture fLastMask; 228 // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is 229 // used by GrClipMaskManager to position a rect and compute texture coords for the mask. 230 GrIRect fLastBound; 231 }; 232 233 GrContext* fContext; 234 SkDeque fStack; 235 236 typedef GrNoncopyable INHERITED; 237 }; 238 239 #endif // GrClipMaskCache_DEFINED 240