• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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