blob: a66f34c0a6519e74a8b1859b23df0fedc2711b5a [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"
robertphillips@google.combeb1af22014-05-07 21:31:09 +000012#include "SkPicturePlayback.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000013
14SkPicture::AccelData::Key GPUAccelData::ComputeAccelDataKey() {
15 static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
16
17 return gGPUID;
18}
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000019
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +000020// The GrGather device performs GPU-backend-specific preprocessing on
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000021// 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
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000032 GrGatherDevice(int width, int height, SkPicture* picture, GPUAccelData* accelData,
33 int saveLayerDepth) {
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000034 fPicture = picture;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000035 fSaveLayerDepth = saveLayerDepth;
36 fInfo.fValid = true;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000037 fInfo.fSize.set(width, height);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000038 fInfo.fPaint = NULL;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000039 fInfo.fSaveLayerOpID = fPicture->EXPERIMENTAL_curOpID();
40 fInfo.fRestoreOpID = 0;
41 fInfo.fHasNestedLayers = false;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000042 fInfo.fIsNested = (2 == fSaveLayerDepth);
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000043
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +000044 fEmptyBitmap.setConfig(SkImageInfo::Make(fInfo.fSize.fWidth,
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +000045 fInfo.fSize.fHeight,
46 kUnknown_SkColorType,
47 kIgnore_SkAlphaType));
48 fAccelData = accelData;
49 fAlreadyDrawn = false;
50 }
51
52 virtual ~GrGatherDevice() { }
53
54 virtual int width() const SK_OVERRIDE { return fInfo.fSize.width(); }
55 virtual int height() const SK_OVERRIDE { return fInfo.fSize.height(); }
56 virtual bool isOpaque() const SK_OVERRIDE { return false; }
57 virtual SkBitmap::Config config() const SK_OVERRIDE {
58 return SkBitmap::kNo_Config;
59 }
60 virtual SkImageInfo imageInfo() const SK_OVERRIDE {
61 return fEmptyBitmap.info();
62 }
63
64#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
65 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
66 SkCanvas::Config8888 config8888) SK_OVERRIDE {
67 NotSupported();
68 }
69#endif
70 virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
71
72protected:
73 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
74 return false;
75 }
76 virtual void clear(SkColor color) SK_OVERRIDE {
77 NothingToDo();
78 }
79 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
80 }
81 virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
82 const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
83 }
84 virtual void drawRect(const SkDraw& draw, const SkRect& rect,
85 const SkPaint& paint) SK_OVERRIDE {
86 }
87 virtual void drawOval(const SkDraw& draw, const SkRect& rect,
88 const SkPaint& paint) SK_OVERRIDE {
89 }
90 virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
91 const SkPaint& paint) SK_OVERRIDE {
92 }
93 virtual void drawPath(const SkDraw& draw, const SkPath& path,
94 const SkPaint& paint, const SkMatrix* prePathMatrix,
95 bool pathIsMutable) SK_OVERRIDE {
96 }
97 virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
98 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
99 }
100 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
101 int x, int y, const SkPaint& paint) SK_OVERRIDE {
102 }
103 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
104 const SkRect* srcOrNull, const SkRect& dst,
105 const SkPaint& paint,
106 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
107 }
108 virtual void drawText(const SkDraw& draw, const void* text, size_t len,
109 SkScalar x, SkScalar y,
110 const SkPaint& paint) SK_OVERRIDE {
111 }
112 virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
113 const SkScalar pos[], SkScalar constY,
114 int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
115 }
116 virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
117 const SkPath& path, const SkMatrix* matrix,
118 const SkPaint& paint) SK_OVERRIDE {
119 }
120 virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
121 const SkPoint verts[], const SkPoint texs[],
122 const SkColor colors[], SkXfermode* xmode,
123 const uint16_t indices[], int indexCount,
124 const SkPaint& paint) SK_OVERRIDE {
125 }
126 virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y,
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000127 const SkPaint& paint) SK_OVERRIDE {
128 // deviceIn is the one that is being "restored" back to its parent
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000129 GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn);
130
131 if (device->fAlreadyDrawn) {
132 return;
133 }
134
135 device->fInfo.fRestoreOpID = fPicture->EXPERIMENTAL_curOpID();
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000136 device->fInfo.fCTM = *draw.fMatrix;
137 device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
138 SkIntToScalar(-device->getOrigin().fY));
139
robertphillips@google.com3d41c4a2014-05-08 18:45:20 +0000140 // We need the x & y values that will yield 'getOrigin' when transformed
141 // by 'draw.fMatrix'.
142 device->fInfo.fOffset.iset(device->getOrigin());
143
144 SkMatrix invMatrix;
145 if (draw.fMatrix->invert(&invMatrix)) {
146 invMatrix.mapPoints(&device->fInfo.fOffset, 1);
147 } else {
148 device->fInfo.fValid = false;
149 }
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000150
151 if (NeedsDeepCopy(paint)) {
152 // This NULL acts as a signal that the paint was uncopyable (for now)
153 device->fInfo.fPaint = NULL;
154 device->fInfo.fValid = false;
155 } else {
156 device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint));
157 }
158
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000159 fAccelData->addSaveLayerInfo(device->fInfo);
160 device->fAlreadyDrawn = true;
161 }
162 // TODO: allow this call to return failure, or move to SkBitmapDevice only.
163 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
164 return fEmptyBitmap;
165 }
166#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
167 virtual bool onReadPixels(const SkBitmap& bitmap,
168 int x, int y,
169 SkCanvas::Config8888 config8888) SK_OVERRIDE {
170 NotSupported();
171 return false;
172 }
173#endif
174 virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
175 virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
176 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
177 virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
178 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
179 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
180 return false;
181 }
182
183private:
184 // The picture being processed
185 SkPicture *fPicture;
186
187 SkBitmap fEmptyBitmap; // legacy -- need to remove
188
189 // All information gathered during the gather process is stored here
190 GPUAccelData* fAccelData;
191
192 // true if this device has already been drawn back to its parent(s) at least
193 // once.
194 bool fAlreadyDrawn;
195
196 // The information regarding the saveLayer call this device represents.
197 GPUAccelData::SaveLayerInfo fInfo;
198
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000199 // The depth of this device in the saveLayer stack
200 int fSaveLayerDepth;
201
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000202 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
203 NotSupported();
204 }
205
206 virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
207 // we expect to only get called via savelayer, in which case it is fine.
208 SkASSERT(kSaveLayer_Usage == usage);
209
210 fInfo.fHasNestedLayers = true;
skia.committer@gmail.coma5b068c2014-05-07 03:04:15 +0000211 return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPicture,
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000212 fAccelData, fSaveLayerDepth+1));
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000213 }
214
215 virtual void flush() SK_OVERRIDE {}
216
217 static void NotSupported() {
218 SkDEBUGFAIL("this method should never be called");
219 }
220
221 static void NothingToDo() {}
222
223 typedef SkBaseDevice INHERITED;
224};
225
226// The GrGatherCanvas allows saveLayers but simplifies clipping. It is really
227// only intended to be used as:
228//
229// GrGatherDevice dev(w, h, picture, accelData);
230// GrGatherCanvas canvas(..., picture);
231// canvas.gather();
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000232//
233// which is all just to fill in 'accelData'
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000234class SK_API GrGatherCanvas : public SkCanvas {
235public:
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000236 GrGatherCanvas(GrGatherDevice* device, SkPicture* pict)
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000237 : INHERITED(device)
238 , fPicture(pict) {
239 }
240
241 void gather() {
242 if (NULL == fPicture || 0 == fPicture->width() || 0 == fPicture->height()) {
243 return;
244 }
245
246 this->clipRect(SkRect::MakeWH(SkIntToScalar(fPicture->width()),
247 SkIntToScalar(fPicture->height())),
248 SkRegion::kIntersect_Op, false);
249 this->drawPicture(*fPicture);
250 }
251
252 virtual void drawPicture(SkPicture& picture) SK_OVERRIDE {
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000253 // BBH-based rendering doesn't re-issue many of the operations the gather
254 // process cares about (e.g., saves and restores) so it must be disabled.
255 if (NULL != picture.fPlayback) {
256 picture.fPlayback->setUseBBH(false);
257 }
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000258 picture.draw(this);
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000259 if (NULL != picture.fPlayback) {
260 picture.fPlayback->setUseBBH(true);
261 }
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000262 }
263protected:
264 // disable aa for speed
265 virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
266 this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
267 }
268
269 // for speed, just respect the bounds, and disable AA. May give us a few
270 // false positives and negatives.
271 virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
272 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
273 path.isInverseFillType());
274 }
275 virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
276 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
277 }
278
279private:
280 SkPicture* fPicture;
281
282 typedef SkCanvas INHERITED;
283};
284
skia.committer@gmail.com2c48ee82014-04-01 03:07:47 +0000285// GatherGPUInfo is only intended to be called within the context of SkGpuDevice's
286// EXPERIMENTAL_optimize method.
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000287void GatherGPUInfo(SkPicture* pict, GPUAccelData* accelData) {
288 if (0 == pict->width() || 0 == pict->height()) {
289 return ;
290 }
291
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000292 GrGatherDevice device(pict->width(), pict->height(), pict, accelData, 0);
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000293 GrGatherCanvas canvas(&device, pict);
294
295 canvas.gather();
296}