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