Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrLayerCache.cpp
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
12 DECLARE_SKMESSAGEBUS_MESSAGE(GrPictureDeletedMessage);
13
14 #ifdef SK_DEBUG
15 void GrCachedLayer::validate(const GrTexture* backingTexture) const {
16     SkASSERT(SK_InvalidGenID != fKey.pictureID());
17     SkASSERT(fKey.start() > 0 && fKey.stop() > 0);
18
19
20     if (NULL != fTexture) {
21         // If the layer is in some texture then it must occupy some rectangle
22         SkASSERT(!fRect.isEmpty());
23         if (!this->isAtlased()) {
24             // If it isn't atlased then the rectangle should start at the origin
25             SkASSERT(0.0f == fRect.fLeft && 0.0f == fRect.fTop);
26         }
27     } else {
28         SkASSERT(fRect.isEmpty());
29         SkASSERT(NULL == fPlot);
30         SkASSERT(!fLocked);     // layers without a texture cannot be locked
31     }
32
33     if (NULL != fPlot) {
34         // If a layer has a plot (i.e., is atlased) then it must point to
35         // the backing texture. Additionally, its rect should be non-empty.
36         SkASSERT(NULL != fTexture && backingTexture == fTexture);
37         SkASSERT(!fRect.isEmpty());
38     }
39
40     if (fLocked) {
41         // If a layer is locked it must have a texture (though it need not be
42         // the atlas-backing texture) and occupy some space.
43         SkASSERT(NULL != fTexture);
44         SkASSERT(!fRect.isEmpty());
45     }
46 }
47
48 class GrAutoValidateLayer : ::SkNoncopyable {
49 public:
50     GrAutoValidateLayer(GrTexture* backingTexture, const GrCachedLayer* layer) 
51         : fBackingTexture(backingTexture)
52         , fLayer(layer) {
53         if (NULL != fLayer) {
54             fLayer->validate(backingTexture);
55         }
56     }
57     ~GrAutoValidateLayer() {
58         if (NULL != fLayer) {
59             fLayer->validate(fBackingTexture);
60         }
61     }
62     void setBackingTexture(GrTexture* backingTexture) {
63         SkASSERT(NULL == fBackingTexture || fBackingTexture == backingTexture);
64         fBackingTexture = backingTexture;
65     }
66
67 private:
68     const GrTexture* fBackingTexture;
69     const GrCachedLayer* fLayer;
70 };
71 #endif
72
73 GrLayerCache::GrLayerCache(GrContext* context)
74     : fContext(context) {
75     this->initAtlas();
76     memset(fPlotLocks, 0, sizeof(fPlotLocks));
77 }
78
79 GrLayerCache::~GrLayerCache() {
80
81     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
82     for (; !iter.done(); ++iter) {
83         GrCachedLayer* layer = &(*iter);
84         this->unlock(layer);
85         SkDELETE(layer);
86     }
87
88     // The atlas only lets go of its texture when the atlas is deleted. 
89     fAtlas.free();    
90 }
91
92 void GrLayerCache::initAtlas() {
93     SkASSERT(NULL == fAtlas.get());
94
95     SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
96     fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig,
97                                       kRenderTarget_GrTextureFlagBit,
98                                       textureSize, kNumPlotsX, kNumPlotsY, false)));
99 }
100
101 void GrLayerCache::freeAll() {
102
103     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
104     for (; !iter.done(); ++iter) {
105         GrCachedLayer* layer = &(*iter);
106         this->unlock(layer);
107         SkDELETE(layer);
108     }
109     fLayerHash.rewind();
110
111     // The atlas only lets go of its texture when the atlas is deleted. 
112     fAtlas.free();
113     // GrLayerCache always assumes an atlas exists so recreate it. The atlas 
114     // lazily allocates a replacement texture so reallocating a new 
115     // atlas here won't disrupt a GrContext::contextDestroyed or freeGpuResources.
116     // TODO: Make GrLayerCache lazily allocate the atlas manager?
117     this->initAtlas();
118 }
119
120 GrCachedLayer* GrLayerCache::createLayer(const SkPicture* picture, 
121                                          int start, int stop, 
122                                          const SkMatrix& ctm) {
123     SkASSERT(picture->uniqueID() != SK_InvalidGenID && start > 0 && stop > 0);
124
125     GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (picture->uniqueID(), start, stop, ctm));
126     fLayerHash.add(layer);
127     return layer;
128 }
129
130 GrCachedLayer* GrLayerCache::findLayer(const SkPicture* picture, 
131                                        int start, int stop, 
132                                        const SkMatrix& ctm) {
133     SkASSERT(picture->uniqueID() != SK_InvalidGenID && start > 0 && stop > 0);
134     return fLayerHash.find(GrCachedLayer::Key(picture->uniqueID(), start, stop, ctm));
135 }
136
137 GrCachedLayer* GrLayerCache::findLayerOrCreate(const SkPicture* picture, 
138                                                int start, int stop,
139                                                const SkMatrix& ctm) {
140     SkASSERT(picture->uniqueID() != SK_InvalidGenID && start > 0 && stop > 0);
141     GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(picture->uniqueID(), 
142                                                               start, stop, ctm));
143     if (NULL == layer) {
144         layer = this->createLayer(picture, start, stop, ctm);
145     }
146
147     return layer;
148 }
149
150 bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
151     SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
152
153     if (layer->locked()) {
154         // This layer is already locked
155 #ifdef SK_DEBUG
156         if (layer->isAtlased()) {
157             // It claims to be atlased
158             SkASSERT(layer->rect().width() == desc.fWidth);
159             SkASSERT(layer->rect().height() == desc.fHeight);
160         }
161 #endif
162         return true;
163     }
164
165     if (layer->isAtlased()) {
166         // Hooray it is still in the atlas - make sure it stays there
167         layer->setLocked(true);
168         fPlotLocks[layer->plot()->id()]++;
169         return true;
170     } else if (PlausiblyAtlasable(desc.fWidth, desc.fHeight)) {
171         // Not in the atlas - will it fit?
172         GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
173         if (NULL == pictInfo) {
174             pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID()));
175             fPictureHash.add(pictInfo);
176         }
177
178         SkIPoint16 loc;
179         for (int i = 0; i < 2; ++i) { // extra pass in case we fail to add but are able to purge
180             GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage,
181                                               desc.fWidth, desc.fHeight,
182                                               NULL, &loc);
183             // addToAtlas can allocate the backing texture
184             SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture()));
185             if (NULL != plot) {
186                 // The layer was successfully added to the atlas
187                 GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY,
188                                                        SkToS16(desc.fWidth), 
189                                                        SkToS16(desc.fHeight));
190                 layer->setTexture(fAtlas->getTexture(), bounds);
191                 layer->setPlot(plot);
192                 layer->setLocked(true);
193                 fPlotLocks[layer->plot()->id()]++;
194                 return false;
195             }
196
197             // The layer was rejected by the atlas (even though we know it is 
198             // plausibly atlas-able). See if a plot can be purged and try again.
199             if (!this->purgePlot()) {
200                 break;  // We weren't able to purge any plots
201             }
202         }
203     }
204
205     // The texture wouldn't fit in the cache - give it it's own texture.
206     // This path always uses a new scratch texture and (thus) doesn't cache anything.
207     // This can yield a lot of re-rendering
208     SkAutoTUnref<GrTexture> tex(fContext->lockAndRefScratchTexture(desc,
209                                                         GrContext::kApprox_ScratchTexMatch));
210
211     layer->setTexture(tex, GrIRect16::MakeWH(SkToS16(desc.fWidth), SkToS16(desc.fHeight)));
212     layer->setLocked(true);
213     return false;
214 }
215
216 void GrLayerCache::unlock(GrCachedLayer* layer) {
217     SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
218
219     if (NULL == layer || !layer->locked()) {
220         // invalid or not locked
221         return;
222     }
223
224     if (layer->isAtlased()) {
225         const int plotID = layer->plot()->id();
226
227         SkASSERT(fPlotLocks[plotID] > 0);
228         fPlotLocks[plotID]--;
229         // At this point we could aggressively clear out un-locked plots but
230         // by delaying we may be able to reuse some of the atlased layers later.
231 #if 0
232         // This testing code aggressively removes the atlased layers. This
233         // can be used to separate the performance contribution of less
234         // render target pingponging from that due to the re-use of cached layers
235         GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
236         SkASSERT(NULL != pictInfo);
237         
238         GrAtlas::RemovePlot(&pictInfo->fPlotUsage, layer->plot());
239         
240         layer->setPlot(NULL);
241         layer->setTexture(NULL, GrIRect16::MakeEmpty());
242 #endif
243
244     } else {
245         fContext->unlockScratchTexture(layer->texture());
246         layer->setTexture(NULL, GrIRect16::MakeEmpty());
247     }
248
249     layer->setLocked(false);
250 }
251
252 #ifdef SK_DEBUG
253 void GrLayerCache::validate() const {
254     int plotLocks[kNumPlotsX * kNumPlotsY];
255     memset(plotLocks, 0, sizeof(plotLocks));
256
257     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::ConstIter iter(&fLayerHash);
258     for (; !iter.done(); ++iter) {
259         const GrCachedLayer* layer = &(*iter);
260
261         layer->validate(fAtlas->getTexture());
262
263         const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
264         if (NULL != pictInfo) {
265             // In aggressive cleanup mode a picture info should only exist if
266             // it has some atlased layers
267             SkASSERT(!pictInfo->fPlotUsage.isEmpty());
268         } else {
269             // If there is no picture info for this layer then all of its
270             // layers should be non-atlased.
271             SkASSERT(!layer->isAtlased());
272         }
273
274         if (NULL != layer->plot()) {
275             SkASSERT(NULL != pictInfo);
276             SkASSERT(pictInfo->fPictureID == layer->pictureID());
277
278             SkASSERT(pictInfo->fPlotUsage.contains(layer->plot()));
279
280             if (layer->locked()) {
281                 plotLocks[layer->plot()->id()]++;
282             }
283         } 
284     }
285
286     for (int i = 0; i < kNumPlotsX*kNumPlotsY; ++i) {
287         SkASSERT(plotLocks[i] == fPlotLocks[i]);
288     }
289 }
290
291 class GrAutoValidateCache : ::SkNoncopyable {
292 public:
293     explicit GrAutoValidateCache(GrLayerCache* cache)
294         : fCache(cache) {
295         fCache->validate();
296     }
297     ~GrAutoValidateCache() {
298         fCache->validate();
299     }
300 private:
301     GrLayerCache* fCache;
302 };
303 #endif
304
305 void GrLayerCache::purge(uint32_t pictureID) {
306
307     SkDEBUGCODE(GrAutoValidateCache avc(this);)
308
309     // We need to find all the layers associated with 'picture' and remove them.
310     SkTDArray<GrCachedLayer*> toBeRemoved;
311
312     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
313     for (; !iter.done(); ++iter) {
314         if (pictureID == (*iter).pictureID()) {
315             *toBeRemoved.append() = &(*iter);
316         }
317     }
318
319     for (int i = 0; i < toBeRemoved.count(); ++i) {
320         this->unlock(toBeRemoved[i]);
321         fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
322         SkDELETE(toBeRemoved[i]);
323     }
324
325     GrPictureInfo* pictInfo = fPictureHash.find(pictureID);
326     if (NULL != pictInfo) {
327         fPictureHash.remove(pictureID);
328         SkDELETE(pictInfo);
329     }
330 }
331
332 bool GrLayerCache::purgePlot() {
333     SkDEBUGCODE(GrAutoValidateCache avc(this);)
334
335     GrAtlas::PlotIter iter;
336     GrPlot* plot;
337     for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
338          NULL != plot;
339          plot = iter.prev()) {
340         if (fPlotLocks[plot->id()] > 0) {
341             continue;
342         }
343
344         // We need to find all the layers in 'plot' and remove them.
345         SkTDArray<GrCachedLayer*> toBeRemoved;
346
347         SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
348         for (; !iter.done(); ++iter) {
349             if (plot == (*iter).plot()) {
350                 *toBeRemoved.append() = &(*iter);
351             }
352         }
353
354         for (int i = 0; i < toBeRemoved.count(); ++i) {
355             SkASSERT(!toBeRemoved[i]->locked());
356
357             GrPictureInfo* pictInfo = fPictureHash.find(toBeRemoved[i]->pictureID());
358             SkASSERT(NULL != pictInfo);
359
360             GrAtlas::RemovePlot(&pictInfo->fPlotUsage, plot);
361
362             // Aggressively remove layers and, if now totally uncached, picture info
363             fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
364             SkDELETE(toBeRemoved[i]);
365
366             if (pictInfo->fPlotUsage.isEmpty()) {
367                 fPictureHash.remove(pictInfo->fPictureID);
368                 SkDELETE(pictInfo);
369             }
370         }
371
372         plot->resetRects();
373         return true;
374     }
375
376     return false;
377 }
378
379 class GrPictureDeletionListener : public SkPicture::DeletionListener {
380     virtual void onDeletion(uint32_t pictureID) SK_OVERRIDE{
381         const GrPictureDeletedMessage message = { pictureID };
382         SkMessageBus<GrPictureDeletedMessage>::Post(message);
383     }
384 };
385
386 void GrLayerCache::trackPicture(const SkPicture* picture) {
387     if (NULL == fDeletionListener) {
388         fDeletionListener.reset(SkNEW(GrPictureDeletionListener));
389     }
390
391     picture->addDeletionListener(fDeletionListener);
392 }
393
394 void GrLayerCache::processDeletedPictures() {
395     SkTDArray<GrPictureDeletedMessage> deletedPictures;
396     fPictDeletionInbox.poll(&deletedPictures);
397
398     for (int i = 0; i < deletedPictures.count(); i++) {
399         this->purge(deletedPictures[i].pictureID);
400     }
401 }
402