diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrLayerCache.cpp | 87 | ||||
-rw-r--r-- | src/gpu/GrLayerCache.h | 47 |
2 files changed, 109 insertions, 25 deletions
diff --git a/src/gpu/GrLayerCache.cpp b/src/gpu/GrLayerCache.cpp index 9688cac650..ff26750df7 100644 --- a/src/gpu/GrLayerCache.cpp +++ b/src/gpu/GrLayerCache.cpp @@ -41,8 +41,33 @@ private: int fLayerID; }; +/** + * PictureKey just wraps a picture's unique ID for GrTHashTable. It is used to + * look up a picture's GrPictureInfo (i.e., its GrPlot usage). + */ +class GrLayerCache::PictureKey { +public: + PictureKey(uint32_t pictureID) : fPictureID(pictureID) { } + + uint32_t pictureID() const { return fPictureID; } + + uint32_t getHash() const { return fPictureID; } + + static bool LessThan(const GrPictureInfo& pictInfo, const PictureKey& key) { + return pictInfo.fPictureID < key.pictureID(); + } + + static bool Equals(const GrPictureInfo& pictInfo, const PictureKey& key) { + return pictInfo.fPictureID == key.pictureID(); + + } + +private: + uint32_t fPictureID; +}; + #ifdef SK_DEBUG -void GrCachedLayer::validate(GrTexture* backingTexture) const { +void GrCachedLayer::validate(const GrTexture* backingTexture) const { SkASSERT(SK_InvalidGenID != fPictureID); SkASSERT(-1 != fLayerID); @@ -55,6 +80,14 @@ void GrCachedLayer::validate(GrTexture* backingTexture) const { } } else { SkASSERT(fRect.isEmpty()); + SkASSERT(NULL == fPlot); + } + + if (NULL != fPlot) { + // If a layer has a plot (i.e., is atlased) then it must point to + // the backing texture. Additionally, its rect should be non-empty. + SkASSERT(NULL != fTexture && backingTexture == fTexture); + SkASSERT(!fRect.isEmpty()); } } @@ -72,9 +105,13 @@ public: fLayer->validate(fBackingTexture); } } + void setBackingTexture(GrTexture* backingTexture) { + SkASSERT(NULL == fBackingTexture || fBackingTexture == backingTexture); + fBackingTexture = backingTexture; + } private: - GrTexture* fBackingTexture; + const GrTexture* fBackingTexture; const GrCachedLayer* fLayer; }; #endif @@ -106,7 +143,7 @@ void GrLayerCache::initAtlas() { SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight); fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig, kRenderTarget_GrTextureFlagBit, - textureSize, 1, 1, false))); + textureSize, kNumPlotsX, kNumPlotsY, false))); } void GrLayerCache::freeAll() { @@ -165,14 +202,26 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) { } #if USE_ATLAS - SkIPoint16 loc; - GrPlot* plot = fAtlas->addToAtlas(&fPlotUsage, desc.fWidth, desc.fHeight, NULL, &loc); - if (NULL != plot) { - GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY, - SkToS16(desc.fWidth), SkToS16(desc.fHeight)); - layer->setTexture(fAtlas->getTexture(), bounds); - layer->setAtlased(true); - return false; + { + GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(layer->pictureID())); + if (NULL == pictInfo) { + pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID())); + fPictureHash.insert(PictureKey(layer->pictureID()), pictInfo); + } + + SkIPoint16 loc; + GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage, + desc.fWidth, desc.fHeight, + NULL, &loc); + // addToAtlas can allocate the backing texture + SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture())); + if (NULL != plot) { + GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY, + SkToS16(desc.fWidth), SkToS16(desc.fHeight)); + layer->setTexture(fAtlas->getTexture(), bounds); + layer->setPlot(plot); + return false; + } } #endif @@ -192,9 +241,13 @@ void GrLayerCache::unlock(GrCachedLayer* layer) { } if (layer->isAtlased()) { - // The atlas doesn't currently use a scratch texture (and we would have - // to free up space differently anyways) - // TODO: unlock atlas space when a recycling rectanizer is available + SkASSERT(layer->texture() == fAtlas->getTexture()); + + GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(layer->pictureID())); + SkASSERT(NULL != pictInfo); + pictInfo->fPlotUsage.isEmpty(); // just to silence compiler warnings for the time being + + // TODO: purging from atlas goes here } else { fContext->unlockScratchTexture(layer->texture()); layer->setTexture(NULL, GrIRect16::MakeEmpty()); @@ -247,4 +300,10 @@ void GrLayerCache::purge(const SkPicture* picture) { fLayerHash.remove(key, toBeRemoved[i]); SkDELETE(toBeRemoved[i]); } + + GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(picture->uniqueID())); + if (NULL != pictInfo) { + fPictureHash.remove(PictureKey(picture->uniqueID()), pictInfo); + SkDELETE(pictInfo); + } } diff --git a/src/gpu/GrLayerCache.h b/src/gpu/GrLayerCache.h index 566a738279..347fa232ab 100644 --- a/src/gpu/GrLayerCache.h +++ b/src/gpu/GrLayerCache.h @@ -16,20 +16,29 @@ #include "GrPictureUtils.h" #include "GrRect.h" -class GrGpu; class SkPicture; +// GrPictureInfo stores the atlas plots used by a single picture. A single +// plot may be used to store layers from multiple pictures. +struct GrPictureInfo { +public: + GrPictureInfo(uint32_t pictureID) : fPictureID(pictureID) { } + + uint32_t fPictureID; + + GrAtlas::ClientPlotUsage fPlotUsage; +}; + // GrCachedLayer encapsulates the caching information for a single saveLayer. // // Atlased layers get a ref to the backing GrTexture while non-atlased layers // get a ref to the GrTexture in which they reside. In both cases 'fRect' // contains the layer's extent in its texture. -// -// TODO: can we easily reuse the empty space in the non-atlased GrTexture's? +// Atlased layers also get a pointer to the plot in which they reside. struct GrCachedLayer { public: GrCachedLayer(uint32_t pictureID, int layerID) - : fAtlased(false) { + : fPlot(NULL) { fPictureID = pictureID; fLayerID = layerID; fTexture = NULL; @@ -51,10 +60,15 @@ public: GrTexture* texture() { return fTexture; } const GrIRect16& rect() const { return fRect; } - void setAtlased(bool atlased) { fAtlased = atlased; } - bool isAtlased() const { return fAtlased; } + void setPlot(GrPlot* plot) { + SkASSERT(NULL == fPlot); + fPlot = plot; + } + GrPlot* plot() { return fPlot; } + + bool isAtlased() const { return NULL != fPlot; } - SkDEBUGCODE(void validate(GrTexture* backingTexture) const;) + SkDEBUGCODE(void validate(const GrTexture* backingTexture) const;) private: // ID of the picture of which this layer is a part @@ -69,13 +83,14 @@ private: // non-NULL, that means that the texture is locked in the texture cache. GrTexture* fTexture; - // True if this layer is in an atlas; false otherwise. - bool fAtlased; - // For both atlased and non-atlased layers 'fRect' contains the bound of // the layer in whichever texture it resides. It is empty when 'fTexture' // is NULL. GrIRect16 fRect; + + // For atlased layers, fPlot stores the atlas plot in which the layer rests. + // It is always NULL for non-atlased layers. + GrPlot* fPlot; }; // The GrLayerCache caches pre-computed saveLayers for later rendering. @@ -112,9 +127,19 @@ public: SkDEBUGCODE(void validate() const;) private: + static const int kNumPlotsX = 2; + static const int kNumPlotsY = 2; + GrContext* fContext; // pointer back to owning context SkAutoTDelete<GrAtlas> fAtlas; // TODO: could lazily allocate - GrAtlas::ClientPlotUsage fPlotUsage; + + // We cache this information here (rather then, say, on the owning picture) + // because we want to be able to clean it up as needed (e.g., if a picture + // is leaked and never cleans itself up we still want to be able to + // remove the GrPictureInfo once its layers are purged from all the atlas + // plots). + class PictureKey; + GrTHashTable<GrPictureInfo, PictureKey, 7> fPictureHash; class PictureLayerKey; GrTHashTable<GrCachedLayer, PictureLayerKey, 7> fLayerHash; |