blob: 521160ac8afd172d34b4d79ab8914fbbb2e20102 [file] [log] [blame]
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +00001/*
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 "GrPictureUtils.h"
robertphillipsd6283302014-08-27 11:53:28 -07009
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000010#include "SkPaintPriv.h"
robertphillipsd6283302014-08-27 11:53:28 -070011#include "SkRecord.h"
12#include "SkRecords.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000013
robertphillips6617d502014-08-18 09:39:34 -070014SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000015 static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
16
17 return gGPUID;
18}
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000019
robertphillipsd6283302014-08-27 11:53:28 -070020// SkRecord visitor to gather saveLayer/restore information.
21class CollectLayers {
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000022public:
robertphillipsd6283302014-08-27 11:53:28 -070023 CollectLayers(const SkPicture* pict, GrAccelData* accelData)
24 : fPictureID(pict->uniqueID())
25 , fCTM(&SkMatrix::I())
26 , fCurrentClipBounds(SkIRect::MakeXYWH(0, 0, pict->width(), pict->height()))
27 , fSaveLayersInStack(0)
28 , fAccelData(accelData) {
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000029
robertphillipsd6283302014-08-27 11:53:28 -070030 if (NULL == pict->fRecord.get()) {
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000031 return;
32 }
33
robertphillipsd6283302014-08-27 11:53:28 -070034 for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp) {
35 pict->fRecord->visit<void>(fCurrentOp, *this);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000036 }
37
robertphillipsd6283302014-08-27 11:53:28 -070038 while (!fSaveStack.isEmpty()) {
39 this->popSaveBlock();
robertphillips9b14f262014-06-04 05:40:44 -070040 }
41 }
42
robertphillipsd6283302014-08-27 11:53:28 -070043 template <typename T> void operator()(const T& op) {
44 this->updateCTM(op);
45 this->updateClipBounds(op);
46 this->trackSaveLayers(op);
47 }
48
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000049private:
robertphillipsd6283302014-08-27 11:53:28 -070050
51 class SaveInfo {
52 public:
53 SaveInfo() { }
54 SaveInfo(int opIndex, bool isSaveLayer, const SkPaint* paint, const SkIRect& bounds)
55 : fStartIndex(opIndex)
56 , fIsSaveLayer(isSaveLayer)
57 , fHasNestedSaveLayer(false)
58 , fPaint(paint)
59 , fBounds(bounds) {
60
61 }
62
63 int fStartIndex;
64 bool fIsSaveLayer;
65 bool fHasNestedSaveLayer;
66 const SkPaint* fPaint;
67 SkIRect fBounds;
68 };
69
70 uint32_t fPictureID;
71 unsigned int fCurrentOp;
72 const SkMatrix* fCTM;
73 SkIRect fCurrentClipBounds;
74 int fSaveLayersInStack;
75 SkTDArray<SaveInfo> fSaveStack;
76 GrAccelData* fAccelData;
77
78 template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ }
79 void updateCTM(const SkRecords::Restore& op) { fCTM = &op.matrix; }
80 void updateCTM(const SkRecords::SetMatrix& op) { fCTM = &op.matrix; }
81
82 template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
83 // Each of these devBounds fields is the state of the device bounds after the op.
84 // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
85 void updateClipBounds(const SkRecords::Restore& op) { fCurrentClipBounds = op.devBounds; }
86 void updateClipBounds(const SkRecords::ClipPath& op) { fCurrentClipBounds = op.devBounds; }
87 void updateClipBounds(const SkRecords::ClipRRect& op) { fCurrentClipBounds = op.devBounds; }
88 void updateClipBounds(const SkRecords::ClipRect& op) { fCurrentClipBounds = op.devBounds; }
89 void updateClipBounds(const SkRecords::ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
90 void updateClipBounds(const SkRecords::SaveLayer& op) {
91 if (NULL != op.bounds) {
92 fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
93 }
94 }
95
96 template <typename T> void trackSaveLayers(const T& op) {
97 /* most ops aren't involved in saveLayers */
98 }
99 void trackSaveLayers(const SkRecords::Save& s) { this->pushSaveBlock(); }
100 void trackSaveLayers(const SkRecords::SaveLayer& sl) { this->pushSaveLayerBlock(sl.paint); }
101 void trackSaveLayers(const SkRecords::Restore& r) { this->popSaveBlock(); }
102 void trackSaveLayers(const SkRecords::DrawPicture& dp) {
103 // For sub-pictures, we wrap their layer information within the parent
104 // picture's rendering hierarchy
105 const GrAccelData* childData = GPUOptimize(dp.picture);
106
107 for (int i = 0; i < childData->numSaveLayers(); ++i) {
108 const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i);
109
110 this->updateStackForSaveLayer();
111
112 GrAccelData::SaveLayerInfo dst;
113
114 // TODO: need to store an SkRect in GrAccelData::SaveLayerInfo?
115 SkRect srcRect = SkRect::MakeXYWH(SkIntToScalar(src.fOffset.fX),
116 SkIntToScalar(src.fOffset.fY),
117 SkIntToScalar(src.fSize.width()),
118 SkIntToScalar(src.fSize.height()));
119 SkIRect newClip(fCurrentClipBounds);
120 newClip.intersect(this->adjustAndMap(srcRect, dp.paint));
121
122 dst.fValid = true;
123 dst.fPictureID = dp.picture->uniqueID();
124 dst.fSize = SkISize::Make(newClip.width(), newClip.height());
125 dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop);
126 dst.fOriginXform = *fCTM;
127 dst.fOriginXform.postConcat(src.fOriginXform);
128 dst.fOriginXform.postTranslate(SkIntToScalar(-newClip.fLeft),
129 SkIntToScalar(-newClip.fTop));
130
131 if (NULL == src.fPaint) {
132 dst.fPaint = NULL;
133 } else {
134 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
135 }
136
137 dst.fSaveLayerOpID = src.fSaveLayerOpID;
138 dst.fRestoreOpID = src.fRestoreOpID;
139 dst.fHasNestedLayers = src.fHasNestedLayers;
140 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
141
142 fAccelData->addSaveLayerInfo(dst);
143 }
144 }
145
146 void pushSaveBlock() {
147 fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
148 }
149
150 // Inform all the saveLayers already on the stack that they now have a
151 // nested saveLayer inside them
152 void updateStackForSaveLayer() {
153 for (int index = fSaveStack.count() - 1; index >= 0; --index) {
154 if (fSaveStack[index].fHasNestedSaveLayer) {
155 break;
156 }
157 fSaveStack[index].fHasNestedSaveLayer = true;
158 if (fSaveStack[index].fIsSaveLayer) {
159 break;
160 }
161 }
162 }
163
164 void pushSaveLayerBlock(const SkPaint* paint) {
165 this->updateStackForSaveLayer();
166
167 fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
168 ++fSaveLayersInStack;
169 }
170
171 void popSaveBlock() {
172 if (fSaveStack.count() <= 0) {
173 SkASSERT(false);
174 return;
175 }
176
177 SaveInfo si;
178 fSaveStack.pop(&si);
179
180 if (!si.fIsSaveLayer) {
181 return;
182 }
183
184 --fSaveLayersInStack;
185
186 GrAccelData::SaveLayerInfo slInfo;
187
188 slInfo.fValid = true;
189 slInfo.fPictureID = fPictureID;
190 slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height());
191 slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop);
192 slInfo.fOriginXform = *fCTM;
193 slInfo.fOriginXform.postTranslate(SkIntToScalar(-si.fBounds.fLeft),
194 SkIntToScalar(-si.fBounds.fTop));
195
196 if (NULL == si.fPaint) {
197 slInfo.fPaint = NULL;
198 } else {
199 slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
200 }
201
202 slInfo.fSaveLayerOpID = si.fStartIndex;
203 slInfo.fRestoreOpID = fCurrentOp;
204 slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
205 slInfo.fIsNested = fSaveLayersInStack > 0;
206
207 fAccelData->addSaveLayerInfo(slInfo);
208 }
209
210 // Returns true if rect was meaningfully adjusted for the effects of paint,
211 // false if the paint could affect the rect in unknown ways.
212 static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
213 if (paint) {
214 if (paint->canComputeFastBounds()) {
215 *rect = paint->computeFastBounds(*rect, rect);
216 return true;
217 }
218 return false;
219 }
220 return true;
221 }
222
223 // Adjust rect for all paints that may affect its geometry, then map it to device space.
224 SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
225 // Inverted rectangles really confuse our BBHs.
226 rect.sort();
227
228 // Adjust the rect for its own paint.
229 if (!AdjustForPaint(paint, &rect)) {
230 // The paint could do anything to our bounds. The only safe answer is the current clip.
231 return fCurrentClipBounds;
232 }
233
234 // Adjust rect for all the paints from the SaveLayers we're inside.
235 for (int i = fSaveStack.count() - 1; i >= 0; i--) {
236 if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) {
237 // Same deal as above.
238 return fCurrentClipBounds;
239 }
240 }
241
242 // Map the rect back to device space.
243 fCTM->mapRect(&rect);
244 SkIRect devRect;
245 rect.roundOut(&devRect);
246
247 // Nothing can draw outside the current clip.
248 // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
249 devRect.intersect(fCurrentClipBounds);
250 return devRect;
251 }
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000252};
253
robertphillipsd6283302014-08-27 11:53:28 -0700254
255// GPUOptimize is only intended to be called within the context of SkGpuDevice's
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000256// EXPERIMENTAL_optimize method.
robertphillipsd6283302014-08-27 11:53:28 -0700257const GrAccelData* GPUOptimize(const SkPicture* pict) {
robertphillipsce4dd3d2014-07-07 13:46:35 -0700258 if (NULL == pict || 0 == pict->width() || 0 == pict->height()) {
robertphillipsd6283302014-08-27 11:53:28 -0700259 return NULL;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000260 }
261
robertphillipsd6283302014-08-27 11:53:28 -0700262 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000263
robertphillipsd6283302014-08-27 11:53:28 -0700264 const GrAccelData* existing =
265 static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
266 if (NULL != existing) {
267 return existing;
268 }
robertphillipsce4dd3d2014-07-07 13:46:35 -0700269
robertphillipsd6283302014-08-27 11:53:28 -0700270 SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
271
272 pict->EXPERIMENTAL_addAccelData(data);
273
274 CollectLayers collector(pict, data);
275
276 return data;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000277}