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