Make GrLayerCache use multiple plots in its atlas
Until we have a recycling Rectanizer the atlas purging must occur at the GrPlot level. This CL breaks the atlas into four plots to give some room for purging (without trashing the entire atlas). This is calved off of (Add atlased layer purging - https://codereview.chromium.org/367073002/) R=jvanverth@google.com Author: robertphillips@google.com Review URL: https://codereview.chromium.org/397873004
This commit is contained in:
parent
a8f774549e
commit
261b8a98dc
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
|
||||
SkDEBUGCODE(void validate(GrTexture* backingTexture) const;)
|
||||
bool isAtlased() const { return NULL != fPlot; }
|
||||
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user