blob: 62c97208cc5be948a1cea66559fc5b6aa26945d7 [file] [log] [blame]
robertphillips@google.come930a072014-04-03 00:34:27 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrAtlas.h"
9#include "GrGpu.h"
10#include "GrLayerCache.h"
11
12/**
13 * PictureLayerKey just wraps a saveLayer's id in the picture for GrTHashTable.
14 */
15class GrLayerCache::PictureLayerKey {
16public:
skia.committer@gmail.coma9157722014-04-03 03:04:26 +000017 PictureLayerKey(uint32_t pictureID, int layerID)
robertphillips@google.come930a072014-04-03 00:34:27 +000018 : fPictureID(pictureID)
19 , fLayerID(layerID) {
20 }
21
22 uint32_t pictureID() const { return fPictureID; }
23 int layerID() const { return fLayerID; }
24
25 uint32_t getHash() const { return (fPictureID << 16) | fLayerID; }
26
commit-bot@chromium.org365cd312014-04-11 15:53:47 +000027 static bool LessThan(const GrCachedLayer& layer, const PictureLayerKey& key) {
robertphillips@google.come930a072014-04-03 00:34:27 +000028 if (layer.pictureID() == key.pictureID()) {
29 return layer.layerID() < key.layerID();
30 }
31
32 return layer.pictureID() < key.pictureID();
33 }
34
commit-bot@chromium.org365cd312014-04-11 15:53:47 +000035 static bool Equals(const GrCachedLayer& layer, const PictureLayerKey& key) {
robertphillips@google.come930a072014-04-03 00:34:27 +000036 return layer.pictureID() == key.pictureID() && layer.layerID() == key.layerID();
37 }
38
39private:
40 uint32_t fPictureID;
41 int fLayerID;
42};
43
robertphillips4ec84da2014-06-24 13:10:43 -070044GrLayerCache::GrLayerCache(GrContext* context)
robertphillips952841b2014-06-30 08:26:50 -070045 : fContext(context) {
46 this->initAtlas();
robertphillips@google.come930a072014-04-03 00:34:27 +000047}
48
49GrLayerCache::~GrLayerCache() {
robertphillips952841b2014-06-30 08:26:50 -070050 SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray();
51 for (int i = 0; i < fLayerHash.count(); ++i) {
52 this->unlock(layerArray[i]);
53 }
54
55 fLayerHash.deleteAll();
56
57 // The atlas only lets go of its texture when the atlas is deleted.
58 fAtlas.free();
robertphillips@google.come930a072014-04-03 00:34:27 +000059}
60
robertphillips952841b2014-06-30 08:26:50 -070061void GrLayerCache::initAtlas() {
robertphillips@google.come930a072014-04-03 00:34:27 +000062 static const int kAtlasTextureWidth = 1024;
63 static const int kAtlasTextureHeight = 1024;
64
robertphillips1d86ee82014-06-24 15:08:49 -070065 SkASSERT(NULL == fAtlas.get());
robertphillips@google.come930a072014-04-03 00:34:27 +000066
67 // The layer cache only gets 1 plot
68 SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
robertphillips1d86ee82014-06-24 15:08:49 -070069 fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig,
robertphillips952841b2014-06-30 08:26:50 -070070 kRenderTarget_GrTextureFlagBit,
robertphillips1d86ee82014-06-24 15:08:49 -070071 textureSize, 1, 1, false)));
robertphillips@google.come930a072014-04-03 00:34:27 +000072}
73
74void GrLayerCache::freeAll() {
robertphillips952841b2014-06-30 08:26:50 -070075 SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray();
76 for (int i = 0; i < fLayerHash.count(); ++i) {
77 this->unlock(layerArray[i]);
78 }
79
robertphillips@google.come930a072014-04-03 00:34:27 +000080 fLayerHash.deleteAll();
robertphillips952841b2014-06-30 08:26:50 -070081
82 // The atlas only lets go of its texture when the atlas is deleted.
robertphillips1d86ee82014-06-24 15:08:49 -070083 fAtlas.free();
robertphillips952841b2014-06-30 08:26:50 -070084 // GrLayerCache always assumes an atlas exists so recreate it. The atlas
85 // lazily allocates a replacement texture so reallocating a new
86 // atlas here won't disrupt a GrContext::contextDestroyed or freeGpuResources.
87 // TODO: Make GrLayerCache lazily allocate the atlas manager?
88 this->initAtlas();
robertphillips@google.come930a072014-04-03 00:34:27 +000089}
90
robertphillips9b14f262014-06-04 05:40:44 -070091GrCachedLayer* GrLayerCache::createLayer(const SkPicture* picture, int layerID) {
robertphillipse462f2b2014-06-29 17:16:27 -070092 SkASSERT(picture->uniqueID() != SK_InvalidGenID);
robertphillips952841b2014-06-30 08:26:50 -070093
94 GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (picture->uniqueID(), layerID));
commit-bot@chromium.org2b4e3702014-04-07 18:26:22 +000095 fLayerHash.insert(PictureLayerKey(picture->uniqueID(), layerID), layer);
robertphillips@google.come930a072014-04-03 00:34:27 +000096 return layer;
97}
98
robertphillips4ec84da2014-06-24 13:10:43 -070099GrCachedLayer* GrLayerCache::findLayer(const SkPicture* picture, int layerID) {
100 SkASSERT(picture->uniqueID() != SK_InvalidGenID);
101 return fLayerHash.find(PictureLayerKey(picture->uniqueID(), layerID));
102}
robertphillips@google.come930a072014-04-03 00:34:27 +0000103
robertphillips9b14f262014-06-04 05:40:44 -0700104GrCachedLayer* GrLayerCache::findLayerOrCreate(const SkPicture* picture, int layerID) {
commit-bot@chromium.org2b4e3702014-04-07 18:26:22 +0000105 SkASSERT(picture->uniqueID() != SK_InvalidGenID);
commit-bot@chromium.org365cd312014-04-11 15:53:47 +0000106 GrCachedLayer* layer = fLayerHash.find(PictureLayerKey(picture->uniqueID(), layerID));
robertphillips@google.come930a072014-04-03 00:34:27 +0000107 if (NULL == layer) {
108 layer = this->createLayer(picture, layerID);
109 }
robertphillips4ec84da2014-06-24 13:10:43 -0700110
robertphillips@google.come930a072014-04-03 00:34:27 +0000111 return layer;
112}
robertphillips4ec84da2014-06-24 13:10:43 -0700113
114bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
robertphillips4ec84da2014-06-24 13:10:43 -0700115
robertphillips952841b2014-06-30 08:26:50 -0700116 if (NULL != layer->texture()) {
117 // This layer is already locked
118#ifdef SK_DEBUG
119 if (!layer->rect().isEmpty()) {
120 // It claims to be atlased
121 SkASSERT(layer->rect().width() == desc.fWidth);
122 SkASSERT(layer->rect().height() == desc.fHeight);
123 }
124#endif
125 return true;
126 }
127
128#if USE_ATLAS
129 SkIPoint16 loc;
130 GrPlot* plot = fAtlas->addToAtlas(&fPlotUsage, desc.fWidth, desc.fHeight, NULL, &loc);
131 if (NULL != plot) {
132 GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY,
133 SkToS16(desc.fWidth), SkToS16(desc.fHeight));
134 layer->setTexture(fAtlas->getTexture(), bounds);
135 return false;
136 }
137#endif
138
139 // This path always uses a new scratch texture and (thus) doesn't cache anything.
robertphillips4ec84da2014-06-24 13:10:43 -0700140 // This can yield a lot of re-rendering
robertphillips952841b2014-06-30 08:26:50 -0700141 layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch),
142 GrIRect16::MakeEmpty());
robertphillips4ec84da2014-06-24 13:10:43 -0700143 return false;
144}
145
146void GrLayerCache::unlock(GrCachedLayer* layer) {
robertphillips952841b2014-06-30 08:26:50 -0700147 if (NULL == layer || NULL == layer->texture()) {
robertphillips4ec84da2014-06-24 13:10:43 -0700148 return;
149 }
150
robertphillips952841b2014-06-30 08:26:50 -0700151 // The atlas doesn't currently use a scratch texture (and we would have
152 // to free up space differently anyways)
153 // TODO: unlock atlas space when a recycling rectanizer is available
154 if (layer->texture() != fAtlas->getTexture()) {
155 fContext->unlockScratchTexture(layer->texture());
156 layer->setTexture(NULL, GrIRect16::MakeEmpty());
157 }
158}
159
160void GrLayerCache::purge(const SkPicture* picture) {
161 // This is somewhat of an abuse of GrTHashTable. We need to find all the
162 // layers associated with 'picture' but the usual hash calls only look for
163 // exact key matches. This code peeks into the hash table's innards to
164 // find all the 'picture'-related layers.
165 // TODO: use a different data structure for the layer hash?
166 SkTDArray<GrCachedLayer*> toBeRemoved;
167
168 const SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray();
169 for (int i = 0; i < fLayerHash.count(); ++i) {
170 if (picture->uniqueID() == layerArray[i]->pictureID()) {
171 *toBeRemoved.append() = layerArray[i];
172 }
173 }
174
175 for (int i = 0; i < toBeRemoved.count(); ++i) {
176 this->unlock(toBeRemoved[i]);
177
178 PictureLayerKey key(picture->uniqueID(), toBeRemoved[i]->layerID());
179 fLayerHash.remove(key, toBeRemoved[i]);
180 SkDELETE(toBeRemoved[i]);
181 }
robertphillips4ec84da2014-06-24 13:10:43 -0700182}