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 "GrLayerCache.h"
9 #include "GrLayerHoister.h"
10 #include "GrRecordReplaceDraw.h"
11 
12 #include "SkBigPicture.h"
13 #include "SkCanvas.h"
14 #include "SkGpuDevice.h"
15 #include "SkLayerInfo.h"
16 #include "SkRecordDraw.h"
17 #include "SkSurface.h"
18 #include "SkSurface_Gpu.h"
19 
20 // Create the layer information for the hoisted layer and secure the
21 // required texture/render target resources.
prepare_for_hoisting(GrLayerCache * layerCache,const SkPicture * topLevelPicture,const SkMatrix & initialMat,const SkLayerInfo::BlockInfo & info,const SkIRect & srcIR,const SkIRect & dstIR,SkTDArray<GrHoistedLayer> * needRendering,SkTDArray<GrHoistedLayer> * recycled,bool attemptToAtlas,int numSamples)22 static void prepare_for_hoisting(GrLayerCache* layerCache,
23                                  const SkPicture* topLevelPicture,
24                                  const SkMatrix& initialMat,
25                                  const SkLayerInfo::BlockInfo& info,
26                                  const SkIRect& srcIR,
27                                  const SkIRect& dstIR,
28                                  SkTDArray<GrHoistedLayer>* needRendering,
29                                  SkTDArray<GrHoistedLayer>* recycled,
30                                  bool attemptToAtlas,
31                                  int numSamples) {
32     const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture;
33 
34     GrCachedLayer* layer = layerCache->findLayerOrCreate(topLevelPicture->uniqueID(),
35                                                          SkToInt(info.fSaveLayerOpID),
36                                                          SkToInt(info.fRestoreOpID),
37                                                          srcIR,
38                                                          dstIR,
39                                                          initialMat,
40                                                          info.fKey,
41                                                          info.fKeySize,
42                                                          info.fPaint);
43     GrSurfaceDesc desc;
44     desc.fFlags = kRenderTarget_GrSurfaceFlag;
45     desc.fWidth = srcIR.width();
46     desc.fHeight = srcIR.height();
47     desc.fConfig = kSkia8888_GrPixelConfig;
48     desc.fSampleCnt = numSamples;
49 
50     bool locked, needsRendering;
51     if (attemptToAtlas) {
52         locked = layerCache->tryToAtlas(layer, desc, &needsRendering);
53     } else {
54         locked = layerCache->lock(layer, desc, &needsRendering);
55     }
56     if (!locked) {
57         // GPU resources could not be secured for the hoisting of this layer
58         return;
59     }
60 
61     if (attemptToAtlas) {
62         SkASSERT(layer->isAtlased());
63     }
64 
65     GrHoistedLayer* hl;
66 
67     if (needsRendering) {
68         if (!attemptToAtlas) {
69             SkASSERT(!layer->isAtlased());
70         }
71         hl = needRendering->append();
72     } else {
73         hl = recycled->append();
74     }
75 
76     layerCache->addUse(layer);
77     hl->fLayer = layer;
78     hl->fPicture = pict;
79     hl->fLocalMat = info.fLocalMat;
80     hl->fInitialMat = initialMat;
81     hl->fPreMat = initialMat;
82     hl->fPreMat.preConcat(info.fPreMat);
83 }
84 
85 // Compute the source rect and return false if it is empty.
compute_source_rect(const SkLayerInfo::BlockInfo & info,const SkMatrix & initialMat,const SkIRect & dstIR,SkIRect * srcIR)86 static bool compute_source_rect(const SkLayerInfo::BlockInfo& info, const SkMatrix& initialMat,
87                                 const SkIRect& dstIR, SkIRect* srcIR) {
88     SkIRect clipBounds = dstIR;
89 
90     SkMatrix totMat = initialMat;
91     totMat.preConcat(info.fPreMat);
92     totMat.preConcat(info.fLocalMat);
93 
94     if (info.fPaint && info.fPaint->getImageFilter()) {
95         info.fPaint->getImageFilter()->filterBounds(clipBounds, totMat, &clipBounds);
96     }
97 
98     if (!info.fSrcBounds.isEmpty()) {
99         SkRect r;
100 
101         totMat.mapRect(&r, info.fSrcBounds);
102         r.roundOut(srcIR);
103 
104         if (!srcIR->intersect(clipBounds)) {
105             return false;
106         }
107     } else {
108         *srcIR = clipBounds;
109     }
110 
111     return true;
112 }
113 
114 // Atlased layers must be small enough to fit in the atlas, not have a
115 // paint with an image filter and be neither nested nor nesting.
116 // TODO: allow leaf nested layers to appear in the atlas.
FindLayersToAtlas(GrContext * context,const SkPicture * topLevelPicture,const SkMatrix & initialMat,const SkRect & query,SkTDArray<GrHoistedLayer> * atlased,SkTDArray<GrHoistedLayer> * recycled,int numSamples)117 void GrLayerHoister::FindLayersToAtlas(GrContext* context,
118                                        const SkPicture* topLevelPicture,
119                                        const SkMatrix& initialMat,
120                                        const SkRect& query,
121                                        SkTDArray<GrHoistedLayer>* atlased,
122                                        SkTDArray<GrHoistedLayer>* recycled,
123                                        int numSamples) {
124     if (0 != numSamples) {
125         // MSAA layers are currently never atlased
126         return;
127     }
128 
129     GrLayerCache* layerCache = context->getLayerCache();
130     layerCache->processDeletedPictures();
131 
132     const SkBigPicture::AccelData* topLevelData = nullptr;
133     if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) {
134         topLevelData = bp->accelData();
135     }
136     if (!topLevelData) {
137         return;
138     }
139 
140     const SkLayerInfo *topLevelGPUData = static_cast<const SkLayerInfo*>(topLevelData);
141     if (0 == topLevelGPUData->numBlocks()) {
142         return;
143     }
144 
145     atlased->setReserve(atlased->count() + topLevelGPUData->numBlocks());
146 
147     for (int i = 0; i < topLevelGPUData->numBlocks(); ++i) {
148         const SkLayerInfo::BlockInfo& info = topLevelGPUData->block(i);
149 
150         // TODO: ignore perspective projected layers here?
151         bool disallowAtlasing = info.fHasNestedLayers || info.fIsNested ||
152                                 (info.fPaint && info.fPaint->getImageFilter());
153 
154         if (disallowAtlasing) {
155             continue;
156         }
157 
158         SkRect layerRect;
159         initialMat.mapRect(&layerRect, info.fBounds);
160         if (!layerRect.intersect(query)) {
161             continue;
162         }
163 
164         const SkIRect dstIR = layerRect.roundOut();
165 
166         SkIRect srcIR;
167 
168         if (!compute_source_rect(info, initialMat, dstIR, &srcIR) ||
169             !GrLayerCache::PlausiblyAtlasable(srcIR.width(), srcIR.height())) {
170             continue;
171         }
172 
173         prepare_for_hoisting(layerCache, topLevelPicture, initialMat,
174                              info, srcIR, dstIR, atlased, recycled, true, 0);
175     }
176 
177 }
178 
FindLayersToHoist(GrContext * context,const SkPicture * topLevelPicture,const SkMatrix & initialMat,const SkRect & query,SkTDArray<GrHoistedLayer> * needRendering,SkTDArray<GrHoistedLayer> * recycled,int numSamples)179 void GrLayerHoister::FindLayersToHoist(GrContext* context,
180                                        const SkPicture* topLevelPicture,
181                                        const SkMatrix& initialMat,
182                                        const SkRect& query,
183                                        SkTDArray<GrHoistedLayer>* needRendering,
184                                        SkTDArray<GrHoistedLayer>* recycled,
185                                        int numSamples) {
186     GrLayerCache* layerCache = context->getLayerCache();
187 
188     layerCache->processDeletedPictures();
189 
190     const SkBigPicture::AccelData* topLevelData = nullptr;
191     if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) {
192         topLevelData = bp->accelData();
193     }
194     if (!topLevelData) {
195         return;
196     }
197 
198     const SkLayerInfo *topLevelGPUData = static_cast<const SkLayerInfo*>(topLevelData);
199     if (0 == topLevelGPUData->numBlocks()) {
200         return;
201     }
202 
203     // Find and prepare for hoisting all the layers that intersect the query rect
204     for (int i = 0; i < topLevelGPUData->numBlocks(); ++i) {
205         const SkLayerInfo::BlockInfo& info = topLevelGPUData->block(i);
206         if (info.fIsNested) {
207             // Parent layers are currently hoisted while nested layers are not.
208             continue;
209         }
210 
211         SkRect layerRect;
212         initialMat.mapRect(&layerRect, info.fBounds);
213         if (!layerRect.intersect(query)) {
214             continue;
215         }
216 
217         const SkIRect dstIR = layerRect.roundOut();
218 
219         SkIRect srcIR;
220         if (!compute_source_rect(info, initialMat, dstIR, &srcIR)) {
221             continue;
222         }
223 
224         prepare_for_hoisting(layerCache, topLevelPicture, initialMat, info, srcIR, dstIR,
225                              needRendering, recycled, false, numSamples);
226     }
227 }
228 
DrawLayersToAtlas(GrContext * context,const SkTDArray<GrHoistedLayer> & atlased)229 void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
230                                        const SkTDArray<GrHoistedLayer>& atlased) {
231     if (atlased.count() > 0) {
232         // All the atlased layers are rendered into the same GrTexture
233         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
234         SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
235                                         atlased[0].fLayer->texture()->asRenderTarget(), &props));
236 
237         SkCanvas* atlasCanvas = surface->getCanvas();
238 
239         for (int i = 0; i < atlased.count(); ++i) {
240             const GrCachedLayer* layer = atlased[i].fLayer;
241             const SkBigPicture* pict = atlased[i].fPicture->asSkBigPicture();
242             if (!pict) {
243                 // TODO: can we assume / assert this?
244                 continue;
245             }
246             const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
247             SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();)
248 
249             SkASSERT(!layerPaint || !layerPaint->getImageFilter());
250             SkASSERT(!layer->filter());
251 
252             atlasCanvas->save();
253 
254             // Add a rect clip to make sure the rendering doesn't
255             // extend beyond the boundaries of the atlased sub-rect
256             const SkRect bound = SkRect::Make(layer->rect());
257             atlasCanvas->clipRect(bound);
258             atlasCanvas->clear(0);
259 
260             // '-offset' maps the layer's top/left to the origin.
261             // Since this layer is atlased, the top/left corner needs
262             // to be offset to the correct location in the backing texture.
263             SkMatrix initialCTM;
264             initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY));
265             initialCTM.preTranslate(bound.fLeft, bound.fTop);
266             initialCTM.preConcat(atlased[i].fPreMat);
267 
268             atlasCanvas->setMatrix(initialCTM);
269             atlasCanvas->concat(atlased[i].fLocalMat);
270 
271             pict->partialPlayback(atlasCanvas, layer->start() + 1, layer->stop(), initialCTM);
272             atlasCanvas->restore();
273         }
274 
275         atlasCanvas->flush();
276     }
277 }
278 
FilterLayer(GrContext * context,SkGpuDevice * device,const GrHoistedLayer & info)279 void GrLayerHoister::FilterLayer(GrContext* context,
280                                  SkGpuDevice* device,
281                                  const GrHoistedLayer& info) {
282     GrCachedLayer* layer = info.fLayer;
283 
284     SkASSERT(layer->filter());
285 
286     static const int kDefaultCacheSize = 32 * 1024 * 1024;
287 
288     SkBitmap filteredBitmap;
289     SkIPoint offset = SkIPoint::Make(0, 0);
290 
291     const SkIPoint filterOffset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
292 
293     SkMatrix totMat = SkMatrix::I();
294     totMat.preConcat(info.fPreMat);
295     totMat.preConcat(info.fLocalMat);
296     totMat.postTranslate(-SkIntToScalar(filterOffset.fX), -SkIntToScalar(filterOffset.fY));
297 
298     SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop);
299     SkIRect clipBounds = layer->rect();
300 
301     // This cache is transient, and is freed (along with all its contained
302     // textures) when it goes out of scope.
303     SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kDefaultCacheSize));
304     SkImageFilter::Context filterContext(totMat, clipBounds, cache);
305 
306     SkImageFilter::DeviceProxy proxy(device);
307     SkBitmap src;
308     GrWrapTextureInBitmap(layer->texture(), layer->texture()->width(), layer->texture()->height(),
309                           false, &src);
310 
311     if (!layer->filter()->filterImageDeprecated(&proxy, src, filterContext,
312                                                 &filteredBitmap, &offset)) {
313         // Filtering failed. Press on with the unfiltered version.
314         return;
315     }
316 
317     SkIRect newRect = SkIRect::MakeWH(filteredBitmap.width(), filteredBitmap.height());
318     layer->setTexture(filteredBitmap.getTexture(), newRect, false);
319     layer->setOffset(offset);
320 }
321 
DrawLayers(GrContext * context,const SkTDArray<GrHoistedLayer> & layers)322 void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLayer>& layers) {
323     for (int i = 0; i < layers.count(); ++i) {
324         GrCachedLayer* layer = layers[i].fLayer;
325         const SkBigPicture* pict = layers[i].fPicture->asSkBigPicture();
326         if (!pict) {
327             // TODO: can we assume / assert this?
328             continue;
329         }
330         const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
331 
332         // Each non-atlased layer has its own GrTexture
333         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
334         SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
335                                         layer->texture()->asRenderTarget(), &props));
336 
337         SkCanvas* layerCanvas = surface->getCanvas();
338 
339         SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop);
340 
341         // Add a rect clip to make sure the rendering doesn't
342         // extend beyond the boundaries of the layer
343         const SkRect bound = SkRect::Make(layer->rect());
344         layerCanvas->clipRect(bound);
345         layerCanvas->clear(SK_ColorTRANSPARENT);
346 
347         SkMatrix initialCTM;
348         initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY));
349         initialCTM.preConcat(layers[i].fPreMat);
350 
351         layerCanvas->setMatrix(initialCTM);
352         layerCanvas->concat(layers[i].fLocalMat);
353 
354         pict->partialPlayback(layerCanvas, layer->start()+1, layer->stop(), initialCTM);
355         layerCanvas->flush();
356 
357         if (layer->filter()) {
358             SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(surface.get());
359 
360             FilterLayer(context, gpuSurf->getDevice(), layers[i]);
361         }
362     }
363 }
364 
UnlockLayers(GrContext * context,const SkTDArray<GrHoistedLayer> & layers)365 void GrLayerHoister::UnlockLayers(GrContext* context,
366                                   const SkTDArray<GrHoistedLayer>& layers) {
367     GrLayerCache* layerCache = context->getLayerCache();
368 
369     for (int i = 0; i < layers.count(); ++i) {
370         layerCache->removeUse(layers[i].fLayer);
371     }
372 
373     SkDEBUGCODE(layerCache->validate();)
374 }
375 
Begin(GrContext * context)376 void GrLayerHoister::Begin(GrContext* context) {
377     GrLayerCache* layerCache = context->getLayerCache();
378 
379     layerCache->begin();
380 }
381 
End(GrContext * context)382 void GrLayerHoister::End(GrContext* context) {
383     GrLayerCache* layerCache = context->getLayerCache();
384 
385 #if !GR_CACHE_HOISTED_LAYERS
386 
387     // This code completely clears out the atlas. It is required when
388     // caching is disabled so the atlas doesn't fill up and force more
389     // free floating layers
390     layerCache->purgeAll();
391 #endif
392 
393     layerCache->end();
394 }
395