aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrLayerCache.cpp
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2014-06-30 08:26:50 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-06-30 08:26:50 -0700
commit952841bf41a81228c23d16c7204b458abe0d7136 (patch)
tree31a4bff5594b2ea0e582c27b927a8bc9a14f0dc3 /src/gpu/GrLayerCache.cpp
parenta75b0fadbdec4214afec6dd727fd224d34ed164f (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.cpp97
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]);
+ }
}