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