diff options
author | 2014-06-30 08:26:50 -0700 | |
---|---|---|
committer | 2014-06-30 08:26:50 -0700 | |
commit | 952841bf41a81228c23d16c7204b458abe0d7136 (patch) | |
tree | 31a4bff5594b2ea0e582c27b927a8bc9a14f0dc3 /src/gpu/GrLayerCache.cpp | |
parent | a75b0fadbdec4214afec6dd727fd224d34ed164f (diff) |
Begin atlasing
This CL makes it possible for pulled-forward-layers to be atlased. It currently has a couple glaring limitations (which is why it is disabled):
1) the atlased layers cannot be purged nor aged out
2) the texture backing the atlas is not pulled from (or returned to) the resource cache
#1 is on hold until we have a recycling rectanizer
A separate major limitation (the non-atlased layers aren't cached) is blocked until we can transmute entries in the resource cache from scratch to non-scratch while potentially preserving their contents.
Committed: https://skia.googlesource.com/skia/+/55e61f0ef4e5c8c34ac107deaadc9b4ffef3111b
R=bsalomon@google.com
Author: robertphillips@google.com
Review URL: https://codereview.chromium.org/354533004
Diffstat (limited to 'src/gpu/GrLayerCache.cpp')
-rw-r--r-- | src/gpu/GrLayerCache.cpp | 97 |
1 files changed, 85 insertions, 12 deletions
diff --git a/src/gpu/GrLayerCache.cpp b/src/gpu/GrLayerCache.cpp index c20d809062..62c97208cc 100644 --- a/src/gpu/GrLayerCache.cpp +++ b/src/gpu/GrLayerCache.cpp @@ -42,14 +42,23 @@ private: }; GrLayerCache::GrLayerCache(GrContext* context) - : fContext(context) - , fLayerPool(16) { // TODO: may need to increase this later + : fContext(context) { + this->initAtlas(); } GrLayerCache::~GrLayerCache() { + SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray(); + for (int i = 0; i < fLayerHash.count(); ++i) { + this->unlock(layerArray[i]); + } + + fLayerHash.deleteAll(); + + // The atlas only lets go of its texture when the atlas is deleted. + fAtlas.free(); } -void GrLayerCache::init() { +void GrLayerCache::initAtlas() { static const int kAtlasTextureWidth = 1024; static const int kAtlasTextureHeight = 1024; @@ -58,19 +67,31 @@ void GrLayerCache::init() { // The layer cache only gets 1 plot SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight); fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig, + kRenderTarget_GrTextureFlagBit, textureSize, 1, 1, false))); } void GrLayerCache::freeAll() { + SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray(); + for (int i = 0; i < fLayerHash.count(); ++i) { + this->unlock(layerArray[i]); + } + fLayerHash.deleteAll(); + + // 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::contextDestroyed or freeGpuResources. + // TODO: Make GrLayerCache lazily allocate the atlas manager? + this->initAtlas(); } GrCachedLayer* GrLayerCache::createLayer(const SkPicture* picture, int layerID) { - GrCachedLayer* layer = fLayerPool.alloc(); - SkASSERT(picture->uniqueID() != SK_InvalidGenID); - layer->init(picture->uniqueID(), layerID); + + GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (picture->uniqueID(), layerID)); fLayerHash.insert(PictureLayerKey(picture->uniqueID(), layerID), layer); return layer; } @@ -91,19 +112,71 @@ GrCachedLayer* GrLayerCache::findLayerOrCreate(const SkPicture* picture, int lay } bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) { - SkASSERT(NULL == layer->getTexture()); - // This just uses scratch textures and doesn't cache the texture. + if (NULL != layer->texture()) { + // This layer is already locked +#ifdef SK_DEBUG + if (!layer->rect().isEmpty()) { + // It claims to be atlased + SkASSERT(layer->rect().width() == desc.fWidth); + SkASSERT(layer->rect().height() == desc.fHeight); + } +#endif + return true; + } + +#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); + return false; + } +#endif + + // This path always uses a new scratch texture and (thus) doesn't cache anything. // This can yield a lot of re-rendering - layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch)); + layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch), + GrIRect16::MakeEmpty()); return false; } void GrLayerCache::unlock(GrCachedLayer* layer) { - if (NULL == layer || NULL == layer->getTexture()) { + if (NULL == layer || NULL == layer->texture()) { return; } - fContext->unlockScratchTexture(layer->getTexture()); - layer->setTexture(NULL); + // 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 + if (layer->texture() != fAtlas->getTexture()) { + fContext->unlockScratchTexture(layer->texture()); + layer->setTexture(NULL, GrIRect16::MakeEmpty()); + } +} + +void GrLayerCache::purge(const SkPicture* picture) { + // This is somewhat of an abuse of GrTHashTable. We need to find all the + // layers associated with 'picture' but the usual hash calls only look for + // exact key matches. This code peeks into the hash table's innards to + // find all the 'picture'-related layers. + // TODO: use a different data structure for the layer hash? + SkTDArray<GrCachedLayer*> toBeRemoved; + + const SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray(); + for (int i = 0; i < fLayerHash.count(); ++i) { + if (picture->uniqueID() == layerArray[i]->pictureID()) { + *toBeRemoved.append() = layerArray[i]; + } + } + + for (int i = 0; i < toBeRemoved.count(); ++i) { + this->unlock(toBeRemoved[i]); + + PictureLayerKey key(picture->uniqueID(), toBeRemoved[i]->layerID()); + fLayerHash.remove(key, toBeRemoved[i]); + SkDELETE(toBeRemoved[i]); + } } |