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