blob: e91980fa1000f6045a516b2635527c9008544080 [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
robertphillips3aac6e02014-10-20 08:52:40 -0700111 SkRect srcRect = SkRect::Make(src.fBounds);
robertphillipsd6283302014-08-27 11:53:28 -0700112 SkIRect newClip(fCurrentClipBounds);
robertphillips3aac6e02014-10-20 08:52:40 -0700113
114 if (!newClip.intersect(this->adjustAndMap(srcRect, dp.paint))) {
115 continue;
116 }
117
118 this->updateStackForSaveLayer();
robertphillipsd6283302014-08-27 11:53:28 -0700119
robertphillips30d2cc62014-09-24 08:52:18 -0700120 GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo();
121
robertphillips30d2cc62014-09-24 08:52:18 -0700122 // If src.fPicture is NULL the layer is in dp.picture; otherwise
123 // it belongs to a sub-picture.
124 dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture);
125 dst.fPicture->ref();
robertphillips3aac6e02014-10-20 08:52:40 -0700126 dst.fBounds = newClip;
robertphillips9e6835d2014-10-22 05:33:52 -0700127 dst.fLocalMat = src.fLocalMat;
128 dst.fPreMat = src.fPreMat;
129 dst.fPreMat.preConcat(*fCTM);
robertphillips30d2cc62014-09-24 08:52:18 -0700130 if (src.fPaint) {
robertphillipsd6283302014-08-27 11:53:28 -0700131 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
132 }
robertphillipsd6283302014-08-27 11:53:28 -0700133 dst.fSaveLayerOpID = src.fSaveLayerOpID;
134 dst.fRestoreOpID = src.fRestoreOpID;
135 dst.fHasNestedLayers = src.fHasNestedLayers;
136 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
robertphillipsd6283302014-08-27 11:53:28 -0700137 }
138 }
139
140 void pushSaveBlock() {
141 fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
142 }
143
144 // Inform all the saveLayers already on the stack that they now have a
145 // nested saveLayer inside them
146 void updateStackForSaveLayer() {
147 for (int index = fSaveStack.count() - 1; index >= 0; --index) {
148 if (fSaveStack[index].fHasNestedSaveLayer) {
149 break;
150 }
151 fSaveStack[index].fHasNestedSaveLayer = true;
152 if (fSaveStack[index].fIsSaveLayer) {
153 break;
154 }
155 }
156 }
157
158 void pushSaveLayerBlock(const SkPaint* paint) {
159 this->updateStackForSaveLayer();
160
161 fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
162 ++fSaveLayersInStack;
163 }
164
165 void popSaveBlock() {
166 if (fSaveStack.count() <= 0) {
167 SkASSERT(false);
168 return;
169 }
170
171 SaveInfo si;
172 fSaveStack.pop(&si);
173
174 if (!si.fIsSaveLayer) {
175 return;
176 }
177
178 --fSaveLayersInStack;
179
robertphillips30d2cc62014-09-24 08:52:18 -0700180 GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo();
robertphillipsd6283302014-08-27 11:53:28 -0700181
robertphillips30d2cc62014-09-24 08:52:18 -0700182 SkASSERT(NULL == slInfo.fPicture); // This layer is in the top-most picture
robertphillips3aac6e02014-10-20 08:52:40 -0700183 slInfo.fBounds = si.fBounds;
robertphillips9e6835d2014-10-22 05:33:52 -0700184 slInfo.fLocalMat = *fCTM;
185 slInfo.fPreMat = SkMatrix::I();
robertphillips30d2cc62014-09-24 08:52:18 -0700186 if (si.fPaint) {
robertphillipsd6283302014-08-27 11:53:28 -0700187 slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
188 }
robertphillipsd6283302014-08-27 11:53:28 -0700189 slInfo.fSaveLayerOpID = si.fStartIndex;
190 slInfo.fRestoreOpID = fCurrentOp;
191 slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
192 slInfo.fIsNested = fSaveLayersInStack > 0;
robertphillipsd6283302014-08-27 11:53:28 -0700193 }
194
195 // Returns true if rect was meaningfully adjusted for the effects of paint,
196 // false if the paint could affect the rect in unknown ways.
197 static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
198 if (paint) {
199 if (paint->canComputeFastBounds()) {
200 *rect = paint->computeFastBounds(*rect, rect);
201 return true;
202 }
203 return false;
204 }
205 return true;
206 }
207
208 // Adjust rect for all paints that may affect its geometry, then map it to device space.
209 SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
210 // Inverted rectangles really confuse our BBHs.
211 rect.sort();
212
213 // Adjust the rect for its own paint.
214 if (!AdjustForPaint(paint, &rect)) {
215 // The paint could do anything to our bounds. The only safe answer is the current clip.
216 return fCurrentClipBounds;
217 }
218
219 // Adjust rect for all the paints from the SaveLayers we're inside.
220 for (int i = fSaveStack.count() - 1; i >= 0; i--) {
221 if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) {
222 // Same deal as above.
223 return fCurrentClipBounds;
224 }
225 }
226
227 // Map the rect back to device space.
228 fCTM->mapRect(&rect);
229 SkIRect devRect;
230 rect.roundOut(&devRect);
231
232 // Nothing can draw outside the current clip.
233 // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
234 devRect.intersect(fCurrentClipBounds);
235 return devRect;
236 }
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000237};
238
robertphillipsd6283302014-08-27 11:53:28 -0700239
240// GPUOptimize is only intended to be called within the context of SkGpuDevice's
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000241// EXPERIMENTAL_optimize method.
robertphillipsd6283302014-08-27 11:53:28 -0700242const GrAccelData* GPUOptimize(const SkPicture* pict) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700243 if (NULL == pict || pict->cullRect().isEmpty()) {
robertphillipsd6283302014-08-27 11:53:28 -0700244 return NULL;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000245 }
246
robertphillipsd6283302014-08-27 11:53:28 -0700247 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000248
robertphillipsd6283302014-08-27 11:53:28 -0700249 const GrAccelData* existing =
250 static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
bsalomon49f085d2014-09-05 13:34:00 -0700251 if (existing) {
robertphillipsd6283302014-08-27 11:53:28 -0700252 return existing;
253 }
robertphillipsce4dd3d2014-07-07 13:46:35 -0700254
robertphillipsd6283302014-08-27 11:53:28 -0700255 SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
256
257 pict->EXPERIMENTAL_addAccelData(data);
258
259 CollectLayers collector(pict, data);
260
261 return data;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000262}