OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrAtlas.h" | 8 #include "GrAtlas.h" |
9 #include "GrGpu.h" | 9 #include "GrGpu.h" |
10 #include "GrLayerCache.h" | 10 #include "GrLayerCache.h" |
11 | 11 |
12 /** | |
13 * PictureLayerKey just wraps a saveLayer's id in a picture for GrTHashTable. | |
14 */ | |
15 class GrLayerCache::PictureLayerKey { | |
16 public: | |
17 PictureLayerKey(uint32_t pictureID, int layerID) | |
18 : 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 | |
27 static bool LessThan(const GrCachedLayer& layer, const PictureLayerKey& key) { | |
28 if (layer.pictureID() == key.pictureID()) { | |
29 return layer.layerID() < key.layerID(); | |
30 } | |
31 | |
32 return layer.pictureID() < key.pictureID(); | |
33 } | |
34 | |
35 static bool Equals(const GrCachedLayer& layer, const PictureLayerKey& key) { | |
36 return layer.pictureID() == key.pictureID() && layer.layerID() == key.la yerID(); | |
37 } | |
38 | |
39 private: | |
40 uint32_t fPictureID; | |
41 int fLayerID; | |
42 }; | |
43 | |
44 /** | |
45 * PictureKey just wraps a picture's unique ID for GrTHashTable. It is used to | |
46 * look up a picture's GrPictureInfo (i.e., its GrPlot usage). | |
47 */ | |
48 class GrLayerCache::PictureKey { | |
49 public: | |
50 PictureKey(uint32_t pictureID) : fPictureID(pictureID) { } | |
51 | |
52 uint32_t pictureID() const { return fPictureID; } | |
53 | |
54 uint32_t getHash() const { return fPictureID; } | |
55 | |
56 static bool LessThan(const GrPictureInfo& pictInfo, const PictureKey& key) { | |
57 return pictInfo.fPictureID < key.pictureID(); | |
58 } | |
59 | |
60 static bool Equals(const GrPictureInfo& pictInfo, const PictureKey& key) { | |
61 return pictInfo.fPictureID == key.pictureID(); | |
62 | |
63 } | |
64 | |
65 private: | |
66 uint32_t fPictureID; | |
67 }; | |
68 | |
69 #ifdef SK_DEBUG | 12 #ifdef SK_DEBUG |
70 void GrCachedLayer::validate(const GrTexture* backingTexture) const { | 13 void GrCachedLayer::validate(const GrTexture* backingTexture) const { |
71 SkASSERT(SK_InvalidGenID != fPictureID); | 14 SkASSERT(SK_InvalidGenID != fKey.getPictureID()); |
72 SkASSERT(-1 != fLayerID); | 15 SkASSERT(-1 != fKey.getLayerID()); |
16 | |
73 | 17 |
74 if (NULL != fTexture) { | 18 if (NULL != fTexture) { |
75 // If the layer is in some texture then it must occupy some rectangle | 19 // If the layer is in some texture then it must occupy some rectangle |
76 SkASSERT(!fRect.isEmpty()); | 20 SkASSERT(!fRect.isEmpty()); |
77 if (!this->isAtlased()) { | 21 if (!this->isAtlased()) { |
78 // If it isn't atlased then the rectangle should start at the origin | 22 // If it isn't atlased then the rectangle should start at the origin |
79 SkASSERT(0.0f == fRect.fLeft && 0.0f == fRect.fTop); | 23 SkASSERT(0.0f == fRect.fLeft && 0.0f == fRect.fTop); |
80 } | 24 } |
81 } else { | 25 } else { |
82 SkASSERT(fRect.isEmpty()); | 26 SkASSERT(fRect.isEmpty()); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
114 const GrTexture* fBackingTexture; | 58 const GrTexture* fBackingTexture; |
115 const GrCachedLayer* fLayer; | 59 const GrCachedLayer* fLayer; |
116 }; | 60 }; |
117 #endif | 61 #endif |
118 | 62 |
119 GrLayerCache::GrLayerCache(GrContext* context) | 63 GrLayerCache::GrLayerCache(GrContext* context) |
120 : fContext(context) { | 64 : fContext(context) { |
121 this->initAtlas(); | 65 this->initAtlas(); |
122 } | 66 } |
123 | 67 |
124 GrLayerCache::~GrLayerCache() { | 68 class UnlockAndDeleteFunctor { |
125 SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray(); | 69 public: |
126 for (int i = 0; i < fLayerHash.count(); ++i) { | 70 UnlockAndDeleteFunctor(GrLayerCache* cache) : fCache(cache) {} |
127 this->unlock(layerArray[i]); | 71 |
72 void operator()(GrCachedLayer& layer) { | |
73 fCache->unlock(&layer); | |
74 SkDELETE(&layer); | |
128 } | 75 } |
129 | 76 |
130 fLayerHash.deleteAll(); | 77 private: |
78 GrLayerCache* fCache; | |
79 }; | |
80 | |
81 GrLayerCache::~GrLayerCache() { | |
82 | |
83 fLayerHash.mutateAll(UnlockAndDeleteFunctor(this)); | |
mtklein
2014/07/17 19:36:20
Now that I'm remembering, maybe adding mutateAll m
robertphillips
2014/07/17 20:02:46
Yeah it's not a fantastic clarity win. I think it
| |
131 | 84 |
132 // The atlas only lets go of its texture when the atlas is deleted. | 85 // The atlas only lets go of its texture when the atlas is deleted. |
133 fAtlas.free(); | 86 fAtlas.free(); |
134 } | 87 } |
135 | 88 |
136 void GrLayerCache::initAtlas() { | 89 void GrLayerCache::initAtlas() { |
137 static const int kAtlasTextureWidth = 1024; | 90 static const int kAtlasTextureWidth = 1024; |
138 static const int kAtlasTextureHeight = 1024; | 91 static const int kAtlasTextureHeight = 1024; |
139 | 92 |
140 SkASSERT(NULL == fAtlas.get()); | 93 SkASSERT(NULL == fAtlas.get()); |
141 | 94 |
142 // The layer cache only gets 1 plot | 95 // The layer cache only gets 1 plot |
143 SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight) ; | 96 SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight) ; |
144 fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfi g, | 97 fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfi g, |
145 kRenderTarget_GrTextureFlagBit, | 98 kRenderTarget_GrTextureFlagBit, |
146 textureSize, kNumPlotsX, kNumPlotsY, false ))); | 99 textureSize, kNumPlotsX, kNumPlotsY, false ))); |
147 } | 100 } |
148 | 101 |
149 void GrLayerCache::freeAll() { | 102 void GrLayerCache::freeAll() { |
150 SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray(); | |
151 for (int i = 0; i < fLayerHash.count(); ++i) { | |
152 this->unlock(layerArray[i]); | |
153 } | |
154 | 103 |
155 fLayerHash.deleteAll(); | 104 fLayerHash.mutateAll(UnlockAndDeleteFunctor(this)); |
105 fLayerHash.rewind(); | |
156 | 106 |
157 // The atlas only lets go of its texture when the atlas is deleted. | 107 // The atlas only lets go of its texture when the atlas is deleted. |
158 fAtlas.free(); | 108 fAtlas.free(); |
159 // GrLayerCache always assumes an atlas exists so recreate it. The atlas | 109 // GrLayerCache always assumes an atlas exists so recreate it. The atlas |
160 // lazily allocates a replacement texture so reallocating a new | 110 // lazily allocates a replacement texture so reallocating a new |
161 // atlas here won't disrupt a GrContext::contextDestroyed or freeGpuResource s. | 111 // atlas here won't disrupt a GrContext::contextDestroyed or freeGpuResource s. |
162 // TODO: Make GrLayerCache lazily allocate the atlas manager? | 112 // TODO: Make GrLayerCache lazily allocate the atlas manager? |
163 this->initAtlas(); | 113 this->initAtlas(); |
164 } | 114 } |
165 | 115 |
166 GrCachedLayer* GrLayerCache::createLayer(const SkPicture* picture, int layerID) { | 116 GrCachedLayer* GrLayerCache::createLayer(const SkPicture* picture, int layerID) { |
167 SkASSERT(picture->uniqueID() != SK_InvalidGenID); | 117 SkASSERT(picture->uniqueID() != SK_InvalidGenID && layerID >= 0); |
168 | 118 |
169 GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (picture->uniqueID(), layer ID)); | 119 GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (picture->uniqueID(), layer ID)); |
170 fLayerHash.insert(PictureLayerKey(picture->uniqueID(), layerID), layer); | 120 fLayerHash.add(layer); |
171 return layer; | 121 return layer; |
172 } | 122 } |
173 | 123 |
174 GrCachedLayer* GrLayerCache::findLayer(const SkPicture* picture, int layerID) { | 124 GrCachedLayer* GrLayerCache::findLayer(const SkPicture* picture, int layerID) { |
175 SkASSERT(picture->uniqueID() != SK_InvalidGenID); | 125 SkASSERT(picture->uniqueID() != SK_InvalidGenID && layerID >= 0); |
176 return fLayerHash.find(PictureLayerKey(picture->uniqueID(), layerID)); | 126 return fLayerHash.find(GrCachedLayer::Key(picture->uniqueID(), layerID)); |
177 } | 127 } |
178 | 128 |
179 GrCachedLayer* GrLayerCache::findLayerOrCreate(const SkPicture* picture, int lay erID) { | 129 GrCachedLayer* GrLayerCache::findLayerOrCreate(const SkPicture* picture, int lay erID) { |
180 SkASSERT(picture->uniqueID() != SK_InvalidGenID); | 130 SkASSERT(picture->uniqueID() != SK_InvalidGenID && layerID >= 0); |
181 GrCachedLayer* layer = fLayerHash.find(PictureLayerKey(picture->uniqueID(), layerID)); | 131 GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(picture->uniqueID( ), layerID)); |
182 if (NULL == layer) { | 132 if (NULL == layer) { |
183 layer = this->createLayer(picture, layerID); | 133 layer = this->createLayer(picture, layerID); |
184 } | 134 } |
185 | 135 |
186 return layer; | 136 return layer; |
187 } | 137 } |
188 | 138 |
189 bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) { | 139 bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) { |
190 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);) | 140 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);) |
191 | 141 |
192 if (NULL != layer->texture()) { | 142 if (NULL != layer->texture()) { |
193 // This layer is already locked | 143 // This layer is already locked |
194 #ifdef SK_DEBUG | 144 #ifdef SK_DEBUG |
195 if (layer->isAtlased()) { | 145 if (layer->isAtlased()) { |
196 // It claims to be atlased | 146 // It claims to be atlased |
197 SkASSERT(layer->rect().width() == desc.fWidth); | 147 SkASSERT(layer->rect().width() == desc.fWidth); |
198 SkASSERT(layer->rect().height() == desc.fHeight); | 148 SkASSERT(layer->rect().height() == desc.fHeight); |
199 } | 149 } |
200 #endif | 150 #endif |
201 return true; | 151 return true; |
202 } | 152 } |
203 | 153 |
204 #if USE_ATLAS | 154 #if USE_ATLAS |
205 { | 155 { |
206 GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(layer->pictureID( ))); | 156 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); |
207 if (NULL == pictInfo) { | 157 if (NULL == pictInfo) { |
208 pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID())); | 158 pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID())); |
209 fPictureHash.insert(PictureKey(layer->pictureID()), pictInfo); | 159 fPictureHash.add(pictInfo); |
210 } | 160 } |
211 | 161 |
212 SkIPoint16 loc; | 162 SkIPoint16 loc; |
213 GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage, | 163 GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage, |
214 desc.fWidth, desc.fHeight, | 164 desc.fWidth, desc.fHeight, |
215 NULL, &loc); | 165 NULL, &loc); |
216 // addToAtlas can allocate the backing texture | 166 // addToAtlas can allocate the backing texture |
217 SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture())); | 167 SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture())); |
218 if (NULL != plot) { | 168 if (NULL != plot) { |
219 GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY, | 169 GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY, |
(...skipping 16 matching lines...) Expand all Loading... | |
236 void GrLayerCache::unlock(GrCachedLayer* layer) { | 186 void GrLayerCache::unlock(GrCachedLayer* layer) { |
237 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);) | 187 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);) |
238 | 188 |
239 if (NULL == layer || NULL == layer->texture()) { | 189 if (NULL == layer || NULL == layer->texture()) { |
240 return; | 190 return; |
241 } | 191 } |
242 | 192 |
243 if (layer->isAtlased()) { | 193 if (layer->isAtlased()) { |
244 SkASSERT(layer->texture() == fAtlas->getTexture()); | 194 SkASSERT(layer->texture() == fAtlas->getTexture()); |
245 | 195 |
246 GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(layer->pictureID( ))); | 196 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID()); |
247 SkASSERT(NULL != pictInfo); | 197 SkASSERT(NULL != pictInfo); |
248 pictInfo->fPlotUsage.isEmpty(); // just to silence compiler warnings for the time being | 198 pictInfo->fPlotUsage.isEmpty(); // just to silence compiler warnings for the time being |
249 | 199 |
250 // TODO: purging from atlas goes here | 200 // TODO: purging from atlas goes here |
251 } else { | 201 } else { |
252 fContext->unlockScratchTexture(layer->texture()); | 202 fContext->unlockScratchTexture(layer->texture()); |
253 layer->setTexture(NULL, GrIRect16::MakeEmpty()); | 203 layer->setTexture(NULL, GrIRect16::MakeEmpty()); |
254 } | 204 } |
255 } | 205 } |
256 | 206 |
257 #ifdef SK_DEBUG | 207 #ifdef SK_DEBUG |
258 void GrLayerCache::validate() const { | 208 void GrLayerCache::validate() const { |
259 const SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray(); | 209 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::ConstIter iter(&fLayerHas h); |
260 for (int i = 0; i < fLayerHash.count(); ++i) { | 210 for (; !iter.done(); ++iter) { |
261 layerArray[i]->validate(fAtlas->getTexture()); | 211 (*iter).validate(fAtlas->getTexture()); |
262 } | 212 } |
263 } | 213 } |
264 | 214 |
265 class GrAutoValidateCache : ::SkNoncopyable { | 215 class GrAutoValidateCache : ::SkNoncopyable { |
266 public: | 216 public: |
267 explicit GrAutoValidateCache(GrLayerCache* cache) | 217 explicit GrAutoValidateCache(GrLayerCache* cache) |
268 : fCache(cache) { | 218 : fCache(cache) { |
269 fCache->validate(); | 219 fCache->validate(); |
270 } | 220 } |
271 ~GrAutoValidateCache() { | 221 ~GrAutoValidateCache() { |
272 fCache->validate(); | 222 fCache->validate(); |
273 } | 223 } |
274 private: | 224 private: |
275 GrLayerCache* fCache; | 225 GrLayerCache* fCache; |
276 }; | 226 }; |
277 #endif | 227 #endif |
278 | 228 |
279 void GrLayerCache::purge(const SkPicture* picture) { | 229 void GrLayerCache::purge(const SkPicture* picture) { |
280 SkDEBUGCODE(GrAutoValidateCache avc(this);) | 230 SkDEBUGCODE(GrAutoValidateCache avc(this);) |
281 | 231 |
282 // This is somewhat of an abuse of GrTHashTable. We need to find all the | 232 // We need to find all the layers associated with 'picture' and remove them. |
283 // layers associated with 'picture' but the usual hash calls only look for | |
284 // exact key matches. This code peeks into the hash table's innards to | |
285 // find all the 'picture'-related layers. | |
286 // TODO: use a different data structure for the layer hash? | |
287 SkTDArray<GrCachedLayer*> toBeRemoved; | 233 SkTDArray<GrCachedLayer*> toBeRemoved; |
288 | 234 |
289 const SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray(); | 235 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash); |
290 for (int i = 0; i < fLayerHash.count(); ++i) { | 236 for (; !iter.done(); ++iter) { |
291 if (picture->uniqueID() == layerArray[i]->pictureID()) { | 237 if (picture->uniqueID() == (*iter).pictureID()) { |
292 *toBeRemoved.append() = layerArray[i]; | 238 *toBeRemoved.append() = &(*iter); |
293 } | 239 } |
294 } | 240 } |
295 | 241 |
296 for (int i = 0; i < toBeRemoved.count(); ++i) { | 242 for (int i = 0; i < toBeRemoved.count(); ++i) { |
297 this->unlock(toBeRemoved[i]); | 243 this->unlock(toBeRemoved[i]); |
298 | 244 fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i])); |
299 PictureLayerKey key(picture->uniqueID(), toBeRemoved[i]->layerID()); | |
300 fLayerHash.remove(key, toBeRemoved[i]); | |
301 SkDELETE(toBeRemoved[i]); | 245 SkDELETE(toBeRemoved[i]); |
302 } | 246 } |
303 | 247 |
304 GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(picture->uniqueID())) ; | 248 GrPictureInfo* pictInfo = fPictureHash.find(picture->uniqueID()); |
305 if (NULL != pictInfo) { | 249 if (NULL != pictInfo) { |
306 fPictureHash.remove(PictureKey(picture->uniqueID()), pictInfo); | 250 fPictureHash.remove(picture->uniqueID()); |
307 SkDELETE(pictInfo); | 251 SkDELETE(pictInfo); |
308 } | 252 } |
309 } | 253 } |
OLD | NEW |