GradientBench.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * Copyright 2011 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. #include "bench/Benchmark.h"
  8. #include "include/core/SkBitmap.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkColorPriv.h"
  11. #include "include/core/SkPaint.h"
  12. #include "include/core/SkShader.h"
  13. #include "include/core/SkString.h"
  14. #include "include/effects/SkGradientShader.h"
  15. struct GradData {
  16. int fCount;
  17. const SkColor* fColors;
  18. const SkScalar* fPos;
  19. const char* fName;
  20. };
  21. static const SkColor gColors[] = {
  22. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  23. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  24. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  25. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  26. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  27. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  28. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  29. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  30. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
  31. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, // 10 lines, 50 colors
  32. };
  33. static const SkColor gShallowColors[] = { 0xFF555555, 0xFF444444 };
  34. static const SkScalar gPos[] = {0.25f, 0.75f};
  35. // We have several special-cases depending on the number (and spacing) of colors, so
  36. // try to exercise those here.
  37. static const GradData gGradData[] = {
  38. { 2, gColors, nullptr, "" },
  39. { 50, gColors, nullptr, "_hicolor" }, // many color gradient
  40. { 3, gColors, nullptr, "_3color" },
  41. { 2, gShallowColors, nullptr, "_shallow" },
  42. { 2, gColors, gPos, "_pos" },
  43. };
  44. /// Ignores scale
  45. static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data,
  46. SkTileMode tm, float scale) {
  47. return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm);
  48. }
  49. static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data,
  50. SkTileMode tm, float scale) {
  51. SkPoint center;
  52. center.set(SkScalarAve(pts[0].fX, pts[1].fX),
  53. SkScalarAve(pts[0].fY, pts[1].fY));
  54. return SkGradientShader::MakeRadial(center, center.fX * scale, data.fColors,
  55. data.fPos, data.fCount, tm);
  56. }
  57. /// Ignores scale
  58. static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data,
  59. SkTileMode tm, float scale) {
  60. SkPoint center;
  61. center.set(SkScalarAve(pts[0].fX, pts[1].fX),
  62. SkScalarAve(pts[0].fY, pts[1].fY));
  63. return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
  64. }
  65. /// Ignores scale
  66. static sk_sp<SkShader> MakeConical(const SkPoint pts[2], const GradData& data,
  67. SkTileMode tm, float scale) {
  68. SkPoint center0, center1;
  69. center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
  70. SkScalarAve(pts[0].fY, pts[1].fY));
  71. center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
  72. SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
  73. return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
  74. center0, (pts[1].fX - pts[0].fX) / 2,
  75. data.fColors, data.fPos, data.fCount, tm);
  76. }
  77. /// Ignores scale
  78. static sk_sp<SkShader> MakeConicalZeroRad(const SkPoint pts[2], const GradData& data,
  79. SkTileMode tm, float scale) {
  80. SkPoint center0, center1;
  81. center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
  82. SkScalarAve(pts[0].fY, pts[1].fY));
  83. center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
  84. SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
  85. return SkGradientShader::MakeTwoPointConical(center1, 0.0,
  86. center0, (pts[1].fX - pts[0].fX) / 2,
  87. data.fColors, data.fPos, data.fCount, tm);
  88. }
  89. /// Ignores scale
  90. static sk_sp<SkShader> MakeConicalOutside(const SkPoint pts[2], const GradData& data,
  91. SkTileMode tm, float scale) {
  92. SkPoint center0, center1;
  93. SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
  94. SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
  95. center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
  96. center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
  97. return SkGradientShader::MakeTwoPointConical(center0, radius0,
  98. center1, radius1,
  99. data.fColors, data.fPos,
  100. data.fCount, tm);
  101. }
  102. /// Ignores scale
  103. static sk_sp<SkShader> MakeConicalOutsideZeroRad(const SkPoint pts[2], const GradData& data,
  104. SkTileMode tm, float scale) {
  105. SkPoint center0, center1;
  106. SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
  107. SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
  108. center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
  109. center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
  110. return SkGradientShader::MakeTwoPointConical(center0, 0.0,
  111. center1, radius1,
  112. data.fColors, data.fPos,
  113. data.fCount, tm);
  114. }
  115. typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data,
  116. SkTileMode tm, float scale);
  117. static const struct {
  118. GradMaker fMaker;
  119. const char* fName;
  120. } gGrads[] = {
  121. { MakeLinear, "linear" },
  122. { MakeRadial, "radial1" },
  123. { MakeSweep, "sweep" },
  124. { MakeConical, "conical" },
  125. { MakeConicalZeroRad, "conicalZero" },
  126. { MakeConicalOutside, "conicalOut" },
  127. { MakeConicalOutsideZeroRad, "conicalOutZero" },
  128. };
  129. enum GradType { // these must match the order in gGrads
  130. kLinear_GradType,
  131. kRadial_GradType,
  132. kSweep_GradType,
  133. kConical_GradType,
  134. kConicalZero_GradType,
  135. kConicalOut_GradType,
  136. kConicalOutZero_GradType
  137. };
  138. enum GeomType {
  139. kRect_GeomType,
  140. kOval_GeomType
  141. };
  142. static const char* tilemodename(SkTileMode tm) {
  143. switch (tm) {
  144. case SkTileMode::kClamp:
  145. return "clamp";
  146. case SkTileMode::kRepeat:
  147. return "repeat";
  148. case SkTileMode::kMirror:
  149. return "mirror";
  150. case SkTileMode::kDecal:
  151. return "decal";
  152. }
  153. return "";
  154. }
  155. static const char* geomtypename(GeomType gt) {
  156. switch (gt) {
  157. case kRect_GeomType:
  158. return "rectangle";
  159. case kOval_GeomType:
  160. return "oval";
  161. default:
  162. SkDEBUGFAIL("unknown geometry type");
  163. return "error";
  164. }
  165. }
  166. ///////////////////////////////////////////////////////////////////////////////
  167. class GradientBench : public Benchmark {
  168. public:
  169. GradientBench(GradType gradType,
  170. GradData data = gGradData[0],
  171. SkTileMode tm = SkTileMode::kClamp,
  172. GeomType geomType = kRect_GeomType,
  173. float scale = 1.0f)
  174. : fGeomType(geomType) {
  175. fName.printf("gradient_%s_%s", gGrads[gradType].fName,
  176. tilemodename(tm));
  177. if (geomType != kRect_GeomType) {
  178. fName.appendf("_%s", geomtypename(geomType));
  179. }
  180. if (scale != 1.f) {
  181. fName.appendf("_scale_%g", scale);
  182. }
  183. fName.append(data.fName);
  184. this->setupPaint(&fPaint);
  185. fPaint.setShader(MakeShader(gradType, data, tm, scale));
  186. }
  187. GradientBench(GradType gradType, GradData data, bool dither)
  188. : fGeomType(kRect_GeomType) {
  189. const char *tmname = tilemodename(SkTileMode::kClamp);
  190. fName.printf("gradient_%s_%s", gGrads[gradType].fName, tmname);
  191. fName.append(data.fName);
  192. if (dither) {
  193. fName.appendf("_dither");
  194. }
  195. this->setupPaint(&fPaint);
  196. fPaint.setShader(MakeShader(gradType, data, SkTileMode::kClamp, 1.0f));
  197. fPaint.setDither(dither);
  198. }
  199. protected:
  200. const char* onGetName() override {
  201. return fName.c_str();
  202. }
  203. SkIPoint onGetSize() override {
  204. return SkIPoint::Make(kSize, kSize);
  205. }
  206. void onDraw(int loops, SkCanvas* canvas) override {
  207. const SkRect r = SkRect::MakeIWH(kSize, kSize);
  208. for (int i = 0; i < loops; i++) {
  209. switch (fGeomType) {
  210. case kRect_GeomType:
  211. canvas->drawRect(r, fPaint);
  212. break;
  213. case kOval_GeomType:
  214. canvas->drawOval(r, fPaint);
  215. break;
  216. }
  217. }
  218. }
  219. private:
  220. typedef Benchmark INHERITED;
  221. sk_sp<SkShader> MakeShader(GradType gradType, GradData data,
  222. SkTileMode tm, float scale) {
  223. const SkPoint pts[2] = {
  224. { 0, 0 },
  225. { SkIntToScalar(kSize), SkIntToScalar(kSize) }
  226. };
  227. return gGrads[gradType].fMaker(pts, data, tm, scale);
  228. }
  229. static const int kSize = 400;
  230. SkString fName;
  231. SkPaint fPaint;
  232. const GeomType fGeomType;
  233. };
  234. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0]); )
  235. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); )
  236. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); )
  237. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[4]); )
  238. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkTileMode::kRepeat); )
  239. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1], SkTileMode::kRepeat); )
  240. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2], SkTileMode::kRepeat); )
  241. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkTileMode::kMirror); )
  242. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1], SkTileMode::kMirror); )
  243. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2], SkTileMode::kMirror); )
  244. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); )
  245. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); )
  246. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[2]); )
  247. // Draw a radial gradient of radius 1/2 on a rectangle; half the lines should
  248. // be completely pinned, the other half should pe partially pinned
  249. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkTileMode::kClamp, kRect_GeomType, 0.5f); )
  250. // Draw a radial gradient on a circle of equal size; all the lines should
  251. // hit the unpinned fast path (so long as GradientBench.W == H)
  252. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkTileMode::kClamp, kOval_GeomType); )
  253. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkTileMode::kMirror); )
  254. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkTileMode::kRepeat); )
  255. DEF_BENCH( return new GradientBench(kSweep_GradType); )
  256. DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); )
  257. DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); )
  258. DEF_BENCH( return new GradientBench(kConical_GradType); )
  259. DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); )
  260. DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); )
  261. DEF_BENCH( return new GradientBench(kConicalZero_GradType); )
  262. DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[1]); )
  263. DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[2]); )
  264. DEF_BENCH( return new GradientBench(kConicalOut_GradType); )
  265. DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[1]); )
  266. DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[2]); )
  267. DEF_BENCH( return new GradientBench(kConicalOutZero_GradType); )
  268. DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[1]); )
  269. DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[2]); )
  270. // Dithering
  271. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], true); )
  272. DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], false); )
  273. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], true); )
  274. DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], false); )
  275. DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], true); )
  276. DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], false); )
  277. DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], true); )
  278. DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], false); )
  279. ///////////////////////////////////////////////////////////////////////////////
  280. class Gradient2Bench : public Benchmark {
  281. SkString fName;
  282. bool fHasAlpha;
  283. public:
  284. Gradient2Bench(bool hasAlpha) {
  285. fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque");
  286. fHasAlpha = hasAlpha;
  287. }
  288. protected:
  289. virtual const char* onGetName() {
  290. return fName.c_str();
  291. }
  292. virtual void onDraw(int loops, SkCanvas* canvas) {
  293. SkPaint paint;
  294. this->setupPaint(&paint);
  295. const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
  296. const SkPoint pts[] = {
  297. { 0, 0 },
  298. { SkIntToScalar(100), SkIntToScalar(100) },
  299. };
  300. for (int i = 0; i < loops; i++) {
  301. const int gray = i % 256;
  302. const int alpha = fHasAlpha ? gray : 0xFF;
  303. SkColor colors[] = {
  304. SK_ColorBLACK,
  305. SkColorSetARGB(alpha, gray, gray, gray),
  306. SK_ColorWHITE };
  307. paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr,
  308. SK_ARRAY_COUNT(colors),
  309. SkTileMode::kClamp));
  310. canvas->drawRect(r, paint);
  311. }
  312. }
  313. private:
  314. typedef Benchmark INHERITED;
  315. };
  316. DEF_BENCH( return new Gradient2Bench(false); )
  317. DEF_BENCH( return new Gradient2Bench(true); )