2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "GrLayerCache.h"
9 #include "GrLayerHoister.h"
10 #include "GrRecordReplaceDraw.h"
13 #include "SkGrPixelRef.h"
14 #include "SkRecordDraw.h"
15 #include "SkSurface.h"
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;
28 SkMatrix combined = SkMatrix::Concat(info.fPreMat, info.fLocalMat);
30 GrCachedLayer* layer = layerCache->findLayerOrCreate(pict->uniqueID(),
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
43 bool locked, needsRendering;
45 locked = layerCache->tryToAtlas(layer, desc, &needsRendering);
47 locked = layerCache->lock(layer, desc, &needsRendering);
50 // GPU resources could not be secured for the hoisting of this layer
55 SkASSERT(layer->isAtlased());
61 if (!attemptToAtlas) {
62 SkASSERT(!layer->isAtlased());
64 hl = needRendering->append();
66 hl = recycled->append();
69 layerCache->addUse(layer);
72 hl->fOffset = SkIPoint::Make(layerRect.fLeft, layerRect.fTop);
73 hl->fLocalMat = info.fLocalMat;
74 hl->fPreMat = info.fPreMat;
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,
83 SkTDArray<GrHoistedLayer>* atlased,
84 SkTDArray<GrHoistedLayer>* recycled) {
85 GrLayerCache* layerCache = context->getLayerCache();
87 layerCache->processDeletedPictures();
89 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
91 const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
96 const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData);
97 if (0 == topLevelGPUData->numSaveLayers()) {
101 atlased->setReserve(atlased->count() + topLevelGPUData->numSaveLayers());
103 for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) {
104 const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i);
106 // TODO: ignore perspective projected layers here?
107 bool disallowAtlasing = info.fHasNestedLayers || info.fIsNested ||
108 (info.fPaint && info.fPaint->getImageFilter());
110 if (disallowAtlasing) {
114 SkRect layerRect = info.fBounds;
115 if (!layerRect.intersect(query)) {
120 layerRect.roundOut(&ir);
122 if (!GrLayerCache::PlausiblyAtlasable(ir.width(), ir.height())) {
126 prepare_for_hoisting(layerCache, topLevelPicture, info, ir, atlased, recycled, true);
131 void GrLayerHoister::FindLayersToHoist(GrContext* context,
132 const SkPicture* topLevelPicture,
134 SkTDArray<GrHoistedLayer>* needRendering,
135 SkTDArray<GrHoistedLayer>* recycled) {
136 GrLayerCache* layerCache = context->getLayerCache();
138 layerCache->processDeletedPictures();
140 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
142 const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
147 const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData);
148 if (0 == topLevelGPUData->numSaveLayers()) {
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.
160 SkRect layerRect = info.fBounds;
161 if (!layerRect.intersect(query)) {
166 layerRect.roundOut(&ir);
168 prepare_for_hoisting(layerCache, topLevelPicture, info, ir,
169 needRendering, recycled, false);
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();
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;
186 SkMatrix combined = SkMatrix::Concat(layers[i].fPreMat, layers[i].fLocalMat);
188 GrReplacements::ReplacementInfo* layerInfo =
189 replacements->newReplacement(picture->uniqueID(),
192 layerInfo->fStop = layer->stop();
193 layerInfo->fPos = layers[i].fOffset;
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(),
202 layerInfo->fImage = SkImage::NewTexture(bm);
204 layerInfo->fPaint = layers[i].fLayer->paint()
205 ? SkNEW_ARGS(SkPaint, (*layers[i].fLayer->paint()))
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());
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));
222 SkCanvas* atlasCanvas = surface->getCanvas();
225 clearPaint.setColor(SK_ColorTRANSPARENT);
226 clearPaint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref();
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();)
234 SkASSERT(!layerPaint || !layerPaint->getImageFilter());
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);
246 // Since 'clear' doesn't respect the clip we need to draw a rect
247 atlasCanvas->drawRect(bound, clearPaint);
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.
253 initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY));
254 initialCTM.preTranslate(bound.fLeft, bound.fTop);
255 initialCTM.preConcat(atlased[i].fPreMat);
257 atlasCanvas->setMatrix(initialCTM);
258 atlasCanvas->concat(atlased[i].fLocalMat);
260 SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound,
261 layer->start() + 1, layer->stop(), initialCTM);
263 atlasCanvas->restore();
266 atlasCanvas->flush();
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;
276 // Each non-atlased layer has its own GrTexture
277 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
278 layer->texture()->asRenderTarget(), NULL));
280 SkCanvas* layerCanvas = surface->getCanvas();
282 SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop);
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()));
291 layerCanvas->clipRect(bound);
293 layerCanvas->clear(SK_ColorTRANSPARENT);
296 initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY));
297 initialCTM.preConcat(layers[i].fPreMat);
299 layerCanvas->setMatrix(initialCTM);
300 layerCanvas->concat(layers[i].fLocalMat);
302 SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound,
303 layer->start()+1, layer->stop(), initialCTM);
305 layerCanvas->flush();
309 void GrLayerHoister::UnlockLayers(GrContext* context,
310 const SkTDArray<GrHoistedLayer>& layers) {
311 GrLayerCache* layerCache = context->getLayerCache();
313 for (int i = 0; i < layers.count(); ++i) {
314 layerCache->removeUse(layers[i].fLayer);
317 SkDEBUGCODE(layerCache->validate();)
320 void GrLayerHoister::PurgeCache(GrContext* context) {
321 #if !GR_CACHE_HOISTED_LAYERS
322 GrLayerCache* layerCache = context->getLayerCache();
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();