ChartBench.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright 2013 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/SkCanvas.h"
  9. #include "include/core/SkPaint.h"
  10. #include "include/core/SkPath.h"
  11. #include "include/private/SkTDArray.h"
  12. #include "include/utils/SkRandom.h"
  13. /**
  14. * This is a conversion of samplecode/SampleChart.cpp into a bench. It sure would be nice to be able
  15. * to write one subclass that can be a GM, bench, and/or Sample.
  16. */
  17. // Generates y values for the chart plots.
  18. static void gen_data(SkScalar yAvg, SkScalar ySpread, int count,
  19. SkRandom* random, SkTDArray<SkScalar>* dataPts) {
  20. dataPts->setCount(count);
  21. for (int i = 0; i < count; ++i) {
  22. (*dataPts)[i] = random->nextRangeScalar(yAvg - SkScalarHalf(ySpread),
  23. yAvg + SkScalarHalf(ySpread));
  24. }
  25. }
  26. // Generates a path to stroke along the top of each plot and a fill path for the area below each
  27. // plot. The fill path is bounded below by the bottomData plot points or a horizontal line at
  28. // yBase if bottomData == nullptr.
  29. // The plots are animated by rotating the data points by leftShift.
  30. static void gen_paths(const SkTDArray<SkScalar>& topData,
  31. const SkTDArray<SkScalar>* bottomData,
  32. SkScalar yBase,
  33. SkScalar xLeft, SkScalar xDelta,
  34. int leftShift,
  35. SkPath* plot, SkPath* fill) {
  36. plot->rewind();
  37. fill->rewind();
  38. plot->incReserve(topData.count());
  39. if (nullptr == bottomData) {
  40. fill->incReserve(topData.count() + 2);
  41. } else {
  42. fill->incReserve(2 * topData.count());
  43. }
  44. leftShift %= topData.count();
  45. SkScalar x = xLeft;
  46. // Account for the leftShift using two loops
  47. int shiftToEndCount = topData.count() - leftShift;
  48. plot->moveTo(x, topData[leftShift]);
  49. fill->moveTo(x, topData[leftShift]);
  50. for (int i = 1; i < shiftToEndCount; ++i) {
  51. plot->lineTo(x, topData[i + leftShift]);
  52. fill->lineTo(x, topData[i + leftShift]);
  53. x += xDelta;
  54. }
  55. for (int i = 0; i < leftShift; ++i) {
  56. plot->lineTo(x, topData[i]);
  57. fill->lineTo(x, topData[i]);
  58. x += xDelta;
  59. }
  60. if (bottomData) {
  61. SkASSERT(bottomData->count() == topData.count());
  62. // iterate backwards over the previous graph's data to generate the bottom of the filled
  63. // area (and account for leftShift).
  64. for (int i = 0; i < leftShift; ++i) {
  65. x -= xDelta;
  66. fill->lineTo(x, (*bottomData)[leftShift - 1 - i]);
  67. }
  68. for (int i = 0; i < shiftToEndCount; ++i) {
  69. x -= xDelta;
  70. fill->lineTo(x, (*bottomData)[bottomData->count() - 1 - i]);
  71. }
  72. } else {
  73. fill->lineTo(x - xDelta, yBase);
  74. fill->lineTo(xLeft, yBase);
  75. }
  76. }
  77. // A set of scrolling line plots with the area between each plot filled. Stresses out GPU path
  78. // filling
  79. class ChartBench : public Benchmark {
  80. public:
  81. ChartBench(bool aa) {
  82. fShift = 0;
  83. fAA = aa;
  84. fSize.fWidth = -1;
  85. fSize.fHeight = -1;
  86. }
  87. protected:
  88. const char* onGetName() override {
  89. if (fAA) {
  90. return "chart_aa";
  91. } else {
  92. return "chart_bw";
  93. }
  94. }
  95. void onDraw(int loops, SkCanvas* canvas) override {
  96. bool sizeChanged = false;
  97. if (canvas->getBaseLayerSize() != fSize) {
  98. fSize = canvas->getBaseLayerSize();
  99. sizeChanged = true;
  100. }
  101. SkScalar ySpread = SkIntToScalar(fSize.fHeight / 20);
  102. SkScalar height = SkIntToScalar(fSize.fHeight);
  103. if (sizeChanged) {
  104. int dataPointCount = SkMax32(fSize.fWidth / kPixelsPerTick + 1, 2);
  105. SkRandom random;
  106. for (int i = 0; i < kNumGraphs; ++i) {
  107. SkScalar y = (kNumGraphs - i) * (height - ySpread) / (kNumGraphs + 1);
  108. fData[i].reset();
  109. gen_data(y, ySpread, dataPointCount, &random, fData + i);
  110. }
  111. }
  112. SkRandom colorRand;
  113. SkColor colors[kNumGraphs];
  114. for (int i = 0; i < kNumGraphs; ++i) {
  115. colors[i] = colorRand.nextU() | 0xff000000;
  116. }
  117. for (int frame = 0; frame < loops; ++frame) {
  118. SkPath plotPath;
  119. SkPath fillPath;
  120. static const SkScalar kStrokeWidth = SkIntToScalar(2);
  121. SkPaint plotPaint;
  122. SkPaint fillPaint;
  123. plotPaint.setAntiAlias(fAA);
  124. plotPaint.setStyle(SkPaint::kStroke_Style);
  125. plotPaint.setStrokeWidth(kStrokeWidth);
  126. plotPaint.setStrokeCap(SkPaint::kRound_Cap);
  127. plotPaint.setStrokeJoin(SkPaint::kRound_Join);
  128. fillPaint.setAntiAlias(fAA);
  129. fillPaint.setStyle(SkPaint::kFill_Style);
  130. SkTDArray<SkScalar>* prevData = nullptr;
  131. for (int i = 0; i < kNumGraphs; ++i) {
  132. gen_paths(fData[i],
  133. prevData,
  134. height,
  135. 0,
  136. SkIntToScalar(kPixelsPerTick),
  137. fShift,
  138. &plotPath,
  139. &fillPath);
  140. // Make the fills partially transparent
  141. fillPaint.setColor((colors[i] & 0x00ffffff) | 0x80000000);
  142. canvas->drawPath(fillPath, fillPaint);
  143. plotPaint.setColor(colors[i]);
  144. canvas->drawPath(plotPath, plotPaint);
  145. prevData = fData + i;
  146. }
  147. fShift += kShiftPerFrame;
  148. }
  149. }
  150. private:
  151. enum {
  152. kNumGraphs = 5,
  153. kPixelsPerTick = 3,
  154. kShiftPerFrame = 1,
  155. };
  156. int fShift;
  157. SkISize fSize;
  158. SkTDArray<SkScalar> fData[kNumGraphs];
  159. bool fAA;
  160. typedef Benchmark INHERITED;
  161. };
  162. //////////////////////////////////////////////////////////////////////////////
  163. DEF_BENCH( return new ChartBench(true); )
  164. DEF_BENCH( return new ChartBench(false); )