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 "SkCanvas.h"
11#include "SkRecordDraw.h"
12#include "GrRecordReplaceDraw.h"
13#include "SkGrPixelRef.h"
14#include "SkSurface.h"
15
16// Return true if any layers are suitable for hoisting
17bool GrLayerHoister::FindLayersToHoist(const SkPicture* topLevelPicture,
18                                       const SkRect& query,
19                                       SkTDArray<HoistedLayer>* atlased,
20                                       SkTDArray<HoistedLayer>* nonAtlased,
21                                       GrLayerCache* layerCache) {
22    bool anyHoisted = false;
23
24    SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
25
26    const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
27    if (NULL == topLevelData) {
28        return false;
29    }
30
31    const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData);
32    if (0 == topLevelGPUData->numSaveLayers()) {
33        return false;
34    }
35
36    // Layer hoisting pre-renders the entire layer since it will be cached and potentially
37    // reused with different clips (e.g., in different tiles). Because of this the
38    // clip will not be limiting the size of the pre-rendered layer. kSaveLayerMaxSize
39    // is used to limit which clips are pre-rendered.
40    static const int kSaveLayerMaxSize = 256;
41
42    SkAutoTArray<bool> pullForward(topLevelGPUData->numSaveLayers());
43
44    // Pre-render all the layers that intersect the query rect
45    for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) {
46        pullForward[i] = false;
47
48        const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i);
49
50        SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX),
51                                            SkIntToScalar(info.fOffset.fY),
52                                            SkIntToScalar(info.fSize.fWidth),
53                                            SkIntToScalar(info.fSize.fHeight));
54
55        if (!SkRect::Intersects(query, layerRect)) {
56            continue;
57        }
58
59        // TODO: once this code is more stable unsuitable layers can
60        // just be omitted during the optimization stage
61        if (!info.fValid ||
62            kSaveLayerMaxSize < info.fSize.fWidth ||
63            kSaveLayerMaxSize < info.fSize.fHeight ||
64            info.fIsNested) {
65            continue;
66        }
67
68        pullForward[i] = true;
69        anyHoisted = true;
70    }
71
72    if (!anyHoisted) {
73        return false;
74    }
75
76    atlased->setReserve(atlased->reserved() + topLevelGPUData->numSaveLayers());
77
78    // Generate the layer and/or ensure it is locked
79    for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) {
80        if (pullForward[i]) {
81            const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i);
82            const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture;
83
84            GrCachedLayer* layer = layerCache->findLayerOrCreate(pict->uniqueID(),
85                                                                 info.fSaveLayerOpID,
86                                                                 info.fRestoreOpID,
87                                                                 info.fOffset,
88                                                                 info.fOriginXform,
89                                                                 info.fPaint);
90
91            GrTextureDesc desc;
92            desc.fFlags = kRenderTarget_GrTextureFlagBit;
93            desc.fWidth = info.fSize.fWidth;
94            desc.fHeight = info.fSize.fHeight;
95            desc.fConfig = kSkia8888_GrPixelConfig;
96            // TODO: need to deal with sample count
97
98            bool needsRendering = layerCache->lock(layer, desc,
99                                                   info.fHasNestedLayers || info.fIsNested);
100            if (NULL == layer->texture()) {
101                continue;
102            }
103
104            if (needsRendering) {
105                HoistedLayer* info;
106
107                if (layer->isAtlased()) {
108                    info = atlased->append();
109                } else {
110                    info = nonAtlased->append();
111                }
112
113                info->fLayer = layer;
114                info->fPicture = pict;
115            }
116        }
117    }
118
119    return anyHoisted;
120}
121
122static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* result) {
123    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
124    result->setInfo(info);
125    result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
126}
127
128static void convert_layers_to_replacements(const SkTDArray<GrLayerHoister::HoistedLayer>& layers,
129                                           GrReplacements* replacements) {
130    // TODO: just replace GrReplacements::ReplacementInfo with GrCachedLayer?
131    for (int i = 0; i < layers.count(); ++i) {
132        GrReplacements::ReplacementInfo* layerInfo = replacements->push();
133        layerInfo->fStart = layers[i].fLayer->start();
134        layerInfo->fStop = layers[i].fLayer->stop();
135        layerInfo->fPos = layers[i].fLayer->offset();;
136
137        SkBitmap bm;
138        wrap_texture(layers[i].fLayer->texture(),
139                     !layers[i].fLayer->isAtlased() ? layers[i].fLayer->rect().width()
140                                                    : layers[i].fLayer->texture()->width(),
141                     !layers[i].fLayer->isAtlased() ? layers[i].fLayer->rect().height()
142                                                    : layers[i].fLayer->texture()->height(),
143                     &bm);
144        layerInfo->fImage = SkImage::NewTexture(bm);
145
146        layerInfo->fPaint = layers[i].fLayer->paint()
147                                ? SkNEW_ARGS(SkPaint, (*layers[i].fLayer->paint()))
148                                : NULL;
149
150        layerInfo->fSrcRect = SkIRect::MakeXYWH(layers[i].fLayer->rect().fLeft,
151                                                layers[i].fLayer->rect().fTop,
152                                                layers[i].fLayer->rect().width(),
153                                                layers[i].fLayer->rect().height());
154    }
155}
156
157void GrLayerHoister::DrawLayers(const SkTDArray<HoistedLayer>& atlased,
158                                const SkTDArray<HoistedLayer>& nonAtlased,
159                                GrReplacements* replacements) {
160    // Render the atlased layers that require it
161    if (atlased.count() > 0) {
162        // All the atlased layers are rendered into the same GrTexture
163        SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
164                                        atlased[0].fLayer->texture()->asRenderTarget(), NULL));
165
166        SkCanvas* atlasCanvas = surface->getCanvas();
167
168        SkPaint paint;
169        paint.setColor(SK_ColorTRANSPARENT);
170        paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref();
171
172        for (int i = 0; i < atlased.count(); ++i) {
173            GrCachedLayer* layer = atlased[i].fLayer;
174            const SkPicture* pict = atlased[i].fPicture;
175
176            atlasCanvas->save();
177
178            // Add a rect clip to make sure the rendering doesn't
179            // extend beyond the boundaries of the atlased sub-rect
180            SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
181                                            SkIntToScalar(layer->rect().fTop),
182                                            SkIntToScalar(layer->rect().width()),
183                                            SkIntToScalar(layer->rect().height()));
184            atlasCanvas->clipRect(bound);
185
186            // Since 'clear' doesn't respect the clip we need to draw a rect
187            // TODO: ensure none of the atlased layers contain a clear call!
188            atlasCanvas->drawRect(bound, paint);
189
190            // info.fCTM maps the layer's top/left to the origin.
191            // Since this layer is atlased, the top/left corner needs
192            // to be offset to the correct location in the backing texture.
193            SkMatrix initialCTM;
194            initialCTM.setTranslate(SkIntToScalar(-layer->offset().fX),
195                                    SkIntToScalar(-layer->offset().fY));
196            initialCTM.postTranslate(bound.fLeft, bound.fTop);
197
198            atlasCanvas->translate(SkIntToScalar(-layer->offset().fX),
199                                   SkIntToScalar(-layer->offset().fY));
200            atlasCanvas->translate(bound.fLeft, bound.fTop);
201            atlasCanvas->concat(layer->ctm());
202
203            SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound,
204                                layer->start()+1, layer->stop(), initialCTM);
205
206            atlasCanvas->restore();
207        }
208
209        atlasCanvas->flush();
210    }
211
212    // Render the non-atlased layers that require it
213    for (int i = 0; i < nonAtlased.count(); ++i) {
214        GrCachedLayer* layer = nonAtlased[i].fLayer;
215        const SkPicture* pict = nonAtlased[i].fPicture;
216
217        // Each non-atlased layer has its own GrTexture
218        SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
219                                        layer->texture()->asRenderTarget(), NULL));
220
221        SkCanvas* layerCanvas = surface->getCanvas();
222
223        // Add a rect clip to make sure the rendering doesn't
224        // extend beyond the boundaries of the atlased sub-rect
225        SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
226                                        SkIntToScalar(layer->rect().fTop),
227                                        SkIntToScalar(layer->rect().width()),
228                                        SkIntToScalar(layer->rect().height()));
229
230        layerCanvas->clipRect(bound); // TODO: still useful?
231
232        layerCanvas->clear(SK_ColorTRANSPARENT);
233
234        SkMatrix initialCTM;
235        initialCTM.setTranslate(SkIntToScalar(-layer->offset().fX),
236                                SkIntToScalar(-layer->offset().fY));
237
238        layerCanvas->translate(SkIntToScalar(-layer->offset().fX),
239                               SkIntToScalar(-layer->offset().fY));
240        layerCanvas->concat(layer->ctm());
241
242        SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound,
243                            layer->start()+1, layer->stop(), initialCTM);
244
245        layerCanvas->flush();
246    }
247
248    convert_layers_to_replacements(atlased, replacements);
249    convert_layers_to_replacements(nonAtlased, replacements);
250}
251
252static void unlock_layer_in_cache(GrLayerCache* layerCache,
253                                  const SkPicture* picture,
254                                  GrCachedLayer* layer) {
255    layerCache->unlock(layer);
256
257#if DISABLE_CACHING
258    // This code completely clears out the atlas. It is required when
259    // caching is disabled so the atlas doesn't fill up and force more
260    // free floating layers
261    layerCache->purge(picture->uniqueID());
262#endif
263}
264
265void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache,
266                                  const SkTDArray<HoistedLayer>& atlased,
267                                  const SkTDArray<HoistedLayer>& nonAtlased) {
268
269    for (int i = 0; i < atlased.count(); ++i) {
270        unlock_layer_in_cache(layerCache, atlased[i].fPicture, atlased[i].fLayer);
271    }
272
273    for (int i = 0; i < nonAtlased.count(); ++i) {
274        unlock_layer_in_cache(layerCache, nonAtlased[i].fPicture, nonAtlased[i].fLayer);
275    }
276
277#if DISABLE_CACHING
278    // This code completely clears out the atlas. It is required when
279    // caching is disabled so the atlas doesn't fill up and force more
280    // free floating layers
281    layerCache->purgeAll();
282#endif
283}
284
285