1 /*
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 #include "GrSurfacePriv.h"
12
13 #ifdef SK_DEBUG
validate(const GrTexture * backingTexture) const14 void GrCachedLayer::validate(const GrTexture* backingTexture) const {
15 SkASSERT(SK_InvalidGenID != fKey.pictureID());
16
17 if (fTexture) {
18 // If the layer is in some texture then it must occupy some rectangle
19 SkASSERT(!fRect.isEmpty());
20 if (!this->isAtlased()) {
21 // If it isn't atlased then the rectangle should start at the origin
22 SkASSERT(0.0f == fRect.fLeft && 0.0f == fRect.fTop);
23 }
24 } else {
25 SkASSERT(fRect.isEmpty());
26 SkASSERT(NULL == fPlot);
27 SkASSERT(!fLocked); // layers without a texture cannot be locked
28 }
29
30 if (fPlot) {
31 // If a layer has a plot (i.e., is atlased) then it must point to
32 // the backing texture. Additionally, its rect should be non-empty.
33 SkASSERT(fTexture && backingTexture == fTexture);
34 SkASSERT(!fRect.isEmpty());
35 }
36
37 if (fLocked) {
38 // If a layer is locked it must have a texture (though it need not be
39 // the atlas-backing texture) and occupy some space.
40 SkASSERT(fTexture);
41 SkASSERT(!fRect.isEmpty());
42 }
43
44 // Unfortunately there is a brief time where a layer can be locked
45 // but not used, so we can only check the "used implies locked"
46 // invariant.
47 if (fUses > 0) {
48 SkASSERT(fLocked);
49 } else {
50 SkASSERT(0 == fUses);
51 }
52 }
53
54 class GrAutoValidateLayer : ::SkNoncopyable {
55 public:
GrAutoValidateLayer(GrTexture * backingTexture,const GrCachedLayer * layer)56 GrAutoValidateLayer(GrTexture* backingTexture, const GrCachedLayer* layer)
57 : fBackingTexture(backingTexture)
58 , fLayer(layer) {
59 if (fLayer) {
60 fLayer->validate(backingTexture);
61 }
62 }
~GrAutoValidateLayer()63 ~GrAutoValidateLayer() {
64 if (fLayer) {
65 fLayer->validate(fBackingTexture);
66 }
67 }
setBackingTexture(GrTexture * backingTexture)68 void setBackingTexture(GrTexture* backingTexture) {
69 SkASSERT(NULL == fBackingTexture || fBackingTexture == backingTexture);
70 fBackingTexture = backingTexture;
71 }
72
73 private:
74 const GrTexture* fBackingTexture;
75 const GrCachedLayer* fLayer;
76 };
77 #endif
78
GrLayerCache(GrContext * context)79 GrLayerCache::GrLayerCache(GrContext* context)
80 : fContext(context) {
81 memset(fPlotLocks, 0, sizeof(fPlotLocks));
82 }
83
~GrLayerCache()84 GrLayerCache::~GrLayerCache() {
85
86 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
87 for (; !iter.done(); ++iter) {
88 GrCachedLayer* layer = &(*iter);
89 SkASSERT(0 == layer->uses());
90 this->unlock(layer);
91 SkDELETE(layer);
92 }
93
94 SkASSERT(0 == fPictureHash.count());
95
96 // The atlas only lets go of its texture when the atlas is deleted.
97 fAtlas.free();
98 }
99
initAtlas()100 void GrLayerCache::initAtlas() {
101 SkASSERT(NULL == fAtlas.get());
102 GR_STATIC_ASSERT(kNumPlotsX*kNumPlotsX == GrPictureInfo::kNumPlots);
103
104 SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
105 fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig,
106 kRenderTarget_GrSurfaceFlag,
107 textureSize, kNumPlotsX, kNumPlotsY, false)));
108 }
109
freeAll()110 void GrLayerCache::freeAll() {
111
112 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
113 for (; !iter.done(); ++iter) {
114 GrCachedLayer* layer = &(*iter);
115 this->unlock(layer);
116 SkDELETE(layer);
117 }
118 fLayerHash.rewind();
119
120 // The atlas only lets go of its texture when the atlas is deleted.
121 fAtlas.free();
122 }
123
createLayer(uint32_t pictureID,int start,int stop,const SkIRect & srcIR,const SkIRect & dstIR,const SkMatrix & initialMat,const unsigned * key,int keySize,const SkPaint * paint)124 GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID,
125 int start, int stop,
126 const SkIRect& srcIR,
127 const SkIRect& dstIR,
128 const SkMatrix& initialMat,
129 const unsigned* key,
130 int keySize,
131 const SkPaint* paint) {
132 SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0);
133
134 GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (pictureID, start, stop,
135 srcIR, dstIR, initialMat,
136 key, keySize, paint));
137 fLayerHash.add(layer);
138 return layer;
139 }
140
findLayer(uint32_t pictureID,const SkMatrix & initialMat,const unsigned * key,int keySize)141 GrCachedLayer* GrLayerCache::findLayer(uint32_t pictureID, const SkMatrix& initialMat,
142 const unsigned* key, int keySize) {
143 SkASSERT(pictureID != SK_InvalidGenID);
144 return fLayerHash.find(GrCachedLayer::Key(pictureID, initialMat, key, keySize));
145 }
146
findLayerOrCreate(uint32_t pictureID,int start,int stop,const SkIRect & srcIR,const SkIRect & dstIR,const SkMatrix & initialMat,const unsigned * key,int keySize,const SkPaint * paint)147 GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID,
148 int start, int stop,
149 const SkIRect& srcIR,
150 const SkIRect& dstIR,
151 const SkMatrix& initialMat,
152 const unsigned* key,
153 int keySize,
154 const SkPaint* paint) {
155 SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0);
156 GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(pictureID, initialMat, key, keySize));
157 if (NULL == layer) {
158 layer = this->createLayer(pictureID, start, stop,
159 srcIR, dstIR, initialMat,
160 key, keySize, paint);
161 }
162
163 return layer;
164 }
165
tryToAtlas(GrCachedLayer * layer,const GrSurfaceDesc & desc,bool * needsRendering)166 bool GrLayerCache::tryToAtlas(GrCachedLayer* layer,
167 const GrSurfaceDesc& desc,
168 bool* needsRendering) {
169 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : NULL, layer);)
170
171 SkASSERT(PlausiblyAtlasable(desc.fWidth, desc.fHeight));
172 SkASSERT(0 == desc.fSampleCnt);
173
174 if (layer->locked()) {
175 // This layer is already locked
176 SkASSERT(fAtlas);
177 SkASSERT(layer->isAtlased());
178 SkASSERT(layer->rect().width() == desc.fWidth);
179 SkASSERT(layer->rect().height() == desc.fHeight);
180 *needsRendering = false;
181 return true;
182 }
183
184 if (layer->isAtlased()) {
185 SkASSERT(fAtlas);
186 // Hooray it is still in the atlas - make sure it stays there
187 layer->setLocked(true);
188 this->incPlotLock(layer->plot()->id());
189 *needsRendering = false;
190 return true;
191 } else {
192 if (!fAtlas) {
193 this->initAtlas();
194 if (!fAtlas) {
195 return false;
196 }
197 }
198 // Not in the atlas - will it fit?
199 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
200 if (NULL == pictInfo) {
201 pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID()));
202 fPictureHash.add(pictInfo);
203 }
204
205 SkIPoint16 loc;
206 for (int i = 0; i < 2; ++i) { // extra pass in case we fail to add but are able to purge
207 GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage,
208 desc.fWidth, desc.fHeight,
209 NULL, &loc);
210 // addToAtlas can allocate the backing texture
211 SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture()));
212 if (plot) {
213 #if !GR_CACHE_HOISTED_LAYERS
214 pictInfo->incPlotUsage(plot->id());
215 #endif
216 // The layer was successfully added to the atlas
217 const SkIRect bounds = SkIRect::MakeXYWH(loc.fX, loc.fY,
218 desc.fWidth, desc.fHeight);
219 layer->setTexture(fAtlas->getTexture(), bounds);
220 layer->setPlot(plot);
221 layer->setLocked(true);
222 this->incPlotLock(layer->plot()->id());
223 *needsRendering = true;
224 return true;
225 }
226
227 // The layer was rejected by the atlas (even though we know it is
228 // plausibly atlas-able). See if a plot can be purged and try again.
229 if (!this->purgePlot()) {
230 break; // We weren't able to purge any plots
231 }
232 }
233
234 if (pictInfo->fPlotUsage.isEmpty()) {
235 fPictureHash.remove(pictInfo->fPictureID);
236 SkDELETE(pictInfo);
237 }
238 }
239
240 return false;
241 }
242
lock(GrCachedLayer * layer,const GrSurfaceDesc & desc,bool * needsRendering)243 bool GrLayerCache::lock(GrCachedLayer* layer, const GrSurfaceDesc& desc, bool* needsRendering) {
244 if (layer->locked()) {
245 // This layer is already locked
246 *needsRendering = false;
247 return true;
248 }
249
250 // TODO: make the test for exact match depend on the image filters themselves
251 GrTextureProvider::ScratchTexMatch usage = GrTextureProvider::kApprox_ScratchTexMatch;
252 if (layer->fFilter) {
253 usage = GrTextureProvider::kExact_ScratchTexMatch;
254 }
255
256 SkAutoTUnref<GrTexture> tex(fContext->textureProvider()->refScratchTexture(desc, usage));
257 if (!tex) {
258 return false;
259 }
260
261 layer->setTexture(tex, SkIRect::MakeWH(desc.fWidth, desc.fHeight));
262 layer->setLocked(true);
263 *needsRendering = true;
264 return true;
265 }
266
unlock(GrCachedLayer * layer)267 void GrLayerCache::unlock(GrCachedLayer* layer) {
268 SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : NULL, layer);)
269
270 if (NULL == layer || !layer->locked()) {
271 // invalid or not locked
272 return;
273 }
274
275 if (layer->isAtlased()) {
276 const int plotID = layer->plot()->id();
277
278 this->decPlotLock(plotID);
279 // At this point we could aggressively clear out un-locked plots but
280 // by delaying we may be able to reuse some of the atlased layers later.
281 #if !GR_CACHE_HOISTED_LAYERS
282 // This testing code aggressively removes the atlased layers. This
283 // can be used to separate the performance contribution of less
284 // render target pingponging from that due to the re-use of cached layers
285 GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
286 SkASSERT(pictInfo);
287
288 pictInfo->decPlotUsage(plotID);
289
290 if (0 == pictInfo->plotUsage(plotID)) {
291 GrAtlas::RemovePlot(&pictInfo->fPlotUsage, layer->plot());
292
293 if (pictInfo->fPlotUsage.isEmpty()) {
294 fPictureHash.remove(pictInfo->fPictureID);
295 SkDELETE(pictInfo);
296 }
297 }
298
299 layer->setPlot(NULL);
300 layer->setTexture(NULL, SkIRect::MakeEmpty());
301 #endif
302
303 } else {
304 layer->setTexture(NULL, SkIRect::MakeEmpty());
305 }
306
307 layer->setLocked(false);
308 }
309
310 #ifdef SK_DEBUG
validate() const311 void GrLayerCache::validate() const {
312 int plotLocks[kNumPlotsX * kNumPlotsY];
313 memset(plotLocks, 0, sizeof(plotLocks));
314
315 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::ConstIter iter(&fLayerHash);
316 for (; !iter.done(); ++iter) {
317 const GrCachedLayer* layer = &(*iter);
318
319 layer->validate(fAtlas.get() ? fAtlas->getTexture() : NULL);
320
321 const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
322 if (!pictInfo) {
323 // If there is no picture info for this picture then all of its
324 // layers should be non-atlased.
325 SkASSERT(!layer->isAtlased());
326 }
327
328 if (layer->plot()) {
329 SkASSERT(pictInfo);
330 SkASSERT(pictInfo->fPictureID == layer->pictureID());
331
332 SkASSERT(pictInfo->fPlotUsage.contains(layer->plot()));
333 #if !GR_CACHE_HOISTED_LAYERS
334 SkASSERT(pictInfo->plotUsage(layer->plot()->id()) > 0);
335 #endif
336
337 if (layer->locked()) {
338 plotLocks[layer->plot()->id()]++;
339 }
340 }
341 }
342
343 for (int i = 0; i < kNumPlotsX*kNumPlotsY; ++i) {
344 SkASSERT(plotLocks[i] == fPlotLocks[i]);
345 }
346 }
347
348 class GrAutoValidateCache : ::SkNoncopyable {
349 public:
GrAutoValidateCache(GrLayerCache * cache)350 explicit GrAutoValidateCache(GrLayerCache* cache)
351 : fCache(cache) {
352 fCache->validate();
353 }
~GrAutoValidateCache()354 ~GrAutoValidateCache() {
355 fCache->validate();
356 }
357 private:
358 GrLayerCache* fCache;
359 };
360 #endif
361
purge(uint32_t pictureID)362 void GrLayerCache::purge(uint32_t pictureID) {
363
364 SkDEBUGCODE(GrAutoValidateCache avc(this);)
365
366 // We need to find all the layers associated with 'picture' and remove them.
367 SkTDArray<GrCachedLayer*> toBeRemoved;
368
369 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
370 for (; !iter.done(); ++iter) {
371 if (pictureID == (*iter).pictureID()) {
372 *toBeRemoved.append() = &(*iter);
373 }
374 }
375
376 for (int i = 0; i < toBeRemoved.count(); ++i) {
377 SkASSERT(0 == toBeRemoved[i]->uses());
378 this->unlock(toBeRemoved[i]);
379 fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
380 SkDELETE(toBeRemoved[i]);
381 }
382
383 GrPictureInfo* pictInfo = fPictureHash.find(pictureID);
384 if (pictInfo) {
385 fPictureHash.remove(pictureID);
386 SkDELETE(pictInfo);
387 }
388 }
389
purgePlot()390 bool GrLayerCache::purgePlot() {
391 SkDEBUGCODE(GrAutoValidateCache avc(this);)
392 SkASSERT(fAtlas);
393
394 GrAtlas::PlotIter iter;
395 GrPlot* plot;
396 for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
397 plot;
398 plot = iter.prev()) {
399 if (fPlotLocks[plot->id()] > 0) {
400 continue;
401 }
402
403 this->purgePlot(plot);
404 return true;
405 }
406
407 return false;
408 }
409
purgePlot(GrPlot * plot)410 void GrLayerCache::purgePlot(GrPlot* plot) {
411 SkASSERT(0 == fPlotLocks[plot->id()]);
412
413 // We need to find all the layers in 'plot' and remove them.
414 SkTDArray<GrCachedLayer*> toBeRemoved;
415
416 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
417 for (; !iter.done(); ++iter) {
418 if (plot == (*iter).plot()) {
419 *toBeRemoved.append() = &(*iter);
420 }
421 }
422
423 for (int i = 0; i < toBeRemoved.count(); ++i) {
424 SkASSERT(0 == toBeRemoved[i]->uses());
425 SkASSERT(!toBeRemoved[i]->locked());
426
427 uint32_t pictureIDToRemove = toBeRemoved[i]->pictureID();
428
429 // Aggressively remove layers and, if it becomes totally uncached, delete the picture info
430 fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
431 SkDELETE(toBeRemoved[i]);
432
433 GrPictureInfo* pictInfo = fPictureHash.find(pictureIDToRemove);
434 if (pictInfo) {
435 #if !GR_CACHE_HOISTED_LAYERS
436 SkASSERT(0 == pictInfo->plotUsage(plot->id()));
437 #endif
438 GrAtlas::RemovePlot(&pictInfo->fPlotUsage, plot);
439
440 if (pictInfo->fPlotUsage.isEmpty()) {
441 fPictureHash.remove(pictInfo->fPictureID);
442 SkDELETE(pictInfo);
443 }
444 }
445 }
446
447 plot->resetRects();
448 }
449
450 #if !GR_CACHE_HOISTED_LAYERS
purgeAll()451 void GrLayerCache::purgeAll() {
452 if (!fAtlas) {
453 return;
454 }
455
456 GrAtlas::PlotIter iter;
457 GrPlot* plot;
458 for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
459 plot;
460 plot = iter.prev()) {
461 SkASSERT(0 == fPlotLocks[plot->id()]);
462
463 this->purgePlot(plot);
464 }
465
466 SkASSERT(0 == fPictureHash.count());
467
468 fContext->discardRenderTarget(fAtlas->getTexture()->asRenderTarget());
469 }
470 #endif
471
processDeletedPictures()472 void GrLayerCache::processDeletedPictures() {
473 SkTArray<SkPicture::DeletionMessage> deletedPictures;
474 fPictDeletionInbox.poll(&deletedPictures);
475
476 for (int i = 0; i < deletedPictures.count(); i++) {
477 this->purge(deletedPictures[i].fUniqueID);
478 }
479 }
480
481 #ifdef SK_DEVELOPER
writeLayersToDisk(const SkString & dirName)482 void GrLayerCache::writeLayersToDisk(const SkString& dirName) {
483
484 if (fAtlas) {
485 GrTexture* atlasTexture = fAtlas->getTexture();
486 if (NULL != atlasTexture) {
487 SkString fileName(dirName);
488 fileName.append("\\atlas.png");
489
490 atlasTexture->surfacePriv().savePixels(fileName.c_str());
491 }
492 }
493
494 SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
495 for (; !iter.done(); ++iter) {
496 GrCachedLayer* layer = &(*iter);
497
498 if (layer->isAtlased() || !layer->texture()) {
499 continue;
500 }
501
502 SkString fileName(dirName);
503 fileName.appendf("\\%d", layer->fKey.pictureID());
504 for (int i = 0; i < layer->fKey.keySize(); ++i) {
505 fileName.appendf("-%d", layer->fKey.key()[i]);
506 }
507 fileName.appendf(".png");
508
509 layer->texture()->surfacePriv().savePixels(fileName.c_str());
510 }
511 }
512 #endif
513