/*
* Copyright 2014 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 "SkBlendModePriv.h"
#include "SkCanvas.h"
#include "SkPaint.h"
#include <ctype.h>
/** This benchmark tests rendering rotated rectangles. It can optionally apply AA and/or change the
paint color between each rect in different ways using the ColorType enum. The xfermode used can
be specified as well.
*/
enum ColorType {
kConstantOpaque_ColorType,
kConstantTransparent_ColorType,
kChangingOpaque_ColorType,
kChangingTransparent_ColorType,
kAlternatingOpaqueAndTransparent_ColorType,
};
static inline SkColor start_color(ColorType ct) {
switch (ct) {
case kConstantOpaque_ColorType:
case kChangingOpaque_ColorType:
case kAlternatingOpaqueAndTransparent_ColorType:
return 0xFFA07040;
case kConstantTransparent_ColorType:
case kChangingTransparent_ColorType:
return 0x80A07040;
}
SK_ABORT("Shouldn't reach here.");
return 0;
}
static inline SkColor advance_color(SkColor old, ColorType ct, int step) {
if (kAlternatingOpaqueAndTransparent_ColorType == ct) {
ct = (step & 0x1) ? kChangingOpaque_ColorType : kChangingTransparent_ColorType ;
}
switch (ct) {
case kConstantOpaque_ColorType:
case kConstantTransparent_ColorType:
return old;
case kChangingOpaque_ColorType:
return 0xFF000000 | (old + 0x00010307);
case kChangingTransparent_ColorType:
return (0x00FFFFFF & (old + 0x00010307)) | 0x80000000;
case kAlternatingOpaqueAndTransparent_ColorType:
SK_ABORT("Can't get here");
}
SK_ABORT("Shouldn't reach here.");
return 0;
}
static SkString to_lower(const char* str) {
SkString lower(str);
for (size_t i = 0; i < lower.size(); i++) {
lower[i] = tolower(lower[i]);
}
return lower;
}
class RotRectBench: public Benchmark {
public:
RotRectBench(bool aa, ColorType ct, SkBlendMode mode)
: fAA(aa)
, fColorType(ct)
, fMode(mode) {
this->makeName();
}
protected:
const char* onGetName() override { return fName.c_str(); }
void onDraw(int loops, SkCanvas* canvas) override {
SkPaint paint;
paint.setAntiAlias(fAA);
paint.setBlendMode(fMode);
SkColor color = start_color(fColorType);
int w = this->getSize().x();
int h = this->getSize().y();
static const SkScalar kRectW = 25.1f;
static const SkScalar kRectH = 25.9f;
SkMatrix rotate;
// This value was chosen so that we frequently hit the axis-aligned case.
rotate.setRotate(30.f, kRectW / 2, kRectH / 2);
SkMatrix m = rotate;
SkScalar tx = 0, ty = 0;
for (int i = 0; i < loops; ++i) {
canvas->save();
canvas->translate(tx, ty);
canvas->concat(m);
paint.setColor(color);
color = advance_color(color, fColorType, i);
canvas->drawRect(SkRect::MakeWH(kRectW, kRectH), paint);
canvas->restore();
tx += kRectW + 2;
if (tx > w) {
tx = 0;
ty += kRectH + 2;
if (ty > h) {
ty = 0;
}
}
m.postConcat(rotate);
}
}
private:
void makeName() {
fName = "rotated_rects";
if (fAA) {
fName.append("_aa");
} else {
fName.append("_bw");
}
switch (fColorType) {
case kConstantOpaque_ColorType:
fName.append("_same_opaque");
break;
case kConstantTransparent_ColorType:
fName.append("_same_transparent");
break;
case kChangingOpaque_ColorType:
fName.append("_changing_opaque");
break;
case kChangingTransparent_ColorType:
fName.append("_changing_transparent");
break;
case kAlternatingOpaqueAndTransparent_ColorType:
fName.append("_alternating_transparent_and_opaque");
break;
}
fName.appendf("_%s", to_lower(SkBlendMode_Name(fMode)).c_str());
}
bool fAA;
ColorType fColorType;
SkBlendMode fMode;
SkString fName;
typedef Benchmark INHERITED;
};
// Choose kSrcOver because it always allows coverage and alpha to be conflated. kSrc only allows
// conflation when opaque, and kDarken because it isn't possilbe with standard GL blending.
DEF_BENCH(return new RotRectBench(true, kConstantOpaque_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(true, kConstantTransparent_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(true, kChangingOpaque_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(true, kChangingTransparent_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(true, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrcOver);)
DEF_BENCH(return new RotRectBench(true, kConstantOpaque_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(true, kConstantTransparent_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(true, kChangingOpaque_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(true, kChangingTransparent_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(true, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrc);)
DEF_BENCH(return new RotRectBench(true, kConstantOpaque_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(true, kConstantTransparent_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(true, kChangingOpaque_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(true, kChangingTransparent_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(true, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType, SkBlendMode::kDarken);)
DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kDarken);)