Home | History | Annotate | Download | only in bench
      1 
      2 /*
      3  * Copyright 2013 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "SkBenchmark.h"
     10 #include "SkCanvas.h"
     11 #include "SkPaint.h"
     12 #include "SkRandom.h"
     13 
     14 /**
     15  * This is a conversion of samplecode/SampleChart.cpp into a bench. It sure would be nice to be able
     16  * to write one subclass that can be a GM, bench, and/or Sample.
     17  */
     18 
     19 namespace {
     20 
     21 // Generates y values for the chart plots.
     22 void gen_data(SkScalar yAvg, SkScalar ySpread, int count, SkTDArray<SkScalar>* dataPts) {
     23     dataPts->setCount(count);
     24     static SkMWCRandom gRandom;
     25     for (int i = 0; i < count; ++i) {
     26         (*dataPts)[i] = gRandom.nextRangeScalar(yAvg - SkScalarHalf(ySpread),
     27                                                 yAvg + SkScalarHalf(ySpread));
     28     }
     29 }
     30 
     31 // Generates a path to stroke along the top of each plot and a fill path for the area below each
     32 // plot. The fill path is bounded below by the bottomData plot points or a horizontal line at
     33 // yBase if bottomData == NULL.
     34 // The plots are animated by rotating the data points by leftShift.
     35 void gen_paths(const SkTDArray<SkScalar>& topData,
     36                const SkTDArray<SkScalar>* bottomData,
     37                SkScalar yBase,
     38                SkScalar xLeft, SkScalar xDelta,
     39                int leftShift,
     40                SkPath* plot, SkPath* fill) {
     41     plot->rewind();
     42     fill->rewind();
     43     plot->incReserve(topData.count());
     44     if (NULL == bottomData) {
     45         fill->incReserve(topData.count() + 2);
     46     } else {
     47         fill->incReserve(2 * topData.count());
     48     }
     49 
     50     leftShift %= topData.count();
     51     SkScalar x = xLeft;
     52 
     53     // Account for the leftShift using two loops
     54     int shiftToEndCount = topData.count() - leftShift;
     55     plot->moveTo(x, topData[leftShift]);
     56     fill->moveTo(x, topData[leftShift]);
     57 
     58     for (int i = 1; i < shiftToEndCount; ++i) {
     59         plot->lineTo(x, topData[i + leftShift]);
     60         fill->lineTo(x, topData[i + leftShift]);
     61         x += xDelta;
     62     }
     63 
     64     for (int i = 0; i < leftShift; ++i) {
     65         plot->lineTo(x, topData[i]);
     66         fill->lineTo(x, topData[i]);
     67         x += xDelta;
     68     }
     69 
     70     if (NULL != bottomData) {
     71         SkASSERT(bottomData->count() == topData.count());
     72         // iterate backwards over the previous graph's data to generate the bottom of the filled
     73         // area (and account for leftShift).
     74         for (int i = 0; i < leftShift; ++i) {
     75             x -= xDelta;
     76             fill->lineTo(x, (*bottomData)[leftShift - 1 - i]);
     77         }
     78         for (int i = 0; i < shiftToEndCount; ++i) {
     79             x -= xDelta;
     80             fill->lineTo(x, (*bottomData)[bottomData->count() - 1 - i]);
     81         }
     82     } else {
     83         fill->lineTo(x - xDelta, yBase);
     84         fill->lineTo(xLeft, yBase);
     85     }
     86 }
     87 
     88 }
     89 
     90 // A set of scrolling line plots with the area between each plot filled. Stresses out GPU path
     91 // filling
     92 class ChartBench : public SkBenchmark {
     93 public:
     94     ChartBench(void* param, bool aa) : SkBenchmark(param) {
     95         fShift = 0;
     96         fAA = aa;
     97         fSize.fWidth = -1;
     98         fSize.fHeight = -1;
     99     }
    100 
    101 protected:
    102     virtual const char* onGetName() SK_OVERRIDE {
    103         if (fAA) {
    104             return "chart_aa";
    105         } else {
    106             return "chart_bw";
    107         }
    108     }
    109 
    110     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
    111         bool sizeChanged = false;
    112         if (canvas->getDeviceSize() != fSize) {
    113             fSize = canvas->getDeviceSize();
    114             sizeChanged = true;
    115         }
    116 
    117         SkScalar ySpread = SkIntToScalar(fSize.fHeight / 20);
    118 
    119         SkScalar height = SkIntToScalar(fSize.fHeight);
    120         if (sizeChanged) {
    121             int dataPointCount = SkMax32(fSize.fWidth / kPixelsPerTick + 1, 2);
    122 
    123             for (int i = 0; i < kNumGraphs; ++i) {
    124                 SkScalar y = (kNumGraphs - i) * (height - ySpread) / (kNumGraphs + 1);
    125                 fData[i].reset();
    126                 gen_data(y, ySpread, dataPointCount, fData + i);
    127             }
    128         }
    129 
    130         for (int frame = 0; frame < kFramesPerRun; ++frame) {
    131 
    132             canvas->clear(0xFFE0F0E0);
    133 
    134             static SkMWCRandom colorRand;
    135             static SkColor gColors[kNumGraphs] = { 0x0 };
    136             if (0 == gColors[0]) {
    137                 for (int i = 0; i < kNumGraphs; ++i) {
    138                     gColors[i] = colorRand.nextU() | 0xff000000;
    139                 }
    140             }
    141 
    142             SkPath plotPath;
    143             SkPath fillPath;
    144 
    145             static const SkScalar kStrokeWidth = SkIntToScalar(2);
    146             SkPaint plotPaint;
    147             SkPaint fillPaint;
    148             plotPaint.setAntiAlias(fAA);
    149             plotPaint.setStyle(SkPaint::kStroke_Style);
    150             plotPaint.setStrokeWidth(kStrokeWidth);
    151             plotPaint.setStrokeCap(SkPaint::kRound_Cap);
    152             plotPaint.setStrokeJoin(SkPaint::kRound_Join);
    153             fillPaint.setAntiAlias(fAA);
    154             fillPaint.setStyle(SkPaint::kFill_Style);
    155 
    156             SkTDArray<SkScalar>* prevData = NULL;
    157             for (int i = 0; i < kNumGraphs; ++i) {
    158                 gen_paths(fData[i],
    159                           prevData,
    160                           height,
    161                           0,
    162                           SkIntToScalar(kPixelsPerTick),
    163                           fShift,
    164                           &plotPath,
    165                           &fillPath);
    166 
    167                 // Make the fills partially transparent
    168                 fillPaint.setColor((gColors[i] & 0x00ffffff) | 0x80000000);
    169                 canvas->drawPath(fillPath, fillPaint);
    170 
    171                 plotPaint.setColor(gColors[i]);
    172                 canvas->drawPath(plotPath, plotPaint);
    173 
    174                 prevData = fData + i;
    175             }
    176 
    177             fShift += kShiftPerFrame;
    178         }
    179     }
    180 
    181 private:
    182     enum {
    183         kNumGraphs = 5,
    184         kPixelsPerTick = 3,
    185         kShiftPerFrame = 1,
    186 
    187         kFramesPerRun = SkBENCHLOOP(5),
    188     };
    189     int                 fShift;
    190     SkISize             fSize;
    191     SkTDArray<SkScalar> fData[kNumGraphs];
    192     bool                fAA;
    193 
    194     typedef SkBenchmark INHERITED;
    195 };
    196 
    197 //////////////////////////////////////////////////////////////////////////////
    198 
    199 static SkBenchmark* Fact0(void* p) { return new ChartBench(p, true); }
    200 static SkBenchmark* Fact1(void* p) { return new ChartBench(p, false); }
    201 
    202 static BenchRegistry gReg0(Fact0);
    203 static BenchRegistry gReg1(Fact1);
    204