|  | /* | 
|  | * Copyright 2012 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #include "Benchmark.h" | 
|  | #include "SkCanvas.h" | 
|  | #include "SkColor.h" | 
|  | #include "SkPaint.h" | 
|  | #include "SkPicture.h" | 
|  | #include "SkPictureRecorder.h" | 
|  | #include "SkPoint.h" | 
|  | #include "SkRandom.h" | 
|  | #include "SkRect.h" | 
|  | #include "SkString.h" | 
|  |  | 
|  | class PictureRecordBench : public Benchmark { | 
|  | public: | 
|  | PictureRecordBench(const char name[])  { | 
|  | fName.printf("picture_record_%s", name); | 
|  | } | 
|  |  | 
|  | virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { | 
|  | return backend == kNonRendering_Backend; | 
|  | } | 
|  |  | 
|  | enum { | 
|  | PICTURE_WIDTH = 1000, | 
|  | PICTURE_HEIGHT = 4000, | 
|  | }; | 
|  | protected: | 
|  | virtual const char* onGetName() SK_OVERRIDE { | 
|  | return fName.c_str(); | 
|  | } | 
|  | private: | 
|  | SkString fName; | 
|  | typedef Benchmark INHERITED; | 
|  | }; | 
|  |  | 
|  |  | 
|  | static const int kMaxLoopsPerCanvas = 10000; | 
|  |  | 
|  | /* | 
|  | *  An SkPicture has internal dictionaries to store bitmaps, matrices, paints, | 
|  | *  and regions.  This bench populates those dictionaries to test the speed of | 
|  | *  reading and writing to those particular dictionary data structures. | 
|  | */ | 
|  | class DictionaryRecordBench : public PictureRecordBench { | 
|  | public: | 
|  | DictionaryRecordBench() : INHERITED("dictionaries") {} | 
|  |  | 
|  | protected: | 
|  | virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { | 
|  | SkPictureRecorder recorder; | 
|  | SkCanvas* canvas = NULL; | 
|  |  | 
|  | const SkPoint translateDelta = getTranslateDelta(loops); | 
|  |  | 
|  | for (int i = 0; i < loops; i++) { | 
|  | if (0 == i % kMaxLoopsPerCanvas) { | 
|  | SkAutoTUnref<SkPicture> picture(recorder.endRecording()); | 
|  | canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); | 
|  | } | 
|  |  | 
|  | SkColor color = SK_ColorYELLOW + (i % 255); | 
|  | SkIRect rect = SkIRect::MakeWH(i % PICTURE_WIDTH, i % PICTURE_HEIGHT); | 
|  |  | 
|  | canvas->save(); | 
|  |  | 
|  | // set the clip to the given region | 
|  | SkRegion region; | 
|  | region.setRect(rect); | 
|  | canvas->clipRegion(region); | 
|  |  | 
|  | // fill the clip with a color | 
|  | SkPaint paint; | 
|  | paint.setColor(color); | 
|  | canvas->drawPaint(paint); | 
|  |  | 
|  | // set a matrix on the canvas | 
|  | SkMatrix matrix; | 
|  | matrix.setRotate(SkIntToScalar(i % 360)); | 
|  | canvas->setMatrix(matrix); | 
|  |  | 
|  | // create a simple bitmap | 
|  | SkBitmap bitmap; | 
|  | bitmap.allocPixels(SkImageInfo::Make(10, 10, | 
|  | kRGB_565_SkColorType, kOpaque_SkAlphaType)); | 
|  |  | 
|  | // draw a single color into the bitmap | 
|  | SkCanvas bitmapCanvas(bitmap); | 
|  | bitmapCanvas.drawColor(SkColorSetA(color, i % 255)); | 
|  |  | 
|  | // draw the bitmap onto the canvas | 
|  | canvas->drawBitmapMatrix(bitmap, matrix); | 
|  |  | 
|  | canvas->restore(); | 
|  | canvas->translate(translateDelta.fX, translateDelta.fY); | 
|  | } | 
|  | } | 
|  |  | 
|  | SkPoint getTranslateDelta(int M) { | 
|  | SkIPoint canvasSize = onGetSize(); | 
|  | return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/M), | 
|  | SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/M)); | 
|  | } | 
|  | private: | 
|  | typedef PictureRecordBench INHERITED; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  Populates the SkPaint dictionary with a large number of unique paint | 
|  | *  objects that differ only by color | 
|  | */ | 
|  | class UniquePaintDictionaryRecordBench : public PictureRecordBench { | 
|  | public: | 
|  | UniquePaintDictionaryRecordBench() : INHERITED("unique_paint_dictionary") { } | 
|  |  | 
|  | protected: | 
|  | virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { | 
|  | SkRandom rand; | 
|  | SkPaint paint; | 
|  | SkPictureRecorder recorder; | 
|  | SkCanvas* canvas = NULL; | 
|  | for (int i = 0; i < loops; i++) { | 
|  | if (0 == i % kMaxLoopsPerCanvas) { | 
|  | SkAutoTUnref<SkPicture> picture(recorder.endRecording()); | 
|  | canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); | 
|  | } | 
|  | paint.setColor(rand.nextU()); | 
|  | canvas->drawPaint(paint); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | typedef PictureRecordBench INHERITED; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  Populates the SkPaint dictionary with a number of unique paint | 
|  | *  objects that get reused repeatedly. | 
|  | * | 
|  | *  Re-creating the paint objects in the inner loop slows the benchmark down 10%. | 
|  | *  Using setColor(i % objCount) instead of a random color creates a very high rate | 
|  | *  of hash conflicts, slowing us down 12%. | 
|  | */ | 
|  | class RecurringPaintDictionaryRecordBench : public PictureRecordBench { | 
|  | public: | 
|  | RecurringPaintDictionaryRecordBench() : INHERITED("recurring_paint_dictionary") { | 
|  | SkRandom rand; | 
|  | for (int i = 0; i < ObjCount; i++) { | 
|  | fPaint[i].setColor(rand.nextU()); | 
|  | } | 
|  | } | 
|  |  | 
|  | enum { | 
|  | ObjCount = 100,  // number of unique paint objects | 
|  | }; | 
|  | protected: | 
|  | virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { | 
|  | SkPictureRecorder recorder; | 
|  | SkCanvas* canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); | 
|  | for (int i = 0; i < loops; i++) { | 
|  | canvas->drawPaint(fPaint[i % ObjCount]); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | SkPaint fPaint [ObjCount]; | 
|  | typedef PictureRecordBench INHERITED; | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | DEF_BENCH( return new DictionaryRecordBench(); ) | 
|  | DEF_BENCH( return new UniquePaintDictionaryRecordBench(); ) | 
|  | DEF_BENCH( return new RecurringPaintDictionaryRecordBench(); ) |