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