skia2/bench/PictureRecordBench.cpp
commit-bot@chromium.org 0c4e21da95 Streamline picture_record_recurring_ bench.
Reduce benchmark runtime from ~17 ms to ~13.25ms by moving SkPaint
construction out of the inner loop and by using random colors in the
SkPaints instead of sequential integers, which were seeing bad hashing.

This doesn't actually improve our performance, but makes the benchmark
more focused on pure recording costs.

BUG=
R=mtklein@google.com, reed@google.com, tomhudson@google.com

Author: tomhudson@chromium.org

Review URL: https://chromiumcodereview.appspot.com/18119011

git-svn-id: http://skia.googlecode.com/svn/trunk@10003 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-07-11 14:26:09 +00:00

203 lines
6.0 KiB
C++

/*
* 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 "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPoint.h"
#include "SkRandom.h"
#include "SkRect.h"
#include "SkString.h"
class PictureRecordBench : public SkBenchmark {
public:
PictureRecordBench(void* param, const char name[]) : INHERITED(param) {
fName.printf("picture_record_%s", name);
fPictureWidth = SkIntToScalar(PICTURE_WIDTH);
fPictureHeight = SkIntToScalar(PICTURE_HEIGHT);
fIsRendering = false;
}
enum {
N = SkBENCHLOOP(25), // number of times to create the picture
PICTURE_WIDTH = 1000,
PICTURE_HEIGHT = 4000,
};
protected:
virtual const char* onGetName() {
return fName.c_str();
}
virtual void onDraw(SkCanvas*) {
int n = (int)(N * this->innerLoopScale());
n = SkMax32(1, n);
for (int i = 0; i < n; i++) {
SkPicture picture;
SkCanvas* pCanvas = picture.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
recordCanvas(pCanvas);
// we don't need to draw the picture as the endRecording step will
// do the work of transferring the recorded content into a playback
// object.
picture.endRecording();
}
}
virtual void recordCanvas(SkCanvas* canvas) = 0;
virtual float innerLoopScale() const { return 1; }
SkString fName;
SkScalar fPictureWidth;
SkScalar fPictureHeight;
SkScalar fTextSize;
private:
typedef SkBenchmark INHERITED;
};
/*
* 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(void* param)
: INHERITED(param, "dictionaries") { }
enum {
M = SkBENCHLOOP(100), // number of elements in each dictionary
};
protected:
virtual void recordCanvas(SkCanvas* canvas) {
const SkPoint translateDelta = getTranslateDelta();
for (int i = 0; i < M; i++) {
SkColor color = SK_ColorYELLOW + (i % 255);
SkIRect rect = SkIRect::MakeWH(i,i);
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.setConfig(SkBitmap::kRGB_565_Config, 10, 10);
bitmap.allocPixels();
// 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() {
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(void* param)
: INHERITED(param, "unique_paint_dictionary") { }
enum {
M = SkBENCHLOOP(15000), // number of unique paint objects
};
protected:
virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
virtual void recordCanvas(SkCanvas* canvas) {
SkRandom rand;
for (int i = 0; i < M; i++) {
SkPaint paint;
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(void* param)
: INHERITED(param, "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
M = SkBENCHLOOP(50000), // number of draw iterations
};
protected:
virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
virtual void recordCanvas(SkCanvas* canvas) {
for (int i = 0; i < M; i++) {
canvas->drawPaint(fPaint[i % ObjCount]);
}
}
private:
SkPaint fPaint [ObjCount];
typedef PictureRecordBench INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
static SkBenchmark* Fact0(void* p) { return new DictionaryRecordBench(p); }
static SkBenchmark* Fact1(void* p) { return new UniquePaintDictionaryRecordBench(p); }
static SkBenchmark* Fact2(void* p) { return new RecurringPaintDictionaryRecordBench(p); }
static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg1(Fact1);
static BenchRegistry gReg2(Fact2);