Discard atlas after every MultiPictureDraw::draw
This is intended to prevent ghosting on tiled architectures.
This CL also defers creation of the atlas (and its texture) until it is actually needed.
Committed: https://skia.googlesource.com/skia/+/6d5b5455743414ddb11d2b8c1fe9d7959f2b853d
Review URL: https://codereview.chromium.org/678403002
diff --git a/src/core/SkMultiPictureDraw.cpp b/src/core/SkMultiPictureDraw.cpp
index b59b63b..2690e8f 100644
--- a/src/core/SkMultiPictureDraw.cpp
+++ b/src/core/SkMultiPictureDraw.cpp
@@ -182,6 +182,9 @@
#ifndef SK_IGNORE_GPU_LAYER_HOISTING
GrLayerHoister::UnlockLayers(context, atlasedNeedRendering);
GrLayerHoister::UnlockLayers(context, atlasedRecycled);
+#if !GR_CACHE_HOISTED_LAYERS
+ GrLayerHoister::PurgeCache(context);
+#endif
#endif
}
diff --git a/src/gpu/GrLayerCache.cpp b/src/gpu/GrLayerCache.cpp
index d897c9d..a24c9e0 100644
--- a/src/gpu/GrLayerCache.cpp
+++ b/src/gpu/GrLayerCache.cpp
@@ -81,7 +81,6 @@
GrLayerCache::GrLayerCache(GrContext* context)
: fContext(context) {
- this->initAtlas();
memset(fPlotLocks, 0, sizeof(fPlotLocks));
}
@@ -120,11 +119,6 @@
// The atlas only lets go of its texture when the atlas is deleted.
fAtlas.free();
- // GrLayerCache always assumes an atlas exists so recreate it. The atlas
- // lazily allocates a replacement texture so reallocating a new
- // atlas here won't disrupt a GrContext::abandonContext or freeGpuResources.
- // TODO: Make GrLayerCache lazily allocate the atlas manager?
- this->initAtlas();
}
GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID,
@@ -164,12 +158,13 @@
bool GrLayerCache::tryToAtlas(GrCachedLayer* layer,
const GrSurfaceDesc& desc,
bool* needsRendering) {
- SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
+ SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : NULL, layer);)
SkASSERT(PlausiblyAtlasable(desc.fWidth, desc.fHeight));
if (layer->locked()) {
// This layer is already locked
+ SkASSERT(fAtlas);
SkASSERT(layer->isAtlased());
SkASSERT(layer->rect().width() == desc.fWidth);
SkASSERT(layer->rect().height() == desc.fHeight);
@@ -178,12 +173,19 @@
}
if (layer->isAtlased()) {
+ SkASSERT(fAtlas);
// Hooray it is still in the atlas - make sure it stays there
layer->setLocked(true);
this->incPlotLock(layer->plot()->id());
*needsRendering = false;
return true;
} else {
+ if (!fAtlas) {
+ this->initAtlas();
+ if (!fAtlas) {
+ return false;
+ }
+ }
// Not in the atlas - will it fit?
GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
if (NULL == pictInfo) {
@@ -243,7 +245,7 @@
}
void GrLayerCache::unlock(GrCachedLayer* layer) {
- SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
+ SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : NULL, layer);)
if (NULL == layer || !layer->locked()) {
// invalid or not locked
@@ -256,7 +258,7 @@
this->decPlotLock(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.
-#if DISABLE_CACHING
+#if !GR_CACHE_HOISTED_LAYERS
// This testing code aggressively removes the atlased layers. This
// can be used to separate the performance contribution of less
// render target pingponging from that due to the re-use of cached layers
@@ -285,7 +287,7 @@
for (; !iter.done(); ++iter) {
const GrCachedLayer* layer = &(*iter);
- layer->validate(fAtlas->getTexture());
+ layer->validate(fAtlas.get() ? fAtlas->getTexture() : NULL);
const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
if (!pictInfo) {
@@ -355,6 +357,7 @@
bool GrLayerCache::purgePlot() {
SkDEBUGCODE(GrAutoValidateCache avc(this);)
+ SkASSERT(fAtlas);
GrAtlas::PlotIter iter;
GrPlot* plot;
@@ -409,7 +412,12 @@
plot->resetRects();
}
+#if !GR_CACHE_HOISTED_LAYERS
void GrLayerCache::purgeAll() {
+ if (!fAtlas) {
+ return;
+ }
+
GrAtlas::PlotIter iter;
GrPlot* plot;
for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
@@ -419,7 +427,10 @@
this->purgePlot(plot);
}
+
+ fContext->discardRenderTarget(fAtlas->getTexture()->asRenderTarget());
}
+#endif
class GrPictureDeletionListener : public SkPicture::DeletionListener {
virtual void onDeletion(uint32_t pictureID) SK_OVERRIDE{
@@ -448,12 +459,14 @@
#ifdef SK_DEVELOPER
void GrLayerCache::writeLayersToDisk(const SkString& dirName) {
- GrTexture* atlasTexture = fAtlas->getTexture();
- if (NULL != atlasTexture) {
- SkString fileName(dirName);
- fileName.append("\\atlas.png");
+ if (fAtlas) {
+ GrTexture* atlasTexture = fAtlas->getTexture();
+ if (NULL != atlasTexture) {
+ SkString fileName(dirName);
+ fileName.append("\\atlas.png");
- atlasTexture->surfacePriv().savePixels(fileName.c_str());
+ atlasTexture->surfacePriv().savePixels(fileName.c_str());
+ }
}
SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
diff --git a/src/gpu/GrLayerCache.h b/src/gpu/GrLayerCache.h
index c772332..632cd00 100644
--- a/src/gpu/GrLayerCache.h
+++ b/src/gpu/GrLayerCache.h
@@ -18,6 +18,9 @@
class SkPicture;
+// Set to 0 to disable caching of hoisted layers
+#define GR_CACHE_HOISTED_LAYERS 0
+
// The layer cache listens for these messages to purge picture-related resources.
struct GrPictureDeletedMessage {
uint32_t pictureID;
@@ -249,6 +252,10 @@
return width <= kPlotWidth && height <= kPlotHeight;
}
+#if !GR_CACHE_HOISTED_LAYERS
+ void purgeAll();
+#endif
+
private:
static const int kAtlasTextureWidth = 1024;
static const int kAtlasTextureHeight = 1024;
@@ -291,8 +298,6 @@
const SkIRect& bounds, const SkMatrix& ctm,
const SkPaint* paint);
- void purgeAll();
-
// Remove all the layers (and unlock any resources) associated with 'pictureID'
void purge(uint32_t pictureID);
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp
index 1f7ce41..0057671 100644
--- a/src/gpu/GrLayerHoister.cpp
+++ b/src/gpu/GrLayerHoister.cpp
@@ -314,13 +314,16 @@
layerCache->removeUse(layers[i].fLayer);
}
-#if DISABLE_CACHING
+ SkDEBUGCODE(layerCache->validate();)
+}
+
+void GrLayerHoister::PurgeCache(GrContext* context) {
+#if !GR_CACHE_HOISTED_LAYERS
+ GrLayerCache* layerCache = context->getLayerCache();
+
// This code completely clears out the atlas. It is required when
// caching is disabled so the atlas doesn't fill up and force more
// free floating layers
layerCache->purgeAll();
#endif
-
- SkDEBUGCODE(layerCache->validate();)
}
-
diff --git a/src/gpu/GrLayerHoister.h b/src/gpu/GrLayerHoister.h
index 82dd967..c3a451d 100644
--- a/src/gpu/GrLayerHoister.h
+++ b/src/gpu/GrLayerHoister.h
@@ -87,6 +87,12 @@
@param layers Unneeded layers in the atlas
*/
static void UnlockLayers(GrContext* context, const SkTDArray<GrHoistedLayer>& layers);
+
+ /** Forceably remove all cached layers and release the atlas. Useful for debugging and timing.
+ This is only functional when GR_CACHE_HOISTED_LAYERS is set to 1 in GrLayerCache.h
+ @param context Owner of the layer cache (and thus the layers)
+ */
+ static void PurgeCache(GrContext* context);
};
#endif