From 3bc25e72476a8112c8a983cc7315ae6d403f930a Mon Sep 17 00:00:00 2001 From: robertphillips Date: Fri, 19 Sep 2014 08:56:09 -0700 Subject: [PATCH] Extend MultiPictureDraw GM This new GM case is intended to exercise the matrix oriented aspects of layer caching. R=jvanverth@google.com Author: robertphillips@google.com Review URL: https://codereview.chromium.org/582113004 --- gm/multipicturedraw.cpp | 153 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 20 deletions(-) diff --git a/gm/multipicturedraw.cpp b/gm/multipicturedraw.cpp index 11756a7..eeb5909 100644 --- a/gm/multipicturedraw.cpp +++ b/gm/multipicturedraw.cpp @@ -13,6 +13,7 @@ #include "SkSurface.h" static const SkScalar kRoot3Over2 = 0.86602545f; // sin(60) +static const SkScalar kRoot3 = 1.73205081f; static const int kHexSide = 30; static const int kNumHexX = 6; @@ -20,6 +21,9 @@ static const int kNumHexY = 6; static const int kPicWidth = kNumHexX * kHexSide; static const int kPicHeight = SkScalarCeilToInt((kNumHexY - 0.5f) * 2 * kHexSide * kRoot3Over2); static const SkScalar kInset = 20.0f; +static const int kNumPictures = 3; + +static const int kTriSide = 40; // Create a hexagon centered at (originX, originY) static SkPath make_hex_path(SkScalar originX, SkScalar originY) { @@ -37,7 +41,7 @@ static SkPath make_hex_path(SkScalar originX, SkScalar originY) { // Make a picture that is a tiling of the plane with stroked hexagons where // each hexagon is in its own layer. The layers are to exercise Ganesh's // layer hoisting. -static const SkPicture* make_picture(SkColor fillColor) { +static const SkPicture* make_hex_plane_picture(SkColor fillColor) { // Create a hexagon with its center at the origin SkPath hex = make_hex_path(0, 0); @@ -76,6 +80,93 @@ static const SkPicture* make_picture(SkColor fillColor) { return recorder.endRecording(); } +// Make an equilateral triangle path with its top corner at (originX, originY) +static SkPath make_tri_path(SkScalar originX, SkScalar originY) { + SkPath tri; + tri.moveTo(originX, originY); + tri.rLineTo(SkScalarHalf(kTriSide), 1.5f * kTriSide / kRoot3); + tri.rLineTo(-kTriSide, 0); + tri.close(); + return tri; +} + +static const SkPicture* make_tri_picture() { + SkPath tri = make_tri_path(0, 0); + + SkPaint fill; + fill.setStyle(SkPaint::kFill_Style); + fill.setColor(SK_ColorLTGRAY);; + + SkPaint stroke; + stroke.setStyle(SkPaint::kStroke_Style); + stroke.setStrokeWidth(3); + + SkPictureRecorder recorder; + + SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth), + SkIntToScalar(kPicHeight)); + // The saveLayer/restore block is to exercise layer hoisting + canvas->saveLayer(NULL, NULL); + canvas->drawPath(tri, fill); + canvas->drawPath(tri, stroke); + canvas->restore(); + + return recorder.endRecording(); +} + +static const SkPicture* make_sub_picture(const SkPicture* tri) { + SkPictureRecorder recorder; + + SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth), + SkIntToScalar(kPicHeight)); + + canvas->scale(1.0f/2.0f, 1.0f/2.0f); + + canvas->drawPicture(tri); + + canvas->save(); + canvas->translate(SkScalarHalf(kTriSide), 1.5f * kTriSide / kRoot3); + canvas->drawPicture(tri); + canvas->restore(); + + canvas->save(); + canvas->translate(-SkScalarHalf(kTriSide), 1.5f * kTriSide / kRoot3); + canvas->drawPicture(tri); + canvas->restore(); + + return recorder.endRecording(); +} + +// Create a Sierpinkski-like picture that starts with a top row with a picture +// that just contains a triangle. Subsequent rows take the prior row's picture, +// shrinks it and replicates it 3 times then draws and appropriate number of +// copies of it. +static const SkPicture* make_sierpinski_picture() { + SkAutoTUnref pic(make_tri_picture()); + + SkPictureRecorder recorder; + + SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth), + SkIntToScalar(kPicHeight)); + + static const int kNumLevels = 4; + for (int i = 0; i < kNumLevels; ++i) { + canvas->save(); + canvas->translate(-i*kTriSide / 2.0f, 0); + for (int j = 0; j < i+1; ++j) { + canvas->drawPicture(pic); + canvas->translate(SkIntToScalar(kTriSide), 0); + } + canvas->restore(); + + pic.reset(make_sub_picture(pic)); + + canvas->translate(0, 1.5f * kTriSide / kRoot3); + } + + return recorder.endRecording(); +} + static SkSurface* create_compat_surface(SkCanvas* canvas, int width, int height) { SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); @@ -101,15 +192,15 @@ public: SkPaint* fPaint; }; -typedef void (*PFContentMtd)(SkCanvas* canvas, const SkPicture* pictures[2]); +typedef void (*PFContentMtd)(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]); // Just a single picture with no clip -static void no_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { +static void no_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) { canvas->drawPicture(pictures[0]); } // Two pictures with a rect clip on the second one -static void rect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { +static void rect_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) { canvas->drawPicture(pictures[0]); SkRect rect = pictures[0]->cullRect(); @@ -121,7 +212,7 @@ static void rect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { } // Two pictures with a round rect clip on the second one -static void rrect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { +static void rrect_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) { canvas->drawPicture(pictures[0]); SkRect rect = pictures[0]->cullRect(); @@ -136,7 +227,7 @@ static void rrect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { } // Two pictures with a clip path on the second one -static void path_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { +static void path_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) { canvas->drawPicture(pictures[0]); // Create a hexagon centered on the middle of the hex grid @@ -148,7 +239,7 @@ static void path_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { } // Two pictures with an inverse clip path on the second one -static void invpath_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { +static void invpath_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) { canvas->drawPicture(pictures[0]); // Create a hexagon centered on the middle of the hex grid @@ -160,16 +251,29 @@ static void invpath_clip(SkCanvas* canvas, const SkPicture* pictures[2]) { canvas->drawPicture(pictures[1]); } +// Reuse a single base (triangular) picture a _lot_ (rotated, scaled and translated). +static void sierpinski(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) { + canvas->save(); + canvas->translate(kPicWidth / 2.0f, 0.0f); + canvas->drawPicture(pictures[2]); + + canvas->rotate(180.0f); + canvas->translate(0.0f, -SkIntToScalar(kPicHeight)); + canvas->drawPicture(pictures[2]); + canvas->restore(); +} + static const PFContentMtd gContentMthds[] = { no_clip, rect_clip, rrect_clip, path_clip, - invpath_clip + invpath_clip, + sierpinski }; static void create_content(SkMultiPictureDraw* mpd, PFContentMtd pfGen, - const SkPicture* pictures[2], + const SkPicture* pictures[kNumPictures], SkCanvas* dest, const SkMatrix& xform) { SkAutoTUnref composite; @@ -188,13 +292,13 @@ static void create_content(SkMultiPictureDraw* mpd, PFContentMtd pfGen, } typedef void(*PFLayoutMtd)(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd, - PFContentMtd pfGen, const SkPicture* pictures[2], + PFContentMtd pfGen, const SkPicture* pictures[kNumPictures], SkTArray* composeSteps); // Draw the content into a single canvas static void simple(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd, PFContentMtd pfGen, - const SkPicture* pictures[2], + const SkPicture* pictures[kNumPictures], SkTArray *composeSteps) { ComposeStep& step = composeSteps->push_back(); @@ -209,7 +313,7 @@ static void simple(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd, // Draw the content into multiple canvases/tiles static void tiled(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd, PFContentMtd pfGen, - const SkPicture* pictures[2], + const SkPicture* pictures[kNumPictures], SkTArray *composeSteps) { static const int kNumTilesX = 2; static const int kNumTilesY = 2; @@ -264,8 +368,9 @@ namespace skiagm { kRRectClipMulti_Content, kPathClipMulti_Content, kInvPathClipMulti_Content, + kSierpinski_Content, - kLast_Content = kInvPathClipMulti_Content + kLast_Content = kSierpinski_Content }; static const int kContentCnt = kLast_Content + 1; @@ -283,22 +388,26 @@ namespace skiagm { SkASSERT(SK_ARRAY_COUNT(gLayoutMthds) == kLayoutCnt); SkASSERT(SK_ARRAY_COUNT(gContentMthds) == kContentCnt); - fPictures[0] = fPictures[1] = NULL; + for (int i = 0; i < kNumPictures; ++i) { + fPictures[i] = NULL; + } } virtual ~MultiPictureDraw() { - SkSafeUnref(fPictures[0]); - SkSafeUnref(fPictures[1]); + for (int i = 0; i < kNumPictures; ++i) { + SkSafeUnref(fPictures[i]); + } } protected: Content fContent; Layout fLayout; - const SkPicture* fPictures[2]; + const SkPicture* fPictures[kNumPictures]; virtual void onOnceBeforeDraw() SK_OVERRIDE { - fPictures[0] = make_picture(SK_ColorWHITE); - fPictures[1] = make_picture(SK_ColorGRAY); + fPictures[0] = make_hex_plane_picture(SK_ColorWHITE); + fPictures[1] = make_hex_plane_picture(SK_ColorGRAY); + fPictures[2] = SkRef(make_sierpinski_picture()); } virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { @@ -326,7 +435,7 @@ namespace skiagm { virtual SkString onShortName() SK_OVERRIDE { static const char* gContentNames[] = { - "noclip", "rectclip", "rrectclip", "pathclip", "invpathclip" + "noclip", "rectclip", "rrectclip", "pathclip", "invpathclip", "sierpinski" }; static const char* gLayoutNames[] = { "simple", "tiled" }; @@ -357,6 +466,8 @@ namespace skiagm { MultiPictureDraw::kSimple_Layout));) DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kInvPathClipMulti_Content, MultiPictureDraw::kSimple_Layout));) + DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kSierpinski_Content, + MultiPictureDraw::kSimple_Layout));) DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kNoClipSingle_Content, MultiPictureDraw::kTiled_Layout));) @@ -368,4 +479,6 @@ namespace skiagm { MultiPictureDraw::kTiled_Layout));) DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kInvPathClipMulti_Content, MultiPictureDraw::kTiled_Layout));) + DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kSierpinski_Content, + MultiPictureDraw::kTiled_Layout));) } -- 2.7.4