aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrLayerCache.cpp87
-rw-r--r--src/gpu/GrLayerCache.h47
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;