1 /* 2 * Copyright 2014 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 GrLayerCache_DEFINED 9 #define GrLayerCache_DEFINED 10 11 #include "GrAtlas.h" 12 #include "GrPictureUtils.h" 13 #include "GrRect.h" 14 #include "SkChecksum.h" 15 #include "SkTDynamicHash.h" 16 #include "SkMessageBus.h" 17 18 class SkPicture; 19 20 // The layer cache listens for these messages to purge picture-related resources. 21 struct GrPictureDeletedMessage { 22 uint32_t pictureID; 23 }; 24 25 // GrPictureInfo stores the atlas plots used by a single picture. A single 26 // plot may be used to store layers from multiple pictures. 27 struct GrPictureInfo { 28 public: 29 // for SkTDynamicHash - just use the pictureID as the hash key 30 static const uint32_t& GetKey(const GrPictureInfo& pictInfo) { return pictInfo.fPictureID; } 31 static uint32_t Hash(const uint32_t& key) { return SkChecksum::Mix(key); } 32 33 // GrPictureInfo proper 34 GrPictureInfo(uint32_t pictureID) : fPictureID(pictureID) { } 35 36 const uint32_t fPictureID; 37 38 GrAtlas::ClientPlotUsage fPlotUsage; 39 }; 40 41 // GrCachedLayer encapsulates the caching information for a single saveLayer. 42 // 43 // Atlased layers get a ref to the backing GrTexture while non-atlased layers 44 // get a ref to the GrTexture in which they reside. In both cases 'fRect' 45 // contains the layer's extent in its texture. 46 // Atlased layers also get a pointer to the plot in which they reside. 47 // For non-atlased layers, the lock field just corresponds to locking in 48 // the resource cache. For atlased layers, it implements an additional level 49 // of locking to allow atlased layers to be reused multiple times. 50 struct GrCachedLayer { 51 public: 52 // For SkTDynamicHash 53 struct Key { 54 Key(uint32_t pictureID, int start, int stop, const SkIPoint& offset, const SkMatrix& ctm) 55 : fPictureID(pictureID) 56 , fStart(start) 57 , fStop(stop) 58 , fOffset(offset) 59 , fCTM(ctm) { 60 fCTM.getType(); // force initialization of type so hashes match 61 62 // Key needs to be tightly packed. 63 GR_STATIC_ASSERT(sizeof(Key) == sizeof(uint32_t) + 2 * sizeof(int) + 64 2 * sizeof(int32_t) + 65 9 * sizeof(SkScalar) + sizeof(uint32_t)); 66 } 67 68 bool operator==(const Key& other) const { 69 return fPictureID == other.fPictureID && 70 fStart == other.fStart && 71 fStop == other.fStop && 72 fOffset == other.fOffset && 73 fCTM.cheapEqualTo(other.fCTM); 74 } 75 76 uint32_t pictureID() const { return fPictureID; } 77 int start() const { return fStart; } 78 int stop() const { return fStop; } 79 const SkIPoint& offset() const { return fOffset; } 80 const SkMatrix& ctm() const { return fCTM; } 81 82 private: 83 // ID of the picture of which this layer is a part 84 const uint32_t fPictureID; 85 // The range of commands in the picture this layer represents 86 const int fStart; 87 const int fStop; 88 // The offset of the layer in device space 89 const SkIPoint fOffset; 90 // The CTM applied to this layer in the picture 91 SkMatrix fCTM; 92 }; 93 94 static const Key& GetKey(const GrCachedLayer& layer) { return layer.fKey; } 95 static uint32_t Hash(const Key& key) { 96 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key)); 97 } 98 99 // GrCachedLayer proper 100 GrCachedLayer(uint32_t pictureID, int start, int stop, 101 const SkIPoint& offset, const SkMatrix& ctm, 102 const SkPaint* paint) 103 : fKey(pictureID, start, stop, offset, ctm) 104 , fPaint(paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL) 105 , fTexture(NULL) 106 , fRect(GrIRect16::MakeEmpty()) 107 , fPlot(NULL) 108 , fLocked(false) { 109 SkASSERT(SK_InvalidGenID != pictureID && start >= 0 && stop >= 0); 110 } 111 112 ~GrCachedLayer() { 113 SkSafeUnref(fTexture); 114 SkDELETE(fPaint); 115 } 116 117 uint32_t pictureID() const { return fKey.pictureID(); } 118 int start() const { return fKey.start(); } 119 int stop() const { return fKey.stop(); } 120 const SkIPoint& offset() const { return fKey.offset(); } 121 const SkMatrix& ctm() const { return fKey.ctm(); } 122 123 void setTexture(GrTexture* texture, const GrIRect16& rect) { 124 SkRefCnt_SafeAssign(fTexture, texture); 125 fRect = rect; 126 } 127 GrTexture* texture() { return fTexture; } 128 const SkPaint* paint() const { return fPaint; } 129 const GrIRect16& rect() const { return fRect; } 130 131 void setPlot(GrPlot* plot) { 132 SkASSERT(NULL == plot || NULL == fPlot); 133 fPlot = plot; 134 } 135 GrPlot* plot() { return fPlot; } 136 137 bool isAtlased() const { return SkToBool(fPlot); } 138 139 void setLocked(bool locked) { fLocked = locked; } 140 bool locked() const { return fLocked; } 141 142 SkDEBUGCODE(const GrPlot* plot() const { return fPlot; }) 143 SkDEBUGCODE(void validate(const GrTexture* backingTexture) const;) 144 145 private: 146 const Key fKey; 147 148 // The paint used when dropping the layer down into the owning canvas. 149 // Can be NULL. This class makes a copy for itself. 150 const SkPaint* fPaint; 151 152 // fTexture is a ref on the atlasing texture for atlased layers and a 153 // ref on a GrTexture for non-atlased textures. 154 GrTexture* fTexture; 155 156 // For both atlased and non-atlased layers 'fRect' contains the bound of 157 // the layer in whichever texture it resides. It is empty when 'fTexture' 158 // is NULL. 159 GrIRect16 fRect; 160 161 // For atlased layers, fPlot stores the atlas plot in which the layer rests. 162 // It is always NULL for non-atlased layers. 163 GrPlot* fPlot; 164 165 // For non-atlased layers 'fLocked' should always match "fTexture". 166 // (i.e., if there is a texture it is locked). 167 // For atlased layers, 'fLocked' is true if the layer is in a plot and 168 // actively required for rendering. If the layer is in a plot but not 169 // actively required for rendering, then 'fLocked' is false. If the 170 // layer isn't in a plot then is can never be locked. 171 bool fLocked; 172 }; 173 174 // The GrLayerCache caches pre-computed saveLayers for later rendering. 175 // Non-atlased layers are stored in their own GrTexture while the atlased 176 // layers share a single GrTexture. 177 // Unlike the GrFontCache, the GrTexture atlas only has one GrAtlas (for 8888) 178 // and one GrPlot (for the entire atlas). As such, the GrLayerCache 179 // roughly combines the functionality of the GrFontCache and GrTextStrike 180 // classes. 181 class GrLayerCache { 182 public: 183 GrLayerCache(GrContext*); 184 ~GrLayerCache(); 185 186 // As a cache, the GrLayerCache can be ordered to free up all its cached 187 // elements by the GrContext 188 void freeAll(); 189 190 GrCachedLayer* findLayer(uint32_t pictureID, int start, int stop, 191 const SkIPoint& offset, const SkMatrix& ctm); 192 GrCachedLayer* findLayerOrCreate(uint32_t pictureID, 193 int start, int stop, 194 const SkIPoint& offset, 195 const SkMatrix& ctm, 196 const SkPaint* paint); 197 198 // Inform the cache that layer's cached image is now required. 199 // Return true if the layer must be re-rendered. Return false if the 200 // layer was found in the cache and can be reused. 201 bool lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool dontAtlas); 202 203 // Inform the cache that layer's cached image is not currently required 204 void unlock(GrCachedLayer* layer); 205 206 // Setup to be notified when 'picture' is deleted 207 void trackPicture(const SkPicture* picture); 208 209 // Cleanup after any SkPicture deletions 210 void processDeletedPictures(); 211 212 SkDEBUGCODE(void validate() const;) 213 214 private: 215 static const int kAtlasTextureWidth = 1024; 216 static const int kAtlasTextureHeight = 1024; 217 218 static const int kNumPlotsX = 2; 219 static const int kNumPlotsY = 2; 220 221 static const int kPlotWidth = kAtlasTextureWidth / kNumPlotsX; 222 static const int kPlotHeight = kAtlasTextureHeight / kNumPlotsY; 223 224 GrContext* fContext; // pointer back to owning context 225 SkAutoTDelete<GrAtlas> fAtlas; // TODO: could lazily allocate 226 227 // We cache this information here (rather then, say, on the owning picture) 228 // because we want to be able to clean it up as needed (e.g., if a picture 229 // is leaked and never cleans itself up we still want to be able to 230 // remove the GrPictureInfo once its layers are purged from all the atlas 231 // plots). 232 SkTDynamicHash<GrPictureInfo, uint32_t> fPictureHash; 233 234 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key> fLayerHash; 235 236 SkMessageBus<GrPictureDeletedMessage>::Inbox fPictDeletionInbox; 237 238 SkAutoTUnref<SkPicture::DeletionListener> fDeletionListener; 239 240 // This implements a plot-centric locking mechanism (since the atlas 241 // backing texture is always locked). Each layer that is locked (i.e., 242 // needed for the current rendering) in a plot increments the plot lock 243 // count for that plot. Similarly, once a rendering is complete all the 244 // layers used in it decrement the lock count for the used plots. 245 // Plots with a 0 lock count are open for recycling/purging. 246 int fPlotLocks[kNumPlotsX * kNumPlotsY]; 247 248 void initAtlas(); 249 GrCachedLayer* createLayer(uint32_t pictureID, int start, int stop, 250 const SkIPoint& offset, const SkMatrix& ctm, 251 const SkPaint* paint); 252 253 void purgeAll(); 254 255 // Remove all the layers (and unlock any resources) associated with 'pictureID' 256 void purge(uint32_t pictureID); 257 258 static bool PlausiblyAtlasable(int width, int height) { 259 return width <= kPlotWidth && height <= kPlotHeight; 260 } 261 262 void purgePlot(GrPlot* plot); 263 264 // Try to find a purgeable plot and clear it out. Return true if a plot 265 // was purged; false otherwise. 266 bool purgePlot(); 267 268 // for testing 269 friend class TestingAccess; 270 int numLayers() const { return fLayerHash.count(); } 271 }; 272 273 #endif 274