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 "SkClipStack.h" 13 #include "SkTypes.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 : SkNoncopyable { 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 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 40 41 // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate 42 // an offset to the caller. 43 if (back->fLastMask.texture() && 44 !back->fLastMask.texture()->wasDestroyed() && 45 back->fLastBound == bounds && 46 back->fLastClipGenID == clipGenID) { 47 return true; 48 } 49 50 return false; 51 } 52 reset()53 void reset() { 54 if (fStack.empty()) { 55 // SkASSERT(false); 56 return; 57 } 58 59 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 60 61 back->reset(); 62 } 63 64 /** 65 * After a "push" the clip state is entirely open. Currently, the 66 * entire clip stack will be re-rendered into a new clip mask. 67 * TODO: can we take advantage of the nested nature of the clips to 68 * reduce the mask creation cost? 69 */ 70 void push(); 71 pop()72 void pop() { 73 //SkASSERT(!fStack.empty()); 74 75 if (!fStack.empty()) { 76 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 77 78 back->~GrClipStackFrame(); 79 fStack.pop_back(); 80 } 81 } 82 getLastClipGenID()83 int32_t getLastClipGenID() const { 84 85 if (fStack.empty()) { 86 return SkClipStack::kInvalidGenID; 87 } 88 89 return ((GrClipStackFrame*) fStack.back())->fLastClipGenID; 90 } 91 getLastMask()92 GrTexture* getLastMask() { 93 94 if (fStack.empty()) { 95 SkASSERT(false); 96 return NULL; 97 } 98 99 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 100 101 return back->fLastMask.texture(); 102 } 103 getLastMask()104 const GrTexture* getLastMask() const { 105 106 if (fStack.empty()) { 107 SkASSERT(false); 108 return NULL; 109 } 110 111 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 112 113 return back->fLastMask.texture(); 114 } 115 acquireMask(int32_t clipGenID,const GrTextureDesc & desc,const SkIRect & bound)116 void acquireMask(int32_t clipGenID, 117 const GrTextureDesc& desc, 118 const SkIRect& bound) { 119 120 if (fStack.empty()) { 121 SkASSERT(false); 122 return; 123 } 124 125 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 126 127 back->acquireMask(fContext, clipGenID, desc, bound); 128 } 129 getLastMaskWidth()130 int getLastMaskWidth() const { 131 132 if (fStack.empty()) { 133 SkASSERT(false); 134 return -1; 135 } 136 137 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 138 139 if (NULL == back->fLastMask.texture()) { 140 return -1; 141 } 142 143 return back->fLastMask.texture()->width(); 144 } 145 getLastMaskHeight()146 int getLastMaskHeight() const { 147 148 if (fStack.empty()) { 149 SkASSERT(false); 150 return -1; 151 } 152 153 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 154 155 if (NULL == back->fLastMask.texture()) { 156 return -1; 157 } 158 159 return back->fLastMask.texture()->height(); 160 } 161 getLastBound(SkIRect * bound)162 void getLastBound(SkIRect* bound) const { 163 164 if (fStack.empty()) { 165 SkASSERT(false); 166 bound->setEmpty(); 167 return; 168 } 169 170 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); 171 172 *bound = back->fLastBound; 173 } 174 setContext(GrContext * context)175 void setContext(GrContext* context) { 176 fContext = context; 177 } 178 getContext()179 GrContext* getContext() { 180 return fContext; 181 } 182 183 // TODO: Remove this when we hold cache keys instead of refs to textures. purgeResources()184 void purgeResources() { 185 SkDeque::F2BIter iter(fStack); 186 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next(); 187 frame != NULL; 188 frame = (GrClipStackFrame*) iter.next()) { 189 frame->reset(); 190 } 191 } 192 193 private: 194 struct GrClipStackFrame { 195 GrClipStackFrameGrClipStackFrame196 GrClipStackFrame() { 197 this->reset(); 198 } 199 acquireMaskGrClipStackFrame200 void acquireMask(GrContext* context, 201 int32_t clipGenID, 202 const GrTextureDesc& desc, 203 const SkIRect& bound) { 204 205 fLastClipGenID = clipGenID; 206 207 fLastMask.set(context, desc); 208 209 fLastBound = bound; 210 } 211 resetGrClipStackFrame212 void reset () { 213 fLastClipGenID = SkClipStack::kInvalidGenID; 214 215 GrTextureDesc desc; 216 217 fLastMask.set(NULL, desc); 218 fLastBound.setEmpty(); 219 } 220 221 int32_t fLastClipGenID; 222 // The mask's width & height values are used by GrClipMaskManager to correctly scale the 223 // texture coords for the geometry drawn with this mask. TODO: This should be a cache key 224 // and not a hard ref to a texture. 225 GrAutoScratchTexture fLastMask; 226 // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is 227 // used by GrClipMaskManager to position a rect and compute texture coords for the mask. 228 SkIRect fLastBound; 229 }; 230 231 GrContext* fContext; 232 SkDeque fStack; 233 234 typedef SkNoncopyable INHERITED; 235 }; 236 237 #endif // GrClipMaskCache_DEFINED 238