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 12 #include "GrLayerAtlas.h" 13 #include "GrTexture.h" 14 #include "GrRect.h" 15 16 #include "SkChecksum.h" 17 #include "SkImageFilter.h" 18 #include "SkMessageBus.h" 19 #include "SkPicture.h" 20 #include "SkTDynamicHash.h" 21 22 // Set to 0 to disable caching of hoisted layers 23 #define GR_CACHE_HOISTED_LAYERS 0 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 static const int kNumPlots = 4; 30 31 // for SkTDynamicHash - just use the pictureID as the hash key GetKeyGrPictureInfo32 static const uint32_t& GetKey(const GrPictureInfo& pictInfo) { return pictInfo.fPictureID; } HashGrPictureInfo33 static uint32_t Hash(const uint32_t& key) { return SkChecksum::Mix(key); } 34 35 // GrPictureInfo proper GrPictureInfoGrPictureInfo36 GrPictureInfo(uint32_t pictureID) 37 : fPictureID(pictureID) 38 , fPlotUsage(kNumPlots) { 39 #if !GR_CACHE_HOISTED_LAYERS 40 memset(fPlotUses, 0, sizeof(fPlotUses)); 41 #endif 42 } 43 44 #if !GR_CACHE_HOISTED_LAYERS incPlotUsageGrPictureInfo45 void incPlotUsage(int plotID) { 46 SkASSERT(plotID < kNumPlots); 47 fPlotUses[plotID]++; 48 } 49 decPlotUsageGrPictureInfo50 void decPlotUsage(int plotID) { 51 SkASSERT(plotID < kNumPlots); 52 SkASSERT(fPlotUses[plotID] > 0); 53 fPlotUses[plotID]--; 54 } 55 plotUsageGrPictureInfo56 int plotUsage(int plotID) const { 57 SkASSERT(plotID < kNumPlots); 58 return fPlotUses[plotID]; 59 } 60 #endif 61 62 const uint32_t fPictureID; 63 GrLayerAtlas::ClientPlotUsage fPlotUsage; 64 65 #if !GR_CACHE_HOISTED_LAYERS 66 private: 67 int fPlotUses[kNumPlots]; 68 #endif 69 }; 70 71 // GrCachedLayer encapsulates the caching information for a single saveLayer. 72 // 73 // Atlased layers get a ref to the backing GrTexture while non-atlased layers 74 // get a ref to the GrTexture in which they reside. In both cases 'fRect' 75 // contains the layer's extent in its texture. 76 // Atlased layers also get a pointer to the plot in which they reside. 77 // For non-atlased layers, the lock field just corresponds to locking in 78 // the resource cache. For atlased layers, it implements an additional level 79 // of locking to allow atlased layers to be reused multiple times. 80 struct GrCachedLayer { 81 public: 82 // For SkTDynamicHash 83 struct Key { 84 Key(uint32_t pictureID, const SkMatrix& initialMat, 85 const int* key, int keySize, bool copyKey = false) fKeySizeGrCachedLayer::Key86 : fKeySize(keySize) 87 , fFreeKey(copyKey) { 88 fIDMatrix.fPictureID = pictureID; 89 fIDMatrix.fInitialMat = initialMat; 90 fIDMatrix.fInitialMat.getType(); // force initialization of type so hashes match 91 92 if (copyKey) { 93 int* tempKey = new int[keySize]; 94 memcpy(tempKey, key, keySize*sizeof(int)); 95 fKey = tempKey; 96 } else { 97 fKey = key; 98 } 99 100 // The pictureID/matrix portion needs to be tightly packed. 101 GR_STATIC_ASSERT(sizeof(IDMatrix) == sizeof(uint32_t)+ // pictureID 102 9 * sizeof(SkScalar) + sizeof(uint32_t)); // matrix 103 } 104 ~KeyGrCachedLayer::Key105 ~Key() { 106 if (fFreeKey) { 107 delete[] fKey; 108 } 109 } 110 111 bool operator==(const Key& other) const { 112 if (fKeySize != other.fKeySize) { 113 return false; 114 } 115 return fIDMatrix.fPictureID == other.fIDMatrix.fPictureID && 116 fIDMatrix.fInitialMat.cheapEqualTo(other.fIDMatrix.fInitialMat) && 117 !memcmp(fKey, other.fKey, fKeySize * sizeof(int)); 118 } 119 pictureIDGrCachedLayer::Key120 uint32_t pictureID() const { return fIDMatrix.fPictureID; } 121 122 // TODO: remove these when GrCachedLayer & ReplacementInfo fuse keyGrCachedLayer::Key123 const int* key() const { SkASSERT(fFreeKey); return fKey; } keySizeGrCachedLayer::Key124 int keySize() const { SkASSERT(fFreeKey); return fKeySize; } 125 hashGrCachedLayer::Key126 uint32_t hash() const { 127 uint32_t hash = SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(fKey), 128 fKeySize * sizeof(int)); 129 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&fIDMatrix), 130 sizeof(IDMatrix), hash); 131 } 132 133 private: 134 struct IDMatrix { 135 // ID of the picture of which this layer is a part 136 uint32_t fPictureID; 137 // The initial matrix passed into drawPicture 138 SkMatrix fInitialMat; 139 } fIDMatrix; 140 141 const int* fKey; 142 const int fKeySize; 143 bool fFreeKey; 144 }; 145 GetKeyGrCachedLayer146 static const Key& GetKey(const GrCachedLayer& layer) { return layer.fKey; } HashGrCachedLayer147 static uint32_t Hash(const Key& key) { return key.hash(); } 148 149 // GrCachedLayer proper GrCachedLayerGrCachedLayer150 GrCachedLayer(uint32_t pictureID, 151 int start, 152 int stop, 153 const SkIRect& srcIR, 154 const SkIRect& dstIR, 155 const SkMatrix& ctm, 156 const int* key, 157 int keySize, 158 const SkPaint* paint) 159 : fKey(pictureID, ctm, key, keySize, true) 160 , fStart(start) 161 , fStop(stop) 162 , fSrcIR(srcIR) 163 , fDstIR(dstIR) 164 , fOffset(SkIPoint::Make(0, 0)) 165 , fPaint(paint ? new SkPaint(*paint) : nullptr) 166 , fFilter(nullptr) 167 , fTexture(nullptr) 168 , fAtlased(false) 169 , fRect(SkIRect::MakeEmpty()) 170 , fPlot(nullptr) 171 , fUses(0) 172 , fLocked(false) { 173 SkASSERT(SK_InvalidGenID != pictureID); 174 175 if (fPaint) { 176 if (fPaint->getImageFilter()) { 177 fFilter = SkSafeRef(fPaint->getImageFilter()); 178 fPaint->setImageFilter(nullptr); 179 } 180 } 181 } 182 ~GrCachedLayerGrCachedLayer183 ~GrCachedLayer() { 184 if (!fAtlased) { 185 SkSafeUnref(fTexture); 186 } 187 SkSafeUnref(fFilter); 188 delete fPaint; 189 } 190 pictureIDGrCachedLayer191 uint32_t pictureID() const { return fKey.pictureID(); } 192 // TODO: remove these when GrCachedLayer & ReplacementInfo fuse keyGrCachedLayer193 const int* key() const { return fKey.key(); } keySizeGrCachedLayer194 int keySize() const { return fKey.keySize(); } 195 startGrCachedLayer196 int start() const { return fStart; } 197 // TODO: make bound debug only srcIRGrCachedLayer198 const SkIRect& srcIR() const { return fSrcIR; } dstIRGrCachedLayer199 const SkIRect& dstIR() const { return fDstIR; } stopGrCachedLayer200 int stop() const { return fStop; } setTextureGrCachedLayer201 void setTexture(GrTexture* texture, const SkIRect& rect, bool atlased) { 202 if (texture && !atlased) { 203 texture->ref(); // non-atlased textures carry a ref 204 } 205 if (fTexture && !fAtlased) { 206 fTexture->unref(); // non-atlased textures carry a ref 207 } 208 fTexture = texture; 209 fAtlased = atlased; 210 fRect = rect; 211 if (!fTexture) { 212 fLocked = false; 213 } 214 } textureGrCachedLayer215 GrTexture* texture() { return fTexture; } paintGrCachedLayer216 const SkPaint* paint() const { return fPaint; } filterGrCachedLayer217 const SkImageFilter* filter() const { return fFilter; } rectGrCachedLayer218 const SkIRect& rect() const { return fRect; } 219 setOffsetGrCachedLayer220 void setOffset(const SkIPoint& offset) { fOffset = offset; } offsetGrCachedLayer221 const SkIPoint& offset() const { return fOffset; } 222 setPlotGrCachedLayer223 void setPlot(GrLayerAtlas::Plot* plot) { 224 SkASSERT(nullptr == plot || nullptr == fPlot); 225 fPlot = plot; 226 } plotGrCachedLayer227 GrLayerAtlas::Plot* plot() { return fPlot; } 228 isAtlasedGrCachedLayer229 bool isAtlased() const { SkASSERT(fAtlased == SkToBool(fPlot)); return fAtlased; } 230 setLockedGrCachedLayer231 void setLocked(bool locked) { fLocked = locked; } lockedGrCachedLayer232 bool locked() const { return fLocked; } 233 234 SkDEBUGCODE(const GrLayerAtlas::Plot* plot() const { return fPlot; }) 235 SkDEBUGCODE(void validate(const GrTexture* backingTexture) const;) 236 237 private: 238 const Key fKey; 239 240 // The "saveLayer" operation index of the cached layer 241 const int fStart; 242 // The final "restore" operation index of the cached layer 243 const int fStop; 244 245 // The layer's src rect (i.e., the portion of the source scene required 246 // for filtering). 247 const SkIRect fSrcIR; 248 // The layer's dest rect (i.e., where it will land in device space) 249 const SkIRect fDstIR; 250 // Offset sometimes required by image filters 251 SkIPoint fOffset; 252 253 // The paint used when dropping the layer down into the owning canvas. 254 // Can be nullptr. This class makes a copy for itself. 255 SkPaint* fPaint; 256 257 // The imagefilter that needs to be applied to the layer prior to it being 258 // composited with the rest of the scene. 259 const SkImageFilter* fFilter; 260 261 // fTexture is a ref on the atlasing texture for atlased layers and a 262 // ref on a GrTexture for non-atlased textures. 263 GrTexture* fTexture; 264 265 // true if this layer is in the atlas (and 'fTexture' doesn't carry a ref) 266 // and false if the layer is a free floater (and carries a ref). 267 bool fAtlased; 268 269 // For both atlased and non-atlased layers 'fRect' contains the bound of 270 // the layer in whichever texture it resides. It is empty when 'fTexture' 271 // is nullptr. 272 SkIRect fRect; 273 274 // For atlased layers, fPlot stores the atlas plot in which the layer rests. 275 // It is always nullptr for non-atlased layers. 276 GrLayerAtlas::Plot* fPlot; 277 278 // The number of actively hoisted layers using this cached image (e.g., 279 // extant GrHoistedLayers pointing at this object). This object will 280 // be unlocked when the use count reaches 0. 281 int fUses; 282 283 // For non-atlased layers 'fLocked' should always match "fTexture". 284 // (i.e., if there is a texture it is locked). 285 // For atlased layers, 'fLocked' is true if the layer is in a plot and 286 // actively required for rendering. If the layer is in a plot but not 287 // actively required for rendering, then 'fLocked' is false. If the 288 // layer isn't in a plot then is can never be locked. 289 bool fLocked; 290 addUseGrCachedLayer291 void addUse() { ++fUses; } removeUseGrCachedLayer292 void removeUse() { SkASSERT(fUses > 0); --fUses; } usesGrCachedLayer293 int uses() const { return fUses; } 294 295 friend class GrLayerCache; // for access to usage methods 296 friend class TestingAccess; // for testing 297 }; 298 299 // The GrLayerCache caches pre-computed saveLayers for later rendering. 300 // Non-atlased layers are stored in their own GrTexture while the atlased 301 // layers share a single GrTexture. 302 // Unlike the GrFontCache, the GrLayerCache only has one atlas (for 8888). 303 // As such, the GrLayerCache roughly combines the functionality of the 304 // GrFontCache and GrTextStrike classes. 305 class GrLayerCache { 306 public: 307 GrLayerCache(GrContext*); 308 ~GrLayerCache(); 309 310 // As a cache, the GrLayerCache can be ordered to free up all its cached 311 // elements by the GrContext 312 void freeAll(); 313 314 GrCachedLayer* findLayer(uint32_t pictureID, const SkMatrix& ctm, 315 const int* key, int keySize); 316 GrCachedLayer* findLayerOrCreate(uint32_t pictureID, 317 int start, int stop, 318 const SkIRect& srcIR, 319 const SkIRect& dstIR, 320 const SkMatrix& initialMat, 321 const int* key, int keySize, 322 const SkPaint* paint); 323 324 // Attempt to place 'layer' in the atlas. Return true on success; false on failure. 325 // When true is returned, 'needsRendering' will indicate if the layer must be (re)drawn. 326 // Additionally, the GPU resources will be locked. 327 bool tryToAtlas(GrCachedLayer* layer, const GrSurfaceDesc& desc, bool* needsRendering); 328 329 // Attempt to lock the GPU resources required for a layer. Return true on success; 330 // false on failure. When true is returned 'needsRendering' will indicate if the 331 // layer must be (re)drawn. 332 // Note that atlased layers should already have been locked and rendered so only 333 // free floating layers will have 'needsRendering' set. 334 // Currently, this path always uses a new scratch texture for non-Atlased layers 335 // and (thus) doesn't cache anything. This can yield a lot of re-rendering. 336 // TODO: allow rediscovery of free-floating layers that are still in the resource cache. 337 bool lock(GrCachedLayer* layer, const GrSurfaceDesc& desc, bool* needsRendering); 338 339 // addUse is just here to keep the API symmetric addUse(GrCachedLayer * layer)340 void addUse(GrCachedLayer* layer) { layer->addUse(); } removeUse(GrCachedLayer * layer)341 void removeUse(GrCachedLayer* layer) { 342 layer->removeUse(); 343 if (layer->uses() == 0) { 344 // If no one cares about the layer allow it to be recycled. 345 this->unlock(layer); 346 } 347 } 348 349 // Cleanup after any SkPicture deletions 350 void processDeletedPictures(); 351 352 SkDEBUGCODE(void validate() const;) 353 354 #ifdef SK_DEVELOPER 355 void writeLayersToDisk(const SkString& dirName); 356 #endif 357 PlausiblyAtlasable(int width,int height)358 static bool PlausiblyAtlasable(int width, int height) { 359 return width <= kPlotWidth && height <= kPlotHeight; 360 } 361 362 void begin(); 363 void end(); 364 365 #if !GR_CACHE_HOISTED_LAYERS 366 void purgeAll(); 367 #endif 368 369 private: 370 static const int kAtlasTextureWidth = 1024; 371 static const int kAtlasTextureHeight = 1024; 372 373 static const int kNumPlotsX = 2; 374 static const int kNumPlotsY = 2; 375 376 static const int kPlotWidth = kAtlasTextureWidth / kNumPlotsX; 377 static const int kPlotHeight = kAtlasTextureHeight / kNumPlotsY; 378 379 GrContext* fContext; // pointer back to owning context 380 SkAutoTDelete<GrLayerAtlas> fAtlas; // lazily allocated 381 382 // We cache this information here (rather then, say, on the owning picture) 383 // because we want to be able to clean it up as needed (e.g., if a picture 384 // is leaked and never cleans itself up we still want to be able to 385 // remove the GrPictureInfo once its layers are purged from all the atlas 386 // plots). 387 SkTDynamicHash<GrPictureInfo, uint32_t> fPictureHash; 388 389 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key> fLayerHash; 390 391 SkMessageBus<SkPicture::DeletionMessage>::Inbox fPictDeletionInbox; 392 393 // This implements a plot-centric locking mechanism (since the atlas 394 // backing texture is always locked). Each layer that is locked (i.e., 395 // needed for the current rendering) in a plot increments the plot lock 396 // count for that plot. Similarly, once a rendering is complete all the 397 // layers used in it decrement the lock count for the used plots. 398 // Plots with a 0 lock count are open for recycling/purging. 399 int fPlotLocks[kNumPlotsX * kNumPlotsY]; 400 401 // Inform the cache that layer's cached image is not currently required 402 void unlock(GrCachedLayer* layer); 403 404 void initAtlas(); 405 GrCachedLayer* createLayer(uint32_t pictureID, int start, int stop, 406 const SkIRect& srcIR, const SkIRect& dstIR, 407 const SkMatrix& initialMat, 408 const int* key, int keySize, 409 const SkPaint* paint); 410 411 // Remove all the layers (and unlock any resources) associated with 'pictureID' 412 void purge(uint32_t pictureID); 413 414 void purgePlot(GrLayerAtlas::Plot* plot); 415 416 // Either purge all un-locked plots or just one. Return true if >= 1 plot 417 // was purged; false otherwise. 418 bool purgePlots(bool justOne); 419 incPlotLock(int plotIdx)420 void incPlotLock(int plotIdx) { ++fPlotLocks[plotIdx]; } decPlotLock(int plotIdx)421 void decPlotLock(int plotIdx) { 422 SkASSERT(fPlotLocks[plotIdx] > 0); 423 --fPlotLocks[plotIdx]; 424 } 425 426 // for testing 427 friend class TestingAccess; numLayers()428 int numLayers() const { return fLayerHash.count(); } 429 }; 430 431 #endif 432