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