Add plot-based purging to GrLayerCache
This CL allows a GrPlot full of atlased layer to be purged from the atlas to make room for new layers. R=jvanverth@google.com Author: robertphillips@google.com Review URL: https://codereview.chromium.org/411703003
This commit is contained in:
parent
e7416bfc98
commit
320c92380f
@ -81,6 +81,12 @@ public:
|
||||
public:
|
||||
bool isEmpty() const { return 0 == fPlots.count(); }
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
bool contains(const GrPlot* plot) const {
|
||||
return fPlots.contains(const_cast<GrPlot*>(plot));
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
SkTDArray<GrPlot*> fPlots;
|
||||
|
||||
@ -112,6 +118,18 @@ public:
|
||||
|
||||
void uploadPlotsToTexture();
|
||||
|
||||
enum IterOrder {
|
||||
kLRUFirst_IterOrder,
|
||||
kMRUFirst_IterOrder
|
||||
};
|
||||
|
||||
typedef GrPlotList::Iter PlotIter;
|
||||
GrPlot* iterInit(PlotIter* iter, IterOrder order) {
|
||||
return iter->init(fPlotList, kLRUFirst_IterOrder == order
|
||||
? GrPlotList::Iter::kTail_IterStart
|
||||
: GrPlotList::Iter::kHead_IterStart);
|
||||
}
|
||||
|
||||
private:
|
||||
void makeMRU(GrPlot* plot);
|
||||
|
||||
|
@ -27,6 +27,7 @@ void GrCachedLayer::validate(const GrTexture* backingTexture) const {
|
||||
} else {
|
||||
SkASSERT(fRect.isEmpty());
|
||||
SkASSERT(NULL == fPlot);
|
||||
SkASSERT(!fLocked); // layers without a texture cannot be locked
|
||||
}
|
||||
|
||||
if (NULL != fPlot) {
|
||||
@ -35,6 +36,13 @@ void GrCachedLayer::validate(const GrTexture* backingTexture) const {
|
||||
SkASSERT(NULL != fTexture && backingTexture == fTexture);
|
||||
SkASSERT(!fRect.isEmpty());
|
||||
}
|
||||
|
||||
if (fLocked) {
|
||||
// If a layer is locked it must have a texture (though it need not be
|
||||
// the atlas-backing texture) and occupy some space.
|
||||
SkASSERT(NULL != fTexture);
|
||||
SkASSERT(!fRect.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
class GrAutoValidateLayer : ::SkNoncopyable {
|
||||
@ -65,6 +73,7 @@ private:
|
||||
GrLayerCache::GrLayerCache(GrContext* context)
|
||||
: fContext(context) {
|
||||
this->initAtlas();
|
||||
memset(fPlotLocks, 0, sizeof(fPlotLocks));
|
||||
}
|
||||
|
||||
GrLayerCache::~GrLayerCache() {
|
||||
@ -81,12 +90,8 @@ GrLayerCache::~GrLayerCache() {
|
||||
}
|
||||
|
||||
void GrLayerCache::initAtlas() {
|
||||
static const int kAtlasTextureWidth = 1024;
|
||||
static const int kAtlasTextureHeight = 1024;
|
||||
|
||||
SkASSERT(NULL == fAtlas.get());
|
||||
|
||||
// The layer cache only gets 1 plot
|
||||
SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
|
||||
fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig,
|
||||
kRenderTarget_GrTextureFlagBit,
|
||||
@ -138,7 +143,7 @@ GrCachedLayer* GrLayerCache::findLayerOrCreate(const SkPicture* picture, int lay
|
||||
bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
|
||||
SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
|
||||
|
||||
if (NULL != layer->texture()) {
|
||||
if (layer->locked()) {
|
||||
// This layer is already locked
|
||||
#ifdef SK_DEBUG
|
||||
if (layer->isAtlased()) {
|
||||
@ -151,7 +156,13 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
|
||||
}
|
||||
|
||||
#if USE_ATLAS
|
||||
{
|
||||
if (layer->isAtlased()) {
|
||||
// Hooray it is still in the atlas - make sure it stays there
|
||||
layer->setLocked(true);
|
||||
fPlotLocks[layer->plot()->id()]++;
|
||||
return true;
|
||||
} else if (PlausiblyAtlasable(desc.fWidth, desc.fHeight)) {
|
||||
// Not in the atlas - will it fit?
|
||||
GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
|
||||
if (NULL == pictInfo) {
|
||||
pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID()));
|
||||
@ -159,18 +170,30 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
|
||||
}
|
||||
|
||||
SkIPoint16 loc;
|
||||
for (int i = 0; i < 2; ++i) { // extra pass in case we fail to add but are able to purge
|
||||
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) {
|
||||
// The layer was successfully added to the atlas
|
||||
GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY,
|
||||
SkToS16(desc.fWidth), SkToS16(desc.fHeight));
|
||||
SkToS16(desc.fWidth),
|
||||
SkToS16(desc.fHeight));
|
||||
layer->setTexture(fAtlas->getTexture(), bounds);
|
||||
layer->setPlot(plot);
|
||||
layer->setLocked(true);
|
||||
fPlotLocks[layer->plot()->id()]++;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The layer was rejected by the atlas (even though we know it is
|
||||
// plausibly atlas-able). See if a plot can be purged and try again.
|
||||
if (!this->purgePlot()) {
|
||||
break; // We weren't able to purge any plots
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -179,35 +202,69 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
|
||||
// This can yield a lot of re-rendering
|
||||
layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch),
|
||||
GrIRect16::MakeWH(SkToS16(desc.fWidth), SkToS16(desc.fHeight)));
|
||||
layer->setLocked(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
void GrLayerCache::unlock(GrCachedLayer* layer) {
|
||||
SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
|
||||
|
||||
if (NULL == layer || NULL == layer->texture()) {
|
||||
if (NULL == layer || !layer->locked()) {
|
||||
// invalid or not locked
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer->isAtlased()) {
|
||||
SkASSERT(layer->texture() == fAtlas->getTexture());
|
||||
const int plotID = layer->plot()->id();
|
||||
|
||||
GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
|
||||
SkASSERT(NULL != pictInfo);
|
||||
pictInfo->fPlotUsage.isEmpty(); // just to silence compiler warnings for the time being
|
||||
|
||||
// TODO: purging from atlas goes here
|
||||
SkASSERT(fPlotLocks[plotID] > 0);
|
||||
fPlotLocks[plotID]--;
|
||||
// At this point we could aggressively clear out un-locked plots but
|
||||
// by delaying we may be able to reuse some of the atlased layers later.
|
||||
} else {
|
||||
fContext->unlockScratchTexture(layer->texture());
|
||||
layer->setTexture(NULL, GrIRect16::MakeEmpty());
|
||||
}
|
||||
|
||||
layer->setLocked(false);
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void GrLayerCache::validate() const {
|
||||
int plotLocks[kNumPlotsX * kNumPlotsY];
|
||||
memset(plotLocks, 0, sizeof(plotLocks));
|
||||
|
||||
SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::ConstIter iter(&fLayerHash);
|
||||
for (; !iter.done(); ++iter) {
|
||||
(*iter).validate(fAtlas->getTexture());
|
||||
const GrCachedLayer* layer = &(*iter);
|
||||
|
||||
layer->validate(fAtlas->getTexture());
|
||||
|
||||
const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
|
||||
if (NULL != pictInfo) {
|
||||
// In aggressive cleanup mode a picture info should only exist if
|
||||
// it has some atlased layers
|
||||
SkASSERT(!pictInfo->fPlotUsage.isEmpty());
|
||||
} else {
|
||||
// If there is no picture info for this layer then all of its
|
||||
// layers should be non-atlased.
|
||||
SkASSERT(!layer->isAtlased());
|
||||
}
|
||||
|
||||
if (NULL != layer->plot()) {
|
||||
SkASSERT(NULL != pictInfo);
|
||||
SkASSERT(pictInfo->fPictureID == layer->pictureID());
|
||||
|
||||
SkASSERT(pictInfo->fPlotUsage.contains(layer->plot()));
|
||||
|
||||
if (layer->locked()) {
|
||||
plotLocks[layer->plot()->id()]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < kNumPlotsX*kNumPlotsY; ++i) {
|
||||
SkASSERT(plotLocks[i] == fPlotLocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,6 +309,53 @@ void GrLayerCache::purge(uint32_t pictureID) {
|
||||
}
|
||||
}
|
||||
|
||||
bool GrLayerCache::purgePlot() {
|
||||
SkDEBUGCODE(GrAutoValidateCache avc(this);)
|
||||
|
||||
GrAtlas::PlotIter iter;
|
||||
GrPlot* plot;
|
||||
for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
|
||||
NULL != plot;
|
||||
plot = iter.prev()) {
|
||||
if (fPlotLocks[plot->id()] > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We need to find all the layers in 'plot' and remove them.
|
||||
SkTDArray<GrCachedLayer*> toBeRemoved;
|
||||
|
||||
SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
|
||||
for (; !iter.done(); ++iter) {
|
||||
if (plot == (*iter).plot()) {
|
||||
*toBeRemoved.append() = &(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < toBeRemoved.count(); ++i) {
|
||||
SkASSERT(!toBeRemoved[i]->locked());
|
||||
|
||||
GrPictureInfo* pictInfo = fPictureHash.find(toBeRemoved[i]->pictureID());
|
||||
SkASSERT(NULL != pictInfo);
|
||||
|
||||
GrAtlas::RemovePlot(&pictInfo->fPlotUsage, plot);
|
||||
|
||||
// Aggressively remove layers and, if now totally uncached, picture info
|
||||
fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
|
||||
SkDELETE(toBeRemoved[i]);
|
||||
|
||||
if (pictInfo->fPlotUsage.isEmpty()) {
|
||||
fPictureHash.remove(pictInfo->fPictureID);
|
||||
SkDELETE(pictInfo);
|
||||
}
|
||||
}
|
||||
|
||||
plot->resetRects();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class GrPictureDeletionListener : public SkPicture::DeletionListener {
|
||||
virtual void onDeletion(uint32_t pictureID) SK_OVERRIDE{
|
||||
const GrPictureDeletedMessage message = { pictureID };
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#define USE_ATLAS 0
|
||||
|
||||
#include "GrAllocPool.h"
|
||||
#include "GrAtlas.h"
|
||||
#include "GrPictureUtils.h"
|
||||
#include "GrRect.h"
|
||||
@ -47,6 +46,9 @@ public:
|
||||
// get a ref to the GrTexture in which they reside. In both cases 'fRect'
|
||||
// contains the layer's extent in its texture.
|
||||
// Atlased layers also get a pointer to the plot in which they reside.
|
||||
// For non-atlased layers the lock field just corresponds to locking in
|
||||
// the resource cache. For atlased layers it implements an additional level
|
||||
// of locking to allow atlased layers to be reused multiple times.
|
||||
struct GrCachedLayer {
|
||||
public:
|
||||
// For SkTDynamicHash
|
||||
@ -77,7 +79,8 @@ public:
|
||||
: fKey(pictureID, layerID)
|
||||
, fTexture(NULL)
|
||||
, fRect(GrIRect16::MakeEmpty())
|
||||
, fPlot(NULL) {
|
||||
, fPlot(NULL)
|
||||
, fLocked(false) {
|
||||
SkASSERT(SK_InvalidGenID != pictureID && layerID >= 0);
|
||||
}
|
||||
|
||||
@ -104,14 +107,17 @@ public:
|
||||
|
||||
bool isAtlased() const { return NULL != fPlot; }
|
||||
|
||||
void setLocked(bool locked) { fLocked = locked; }
|
||||
bool locked() const { return fLocked; }
|
||||
|
||||
SkDEBUGCODE(const GrPlot* plot() const { return fPlot; })
|
||||
SkDEBUGCODE(void validate(const GrTexture* backingTexture) const;)
|
||||
|
||||
private:
|
||||
const Key fKey;
|
||||
|
||||
// fTexture is a ref on the atlasing texture for atlased layers and a
|
||||
// ref on a GrTexture for non-atlased textures. In both cases, if this is
|
||||
// non-NULL, that means that the texture is locked in the texture cache.
|
||||
// ref on a GrTexture for non-atlased textures.
|
||||
GrTexture* fTexture;
|
||||
|
||||
// For both atlased and non-atlased layers 'fRect' contains the bound of
|
||||
@ -122,6 +128,14 @@ private:
|
||||
// For atlased layers, fPlot stores the atlas plot in which the layer rests.
|
||||
// It is always NULL for non-atlased layers.
|
||||
GrPlot* fPlot;
|
||||
|
||||
// For non-atlased layers 'fLocked' should always match "NULL != fTexture".
|
||||
// (i.e., if there is a texture it is locked).
|
||||
// For atlased layers, 'fLocked' is true if the layer is in a plot and
|
||||
// actively required for rendering. If the layer is in a plot but not
|
||||
// actively required for rendering, then 'fLocked' is false. If the
|
||||
// layer isn't in a plot then is can never be locked.
|
||||
bool fLocked;
|
||||
};
|
||||
|
||||
// The GrLayerCache caches pre-computed saveLayers for later rendering.
|
||||
@ -161,9 +175,15 @@ public:
|
||||
SkDEBUGCODE(void validate() const;)
|
||||
|
||||
private:
|
||||
static const int kAtlasTextureWidth = 1024;
|
||||
static const int kAtlasTextureHeight = 1024;
|
||||
|
||||
static const int kNumPlotsX = 2;
|
||||
static const int kNumPlotsY = 2;
|
||||
|
||||
static const int kPlotWidth = kAtlasTextureWidth / kNumPlotsX;
|
||||
static const int kPlotHeight = kAtlasTextureHeight / kNumPlotsY;
|
||||
|
||||
GrContext* fContext; // pointer back to owning context
|
||||
SkAutoTDelete<GrAtlas> fAtlas; // TODO: could lazily allocate
|
||||
|
||||
@ -180,12 +200,28 @@ private:
|
||||
|
||||
SkAutoTUnref<SkPicture::DeletionListener> fDeletionListener;
|
||||
|
||||
// This implements a plot-centric locking mechanism (since the atlas
|
||||
// backing texture is always locked). Each layer that is locked (i.e.,
|
||||
// needed for the current rendering) in a plot increments the plot lock
|
||||
// count for that plot. Similarly, once a rendering is complete all the
|
||||
// layers used in it decrement the lock count for the used plots.
|
||||
// Plots with a 0 lock count are open for recycling/purging.
|
||||
int fPlotLocks[kNumPlotsX * kNumPlotsY];
|
||||
|
||||
void initAtlas();
|
||||
GrCachedLayer* createLayer(const SkPicture* picture, int layerID);
|
||||
|
||||
// Remove all the layers (and unlock any resources) associated with 'pictureID'
|
||||
void purge(uint32_t pictureID);
|
||||
|
||||
static bool PlausiblyAtlasable(int width, int height) {
|
||||
return width <= kPlotWidth && height <= kPlotHeight;
|
||||
}
|
||||
|
||||
// Try to find a purgeable plot and clear it out. Return true if a plot
|
||||
// was purged; false otherwise.
|
||||
bool purgePlot();
|
||||
|
||||
// for testing
|
||||
friend class TestingAccess;
|
||||
int numLayers() const { return fLayerHash.count(); }
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "SkTLazy.h"
|
||||
#include "SkUtils.h"
|
||||
#include "SkVertState.h"
|
||||
#include "SkXfermode.h"
|
||||
#include "SkErrorInternals.h"
|
||||
|
||||
#define CACHE_COMPATIBLE_DEVICE_TEXTURES 1
|
||||
@ -2023,6 +2024,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* pi
|
||||
// TODO: ensure none of the atlased layers contain a clear call!
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorTRANSPARENT);
|
||||
paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref();
|
||||
canvas->drawRect(bound, paint);
|
||||
} else {
|
||||
canvas->clear(SK_ColorTRANSPARENT);
|
||||
|
@ -13,8 +13,6 @@
|
||||
#include "SkPictureRecorder.h"
|
||||
#include "Test.h"
|
||||
|
||||
static const int kNumLayers = 5;
|
||||
|
||||
class TestingAccess {
|
||||
public:
|
||||
static int NumLayers(GrLayerCache* cache) {
|
||||
@ -28,31 +26,53 @@ public:
|
||||
// Add several layers to the cache
|
||||
static void create_layers(skiatest::Reporter* reporter,
|
||||
GrLayerCache* cache,
|
||||
const SkPicture& picture) {
|
||||
GrCachedLayer* layers[kNumLayers];
|
||||
const SkPicture& picture,
|
||||
int numToAdd,
|
||||
int idOffset) {
|
||||
|
||||
for (int i = 0; i < kNumLayers; ++i) {
|
||||
layers[i] = cache->findLayerOrCreate(&picture, i);
|
||||
REPORTER_ASSERT(reporter, NULL != layers[i]);
|
||||
GrCachedLayer* layer = cache->findLayer(&picture, i);
|
||||
REPORTER_ASSERT(reporter, layer == layers[i]);
|
||||
for (int i = 0; i < numToAdd; ++i) {
|
||||
GrCachedLayer* layer = cache->findLayerOrCreate(&picture, idOffset+i);
|
||||
REPORTER_ASSERT(reporter, NULL != layer);
|
||||
GrCachedLayer* temp = cache->findLayer(&picture, idOffset+i);
|
||||
REPORTER_ASSERT(reporter, temp == layer);
|
||||
|
||||
REPORTER_ASSERT(reporter, TestingAccess::NumLayers(cache) == i + 1);
|
||||
REPORTER_ASSERT(reporter, TestingAccess::NumLayers(cache) == idOffset + i + 1);
|
||||
|
||||
REPORTER_ASSERT(reporter, picture.uniqueID() == layers[i]->pictureID());
|
||||
REPORTER_ASSERT(reporter, layers[i]->layerID() == i);
|
||||
REPORTER_ASSERT(reporter, NULL == layers[i]->texture());
|
||||
REPORTER_ASSERT(reporter, !layers[i]->isAtlased());
|
||||
REPORTER_ASSERT(reporter, picture.uniqueID() == layer->pictureID());
|
||||
REPORTER_ASSERT(reporter, layer->layerID() == idOffset + i);
|
||||
REPORTER_ASSERT(reporter, NULL == layer->texture());
|
||||
REPORTER_ASSERT(reporter, !layer->isAtlased());
|
||||
}
|
||||
|
||||
cache->trackPicture(&picture);
|
||||
}
|
||||
|
||||
static void lock_layer(skiatest::Reporter* reporter,
|
||||
GrLayerCache* cache,
|
||||
GrCachedLayer* layer) {
|
||||
// Make the layer 512x512 (so it can be atlased)
|
||||
GrTextureDesc desc;
|
||||
desc.fWidth = 512;
|
||||
desc.fHeight = 512;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
bool foundInCache = cache->lock(layer, desc);
|
||||
REPORTER_ASSERT(reporter, !foundInCache);
|
||||
|
||||
foundInCache = cache->lock(layer, desc);
|
||||
REPORTER_ASSERT(reporter, foundInCache);
|
||||
|
||||
REPORTER_ASSERT(reporter, NULL != layer->texture());
|
||||
REPORTER_ASSERT(reporter, layer->locked());
|
||||
}
|
||||
|
||||
// This test case exercises the public API of the GrLayerCache class.
|
||||
// In particular it checks its interaction with the resource cache (w.r.t.
|
||||
// locking & unlocking textures).
|
||||
// TODO: need to add checks on VRAM usage!
|
||||
DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
static const int kInitialNumLayers = 5;
|
||||
|
||||
for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
|
||||
GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
|
||||
|
||||
@ -72,24 +92,14 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
|
||||
GrLayerCache cache(context);
|
||||
|
||||
create_layers(reporter, &cache, *picture);
|
||||
create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
|
||||
|
||||
// Lock the layers making them all 512x512
|
||||
GrTextureDesc desc;
|
||||
desc.fWidth = 512;
|
||||
desc.fHeight = 512;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
for (int i = 0; i < kNumLayers; ++i) {
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
GrCachedLayer* layer = cache.findLayer(picture, i);
|
||||
REPORTER_ASSERT(reporter, NULL != layer);
|
||||
|
||||
bool foundInCache = cache.lock(layer, desc);
|
||||
REPORTER_ASSERT(reporter, !foundInCache);
|
||||
foundInCache = cache.lock(layer, desc);
|
||||
REPORTER_ASSERT(reporter, foundInCache);
|
||||
lock_layer(reporter, &cache, layer);
|
||||
|
||||
REPORTER_ASSERT(reporter, NULL != layer->texture());
|
||||
#if USE_ATLAS
|
||||
// The first 4 layers should be in the atlas (and thus have non-empty
|
||||
// rects)
|
||||
@ -97,6 +107,7 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
REPORTER_ASSERT(reporter, layer->isAtlased());
|
||||
} else {
|
||||
#endif
|
||||
// The 5th layer couldn't fit in the atlas
|
||||
REPORTER_ASSERT(reporter, !layer->isAtlased());
|
||||
#if USE_ATLAS
|
||||
}
|
||||
@ -104,25 +115,26 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
}
|
||||
|
||||
// Unlock the textures
|
||||
for (int i = 0; i < kNumLayers; ++i) {
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
GrCachedLayer* layer = cache.findLayer(picture, i);
|
||||
REPORTER_ASSERT(reporter, NULL != layer);
|
||||
|
||||
cache.unlock(layer);
|
||||
}
|
||||
|
||||
for (int i = 0; i < kNumLayers; ++i) {
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
GrCachedLayer* layer = cache.findLayer(picture, i);
|
||||
REPORTER_ASSERT(reporter, NULL != layer);
|
||||
|
||||
REPORTER_ASSERT(reporter, !layer->locked());
|
||||
#if USE_ATLAS
|
||||
// The first 4 layers should be in the atlas (and thus do not
|
||||
// currently unlock). The final layer should be unlocked.
|
||||
// The first 4 layers should still be in the atlas.
|
||||
if (i < 4) {
|
||||
REPORTER_ASSERT(reporter, NULL != layer->texture());
|
||||
REPORTER_ASSERT(reporter, layer->isAtlased());
|
||||
} else {
|
||||
#endif
|
||||
// The final layer should be unlocked.
|
||||
REPORTER_ASSERT(reporter, NULL == layer->texture());
|
||||
REPORTER_ASSERT(reporter, !layer->isAtlased());
|
||||
#if USE_ATLAS
|
||||
@ -130,6 +142,41 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
// Add an additional layer. Since all the layers are unlocked this
|
||||
// will force out the first atlased layer
|
||||
create_layers(reporter, &cache, *picture, 1, kInitialNumLayers);
|
||||
GrCachedLayer* layer = cache.findLayer(picture, kInitialNumLayers);
|
||||
REPORTER_ASSERT(reporter, NULL != layer);
|
||||
|
||||
lock_layer(reporter, &cache, layer);
|
||||
cache.unlock(layer);
|
||||
}
|
||||
|
||||
for (int i = 0; i < kInitialNumLayers+1; ++i) {
|
||||
GrCachedLayer* layer = cache.findLayer(picture, i);
|
||||
#if USE_ATLAS
|
||||
// 3 old layers plus the new one should be in the atlas.
|
||||
if (1 == i || 2 == i || 3 == i || 5 == i) {
|
||||
REPORTER_ASSERT(reporter, NULL != layer);
|
||||
REPORTER_ASSERT(reporter, !layer->locked());
|
||||
REPORTER_ASSERT(reporter, NULL != layer->texture());
|
||||
REPORTER_ASSERT(reporter, layer->isAtlased());
|
||||
} else if (4 == i) {
|
||||
#endif
|
||||
// The one that was never atlased should still be around
|
||||
REPORTER_ASSERT(reporter, NULL != layer);
|
||||
|
||||
REPORTER_ASSERT(reporter, NULL == layer->texture());
|
||||
REPORTER_ASSERT(reporter, !layer->isAtlased());
|
||||
#if USE_ATLAS
|
||||
} else {
|
||||
// The one bumped out of the atlas (i.e., 0) should be gone
|
||||
REPORTER_ASSERT(reporter, NULL == layer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Free them all SkGpuDevice-style. This will not free up the
|
||||
// atlas' texture but will eliminate all the layers.
|
||||
@ -142,7 +189,7 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
// Test out the GrContext-style purge. This should remove all the layers
|
||||
// and the atlas.
|
||||
// Re-create the layers
|
||||
create_layers(reporter, &cache, *picture);
|
||||
create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
|
||||
|
||||
// Free them again GrContext-style. This should free up everything.
|
||||
cache.freeAll();
|
||||
@ -153,7 +200,7 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
//--------------------------------------------------------------------
|
||||
// Test out the MessageBus-style purge. This will not free the atlas
|
||||
// but should eliminate the free-floating layers.
|
||||
create_layers(reporter, &cache, *picture);
|
||||
create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
|
||||
|
||||
picture.reset(NULL);
|
||||
cache.processDeletedPictures();
|
||||
|
Loading…
Reference in New Issue
Block a user