blob: 6b7d2843fc688d78fd03855eade2c4276e0ba28f [file] [log] [blame]
robertphillips@google.comad7d4812013-04-12 15:13:35 +00001/*
2 * Copyright 2013 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 "gm.h"
9#include "SkDebugCanvas.h"
10#include "SkPictureFlat.h"
11
12#define WARN(msg) \
13 SkDebugf("%s:%d: %s\n", __FILE__, __LINE__, msg);
14
robertphillips@google.comad7d4812013-04-12 15:13:35 +000015// Do the commands in 'input' match the supplied pattern? Note: this is a pretty
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +000016// heavy-weight operation since we are drawing the picture into a debug canvas
robertphillips@google.comad7d4812013-04-12 15:13:35 +000017// to extract the commands.
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +000018static bool check_pattern(SkPicture& input, const SkTDArray<DrawType> &pattern) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +000019 SkDebugCanvas debugCanvas(input.width(), input.height());
20 debugCanvas.setBounds(input.width(), input.height());
21 input.draw(&debugCanvas);
22
23 if (pattern.count() != debugCanvas.getSize()) {
24 return false;
25 }
26
27 for (int i = 0; i < pattern.count(); ++i) {
28 if (pattern[i] != debugCanvas.getDrawCommandAt(i)->getType()) {
29 return false;
30 }
31 }
32
33 return true;
34}
35
36// construct the pattern removed by the SkPictureRecord::remove_save_layer1
37// optimization, i.e.:
38// SAVE_LAYER
39// DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
40// RESTORE
41//
42// saveLayerHasPaint - control if the saveLayer has a paint (the optimization
43// takes a different path if this is false)
44// dbmr2rHasPaint - control if the dbmr2r has a paint (the optimization
45// takes a different path if this is false)
46// colorsMatch - control if the saveLayer and dbmr2r paint colors
47// match (the optimization will fail if they do not)
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +000048static SkPicture* create_save_layer_opt_1(SkTDArray<DrawType>* preOptPattern,
49 SkTDArray<DrawType>* postOptPattern,
50 const SkBitmap& checkerBoard,
51 bool saveLayerHasPaint,
52 bool dbmr2rHasPaint,
53 bool colorsMatch) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +000054 // Create the pattern that should trigger the optimization
55 preOptPattern->setCount(5);
56 (*preOptPattern)[0] = SAVE;
57 (*preOptPattern)[1] = SAVE_LAYER;
58 (*preOptPattern)[2] = DRAW_BITMAP_RECT_TO_RECT;
59 (*preOptPattern)[3] = RESTORE;
60 (*preOptPattern)[4] = RESTORE;
61
62 if (colorsMatch) {
63 // Create the pattern that should appear after the optimization
64 postOptPattern->setCount(5);
65 (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw
66 (*postOptPattern)[1] = SAVE;
67 (*postOptPattern)[2] = DRAW_BITMAP_RECT_TO_RECT;
68 (*postOptPattern)[3] = RESTORE;
69 (*postOptPattern)[4] = RESTORE;
70 } else {
71 // Create the pattern that appears if the optimization doesn't fire
72 postOptPattern->setCount(7);
73 (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw
74 (*postOptPattern)[1] = SAVE;
75 (*postOptPattern)[2] = SAVE_LAYER;
76 (*postOptPattern)[3] = DRAW_BITMAP_RECT_TO_RECT;
77 (*postOptPattern)[4] = RESTORE;
78 (*postOptPattern)[5] = RESTORE;
79 (*postOptPattern)[6] = RESTORE;
80 }
81
82 SkPicture* result = new SkPicture;
83
84 // have to disable the optimizations while generating the picture
85 SkCanvas* canvas = result->beginRecording(100, 100,
86 SkPicture::kDisableRecordOptimizations_RecordingFlag);
87
88 SkPaint saveLayerPaint;
89 saveLayerPaint.setColor(0xCC000000);
90
91 // saveLayer's 'bounds' parameter must be NULL for this optimization
92 if (saveLayerHasPaint) {
93 canvas->saveLayer(NULL, &saveLayerPaint);
94 } else {
95 canvas->saveLayer(NULL, NULL);
96 }
97
98 SkRect rect = { 10, 10, 90, 90 };
99
100 // The dbmr2r's paint must be opaque
101 SkPaint dbmr2rPaint;
102 if (colorsMatch) {
103 dbmr2rPaint.setColor(0xFF000000);
104 } else {
105 dbmr2rPaint.setColor(0xFFFF0000);
106 }
107
108 if (dbmr2rHasPaint) {
109 canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, &dbmr2rPaint);
110 } else {
111 canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, NULL);
112 }
113 canvas->restore();
114
115 result->endRecording();
116
117 return result;
118}
119
120// straight-ahead version that is seen in the skps
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000121static SkPicture* create_save_layer_opt_1_v1(SkTDArray<DrawType>* preOptPattern,
122 SkTDArray<DrawType>* postOptPattern,
123 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000124 return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard,
125 true, // saveLayer has a paint
126 true, // dbmr2r has a paint
127 true); // and the colors match
128}
129
130// alternate version that should still succeed
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000131static SkPicture* create_save_layer_opt_1_v2(SkTDArray<DrawType>* preOptPattern,
132 SkTDArray<DrawType>* postOptPattern,
133 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000134 return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard,
135 false, // saveLayer doesn't have a paint!
136 true, // dbmr2r has a paint
137 true); // color matching not really applicable
138}
139
140// alternate version that should still succeed
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000141static SkPicture* create_save_layer_opt_1_v3(SkTDArray<DrawType>* preOptPattern,
142 SkTDArray<DrawType>* postOptPattern,
143 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000144 return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard,
145 true, // saveLayer has a paint
146 false, // dbmr2r doesn't have a paint!
147 true); // color matching not really applicable
148}
149
150// version in which the optimization fails b.c. the colors don't match
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000151static SkPicture* create_save_layer_opt_1_v4(SkTDArray<DrawType>* preOptPattern,
152 SkTDArray<DrawType>* postOptPattern,
153 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000154 return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard,
155 true, // saveLayer has a paint
156 true, // dbmr2r has a paint
157 false); // and the colors don't match!
158}
159
160// construct the pattern removed by the SkPictureRecord::remove_save_layer2
161// optimization, i.e.:
162// SAVE_LAYER (with NULL == bounds)
163// SAVE
164// CLIP_RECT
165// DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
166// RESTORE
167// RESTORE
168//
169// saveLayerHasPaint - control if the saveLayer has a paint (the optimization
170// takes a different path if this is false)
171// dbmr2rHasPaint - control if the dbmr2r has a paint (the optimization
172// takes a different path if this is false)
173// colorsMatch - control if the saveLayer and dbmr2r paint colors
174// match (the optimization will fail if they do not)
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000175static SkPicture* create_save_layer_opt_2(SkTDArray<DrawType>* preOptPattern,
176 SkTDArray<DrawType>* postOptPattern,
177 const SkBitmap& checkerBoard,
178 bool saveLayerHasPaint,
179 bool dbmr2rHasPaint,
180 bool colorsMatch) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000181 // Create the pattern that should trigger the optimization
182 preOptPattern->setCount(8);
183 (*preOptPattern)[0] = SAVE;
184 (*preOptPattern)[1] = SAVE_LAYER;
185 (*preOptPattern)[2] = SAVE;
186 (*preOptPattern)[3] = CLIP_RECT;
187 (*preOptPattern)[4] = DRAW_BITMAP_RECT_TO_RECT;
188 (*preOptPattern)[5] = RESTORE;
189 (*preOptPattern)[6] = RESTORE;
190 (*preOptPattern)[7] = RESTORE;
191
192 if (colorsMatch) {
193 // Create the pattern that should appear after the optimization
194 postOptPattern->setCount(8);
195 (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw
196 (*postOptPattern)[1] = SAVE;
197 (*postOptPattern)[2] = SAVE;
198 (*postOptPattern)[3] = CLIP_RECT;
199 (*postOptPattern)[4] = DRAW_BITMAP_RECT_TO_RECT;
200 (*postOptPattern)[5] = RESTORE;
201 (*postOptPattern)[6] = RESTORE;
202 (*postOptPattern)[7] = RESTORE;
203 } else {
204 // Create the pattern that appears if the optimization doesn't fire
205 postOptPattern->setCount(10);
206 (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw
207 (*postOptPattern)[1] = SAVE;
208 (*postOptPattern)[2] = SAVE_LAYER;
209 (*postOptPattern)[3] = SAVE;
210 (*postOptPattern)[4] = CLIP_RECT;
211 (*postOptPattern)[5] = DRAW_BITMAP_RECT_TO_RECT;
212 (*postOptPattern)[6] = RESTORE;
213 (*postOptPattern)[7] = RESTORE;
214 (*postOptPattern)[8] = RESTORE;
215 (*postOptPattern)[9] = RESTORE;
216 }
217
218 SkPicture* result = new SkPicture;
219
220 // have to disable the optimizations while generating the picture
221 SkCanvas* canvas = result->beginRecording(100, 100,
222 SkPicture::kDisableRecordOptimizations_RecordingFlag);
223
224 SkPaint saveLayerPaint;
225 saveLayerPaint.setColor(0xCC000000);
226
227 // saveLayer's 'bounds' parameter must be NULL for this optimization
228 if (saveLayerHasPaint) {
229 canvas->saveLayer(NULL, &saveLayerPaint);
230 } else {
231 canvas->saveLayer(NULL, NULL);
232 }
233
234 canvas->save();
235
236 SkRect rect = { 10, 10, 90, 90 };
237 canvas->clipRect(rect);
238
239 // The dbmr2r's paint must be opaque
240 SkPaint dbmr2rPaint;
241 if (colorsMatch) {
242 dbmr2rPaint.setColor(0xFF000000);
243 } else {
244 dbmr2rPaint.setColor(0xFFFF0000);
245 }
246
247 if (dbmr2rHasPaint) {
248 canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, &dbmr2rPaint);
249 } else {
250 canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, NULL);
251 }
252 canvas->restore();
253 canvas->restore();
254
255 result->endRecording();
256
257 return result;
258}
259
260// straight-ahead version that is seen in the skps
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000261static SkPicture* create_save_layer_opt_2_v1(SkTDArray<DrawType>* preOptPattern,
262 SkTDArray<DrawType>* postOptPattern,
263 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000264 return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard,
265 true, // saveLayer has a paint
266 true, // dbmr2r has a paint
267 true); // and the colors match
268}
269
270// alternate version that should still succeed
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000271static SkPicture* create_save_layer_opt_2_v2(SkTDArray<DrawType>* preOptPattern,
272 SkTDArray<DrawType>* postOptPattern,
273 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000274 return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard,
275 false, // saveLayer doesn't have a paint!
276 true, // dbmr2r has a paint
277 true); // color matching not really applicable
278}
279
280// alternate version that should still succeed
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000281static SkPicture* create_save_layer_opt_2_v3(SkTDArray<DrawType>* preOptPattern,
282 SkTDArray<DrawType>* postOptPattern,
283 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000284 return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard,
285 true, // saveLayer has a paint
286 false, // dbmr2r doesn't have a paint!
287 true); // color matching not really applicable
288}
289
290// version in which the optimization fails b.c. the colors don't match
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +0000291static SkPicture* create_save_layer_opt_2_v4(SkTDArray<DrawType>* preOptPattern,
292 SkTDArray<DrawType>* postOptPattern,
293 const SkBitmap& checkerBoard) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000294 return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard,
295 true, // saveLayer has a paint
296 true, // dbmr2r has a paint
297 false); // and the colors don't match!
298}
299
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000300// As our .skp optimizations get folded into the captured skps our code will
301// no longer be locally exercised. This GM manually constructs the patterns
302// our optimizations will remove to test them. It acts as both a GM and a unit
303// test
304class OptimizationsGM : public skiagm::GM {
305public:
306 OptimizationsGM() {
307 this->makeCheckerboard();
308 }
309
310 static const int kWidth = 800;
311 static const int kHeight = 800;
312
313protected:
314 SkString onShortName() {
315 return SkString("optimizations");
316 }
317
318 SkISize onISize() { return SkISize::Make(kWidth, kHeight); }
319
320 typedef SkPicture* (*PFCreateOpt)(SkTDArray<DrawType> *preOptPattern,
321 SkTDArray<DrawType> *postOptPattern,
322 const SkBitmap& checkerBoard);
323
324 virtual void onDraw(SkCanvas* canvas) {
325
326 PFCreateOpt gOpts[] = {
327 create_save_layer_opt_1_v1,
328 create_save_layer_opt_1_v2,
329 create_save_layer_opt_1_v3,
330 create_save_layer_opt_1_v4,
331 create_save_layer_opt_2_v1,
332 create_save_layer_opt_2_v2,
333 create_save_layer_opt_2_v3,
334 create_save_layer_opt_2_v4,
335 };
336
337 SkTDArray<DrawType> prePattern, postPattern;
338 int xPos = 0, yPos = 0;
339
340 for (size_t i = 0; i < SK_ARRAY_COUNT(gOpts); ++i) {
341 SkAutoTUnref<SkPicture> pre((*gOpts[i])(&prePattern, &postPattern, fCheckerboard));
342
343 if (!(check_pattern(*pre, prePattern))) {
344 WARN("Pre optimization pattern mismatch");
345 SkASSERT(0);
346 }
347
348 canvas->save();
349 canvas->translate(SkIntToScalar(xPos), SkIntToScalar(yPos));
350 pre->draw(canvas);
351 xPos += pre->width();
352 canvas->restore();
353
354 // re-render the 'pre' picture and thus 'apply' the optimization
355 SkAutoTUnref<SkPicture> post(new SkPicture);
356
357 SkCanvas* recordCanvas = post->beginRecording(pre->width(), pre->height());
358
359 pre->draw(recordCanvas);
360
361 post->endRecording();
362
363 if (!(check_pattern(*post, postPattern))) {
364 WARN("Post optimization pattern mismatch");
365 SkASSERT(0);
366 }
367
368 canvas->save();
369 canvas->translate(SkIntToScalar(xPos), SkIntToScalar(yPos));
370 post->draw(canvas);
371 xPos += post->width();
372 canvas->restore();
373
374 if (xPos >= kWidth) {
375 // start a new line
376 xPos = 0;
377 yPos += post->height();
378 }
379
380 // TODO: we could also render the pre and post pictures to bitmaps
381 // and manually compare them in this method
382 }
383 }
384
385private:
386 void makeCheckerboard() {
387 static const unsigned int kCheckerboardWidth = 16;
388 static const unsigned int kCheckerboardHeight = 16;
389
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000390 fCheckerboard.setConfig(SkBitmap::kARGB_8888_Config,
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000391 kCheckerboardWidth, kCheckerboardHeight);
392 fCheckerboard.allocPixels();
393 SkAutoLockPixels lock(fCheckerboard);
394 for (unsigned int y = 0; y < kCheckerboardHeight; y += 2) {
395 SkPMColor* scanline = fCheckerboard.getAddr32(0, y);
396 for (unsigned int x = 0; x < kCheckerboardWidth; x += 2) {
397 *scanline++ = 0xFFFFFFFF;
398 *scanline++ = 0xFF000000;
399 }
400 scanline = fCheckerboard.getAddr32(0, y + 1);
401 for (unsigned int x = 0; x < kCheckerboardWidth; x += 2) {
402 *scanline++ = 0xFF000000;
403 *scanline++ = 0xFFFFFFFF;
404 }
405 }
406 }
407
408 SkBitmap fCheckerboard;
409
410 typedef skiagm::GM INHERITED;
411};
412
413//////////////////////////////////////////////////////////////////////////////
414
415DEF_GM( return new OptimizationsGM; )