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.
24static 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.
88static 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.
119void 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
181void 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
230void 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
279SkBitmap 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
288void 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
328void 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
370void 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
381void 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