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 "gm.h"
9 #include "sk_tool_utils.h"
10 
11 #include "SkColorFilter.h"
12 #include "SkMultiPictureDraw.h"
13 #include "SkPictureRecorder.h"
14 #include "SkSurface.h"
15 
16 constexpr SkScalar kRoot3Over2 = 0.86602545f;  // sin(60)
17 constexpr SkScalar kRoot3      = 1.73205081f;
18 
19 constexpr int kHexSide = 30;
20 constexpr int kNumHexX = 6;
21 constexpr int kNumHexY = 6;
22 constexpr int kPicWidth = kNumHexX * kHexSide;
23 constexpr int kPicHeight = (int)((kNumHexY - 0.5f) * 2 * kHexSide * kRoot3Over2 + 0.5f);
24 constexpr SkScalar kInset = 20.0f;
25 constexpr int kNumPictures = 4;
26 
27 constexpr int kTriSide = 40;
28 
29 // Create a hexagon centered at (originX, originY)
make_hex_path(SkScalar originX,SkScalar originY)30 static SkPath make_hex_path(SkScalar originX, SkScalar originY) {
31     SkPath hex;
32     hex.moveTo(originX-kHexSide, originY);
33     hex.rLineTo(SkScalarHalf(kHexSide), kRoot3Over2 * kHexSide);
34     hex.rLineTo(SkIntToScalar(kHexSide), 0);
35     hex.rLineTo(SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
36     hex.rLineTo(-SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
37     hex.rLineTo(-SkIntToScalar(kHexSide), 0);
38     hex.close();
39     return hex;
40 }
41 
42 // Make a picture that is a tiling of the plane with stroked hexagons where
43 // each hexagon is in its own layer. The layers are to exercise Ganesh's
44 // layer hoisting.
make_hex_plane_picture(SkColor fillColor)45 static sk_sp<SkPicture> make_hex_plane_picture(SkColor fillColor) {
46 
47     // Create a hexagon with its center at the origin
48     SkPath hex = make_hex_path(0, 0);
49 
50     SkPaint fill;
51     fill.setStyle(SkPaint::kFill_Style);
52     fill.setColor(fillColor);
53 
54     SkPaint stroke;
55     stroke.setStyle(SkPaint::kStroke_Style);
56     stroke.setStrokeWidth(3);
57 
58     SkPictureRecorder recorder;
59     SkRTreeFactory bbhFactory;
60 
61     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
62                                                SkIntToScalar(kPicHeight),
63                                                &bbhFactory);
64 
65     SkScalar xPos, yPos = 0;
66 
67     for (int y = 0; y < kNumHexY; ++y) {
68         xPos = 0;
69 
70         for (int x = 0; x < kNumHexX; ++x) {
71             canvas->saveLayer(nullptr, nullptr);
72             canvas->translate(xPos, yPos + ((x % 2) ? kRoot3Over2 * kHexSide : 0));
73             canvas->drawPath(hex, fill);
74             canvas->drawPath(hex, stroke);
75             canvas->restore();
76 
77             xPos += 1.5f * kHexSide;
78         }
79 
80         yPos += 2 * kHexSide * kRoot3Over2;
81     }
82 
83     return recorder.finishRecordingAsPicture();
84 }
85 
86 // Create a picture that consists of a single large layer that is tiled
87 // with hexagons.
88 // This is intended to exercise the layer hoisting code's clip handling (in
89 // tile mode).
make_single_layer_hex_plane_picture()90 static sk_sp<SkPicture> make_single_layer_hex_plane_picture() {
91 
92     // Create a hexagon with its center at the origin
93     SkPath hex = make_hex_path(0, 0);
94 
95     SkPaint whiteFill;
96     whiteFill.setStyle(SkPaint::kFill_Style);
97     whiteFill.setColor(SK_ColorWHITE);
98 
99     SkPaint greyFill;
100     greyFill.setStyle(SkPaint::kFill_Style);
101     greyFill.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY));
102 
103     SkPaint stroke;
104     stroke.setStyle(SkPaint::kStroke_Style);
105     stroke.setStrokeWidth(3);
106 
107     SkPictureRecorder recorder;
108     SkRTreeFactory bbhFactory;
109 
110     constexpr SkScalar kBig = 10000.0f;
111     SkCanvas* canvas = recorder.beginRecording(kBig, kBig, &bbhFactory);
112 
113     canvas->saveLayer(nullptr, nullptr);
114 
115     SkScalar xPos = 0.0f, yPos = 0.0f;
116 
117     for (int y = 0; yPos < kBig; ++y) {
118         xPos = 0;
119 
120         for (int x = 0; xPos < kBig; ++x) {
121             canvas->save();
122             canvas->translate(xPos, yPos + ((x % 2) ? kRoot3Over2 * kHexSide : 0));
123             // The color of the filled hex is swapped to yield a different
124             // pattern in each tile. This allows an error in layer hoisting (e.g.,
125             // the clip isn't blocking cache reuse) to cause a visual discrepancy.
126             canvas->drawPath(hex, ((x+y) % 3) ? whiteFill : greyFill);
127             canvas->drawPath(hex, stroke);
128             canvas->restore();
129 
130             xPos += 1.5f * kHexSide;
131         }
132 
133         yPos += 2 * kHexSide * kRoot3Over2;
134     }
135 
136     canvas->restore();
137 
138     return recorder.finishRecordingAsPicture();
139 }
140 
141 // Make an equilateral triangle path with its top corner at (originX, originY)
make_tri_path(SkScalar originX,SkScalar originY)142 static SkPath make_tri_path(SkScalar originX, SkScalar originY) {
143     SkPath tri;
144     tri.moveTo(originX, originY);
145     tri.rLineTo(SkScalarHalf(kTriSide), 1.5f * kTriSide / kRoot3);
146     tri.rLineTo(-kTriSide, 0);
147     tri.close();
148     return tri;
149 }
150 
make_tri_picture()151 static sk_sp<SkPicture> make_tri_picture() {
152     SkPath tri = make_tri_path(SkScalarHalf(kTriSide), 0);
153 
154     SkPaint fill;
155     fill.setStyle(SkPaint::kFill_Style);
156     fill.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY));
157 
158     SkPaint stroke;
159     stroke.setStyle(SkPaint::kStroke_Style);
160     stroke.setStrokeWidth(3);
161 
162     SkPictureRecorder recorder;
163     SkRTreeFactory bbhFactory;
164 
165     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
166                                                SkIntToScalar(kPicHeight),
167                                                &bbhFactory);
168     SkRect r = tri.getBounds();
169     r.outset(2.0f, 2.0f);       // outset for stroke
170     canvas->clipRect(r);
171     // The saveLayer/restore block is to exercise layer hoisting
172     canvas->saveLayer(nullptr, nullptr);
173         canvas->drawPath(tri, fill);
174         canvas->drawPath(tri, stroke);
175     canvas->restore();
176 
177     return recorder.finishRecordingAsPicture();
178 }
179 
make_sub_picture(const SkPicture * tri)180 static sk_sp<SkPicture> make_sub_picture(const SkPicture* tri) {
181     SkPictureRecorder recorder;
182     SkRTreeFactory bbhFactory;
183 
184     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
185                                                SkIntToScalar(kPicHeight),
186                                                &bbhFactory);
187 
188     canvas->scale(1.0f/2.0f, 1.0f/2.0f);
189 
190     canvas->save();
191     canvas->translate(SkScalarHalf(kTriSide), 0);
192     canvas->drawPicture(tri);
193     canvas->restore();
194 
195     canvas->save();
196     canvas->translate(SkIntToScalar(kTriSide), 1.5f * kTriSide / kRoot3);
197     canvas->drawPicture(tri);
198     canvas->restore();
199 
200     canvas->save();
201     canvas->translate(0, 1.5f * kTriSide / kRoot3);
202     canvas->drawPicture(tri);
203     canvas->restore();
204 
205     return recorder.finishRecordingAsPicture();
206 }
207 
208 // Create a Sierpinkski-like picture that starts with a top row with a picture
209 // that just contains a triangle. Subsequent rows take the prior row's picture,
210 // shrinks it and replicates it 3 times then draws and appropriate number of
211 // copies of it.
make_sierpinski_picture()212 static sk_sp<SkPicture> make_sierpinski_picture() {
213     sk_sp<SkPicture> pic(make_tri_picture());
214 
215     SkPictureRecorder recorder;
216     SkRTreeFactory bbhFactory;
217 
218     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
219                                                SkIntToScalar(kPicHeight),
220                                                &bbhFactory);
221 
222     constexpr int kNumLevels = 4;
223     for (int i = 0; i < kNumLevels; ++i) {
224         canvas->save();
225             canvas->translate(kPicWidth/2 - (i+1) * (kTriSide/2.0f), 0.0f);
226             for (int j = 0; j < i+1; ++j) {
227                 canvas->drawPicture(pic);
228                 canvas->translate(SkIntToScalar(kTriSide), 0);
229             }
230         canvas->restore();
231 
232         pic = make_sub_picture(pic.get());
233 
234         canvas->translate(0, 1.5f * kTriSide / kRoot3);
235     }
236 
237     return recorder.finishRecordingAsPicture();
238 }
239 
create_compat_surface(SkCanvas * canvas,int width,int height)240 static sk_sp<SkSurface> create_compat_surface(SkCanvas* canvas, int width, int height) {
241     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
242 
243     auto surface = canvas->makeSurface(info);
244     if (nullptr == surface) {
245         // picture canvas returns nullptr so fall back to raster
246         surface = SkSurface::MakeRaster(info);
247     }
248     return surface;
249 }
250 
251 // This class stores the information required to compose all the result
252 // fragments potentially generated by the MultiPictureDraw object
253 class ComposeStep {
254 public:
ComposeStep()255     ComposeStep() : fX(0.0f), fY(0.0f), fPaint(nullptr) { }
~ComposeStep()256     ~ComposeStep() {
257         delete fPaint;
258     }
259 
260     sk_sp<SkSurface> fSurf;
261     SkScalar   fX;
262     SkScalar   fY;
263     SkPaint*   fPaint;
264 };
265 
266 typedef void (*PFContentMtd)(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]);
267 
268 // Just a single picture with no clip
no_clip(SkCanvas * canvas,const SkPicture * pictures[kNumPictures])269 static void no_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
270     canvas->drawPicture(pictures[0]);
271 }
272 
273 // Two pictures with a rect clip on the second one
rect_clip(SkCanvas * canvas,const SkPicture * pictures[kNumPictures])274 static void rect_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
275     canvas->drawPicture(pictures[0]);
276 
277     SkRect rect = pictures[0]->cullRect();
278     rect.inset(kInset, kInset);
279 
280     canvas->clipRect(rect);
281 
282     canvas->drawPicture(pictures[1]);
283 }
284 
285 // Two pictures with a round rect clip on the second one
rrect_clip(SkCanvas * canvas,const SkPicture * pictures[kNumPictures])286 static void rrect_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
287     canvas->drawPicture(pictures[0]);
288 
289     SkRect rect = pictures[0]->cullRect();
290     rect.inset(kInset, kInset);
291 
292     SkRRect rrect;
293     rrect.setRectXY(rect, kInset, kInset);
294 
295     canvas->clipRRect(rrect);
296 
297     canvas->drawPicture(pictures[1]);
298 }
299 
300 // Two pictures with a clip path on the second one
path_clip(SkCanvas * canvas,const SkPicture * pictures[kNumPictures])301 static void path_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
302     canvas->drawPicture(pictures[0]);
303 
304     // Create a hexagon centered on the middle of the hex grid
305     SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);
306 
307     canvas->clipPath(hex);
308 
309     canvas->drawPicture(pictures[1]);
310 }
311 
312 // Two pictures with an inverse clip path on the second one
invpath_clip(SkCanvas * canvas,const SkPicture * pictures[kNumPictures])313 static void invpath_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
314     canvas->drawPicture(pictures[0]);
315 
316     // Create a hexagon centered on the middle of the hex grid
317     SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);
318     hex.setFillType(SkPath::kInverseEvenOdd_FillType);
319 
320     canvas->clipPath(hex);
321 
322     canvas->drawPicture(pictures[1]);
323 }
324 
325 // Reuse a single base (triangular) picture a _lot_ (rotated, scaled and translated).
sierpinski(SkCanvas * canvas,const SkPicture * pictures[kNumPictures])326 static void sierpinski(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
327     canvas->save();
328         canvas->drawPicture(pictures[2]);
329 
330         canvas->rotate(180.0f);
331         canvas->translate(-SkIntToScalar(kPicWidth), -SkIntToScalar(kPicHeight));
332         canvas->drawPicture(pictures[2]);
333     canvas->restore();
334 }
335 
big_layer(SkCanvas * canvas,const SkPicture * pictures[kNumPictures])336 static void big_layer(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
337     canvas->drawPicture(pictures[3]);
338 }
339 
340 constexpr PFContentMtd gContentMthds[] = {
341     no_clip,
342     rect_clip,
343     rrect_clip,
344     path_clip,
345     invpath_clip,
346     sierpinski,
347     big_layer,
348 };
349 
create_content(SkMultiPictureDraw * mpd,PFContentMtd pfGen,const SkPicture * pictures[kNumPictures],SkCanvas * dest,const SkMatrix & xform)350 static void create_content(SkMultiPictureDraw* mpd, PFContentMtd pfGen,
351                            const SkPicture* pictures[kNumPictures],
352                            SkCanvas* dest, const SkMatrix& xform) {
353     sk_sp<SkPicture> composite;
354 
355     {
356         SkPictureRecorder recorder;
357         SkRTreeFactory bbhFactory;
358 
359         SkCanvas* pictureCanvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
360                                                           SkIntToScalar(kPicHeight),
361                                                           &bbhFactory);
362 
363         (*pfGen)(pictureCanvas, pictures);
364 
365         composite = recorder.finishRecordingAsPicture();
366     }
367 
368     mpd->add(dest, composite.get(), &xform);
369 }
370 
371 typedef void(*PFLayoutMtd)(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
372                            PFContentMtd pfGen, const SkPicture* pictures[kNumPictures],
373                            SkTArray<ComposeStep>* composeSteps);
374 
375 // Draw the content into a single canvas
simple(SkCanvas * finalCanvas,SkMultiPictureDraw * mpd,PFContentMtd pfGen,const SkPicture * pictures[kNumPictures],SkTArray<ComposeStep> * composeSteps)376 static void simple(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
377                    PFContentMtd pfGen,
378                    const SkPicture* pictures[kNumPictures],
379                    SkTArray<ComposeStep> *composeSteps) {
380 
381     ComposeStep& step = composeSteps->push_back();
382 
383     step.fSurf = create_compat_surface(finalCanvas, kPicWidth, kPicHeight);
384 
385     SkCanvas* subCanvas = step.fSurf->getCanvas();
386 
387     create_content(mpd, pfGen, pictures, subCanvas, SkMatrix::I());
388 }
389 
390 // Draw the content into multiple canvases/tiles
tiled(SkCanvas * finalCanvas,SkMultiPictureDraw * mpd,PFContentMtd pfGen,const SkPicture * pictures[kNumPictures],SkTArray<ComposeStep> * composeSteps)391 static void tiled(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
392                   PFContentMtd pfGen,
393                   const SkPicture* pictures[kNumPictures],
394                   SkTArray<ComposeStep> *composeSteps) {
395     const int kNumTilesX = 2;
396     const int kNumTilesY = 2;
397     const int kTileWidth = kPicWidth / kNumTilesX;
398     const int kTileHeight = kPicHeight / kNumTilesY;
399 
400     SkASSERT(kPicWidth == kNumTilesX * kTileWidth);
401     SkASSERT(kPicHeight == kNumTilesY * kTileHeight);
402 
403     const SkColor colors[kNumTilesX][kNumTilesY] = {
404         { SK_ColorCYAN,   SK_ColorMAGENTA },
405         { SK_ColorYELLOW, SK_ColorGREEN   }
406     };
407 
408     for (int y = 0; y < kNumTilesY; ++y) {
409         for (int x = 0; x < kNumTilesX; ++x) {
410             ComposeStep& step = composeSteps->push_back();
411 
412             step.fX = SkIntToScalar(x*kTileWidth);
413             step.fY = SkIntToScalar(y*kTileHeight);
414             step.fPaint = new SkPaint;
415             step.fPaint->setColorFilter(
416                 SkColorFilter::MakeModeFilter(colors[x][y], SkBlendMode::kModulate));
417 
418             step.fSurf = create_compat_surface(finalCanvas, kTileWidth, kTileHeight);
419 
420             SkCanvas* subCanvas = step.fSurf->getCanvas();
421 
422             const SkMatrix trans = SkMatrix::MakeTrans(-SkIntToScalar(x*kTileWidth),
423                                                        -SkIntToScalar(y*kTileHeight));
424 
425             create_content(mpd, pfGen, pictures, subCanvas, trans);
426         }
427     }
428 }
429 
430 constexpr PFLayoutMtd gLayoutMthds[] = { simple, tiled };
431 
432 namespace skiagm {
433     /**
434      * This GM exercises the SkMultiPictureDraw object. It tests the
435      * cross product of:
436      *      tiled vs. all-at-once rendering (e.g., into many or just 1 canvas)
437      *      different clips (e.g., none, rect, rrect)
438      *      single vs. multiple pictures (e.g., normal vs. picture-pile-style content)
439      */
440     class MultiPictureDraw : public GM {
441     public:
442         enum Content {
443             kNoClipSingle_Content,
444             kRectClipMulti_Content,
445             kRRectClipMulti_Content,
446             kPathClipMulti_Content,
447             kInvPathClipMulti_Content,
448             kSierpinski_Content,
449             kBigLayer_Content,
450 
451             kLast_Content = kBigLayer_Content
452         };
453 
454         const int kContentCnt = kLast_Content + 1;
455 
456         enum Layout {
457             kSimple_Layout,
458             kTiled_Layout,
459 
460             kLast_Layout = kTiled_Layout
461         };
462 
463         const int kLayoutCnt = kLast_Layout + 1;
464 
MultiPictureDraw(Content content,Layout layout)465         MultiPictureDraw(Content content, Layout layout) : fContent(content), fLayout(layout) {
466             SkASSERT(SK_ARRAY_COUNT(gLayoutMthds) == kLayoutCnt);
467             SkASSERT(SK_ARRAY_COUNT(gContentMthds) == kContentCnt);
468 
469             for (int i = 0; i < kNumPictures; ++i) {
470                 fPictures[i] = nullptr;
471             }
472         }
473 
~MultiPictureDraw()474         ~MultiPictureDraw() override {
475             for (int i = 0; i < kNumPictures; ++i) {
476                 SkSafeUnref(fPictures[i]);
477             }
478         }
479 
480     protected:
481         Content          fContent;
482         Layout           fLayout;
483         const SkPicture* fPictures[kNumPictures];
484 
onOnceBeforeDraw()485         void onOnceBeforeDraw() override {
486             fPictures[0] = make_hex_plane_picture(SK_ColorWHITE).release();
487             fPictures[1] = make_hex_plane_picture(sk_tool_utils::color_to_565(SK_ColorGRAY)).release();
488             fPictures[2] = make_sierpinski_picture().release();
489             fPictures[3] = make_single_layer_hex_plane_picture().release();
490         }
491 
onDraw(SkCanvas * canvas)492         void onDraw(SkCanvas* canvas) override {
493             SkMultiPictureDraw mpd;
494             SkTArray<ComposeStep> composeSteps;
495 
496             // Fill up the MultiPictureDraw
497             (*gLayoutMthds[fLayout])(canvas, &mpd,
498                                      gContentMthds[fContent],
499                                      fPictures, &composeSteps);
500 
501             mpd.draw();
502 
503             // Compose all the drawn canvases into the final canvas
504             for (int i = 0; i < composeSteps.count(); ++i) {
505                 const ComposeStep& step = composeSteps[i];
506 
507                 canvas->drawImage(step.fSurf->makeImageSnapshot().get(),
508                                   step.fX, step.fY, step.fPaint);
509             }
510         }
511 
onISize()512         SkISize onISize() override { return SkISize::Make(kPicWidth, kPicHeight); }
513 
onShortName()514         SkString onShortName() override {
515             const char* gContentNames[] = {
516                 "noclip", "rectclip", "rrectclip", "pathclip",
517                 "invpathclip", "sierpinski", "biglayer"
518             };
519             const char* gLayoutNames[] = { "simple", "tiled" };
520 
521             SkASSERT(SK_ARRAY_COUNT(gLayoutNames) == kLayoutCnt);
522             SkASSERT(SK_ARRAY_COUNT(gContentNames) == kContentCnt);
523 
524             SkString name("multipicturedraw_");
525 
526             name.append(gContentNames[fContent]);
527             name.append("_");
528             name.append(gLayoutNames[fLayout]);
529             return name;
530         }
531 
runAsBench() const532         bool runAsBench() const override { return true; }
533 
534     private:
535         typedef GM INHERITED;
536     };
537 
538     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kNoClipSingle_Content,
539                                        MultiPictureDraw::kSimple_Layout);)
540     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRectClipMulti_Content,
541                                        MultiPictureDraw::kSimple_Layout);)
542     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRRectClipMulti_Content,
543                                        MultiPictureDraw::kSimple_Layout);)
544     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kPathClipMulti_Content,
545                                        MultiPictureDraw::kSimple_Layout);)
546     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kInvPathClipMulti_Content,
547                                        MultiPictureDraw::kSimple_Layout);)
548     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kSierpinski_Content,
549                                        MultiPictureDraw::kSimple_Layout);)
550     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kBigLayer_Content,
551                                        MultiPictureDraw::kSimple_Layout);)
552 
553     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kNoClipSingle_Content,
554                                        MultiPictureDraw::kTiled_Layout);)
555     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRectClipMulti_Content,
556                                        MultiPictureDraw::kTiled_Layout);)
557     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRRectClipMulti_Content,
558                                        MultiPictureDraw::kTiled_Layout);)
559     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kPathClipMulti_Content,
560                                        MultiPictureDraw::kTiled_Layout);)
561     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kInvPathClipMulti_Content,
562                                        MultiPictureDraw::kTiled_Layout);)
563     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kSierpinski_Content,
564                                        MultiPictureDraw::kTiled_Layout);)
565     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kBigLayer_Content,
566                                        MultiPictureDraw::kTiled_Layout);)
567 }
568