blob: 2dfefcd3feea6d06a05191134b15db3ec6f49162 [file] [log] [blame]
robertphillips98d709b2014-09-02 10:20:50 -07001/*
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 "SkPictureRangePlayback.h"
11#include "SkCanvas.h"
12#include "SkSurface.h"
13
14// Return true if any layers are suitable for hoisting
15bool GrLayerHoister::FindLayersToHoist(const GrAccelData *gpuData,
robertphillips98d709b2014-09-02 10:20:50 -070016 const SkRect& query,
17 bool pullForward[]) {
18 bool anyHoisted = false;
robertphillips98d709b2014-09-02 10:20:50 -070019
20 // Layer hoisting pre-renders the entire layer since it will be cached and potentially
21 // reused with different clips (e.g., in different tiles). Because of this the
22 // clip will not be limiting the size of the pre-rendered layer. kSaveLayerMaxSize
23 // is used to limit which clips are pre-rendered.
24 static const int kSaveLayerMaxSize = 256;
25
robertphillips2ed8a752014-09-03 13:46:02 -070026 // Pre-render all the layers that intersect the query rect
27 for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
28 pullForward[i] = false;
robertphillips98d709b2014-09-02 10:20:50 -070029
robertphillips2ed8a752014-09-03 13:46:02 -070030 const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
robertphillips98d709b2014-09-02 10:20:50 -070031
robertphillips2ed8a752014-09-03 13:46:02 -070032 SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX),
33 SkIntToScalar(info.fOffset.fY),
34 SkIntToScalar(info.fSize.fWidth),
35 SkIntToScalar(info.fSize.fHeight));
robertphillips98d709b2014-09-02 10:20:50 -070036
robertphillips2ed8a752014-09-03 13:46:02 -070037 if (!SkRect::Intersects(query, layerRect)) {
38 continue;
robertphillips98d709b2014-09-02 10:20:50 -070039 }
robertphillips98d709b2014-09-02 10:20:50 -070040
robertphillips2ed8a752014-09-03 13:46:02 -070041 // TODO: once this code is more stable unsuitable layers can
42 // just be omitted during the optimization stage
43 if (!info.fValid ||
44 kSaveLayerMaxSize < info.fSize.fWidth ||
45 kSaveLayerMaxSize < info.fSize.fHeight ||
46 info.fIsNested) {
47 continue;
robertphillips98d709b2014-09-02 10:20:50 -070048 }
robertphillips2ed8a752014-09-03 13:46:02 -070049
50 pullForward[i] = true;
51 anyHoisted = true;
robertphillips98d709b2014-09-02 10:20:50 -070052 }
53
54 return anyHoisted;
55}
56
57void GrLayerHoister::DrawLayers(const SkPicture* picture,
58 const SkTDArray<GrCachedLayer*>& atlased,
59 const SkTDArray<GrCachedLayer*>& nonAtlased) {
60 // Render the atlased layers that require it
61 if (atlased.count() > 0) {
62 // All the atlased layers are rendered into the same GrTexture
63 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
64 atlased[0]->texture()->asRenderTarget(),
65 SkSurface::kStandard_TextRenderMode,
66 SkSurface::kDontClear_RenderTargetFlag));
67
68 SkCanvas* atlasCanvas = surface->getCanvas();
69
70 SkPaint paint;
71 paint.setColor(SK_ColorTRANSPARENT);
72 paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref();
73
74 for (int i = 0; i < atlased.count(); ++i) {
75 GrCachedLayer* layer = atlased[i];
76
77 atlasCanvas->save();
78
79 // Add a rect clip to make sure the rendering doesn't
80 // extend beyond the boundaries of the atlased sub-rect
81 SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
82 SkIntToScalar(layer->rect().fTop),
83 SkIntToScalar(layer->rect().width()),
84 SkIntToScalar(layer->rect().height()));
85 atlasCanvas->clipRect(bound);
86
87 // Since 'clear' doesn't respect the clip we need to draw a rect
88 // TODO: ensure none of the atlased layers contain a clear call!
89 atlasCanvas->drawRect(bound, paint);
90
91 // info.fCTM maps the layer's top/left to the origin.
92 // Since this layer is atlased, the top/left corner needs
93 // to be offset to the correct location in the backing texture.
94 atlasCanvas->translate(bound.fLeft, bound.fTop);
95 atlasCanvas->concat(layer->ctm());
96
97 SkPictureRangePlayback rangePlayback(picture,
98 layer->start(),
99 layer->stop());
100 rangePlayback.draw(atlasCanvas, NULL);
101
102 atlasCanvas->restore();
103 }
104
105 atlasCanvas->flush();
106 }
107
108 // Render the non-atlased layers that require it
109 for (int i = 0; i < nonAtlased.count(); ++i) {
110 GrCachedLayer* layer = nonAtlased[i];
111
112 // Each non-atlased layer has its own GrTexture
113 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
114 layer->texture()->asRenderTarget(),
115 SkSurface::kStandard_TextRenderMode,
116 SkSurface::kDontClear_RenderTargetFlag));
117
118 SkCanvas* layerCanvas = surface->getCanvas();
119
120 // Add a rect clip to make sure the rendering doesn't
121 // extend beyond the boundaries of the atlased sub-rect
122 SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
123 SkIntToScalar(layer->rect().fTop),
124 SkIntToScalar(layer->rect().width()),
125 SkIntToScalar(layer->rect().height()));
126
127 layerCanvas->clipRect(bound); // TODO: still useful?
128
129 layerCanvas->clear(SK_ColorTRANSPARENT);
130
131 layerCanvas->concat(layer->ctm());
132
133 SkPictureRangePlayback rangePlayback(picture,
134 layer->start(),
135 layer->stop());
136 rangePlayback.draw(layerCanvas, NULL);
137
138 layerCanvas->flush();
139 }
140}
141
142void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache, const SkPicture* picture) {
143 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
144
145 const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key);
146 SkASSERT(NULL != data);
147
148 const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
149 SkASSERT(0 != gpuData->numSaveLayers());
150
151 // unlock the layers
152 for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
153 const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
154
155 GrCachedLayer* layer = layerCache->findLayer(picture->uniqueID(),
156 info.fSaveLayerOpID,
157 info.fRestoreOpID,
158 info.fOriginXform);
159 layerCache->unlock(layer);
160 }
161
162#if DISABLE_CACHING
163 // This code completely clears out the atlas. It is required when
164 // caching is disabled so the atlas doesn't fill up and force more
165 // free floating layers
166 layerCache->purge(picture->uniqueID());
167
168 layerCache->purgeAll();
169#endif
170}
171