blob: a29d91ac9d3ec95fa295fd908d8335f0b6847468 [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"
robertphillips98d709b2014-09-02 10:20:50 -070010#include "SkCanvas.h"
robertphillips274b4ba2014-09-04 07:24:18 -070011#include "SkRecordDraw.h"
robertphillips98d709b2014-09-02 10:20:50 -070012#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.
robertphillips4815fe52014-09-16 10:32:43 -070094 SkMatrix initialCTM;
95 initialCTM.setTranslate(SkIntToScalar(-layer->offset().fX),
96 SkIntToScalar(-layer->offset().fY));
97 initialCTM.postTranslate(bound.fLeft, bound.fTop);
98
99 atlasCanvas->translate(SkIntToScalar(-layer->offset().fX),
100 SkIntToScalar(-layer->offset().fY));
robertphillips98d709b2014-09-02 10:20:50 -0700101 atlasCanvas->translate(bound.fLeft, bound.fTop);
102 atlasCanvas->concat(layer->ctm());
103
robertphillips274b4ba2014-09-04 07:24:18 -0700104 SkRecordPartialDraw(*picture->fRecord.get(), atlasCanvas, bound,
robertphillips4815fe52014-09-16 10:32:43 -0700105 layer->start()+1, layer->stop(), initialCTM);
robertphillips98d709b2014-09-02 10:20:50 -0700106
107 atlasCanvas->restore();
108 }
109
110 atlasCanvas->flush();
111 }
112
113 // Render the non-atlased layers that require it
114 for (int i = 0; i < nonAtlased.count(); ++i) {
115 GrCachedLayer* layer = nonAtlased[i];
116
117 // Each non-atlased layer has its own GrTexture
118 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
robertphillips274b4ba2014-09-04 07:24:18 -0700119 layer->texture()->asRenderTarget(),
120 SkSurface::kStandard_TextRenderMode,
121 SkSurface::kDontClear_RenderTargetFlag));
robertphillips98d709b2014-09-02 10:20:50 -0700122
123 SkCanvas* layerCanvas = surface->getCanvas();
124
125 // Add a rect clip to make sure the rendering doesn't
126 // extend beyond the boundaries of the atlased sub-rect
127 SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
128 SkIntToScalar(layer->rect().fTop),
129 SkIntToScalar(layer->rect().width()),
130 SkIntToScalar(layer->rect().height()));
131
132 layerCanvas->clipRect(bound); // TODO: still useful?
133
134 layerCanvas->clear(SK_ColorTRANSPARENT);
135
robertphillips4815fe52014-09-16 10:32:43 -0700136 SkMatrix initialCTM;
137 initialCTM.setTranslate(SkIntToScalar(-layer->offset().fX),
138 SkIntToScalar(-layer->offset().fY));
139
140 layerCanvas->translate(SkIntToScalar(-layer->offset().fX),
141 SkIntToScalar(-layer->offset().fY));
robertphillips98d709b2014-09-02 10:20:50 -0700142 layerCanvas->concat(layer->ctm());
143
robertphillips274b4ba2014-09-04 07:24:18 -0700144 SkRecordPartialDraw(*picture->fRecord.get(), layerCanvas, bound,
robertphillips4815fe52014-09-16 10:32:43 -0700145 layer->start()+1, layer->stop(), initialCTM);
robertphillips98d709b2014-09-02 10:20:50 -0700146
147 layerCanvas->flush();
148 }
149}
150
151void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache, const SkPicture* picture) {
152 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
153
154 const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key);
bsalomon49f085d2014-09-05 13:34:00 -0700155 SkASSERT(data);
robertphillips98d709b2014-09-02 10:20:50 -0700156
157 const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
158 SkASSERT(0 != gpuData->numSaveLayers());
159
160 // unlock the layers
161 for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
162 const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
163
164 GrCachedLayer* layer = layerCache->findLayer(picture->uniqueID(),
165 info.fSaveLayerOpID,
166 info.fRestoreOpID,
robertphillips4815fe52014-09-16 10:32:43 -0700167 info.fOffset,
robertphillips98d709b2014-09-02 10:20:50 -0700168 info.fOriginXform);
169 layerCache->unlock(layer);
170 }
171
172#if DISABLE_CACHING
173 // This code completely clears out the atlas. It is required when
174 // caching is disabled so the atlas doesn't fill up and force more
175 // free floating layers
176 layerCache->purge(picture->uniqueID());
177
178 layerCache->purgeAll();
179#endif
180}
181