| Index: src/gpu/GrLayerCache.cpp | 
| diff --git a/src/gpu/GrLayerCache.cpp b/src/gpu/GrLayerCache.cpp | 
| index c20d8090621cfc3509a4dbd817a5279930a2416e..62c97208cc5be948a1cea66559fc5b6aa26945d7 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]); | 
| +    } | 
| } | 
|  |