blob: da238cef9f04c0cd7fe5c4cbf588638783c09a8d [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
robertphillipsd6283302014-08-27 11:53:28 -0700113 // TODO: need to store an SkRect in GrAccelData::SaveLayerInfo?
114 SkRect srcRect = SkRect::MakeXYWH(SkIntToScalar(src.fOffset.fX),
115 SkIntToScalar(src.fOffset.fY),
116 SkIntToScalar(src.fSize.width()),
117 SkIntToScalar(src.fSize.height()));
118 SkIRect newClip(fCurrentClipBounds);
119 newClip.intersect(this->adjustAndMap(srcRect, dp.paint));
120
robertphillips30d2cc62014-09-24 08:52:18 -0700121 GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo();
122
robertphillips30d2cc62014-09-24 08:52:18 -0700123 // If src.fPicture is NULL the layer is in dp.picture; otherwise
124 // it belongs to a sub-picture.
125 dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture);
126 dst.fPicture->ref();
robertphillipsd6283302014-08-27 11:53:28 -0700127 dst.fSize = SkISize::Make(newClip.width(), newClip.height());
128 dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop);
robertphillipsb5a97152014-09-30 11:33:02 -0700129 dst.fOriginXform = src.fOriginXform;
130 dst.fOriginXform.postConcat(*fCTM);
robertphillips30d2cc62014-09-24 08:52:18 -0700131 if (src.fPaint) {
robertphillipsd6283302014-08-27 11:53:28 -0700132 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
133 }
robertphillipsd6283302014-08-27 11:53:28 -0700134 dst.fSaveLayerOpID = src.fSaveLayerOpID;
135 dst.fRestoreOpID = src.fRestoreOpID;
136 dst.fHasNestedLayers = src.fHasNestedLayers;
137 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
robertphillipsd6283302014-08-27 11:53:28 -0700138 }
139 }
140
141 void pushSaveBlock() {
142 fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
143 }
144
145 // Inform all the saveLayers already on the stack that they now have a
146 // nested saveLayer inside them
147 void updateStackForSaveLayer() {
148 for (int index = fSaveStack.count() - 1; index >= 0; --index) {
149 if (fSaveStack[index].fHasNestedSaveLayer) {
150 break;
151 }
152 fSaveStack[index].fHasNestedSaveLayer = true;
153 if (fSaveStack[index].fIsSaveLayer) {
154 break;
155 }
156 }
157 }
158
159 void pushSaveLayerBlock(const SkPaint* paint) {
160 this->updateStackForSaveLayer();
161
162 fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
163 ++fSaveLayersInStack;
164 }
165
166 void popSaveBlock() {
167 if (fSaveStack.count() <= 0) {
168 SkASSERT(false);
169 return;
170 }
171
172 SaveInfo si;
173 fSaveStack.pop(&si);
174
175 if (!si.fIsSaveLayer) {
176 return;
177 }
178
179 --fSaveLayersInStack;
180
robertphillips30d2cc62014-09-24 08:52:18 -0700181 GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo();
robertphillipsd6283302014-08-27 11:53:28 -0700182
robertphillips30d2cc62014-09-24 08:52:18 -0700183 SkASSERT(NULL == slInfo.fPicture); // This layer is in the top-most picture
robertphillipsd6283302014-08-27 11:53:28 -0700184 slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height());
185 slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop);
186 slInfo.fOriginXform = *fCTM;
robertphillips30d2cc62014-09-24 08:52:18 -0700187 if (si.fPaint) {
robertphillipsd6283302014-08-27 11:53:28 -0700188 slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
189 }
robertphillipsd6283302014-08-27 11:53:28 -0700190 slInfo.fSaveLayerOpID = si.fStartIndex;
191 slInfo.fRestoreOpID = fCurrentOp;
192 slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
193 slInfo.fIsNested = fSaveLayersInStack > 0;
robertphillipsd6283302014-08-27 11:53:28 -0700194 }
195
196 // Returns true if rect was meaningfully adjusted for the effects of paint,
197 // false if the paint could affect the rect in unknown ways.
198 static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
199 if (paint) {
200 if (paint->canComputeFastBounds()) {
201 *rect = paint->computeFastBounds(*rect, rect);
202 return true;
203 }
204 return false;
205 }
206 return true;
207 }
208
209 // Adjust rect for all paints that may affect its geometry, then map it to device space.
210 SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
211 // Inverted rectangles really confuse our BBHs.
212 rect.sort();
213
214 // Adjust the rect for its own paint.
215 if (!AdjustForPaint(paint, &rect)) {
216 // The paint could do anything to our bounds. The only safe answer is the current clip.
217 return fCurrentClipBounds;
218 }
219
220 // Adjust rect for all the paints from the SaveLayers we're inside.
221 for (int i = fSaveStack.count() - 1; i >= 0; i--) {
222 if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) {
223 // Same deal as above.
224 return fCurrentClipBounds;
225 }
226 }
227
228 // Map the rect back to device space.
229 fCTM->mapRect(&rect);
230 SkIRect devRect;
231 rect.roundOut(&devRect);
232
233 // Nothing can draw outside the current clip.
234 // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
235 devRect.intersect(fCurrentClipBounds);
236 return devRect;
237 }
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000238};
239
robertphillipsd6283302014-08-27 11:53:28 -0700240
241// GPUOptimize is only intended to be called within the context of SkGpuDevice's
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000242// EXPERIMENTAL_optimize method.
robertphillipsd6283302014-08-27 11:53:28 -0700243const GrAccelData* GPUOptimize(const SkPicture* pict) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700244 if (NULL == pict || pict->cullRect().isEmpty()) {
robertphillipsd6283302014-08-27 11:53:28 -0700245 return NULL;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000246 }
247
robertphillipsd6283302014-08-27 11:53:28 -0700248 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000249
robertphillipsd6283302014-08-27 11:53:28 -0700250 const GrAccelData* existing =
251 static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
bsalomon49f085d2014-09-05 13:34:00 -0700252 if (existing) {
robertphillipsd6283302014-08-27 11:53:28 -0700253 return existing;
254 }
robertphillipsce4dd3d2014-07-07 13:46:35 -0700255
robertphillipsd6283302014-08-27 11:53:28 -0700256 SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
257
258 pict->EXPERIMENTAL_addAccelData(data);
259
260 CollectLayers collector(pict, data);
261
262 return data;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000263}