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