Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrLayerHoister.cpp
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 "SkGrPixelRef.h"
14 #include "SkRecordDraw.h"
15 #include "SkSurface.h"
16
17 // Create the layer information for the hoisted layer and secure the
18 // required texture/render target resources.
19 static void prepare_for_hoisting(GrLayerCache* layerCache, 
20                                  const SkPicture* topLevelPicture,
21                                  const GrAccelData::SaveLayerInfo& info,
22                                  const SkIRect& layerRect,
23                                  SkTDArray<GrHoistedLayer>* needRendering,
24                                  SkTDArray<GrHoistedLayer>* recycled,
25                                  bool attemptToAtlas) {
26     const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture;
27
28     SkMatrix combined = SkMatrix::Concat(info.fPreMat, info.fLocalMat);
29
30     GrCachedLayer* layer = layerCache->findLayerOrCreate(pict->uniqueID(),
31                                                          info.fSaveLayerOpID,
32                                                          info.fRestoreOpID,
33                                                          layerRect,
34                                                          combined,
35                                                          info.fPaint);
36     GrSurfaceDesc desc;
37     desc.fFlags = kRenderTarget_GrSurfaceFlag;
38     desc.fWidth = layerRect.width();
39     desc.fHeight = layerRect.height();
40     desc.fConfig = kSkia8888_GrPixelConfig;
41     // TODO: need to deal with sample count
42
43     bool locked, needsRendering;
44     if (attemptToAtlas) {
45         locked = layerCache->tryToAtlas(layer, desc, &needsRendering);
46     } else {
47         locked = layerCache->lock(layer, desc, &needsRendering);
48     }
49     if (!locked) {
50         // GPU resources could not be secured for the hoisting of this layer
51         return;
52     }
53
54     if (attemptToAtlas) {
55         SkASSERT(layer->isAtlased());
56     }
57
58     GrHoistedLayer* hl;
59
60     if (needsRendering) {
61         if (!attemptToAtlas) {
62             SkASSERT(!layer->isAtlased());
63         }
64         hl = needRendering->append();
65     } else {
66         hl = recycled->append();
67     }
68     
69     layerCache->addUse(layer);
70     hl->fLayer = layer;
71     hl->fPicture = pict;
72     hl->fOffset = SkIPoint::Make(layerRect.fLeft, layerRect.fTop);
73     hl->fLocalMat = info.fLocalMat;
74     hl->fPreMat = info.fPreMat;
75 }
76
77 // Atlased layers must be small enough to fit in the atlas, not have a
78 // paint with an image filter and be neither nested nor nesting.
79 // TODO: allow leaf nested layers to appear in the atlas.
80 void GrLayerHoister::FindLayersToAtlas(GrContext* context,
81                                        const SkPicture* topLevelPicture,
82                                        const SkRect& query,
83                                        SkTDArray<GrHoistedLayer>* atlased,
84                                        SkTDArray<GrHoistedLayer>* recycled) {
85     GrLayerCache* layerCache = context->getLayerCache();
86
87     layerCache->processDeletedPictures();
88
89     SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
90
91     const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
92     if (!topLevelData) {
93         return;
94     }
95
96     const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData);
97     if (0 == topLevelGPUData->numSaveLayers()) {
98         return;
99     }
100
101     atlased->setReserve(atlased->count() + topLevelGPUData->numSaveLayers());
102
103     for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) {
104         const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i);
105
106         // TODO: ignore perspective projected layers here?
107         bool disallowAtlasing = info.fHasNestedLayers || info.fIsNested ||
108                                 (info.fPaint && info.fPaint->getImageFilter());
109
110         if (disallowAtlasing) {
111             continue;
112         }
113
114         SkRect layerRect = info.fBounds;
115         if (!layerRect.intersect(query)) {
116             continue;
117         }
118
119         SkIRect ir;
120         layerRect.roundOut(&ir);
121
122         if (!GrLayerCache::PlausiblyAtlasable(ir.width(), ir.height())) {
123             continue;
124         }
125
126         prepare_for_hoisting(layerCache, topLevelPicture, info, ir, atlased, recycled, true);
127     }
128
129 }
130
131 void GrLayerHoister::FindLayersToHoist(GrContext* context,
132                                        const SkPicture* topLevelPicture,
133                                        const SkRect& query,
134                                        SkTDArray<GrHoistedLayer>* needRendering,
135                                        SkTDArray<GrHoistedLayer>* recycled) {
136     GrLayerCache* layerCache = context->getLayerCache();
137
138     layerCache->processDeletedPictures();
139
140     SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
141
142     const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
143     if (!topLevelData) {
144         return;
145     }
146
147     const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData);
148     if (0 == topLevelGPUData->numSaveLayers()) {
149         return;
150     }
151
152     // Find and prepare for hoisting all the layers that intersect the query rect
153     for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) {
154         const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i);
155         if (info.fIsNested) {
156             // Parent layers are currently hoisted while nested layers are not.
157             continue;
158         }
159
160         SkRect layerRect = info.fBounds;
161         if (!layerRect.intersect(query)) {
162             continue;
163         }
164
165         SkIRect ir;
166         layerRect.roundOut(&ir);
167
168         prepare_for_hoisting(layerCache, topLevelPicture, info, ir, 
169                              needRendering, recycled, false);
170     }
171 }
172
173 static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* result) {
174     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
175     result->setInfo(info);
176     result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
177 }
178
179 void GrLayerHoister::ConvertLayersToReplacements(const SkTDArray<GrHoistedLayer>& layers,
180                                                  GrReplacements* replacements) {
181     // TODO: just replace GrReplacements::ReplacementInfo with GrCachedLayer?
182     for (int i = 0; i < layers.count(); ++i) {
183         GrCachedLayer* layer = layers[i].fLayer;
184         const SkPicture* picture = layers[i].fPicture;
185
186         SkMatrix combined = SkMatrix::Concat(layers[i].fPreMat, layers[i].fLocalMat);
187
188         GrReplacements::ReplacementInfo* layerInfo =
189                     replacements->newReplacement(picture->uniqueID(),
190                                                  layer->start(),
191                                                  combined);
192         layerInfo->fStop = layer->stop();
193         layerInfo->fPos = layers[i].fOffset;
194
195         SkBitmap bm;
196         wrap_texture(layers[i].fLayer->texture(),
197                      !layers[i].fLayer->isAtlased() ? layers[i].fLayer->rect().width()
198                                                     : layers[i].fLayer->texture()->width(),
199                      !layers[i].fLayer->isAtlased() ? layers[i].fLayer->rect().height()
200                                                     : layers[i].fLayer->texture()->height(),
201                      &bm);
202         layerInfo->fImage = SkImage::NewTexture(bm);
203
204         layerInfo->fPaint = layers[i].fLayer->paint()
205                                 ? SkNEW_ARGS(SkPaint, (*layers[i].fLayer->paint()))
206                                 : NULL;
207
208         layerInfo->fSrcRect = SkIRect::MakeXYWH(layers[i].fLayer->rect().fLeft,
209                                                 layers[i].fLayer->rect().fTop,
210                                                 layers[i].fLayer->rect().width(),
211                                                 layers[i].fLayer->rect().height());
212     }
213 }
214
215 void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
216                                        const SkTDArray<GrHoistedLayer>& atlased) {
217     if (atlased.count() > 0) {
218         // All the atlased layers are rendered into the same GrTexture
219         SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
220                                         atlased[0].fLayer->texture()->asRenderTarget(), NULL));
221
222         SkCanvas* atlasCanvas = surface->getCanvas();
223
224         SkPaint clearPaint;
225         clearPaint.setColor(SK_ColorTRANSPARENT);
226         clearPaint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref();
227
228         for (int i = 0; i < atlased.count(); ++i) {
229             const GrCachedLayer* layer = atlased[i].fLayer;
230             const SkPicture* pict = atlased[i].fPicture;
231             const SkIPoint offset = atlased[i].fOffset;
232             SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();)
233
234             SkASSERT(!layerPaint || !layerPaint->getImageFilter());
235
236             atlasCanvas->save();
237
238             // Add a rect clip to make sure the rendering doesn't
239             // extend beyond the boundaries of the atlased sub-rect
240             SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
241                                             SkIntToScalar(layer->rect().fTop),
242                                             SkIntToScalar(layer->rect().width()),
243                                             SkIntToScalar(layer->rect().height()));
244             atlasCanvas->clipRect(bound);
245
246             // Since 'clear' doesn't respect the clip we need to draw a rect
247             atlasCanvas->drawRect(bound, clearPaint);
248
249             // '-offset' maps the layer's top/left to the origin.
250             // Since this layer is atlased, the top/left corner needs
251             // to be offset to the correct location in the backing texture.
252             SkMatrix initialCTM;
253             initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY));
254             initialCTM.preTranslate(bound.fLeft, bound.fTop);
255             initialCTM.preConcat(atlased[i].fPreMat);
256
257             atlasCanvas->setMatrix(initialCTM);
258             atlasCanvas->concat(atlased[i].fLocalMat);
259
260             SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound,
261                                 layer->start() + 1, layer->stop(), initialCTM);
262
263             atlasCanvas->restore();
264         }
265
266         atlasCanvas->flush();
267     }
268 }
269
270 void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLayer>& layers) {
271     for (int i = 0; i < layers.count(); ++i) {
272         GrCachedLayer* layer = layers[i].fLayer;
273         const SkPicture* pict = layers[i].fPicture;
274         const SkIPoint& offset = layers[i].fOffset;
275
276         // Each non-atlased layer has its own GrTexture
277         SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
278                                         layer->texture()->asRenderTarget(), NULL));
279
280         SkCanvas* layerCanvas = surface->getCanvas();
281
282         SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop);
283
284         // Add a rect clip to make sure the rendering doesn't
285         // extend beyond the boundaries of the layer
286         SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
287                                         SkIntToScalar(layer->rect().fTop),
288                                         SkIntToScalar(layer->rect().width()),
289                                         SkIntToScalar(layer->rect().height()));
290
291         layerCanvas->clipRect(bound);
292
293         layerCanvas->clear(SK_ColorTRANSPARENT);
294
295         SkMatrix initialCTM;
296         initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY));
297         initialCTM.preConcat(layers[i].fPreMat);
298
299         layerCanvas->setMatrix(initialCTM);
300         layerCanvas->concat(layers[i].fLocalMat);
301
302         SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound,
303                             layer->start()+1, layer->stop(), initialCTM);
304
305         layerCanvas->flush();
306     }
307 }
308
309 void GrLayerHoister::UnlockLayers(GrContext* context,
310                                   const SkTDArray<GrHoistedLayer>& layers) {
311     GrLayerCache* layerCache = context->getLayerCache();
312
313     for (int i = 0; i < layers.count(); ++i) {
314         layerCache->removeUse(layers[i].fLayer);
315     }
316
317     SkDEBUGCODE(layerCache->validate();)
318 }
319
320 void GrLayerHoister::PurgeCache(GrContext* context) {
321 #if !GR_CACHE_HOISTED_LAYERS
322     GrLayerCache* layerCache = context->getLayerCache();
323
324     // This code completely clears out the atlas. It is required when
325     // caching is disabled so the atlas doesn't fill up and force more
326     // free floating layers
327     layerCache->purgeAll();
328 #endif
329 }