1 /*
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"
9
10 #include "SkPaintPriv.h"
11 #include "SkRecord.h"
12 #include "SkRecords.h"
13
ComputeAccelDataKey()14 SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
15 static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
16
17 return gGPUID;
18 }
19
20 // SkRecord visitor to gather saveLayer/restore information.
21 class CollectLayers {
22 public:
CollectLayers(const SkPicture * pict,GrAccelData * accelData)23 CollectLayers(const SkPicture* pict, GrAccelData* accelData)
24 : fPictureID(pict->uniqueID())
25 , fCTM(&SkMatrix::I())
26 , fSaveLayersInStack(0)
27 , fAccelData(accelData) {
28
29 pict->cullRect().roundOut(&fCurrentClipBounds);
30
31 if (NULL == pict->fRecord.get()) {
32 return;
33 }
34
35 for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp) {
36 pict->fRecord->visit<void>(fCurrentOp, *this);
37 }
38
39 while (!fSaveStack.isEmpty()) {
40 this->popSaveBlock();
41 }
42 }
43
operator ()(const T & op)44 template <typename T> void operator()(const T& op) {
45 this->updateCTM(op);
46 this->updateClipBounds(op);
47 this->trackSaveLayers(op);
48 }
49
50 private:
51
52 class SaveInfo {
53 public:
SaveInfo()54 SaveInfo() { }
SaveInfo(int opIndex,bool isSaveLayer,const SkPaint * paint,const SkIRect & bounds)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
updateCTM(const T &)79 template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ }
updateCTM(const SkRecords::Restore & op)80 void updateCTM(const SkRecords::Restore& op) { fCTM = &op.matrix; }
updateCTM(const SkRecords::SetMatrix & op)81 void updateCTM(const SkRecords::SetMatrix& op) { fCTM = &op.matrix; }
82
updateClipBounds(const T &)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.
updateClipBounds(const SkRecords::Restore & op)86 void updateClipBounds(const SkRecords::Restore& op) { fCurrentClipBounds = op.devBounds; }
updateClipBounds(const SkRecords::ClipPath & op)87 void updateClipBounds(const SkRecords::ClipPath& op) { fCurrentClipBounds = op.devBounds; }
updateClipBounds(const SkRecords::ClipRRect & op)88 void updateClipBounds(const SkRecords::ClipRRect& op) { fCurrentClipBounds = op.devBounds; }
updateClipBounds(const SkRecords::ClipRect & op)89 void updateClipBounds(const SkRecords::ClipRect& op) { fCurrentClipBounds = op.devBounds; }
updateClipBounds(const SkRecords::ClipRegion & op)90 void updateClipBounds(const SkRecords::ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
updateClipBounds(const SkRecords::SaveLayer & op)91 void updateClipBounds(const SkRecords::SaveLayer& op) {
92 if (op.bounds) {
93 fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
94 }
95 }
96
trackSaveLayers(const T & op)97 template <typename T> void trackSaveLayers(const T& op) {
98 /* most ops aren't involved in saveLayers */
99 }
trackSaveLayers(const SkRecords::Save & s)100 void trackSaveLayers(const SkRecords::Save& s) { this->pushSaveBlock(); }
trackSaveLayers(const SkRecords::SaveLayer & sl)101 void trackSaveLayers(const SkRecords::SaveLayer& sl) { this->pushSaveLayerBlock(sl.paint); }
trackSaveLayers(const SkRecords::Restore & r)102 void trackSaveLayers(const SkRecords::Restore& r) { this->popSaveBlock(); }
trackSaveLayers(const SkRecords::DrawPicture & dp)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 // 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
121 GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo();
122
123 dst.fValid = true;
124 // If src.fPicture is NULL the layer is in dp.picture; otherwise
125 // it belongs to a sub-picture.
126 dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture);
127 dst.fPicture->ref();
128 dst.fSize = SkISize::Make(newClip.width(), newClip.height());
129 dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop);
130 dst.fOriginXform = *fCTM;
131 dst.fOriginXform.postConcat(src.fOriginXform);
132 if (src.fPaint) {
133 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
134 }
135 dst.fSaveLayerOpID = src.fSaveLayerOpID;
136 dst.fRestoreOpID = src.fRestoreOpID;
137 dst.fHasNestedLayers = src.fHasNestedLayers;
138 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
139 }
140 }
141
pushSaveBlock()142 void pushSaveBlock() {
143 fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
144 }
145
146 // Inform all the saveLayers already on the stack that they now have a
147 // nested saveLayer inside them
updateStackForSaveLayer()148 void updateStackForSaveLayer() {
149 for (int index = fSaveStack.count() - 1; index >= 0; --index) {
150 if (fSaveStack[index].fHasNestedSaveLayer) {
151 break;
152 }
153 fSaveStack[index].fHasNestedSaveLayer = true;
154 if (fSaveStack[index].fIsSaveLayer) {
155 break;
156 }
157 }
158 }
159
pushSaveLayerBlock(const SkPaint * paint)160 void pushSaveLayerBlock(const SkPaint* paint) {
161 this->updateStackForSaveLayer();
162
163 fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
164 ++fSaveLayersInStack;
165 }
166
popSaveBlock()167 void popSaveBlock() {
168 if (fSaveStack.count() <= 0) {
169 SkASSERT(false);
170 return;
171 }
172
173 SaveInfo si;
174 fSaveStack.pop(&si);
175
176 if (!si.fIsSaveLayer) {
177 return;
178 }
179
180 --fSaveLayersInStack;
181
182 GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo();
183
184 slInfo.fValid = true;
185 SkASSERT(NULL == slInfo.fPicture); // This layer is in the top-most picture
186 slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height());
187 slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop);
188 slInfo.fOriginXform = *fCTM;
189 if (si.fPaint) {
190 slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
191 }
192 slInfo.fSaveLayerOpID = si.fStartIndex;
193 slInfo.fRestoreOpID = fCurrentOp;
194 slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
195 slInfo.fIsNested = fSaveLayersInStack > 0;
196 }
197
198 // Returns true if rect was meaningfully adjusted for the effects of paint,
199 // false if the paint could affect the rect in unknown ways.
AdjustForPaint(const SkPaint * paint,SkRect * rect)200 static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
201 if (paint) {
202 if (paint->canComputeFastBounds()) {
203 *rect = paint->computeFastBounds(*rect, rect);
204 return true;
205 }
206 return false;
207 }
208 return true;
209 }
210
211 // Adjust rect for all paints that may affect its geometry, then map it to device space.
adjustAndMap(SkRect rect,const SkPaint * paint) const212 SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
213 // Inverted rectangles really confuse our BBHs.
214 rect.sort();
215
216 // Adjust the rect for its own paint.
217 if (!AdjustForPaint(paint, &rect)) {
218 // The paint could do anything to our bounds. The only safe answer is the current clip.
219 return fCurrentClipBounds;
220 }
221
222 // Adjust rect for all the paints from the SaveLayers we're inside.
223 for (int i = fSaveStack.count() - 1; i >= 0; i--) {
224 if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) {
225 // Same deal as above.
226 return fCurrentClipBounds;
227 }
228 }
229
230 // Map the rect back to device space.
231 fCTM->mapRect(&rect);
232 SkIRect devRect;
233 rect.roundOut(&devRect);
234
235 // Nothing can draw outside the current clip.
236 // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
237 devRect.intersect(fCurrentClipBounds);
238 return devRect;
239 }
240 };
241
242
243 // GPUOptimize is only intended to be called within the context of SkGpuDevice's
244 // EXPERIMENTAL_optimize method.
GPUOptimize(const SkPicture * pict)245 const GrAccelData* GPUOptimize(const SkPicture* pict) {
246 if (NULL == pict || pict->cullRect().isEmpty()) {
247 return NULL;
248 }
249
250 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
251
252 const GrAccelData* existing =
253 static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
254 if (existing) {
255 return existing;
256 }
257
258 SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
259
260 pict->EXPERIMENTAL_addAccelData(data);
261
262 CollectLayers collector(pict, data);
263
264 return data;
265 }
266