blob: 7295089e821cefff413d55c425c69c082794c37b [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"
reedd5fa1a42014-08-09 11:08:05 -07009#include "SkCanvasPriv.h"
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000010#include "SkDevice.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000011#include "SkDraw.h"
12#include "SkPaintPriv.h"
robertphillipsdb539902014-07-01 08:47:04 -070013#include "SkPictureData.h"
robertphillipsce4dd3d2014-07-07 13:46:35 -070014#include "SkPicturePlayback.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000015
robertphillips6617d502014-08-18 09:39:34 -070016SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000017 static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
18
19 return gGPUID;
20}
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000021
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +000022// The GrGather device performs GPU-backend-specific preprocessing on
robertphillips6617d502014-08-18 09:39:34 -070023// a picture. The results are stored in a GrAccelData.
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000024//
25// Currently the only interesting work is done in drawDevice (i.e., when a
26// saveLayer is collapsed back into its parent) and, maybe, in onCreateDevice.
27// All the current work could be done much more efficiently by just traversing the
28// raw op codes in the SkPicture (although we would still need to replay all the
29// clip calls).
30class GrGatherDevice : public SkBaseDevice {
31public:
32 SK_DECLARE_INST_COUNT(GrGatherDevice)
33
robertphillips6617d502014-08-18 09:39:34 -070034 GrGatherDevice(int width, int height, SkPicturePlayback* playback, GrAccelData* accelData,
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000035 int saveLayerDepth) {
robertphillipsce4dd3d2014-07-07 13:46:35 -070036 fPlayback = playback;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000037 fSaveLayerDepth = saveLayerDepth;
38 fInfo.fValid = true;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000039 fInfo.fSize.set(width, height);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000040 fInfo.fPaint = NULL;
robertphillipsce4dd3d2014-07-07 13:46:35 -070041 fInfo.fSaveLayerOpID = fPlayback->curOpID();
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000042 fInfo.fRestoreOpID = 0;
43 fInfo.fHasNestedLayers = false;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000044 fInfo.fIsNested = (2 == fSaveLayerDepth);
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000045
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +000046 fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(fInfo.fSize.fWidth, fInfo.fSize.fHeight));
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000047 fAccelData = accelData;
48 fAlreadyDrawn = false;
49 }
50
51 virtual ~GrGatherDevice() { }
52
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000053 virtual SkImageInfo imageInfo() const SK_OVERRIDE {
54 return fEmptyBitmap.info();
55 }
56
57#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
58 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
59 SkCanvas::Config8888 config8888) SK_OVERRIDE {
60 NotSupported();
61 }
62#endif
63 virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
64
65protected:
66 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
67 return false;
68 }
69 virtual void clear(SkColor color) SK_OVERRIDE {
70 NothingToDo();
71 }
72 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
73 }
74 virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
75 const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
76 }
77 virtual void drawRect(const SkDraw& draw, const SkRect& rect,
78 const SkPaint& paint) SK_OVERRIDE {
79 }
80 virtual void drawOval(const SkDraw& draw, const SkRect& rect,
81 const SkPaint& paint) SK_OVERRIDE {
82 }
83 virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
84 const SkPaint& paint) SK_OVERRIDE {
85 }
86 virtual void drawPath(const SkDraw& draw, const SkPath& path,
87 const SkPaint& paint, const SkMatrix* prePathMatrix,
88 bool pathIsMutable) SK_OVERRIDE {
89 }
90 virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
91 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
92 }
93 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
94 int x, int y, const SkPaint& paint) SK_OVERRIDE {
95 }
96 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
97 const SkRect* srcOrNull, const SkRect& dst,
98 const SkPaint& paint,
99 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
100 }
101 virtual void drawText(const SkDraw& draw, const void* text, size_t len,
102 SkScalar x, SkScalar y,
103 const SkPaint& paint) SK_OVERRIDE {
104 }
105 virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
106 const SkScalar pos[], SkScalar constY,
107 int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
108 }
109 virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
110 const SkPath& path, const SkMatrix* matrix,
111 const SkPaint& paint) SK_OVERRIDE {
112 }
113 virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
114 const SkPoint verts[], const SkPoint texs[],
115 const SkColor colors[], SkXfermode* xmode,
116 const uint16_t indices[], int indexCount,
117 const SkPaint& paint) SK_OVERRIDE {
118 }
119 virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y,
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000120 const SkPaint& paint) SK_OVERRIDE {
121 // deviceIn is the one that is being "restored" back to its parent
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000122 GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn);
123
124 if (device->fAlreadyDrawn) {
125 return;
126 }
127
robertphillipsce4dd3d2014-07-07 13:46:35 -0700128 device->fInfo.fRestoreOpID = fPlayback->curOpID();
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000129 device->fInfo.fCTM = *draw.fMatrix;
130 device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
131 SkIntToScalar(-device->getOrigin().fY));
132
commit-bot@chromium.orgf97d65d2014-05-08 23:24:05 +0000133 device->fInfo.fOffset = device->getOrigin();
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000134
135 if (NeedsDeepCopy(paint)) {
136 // This NULL acts as a signal that the paint was uncopyable (for now)
137 device->fInfo.fPaint = NULL;
138 device->fInfo.fValid = false;
139 } else {
140 device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint));
141 }
142
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000143 fAccelData->addSaveLayerInfo(device->fInfo);
144 device->fAlreadyDrawn = true;
145 }
146 // TODO: allow this call to return failure, or move to SkBitmapDevice only.
147 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
148 return fEmptyBitmap;
149 }
150#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
151 virtual bool onReadPixels(const SkBitmap& bitmap,
152 int x, int y,
153 SkCanvas::Config8888 config8888) SK_OVERRIDE {
154 NotSupported();
155 return false;
156 }
157#endif
158 virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
159 virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
160 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
161 virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
162 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
163 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
164 return false;
165 }
166
167private:
robertphillipsce4dd3d2014-07-07 13:46:35 -0700168 // The playback object driving this rendering
169 SkPicturePlayback *fPlayback;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000170
171 SkBitmap fEmptyBitmap; // legacy -- need to remove
172
173 // All information gathered during the gather process is stored here
robertphillips6617d502014-08-18 09:39:34 -0700174 GrAccelData* fAccelData;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000175
176 // true if this device has already been drawn back to its parent(s) at least
177 // once.
178 bool fAlreadyDrawn;
179
180 // The information regarding the saveLayer call this device represents.
robertphillips6617d502014-08-18 09:39:34 -0700181 GrAccelData::SaveLayerInfo fInfo;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000182
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000183 // The depth of this device in the saveLayer stack
184 int fSaveLayerDepth;
185
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000186 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
187 NotSupported();
188 }
189
190 virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
191 // we expect to only get called via savelayer, in which case it is fine.
192 SkASSERT(kSaveLayer_Usage == usage);
193
194 fInfo.fHasNestedLayers = true;
robertphillipsce4dd3d2014-07-07 13:46:35 -0700195 return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPlayback,
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000196 fAccelData, fSaveLayerDepth+1));
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000197 }
198
199 virtual void flush() SK_OVERRIDE {}
200
201 static void NotSupported() {
202 SkDEBUGFAIL("this method should never be called");
203 }
204
205 static void NothingToDo() {}
206
207 typedef SkBaseDevice INHERITED;
208};
209
210// The GrGatherCanvas allows saveLayers but simplifies clipping. It is really
211// only intended to be used as:
212//
213// GrGatherDevice dev(w, h, picture, accelData);
214// GrGatherCanvas canvas(..., picture);
215// canvas.gather();
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000216//
217// which is all just to fill in 'accelData'
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000218class SK_API GrGatherCanvas : public SkCanvas {
219public:
robertphillipsce4dd3d2014-07-07 13:46:35 -0700220 GrGatherCanvas(GrGatherDevice* device) : INHERITED(device) {}
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000221
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000222protected:
223 // disable aa for speed
224 virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
225 this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
226 }
227
228 // for speed, just respect the bounds, and disable AA. May give us a few
229 // false positives and negatives.
230 virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
231 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
232 path.isInverseFillType());
233 }
234 virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
235 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
236 }
237
reedd5fa1a42014-08-09 11:08:05 -0700238 virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
239 const SkPaint* paint) SK_OVERRIDE {
240 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
241
robertphillipsdb539902014-07-01 08:47:04 -0700242 if (NULL != picture->fData.get()) {
robertphillipsce4dd3d2014-07-07 13:46:35 -0700243 // Disable the BBH for the old path so all the draw calls
244 // will be seen. The stock SkPicture::draw method can't be
245 // invoked since it just uses a vanilla SkPicturePlayback.
246 SkPicturePlayback playback(picture);
247 playback.setUseBBH(false);
248 playback.draw(this, NULL);
249 } else {
250 // Since we know this is the SkRecord path we can just call
251 // SkPicture::draw.
252 picture->draw(this);
robertphillips9b14f262014-06-04 05:40:44 -0700253 }
254 }
255
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000256private:
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000257 typedef SkCanvas INHERITED;
258};
259
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000260// GatherGPUInfo is only intended to be called within the context of SkGpuDevice's
261// EXPERIMENTAL_optimize method.
robertphillips6617d502014-08-18 09:39:34 -0700262void GatherGPUInfo(const SkPicture* pict, GrAccelData* accelData) {
robertphillipsce4dd3d2014-07-07 13:46:35 -0700263 if (NULL == pict || 0 == pict->width() || 0 == pict->height()) {
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000264 return ;
265 }
266
robertphillipsce4dd3d2014-07-07 13:46:35 -0700267 // BBH-based rendering doesn't re-issue many of the operations the gather
268 // process cares about (e.g., saves and restores) so it must be disabled.
269 SkPicturePlayback playback(pict);
270 playback.setUseBBH(false);
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000271
robertphillipsce4dd3d2014-07-07 13:46:35 -0700272 GrGatherDevice device(pict->width(), pict->height(), &playback, accelData, 0);
273 GrGatherCanvas canvas(&device);
274
275 canvas.clipRect(SkRect::MakeWH(SkIntToScalar(pict->width()),
276 SkIntToScalar(pict->height())),
277 SkRegion::kIntersect_Op, false);
278 playback.draw(&canvas, NULL);
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000279}