• Home
  • History
  • Annotate
  • 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 "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
FindLayersToHoist(const SkPicture * topLevelPicture,const SkRect & query,SkTDArray<HoistedLayer> * atlased,SkTDArray<HoistedLayer> * nonAtlased,GrLayerCache * layerCache)17 bool 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 
wrap_texture(GrTexture * texture,int width,int height,SkBitmap * result)122 static 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 
convert_layers_to_replacements(const SkTDArray<GrLayerHoister::HoistedLayer> & layers,GrReplacements * replacements)128 static 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 
DrawLayers(const SkTDArray<HoistedLayer> & atlased,const SkTDArray<HoistedLayer> & nonAtlased,GrReplacements * replacements)157 void 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 
unlock_layer_in_cache(GrLayerCache * layerCache,const SkPicture * picture,GrCachedLayer * layer)252 static 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 
UnlockLayers(GrLayerCache * layerCache,const SkTDArray<HoistedLayer> & atlased,const SkTDArray<HoistedLayer> & nonAtlased)265 void 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