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