Upstream version 10.39.225.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 (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 (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(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(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 (fLayer) {
54             fLayer->validate(backingTexture);
55         }
56     }
57     ~GrAutoValidateLayer() {
58         if (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::abandonContext or freeGpuResources.
116     // TODO: Make GrLayerCache lazily allocate the atlas manager?
117     this->initAtlas();
118 }
119
120 GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID, 
121                                          int start, int stop, 
122                                          const SkIPoint& offset,
123                                          const SkMatrix& ctm,
124                                          const SkPaint* paint) {
125     SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0);
126
127     GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (pictureID, start, stop, offset, ctm, paint));
128     fLayerHash.add(layer);
129     return layer;
130 }
131
132 GrCachedLayer* GrLayerCache::findLayer(uint32_t pictureID,
133                                        int start, int stop, 
134                                        const SkIPoint& offset,
135                                        const SkMatrix& ctm) {
136     SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0);
137     return fLayerHash.find(GrCachedLayer::Key(pictureID, start, stop, offset, ctm));
138 }
139
140 GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID,
141                                                int start, int stop,
142                                                const SkIPoint& offset,
143                                                const SkMatrix& ctm,
144                                                const SkPaint* paint) {
145     SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0);
146     GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(pictureID, start, stop, offset, ctm));
147     if (NULL == layer) {
148         layer = this->createLayer(pictureID, start, stop, offset, ctm, paint);
149     }
150
151     return layer;
152 }
153
154 bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool dontAtlas) {
155     SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
156
157     if (layer->locked()) {
158         // This layer is already locked
159 #ifdef SK_DEBUG
160         if (layer->isAtlased()) {
161             // It claims to be atlased
162             SkASSERT(!dontAtlas);
163             SkASSERT(layer->rect().width() == desc.fWidth);
164             SkASSERT(layer->rect().height() == desc.fHeight);
165         }
166 #endif
167         return false;
168     }
169
170     if (layer->isAtlased()) {
171         // Hooray it is still in the atlas - make sure it stays there
172         SkASSERT(!dontAtlas);
173         layer->setLocked(true);
174         fPlotLocks[layer->plot()->id()]++;
175         return false;
176     } else if (!dontAtlas && PlausiblyAtlasable(desc.fWidth, desc.fHeight)) {
177         // Not in the atlas - will it fit?
178         GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
179         if (NULL == pictInfo) {
180             pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID()));
181             fPictureHash.add(pictInfo);
182         }
183
184         SkIPoint16 loc;
185         for (int i = 0; i < 2; ++i) { // extra pass in case we fail to add but are able to purge
186             GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage,
187                                               desc.fWidth, desc.fHeight,
188                                               NULL, &loc);
189             // addToAtlas can allocate the backing texture
190             SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture()));
191             if (plot) {
192                 // The layer was successfully added to the atlas
193                 GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY,
194                                                        SkToS16(desc.fWidth),
195                                                        SkToS16(desc.fHeight));
196                 layer->setTexture(fAtlas->getTexture(), bounds);
197                 layer->setPlot(plot);
198                 layer->setLocked(true);
199                 fPlotLocks[layer->plot()->id()]++;
200                 return true;
201             }
202
203             // The layer was rejected by the atlas (even though we know it is 
204             // plausibly atlas-able). See if a plot can be purged and try again.
205             if (!this->purgePlot()) {
206                 break;  // We weren't able to purge any plots
207             }
208         }
209     }
210
211     // The texture wouldn't fit in the cache - give it it's own texture.
212     // This path always uses a new scratch texture and (thus) doesn't cache anything.
213     // This can yield a lot of re-rendering
214     SkAutoTUnref<GrTexture> tex(fContext->lockAndRefScratchTexture(desc,
215                                                         GrContext::kApprox_ScratchTexMatch));
216
217     layer->setTexture(tex, GrIRect16::MakeWH(SkToS16(desc.fWidth), SkToS16(desc.fHeight)));
218     layer->setLocked(true);
219     return true;
220 }
221
222 void GrLayerCache::unlock(GrCachedLayer* layer) {
223     SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
224
225     if (NULL == layer || !layer->locked()) {
226         // invalid or not locked
227         return;
228     }
229
230     if (layer->isAtlased()) {
231         const int plotID = layer->plot()->id();
232
233         SkASSERT(fPlotLocks[plotID] > 0);
234         fPlotLocks[plotID]--;
235         // At this point we could aggressively clear out un-locked plots but
236         // by delaying we may be able to reuse some of the atlased layers later.
237 #if DISABLE_CACHING
238         // This testing code aggressively removes the atlased layers. This
239         // can be used to separate the performance contribution of less
240         // render target pingponging from that due to the re-use of cached layers
241         GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
242         SkASSERT(pictInfo);
243         
244         GrAtlas::RemovePlot(&pictInfo->fPlotUsage, layer->plot());
245         
246         layer->setPlot(NULL);
247         layer->setTexture(NULL, GrIRect16::MakeEmpty());
248 #endif
249
250     } else {
251         fContext->unlockScratchTexture(layer->texture());
252         layer->setTexture(NULL, GrIRect16::MakeEmpty());
253     }
254
255     layer->setLocked(false);
256 }
257
258 #ifdef SK_DEBUG
259 void GrLayerCache::validate() const {
260     int plotLocks[kNumPlotsX * kNumPlotsY];
261     memset(plotLocks, 0, sizeof(plotLocks));
262
263     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::ConstIter iter(&fLayerHash);
264     for (; !iter.done(); ++iter) {
265         const GrCachedLayer* layer = &(*iter);
266
267         layer->validate(fAtlas->getTexture());
268
269         const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
270         if (pictInfo) {
271             // In aggressive cleanup mode a picture info should only exist if
272             // it has some atlased layers
273 #if !DISABLE_CACHING
274             SkASSERT(!pictInfo->fPlotUsage.isEmpty());
275 #endif
276         } else {
277             // If there is no picture info for this layer then all of its
278             // layers should be non-atlased.
279             SkASSERT(!layer->isAtlased());
280         }
281
282         if (layer->plot()) {
283             SkASSERT(pictInfo);
284             SkASSERT(pictInfo->fPictureID == layer->pictureID());
285
286             SkASSERT(pictInfo->fPlotUsage.contains(layer->plot()));
287
288             if (layer->locked()) {
289                 plotLocks[layer->plot()->id()]++;
290             }
291         } 
292     }
293
294     for (int i = 0; i < kNumPlotsX*kNumPlotsY; ++i) {
295         SkASSERT(plotLocks[i] == fPlotLocks[i]);
296     }
297 }
298
299 class GrAutoValidateCache : ::SkNoncopyable {
300 public:
301     explicit GrAutoValidateCache(GrLayerCache* cache)
302         : fCache(cache) {
303         fCache->validate();
304     }
305     ~GrAutoValidateCache() {
306         fCache->validate();
307     }
308 private:
309     GrLayerCache* fCache;
310 };
311 #endif
312
313 void GrLayerCache::purge(uint32_t pictureID) {
314
315     SkDEBUGCODE(GrAutoValidateCache avc(this);)
316
317     // We need to find all the layers associated with 'picture' and remove them.
318     SkTDArray<GrCachedLayer*> toBeRemoved;
319
320     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
321     for (; !iter.done(); ++iter) {
322         if (pictureID == (*iter).pictureID()) {
323             *toBeRemoved.append() = &(*iter);
324         }
325     }
326
327     for (int i = 0; i < toBeRemoved.count(); ++i) {
328         this->unlock(toBeRemoved[i]);
329         fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
330         SkDELETE(toBeRemoved[i]);
331     }
332
333     GrPictureInfo* pictInfo = fPictureHash.find(pictureID);
334     if (pictInfo) {
335         fPictureHash.remove(pictureID);
336         SkDELETE(pictInfo);
337     }
338 }
339
340 bool GrLayerCache::purgePlot() {
341     SkDEBUGCODE(GrAutoValidateCache avc(this);)
342
343     GrAtlas::PlotIter iter;
344     GrPlot* plot;
345     for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
346          plot;
347          plot = iter.prev()) {
348         if (fPlotLocks[plot->id()] > 0) {
349             continue;
350         }
351
352         this->purgePlot(plot);
353         return true;
354     }
355
356     return false;
357 }
358
359 void GrLayerCache::purgePlot(GrPlot* plot) {
360     SkASSERT(0 == fPlotLocks[plot->id()]);
361
362     // We need to find all the layers in 'plot' and remove them.
363     SkTDArray<GrCachedLayer*> toBeRemoved;
364
365     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
366     for (; !iter.done(); ++iter) {
367         if (plot == (*iter).plot()) {
368             *toBeRemoved.append() = &(*iter);
369         }
370     }
371
372     for (int i = 0; i < toBeRemoved.count(); ++i) {
373         SkASSERT(!toBeRemoved[i]->locked());
374
375         GrPictureInfo* pictInfo = fPictureHash.find(toBeRemoved[i]->pictureID());
376         SkASSERT(pictInfo);
377
378         GrAtlas::RemovePlot(&pictInfo->fPlotUsage, plot);
379
380         // Aggressively remove layers and, if now totally uncached, picture info
381         fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
382         SkDELETE(toBeRemoved[i]);
383
384         if (pictInfo->fPlotUsage.isEmpty()) {
385             fPictureHash.remove(pictInfo->fPictureID);
386             SkDELETE(pictInfo);
387         }
388     }
389
390     plot->resetRects();
391 }
392
393 void GrLayerCache::purgeAll() {
394     GrAtlas::PlotIter iter;
395     GrPlot* plot;
396     for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
397          plot;
398          plot = iter.prev()) {
399         SkASSERT(0 == fPlotLocks[plot->id()]);
400
401         this->purgePlot(plot);
402     }
403 }
404
405 class GrPictureDeletionListener : public SkPicture::DeletionListener {
406     virtual void onDeletion(uint32_t pictureID) SK_OVERRIDE{
407         const GrPictureDeletedMessage message = { pictureID };
408         SkMessageBus<GrPictureDeletedMessage>::Post(message);
409     }
410 };
411
412 void GrLayerCache::trackPicture(const SkPicture* picture) {
413     if (NULL == fDeletionListener) {
414         fDeletionListener.reset(SkNEW(GrPictureDeletionListener));
415     }
416
417     picture->addDeletionListener(fDeletionListener);
418 }
419
420 void GrLayerCache::processDeletedPictures() {
421     SkTDArray<GrPictureDeletedMessage> deletedPictures;
422     fPictDeletionInbox.poll(&deletedPictures);
423
424     for (int i = 0; i < deletedPictures.count(); i++) {
425         this->purge(deletedPictures[i].pictureID);
426     }
427 }
428