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#include "SkDevice.h"
10#include "SkDraw.h"
11#include "SkPaintPriv.h"
12#include "SkPicturePlayback.h"
13
14SkPicture::AccelData::Key GPUAccelData::ComputeAccelDataKey() {
15    static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
16
17    return gGPUID;
18}
19
20// The GrGather device performs GPU-backend-specific preprocessing on
21// a picture. The results are stored in a GPUAccelData.
22//
23// Currently the only interesting work is done in drawDevice (i.e., when a
24// saveLayer is collapsed back into its parent) and, maybe, in onCreateDevice.
25// All the current work could be done much more efficiently by just traversing the
26// raw op codes in the SkPicture (although we would still need to replay all the
27// clip calls).
28class GrGatherDevice : public SkBaseDevice {
29public:
30    SK_DECLARE_INST_COUNT(GrGatherDevice)
31
32    GrGatherDevice(int width, int height, const SkPicture* picture, GPUAccelData* accelData,
33                   int saveLayerDepth) {
34        fPicture = picture;
35        fSaveLayerDepth = saveLayerDepth;
36        fInfo.fValid = true;
37        fInfo.fSize.set(width, height);
38        fInfo.fPaint = NULL;
39        fInfo.fSaveLayerOpID = fPicture->EXPERIMENTAL_curOpID();
40        fInfo.fRestoreOpID = 0;
41        fInfo.fHasNestedLayers = false;
42        fInfo.fIsNested = (2 == fSaveLayerDepth);
43
44        fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(fInfo.fSize.fWidth, fInfo.fSize.fHeight));
45        fAccelData = accelData;
46        fAlreadyDrawn = false;
47    }
48
49    virtual ~GrGatherDevice() { }
50
51    virtual SkImageInfo imageInfo() const SK_OVERRIDE {
52        return fEmptyBitmap.info();
53    }
54
55#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
56    virtual void writePixels(const SkBitmap& bitmap, int x, int y,
57                             SkCanvas::Config8888 config8888) SK_OVERRIDE {
58        NotSupported();
59    }
60#endif
61    virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
62
63protected:
64    virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
65        return false;
66    }
67    virtual void clear(SkColor color) SK_OVERRIDE {
68        NothingToDo();
69    }
70    virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
71    }
72    virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
73                            const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
74    }
75    virtual void drawRect(const SkDraw& draw, const SkRect& rect,
76                          const SkPaint& paint) SK_OVERRIDE {
77    }
78    virtual void drawOval(const SkDraw& draw, const SkRect& rect,
79                          const SkPaint& paint) SK_OVERRIDE {
80    }
81    virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
82                           const SkPaint& paint) SK_OVERRIDE {
83    }
84    virtual void drawPath(const SkDraw& draw, const SkPath& path,
85                          const SkPaint& paint, const SkMatrix* prePathMatrix,
86                          bool pathIsMutable) SK_OVERRIDE {
87    }
88    virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
89                            const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
90    }
91    virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
92                            int x, int y, const SkPaint& paint) SK_OVERRIDE {
93    }
94    virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
95                                const SkRect* srcOrNull, const SkRect& dst,
96                                const SkPaint& paint,
97                                SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
98    }
99    virtual void drawText(const SkDraw& draw, const void* text, size_t len,
100                          SkScalar x, SkScalar y,
101                          const SkPaint& paint) SK_OVERRIDE {
102    }
103    virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
104                             const SkScalar pos[], SkScalar constY,
105                             int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
106    }
107    virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
108                                const SkPath& path, const SkMatrix* matrix,
109                                const SkPaint& paint) SK_OVERRIDE {
110    }
111    virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
112                              const SkPoint verts[], const SkPoint texs[],
113                              const SkColor colors[], SkXfermode* xmode,
114                              const uint16_t indices[], int indexCount,
115                              const SkPaint& paint) SK_OVERRIDE {
116    }
117    virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y,
118                            const SkPaint& paint) SK_OVERRIDE {
119        // deviceIn is the one that is being "restored" back to its parent
120        GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn);
121
122        if (device->fAlreadyDrawn) {
123            return;
124        }
125
126        device->fInfo.fRestoreOpID = fPicture->EXPERIMENTAL_curOpID();
127        device->fInfo.fCTM = *draw.fMatrix;
128        device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
129                                         SkIntToScalar(-device->getOrigin().fY));
130
131        device->fInfo.fOffset = device->getOrigin();
132
133        if (NeedsDeepCopy(paint)) {
134            // This NULL acts as a signal that the paint was uncopyable (for now)
135            device->fInfo.fPaint = NULL;
136            device->fInfo.fValid = false;
137        } else {
138            device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint));
139        }
140
141        fAccelData->addSaveLayerInfo(device->fInfo);
142        device->fAlreadyDrawn = true;
143    }
144    // TODO: allow this call to return failure, or move to SkBitmapDevice only.
145    virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
146        return fEmptyBitmap;
147    }
148#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
149    virtual bool onReadPixels(const SkBitmap& bitmap,
150                              int x, int y,
151                              SkCanvas::Config8888 config8888) SK_OVERRIDE {
152        NotSupported();
153        return false;
154    }
155#endif
156    virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
157    virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
158    virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
159    virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
160    virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
161                             SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
162        return false;
163    }
164
165private:
166    // The picture being processed
167    const SkPicture *fPicture;
168
169    SkBitmap fEmptyBitmap; // legacy -- need to remove
170
171    // All information gathered during the gather process is stored here
172    GPUAccelData* fAccelData;
173
174    // true if this device has already been drawn back to its parent(s) at least
175    // once.
176    bool   fAlreadyDrawn;
177
178    // The information regarding the saveLayer call this device represents.
179    GPUAccelData::SaveLayerInfo fInfo;
180
181    // The depth of this device in the saveLayer stack
182    int fSaveLayerDepth;
183
184    virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
185        NotSupported();
186    }
187
188    virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
189        // we expect to only get called via savelayer, in which case it is fine.
190        SkASSERT(kSaveLayer_Usage == usage);
191
192        fInfo.fHasNestedLayers = true;
193        return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPicture,
194                                           fAccelData, fSaveLayerDepth+1));
195    }
196
197    virtual void flush() SK_OVERRIDE {}
198
199    static void NotSupported() {
200        SkDEBUGFAIL("this method should never be called");
201    }
202
203    static void NothingToDo() {}
204
205    typedef SkBaseDevice INHERITED;
206};
207
208// The GrGatherCanvas allows saveLayers but simplifies clipping. It is really
209// only intended to be used as:
210//
211//      GrGatherDevice dev(w, h, picture, accelData);
212//      GrGatherCanvas canvas(..., picture);
213//      canvas.gather();
214//
215// which is all just to fill in 'accelData'
216class SK_API GrGatherCanvas : public SkCanvas {
217public:
218    GrGatherCanvas(GrGatherDevice* device, const SkPicture* pict)
219        : INHERITED(device)
220        , fPicture(pict) {
221    }
222
223    void gather() {
224        if (NULL == fPicture || 0 == fPicture->width() || 0 == fPicture->height()) {
225            return;
226        }
227
228        this->clipRect(SkRect::MakeWH(SkIntToScalar(fPicture->width()),
229                                      SkIntToScalar(fPicture->height())),
230                       SkRegion::kIntersect_Op, false);
231        this->drawPicture(fPicture);
232    }
233
234protected:
235    // disable aa for speed
236    virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
237        this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
238    }
239
240    // for speed, just respect the bounds, and disable AA. May give us a few
241    // false positives and negatives.
242    virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
243        this->updateClipConservativelyUsingBounds(path.getBounds(), op,
244                                                  path.isInverseFillType());
245    }
246    virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
247        this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
248    }
249
250    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE {
251        // BBH-based rendering doesn't re-issue many of the operations the gather
252        // process cares about (e.g., saves and restores) so it must be disabled.
253        if (NULL != picture->fPlayback) {
254            picture->fPlayback->setUseBBH(false);
255        }
256        picture->draw(this);
257        if (NULL != picture->fPlayback) {
258            picture->fPlayback->setUseBBH(true);
259        }
260    }
261
262private:
263    const SkPicture* fPicture;
264
265    typedef SkCanvas INHERITED;
266};
267
268// GatherGPUInfo is only intended to be called within the context of SkGpuDevice's
269// EXPERIMENTAL_optimize method.
270void GatherGPUInfo(const SkPicture* pict, GPUAccelData* accelData) {
271    if (0 == pict->width() || 0 == pict->height()) {
272        return ;
273    }
274
275    GrGatherDevice device(pict->width(), pict->height(), pict, accelData, 0);
276    GrGatherCanvas canvas(&device, pict);
277
278    canvas.gather();
279}
280