text: /*
   * Copyright 2011 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #include "bench/Benchmark.h"
  #include "include/core/SkCanvas.h"
  #include "include/core/SkPaint.h"
  #include "include/core/SkShader.h"
  #include "include/core/SkString.h"
  #include "include/core/SkVertices.h"
  #include "include/utils/SkRandom.h"
  #include "tools/Resources.h"
  
  // Just want to trigger perspective handling, not dramatically change size
  static void tiny_persp_effect(SkCanvas* canvas) {
      SkMatrix m;
      m.reset();
      m[7] = 0.000001f;
      canvas->concat(m);
  }
  
  enum VertFlags {
      kColors_VertFlag  = 1 << 0,
      kTexture_VertFlag = 1 << 1,
      kPersp_VertFlag   = 1 << 2,
  };
  
  class VertBench : public Benchmark {
      SkString fName;
      enum {
          W = 64*2,
          H = 48*2,
          ROW = 20,
          COL = 20,
          PTS = (ROW + 1) * (COL + 1),
          IDX = ROW * COL * 6,
      };
  
      sk_sp<SkShader> fShader;
      SkPoint fPts[PTS];
      SkColor fColors[PTS];
      uint16_t fIdx[IDX];
      unsigned fFlags;
  
      static void load_2_tris(uint16_t idx[], int x, int y, int rb) {
          int n = y * rb + x;
          idx[0] = n; idx[1] = n + 1; idx[2] = rb + n + 1;
          idx[3] = n; idx[4] = rb + n + 1; idx[5] = n + rb;
      }
  
      void onDelayedSetup() override {
          auto img = GetResourceAsImage("images/mandrill_256.png");
          if (img) {
              fShader = img->makeShader(SkSamplingOptions());
          }
      }
  
  public:
      VertBench(unsigned flags) : fFlags(flags) {
          const SkScalar dx = SkIntToScalar(W) / COL;
          const SkScalar dy = SkIntToScalar(H) / COL;
  
          SkPoint* pts = fPts;
          uint16_t* idx = fIdx;
  
          SkScalar yy = 0;
          for (int y = 0; y <= ROW; y++) {
              SkScalar xx = 0;
              for (int x = 0; x <= COL; ++x) {
                  pts->set(xx, yy);
                  pts += 1;
                  xx += dx;
  
                  if (x < COL && y < ROW) {
                      load_2_tris(idx, x, y, COL + 1);
                      for (int i = 0; i < 6; i++) {
                          SkASSERT(idx[i] < PTS);
                      }
                      idx += 6;
                  }
              }
              yy += dy;
          }
          SkASSERT(PTS == pts - fPts);
          SkASSERT(IDX == idx - fIdx);
  
          SkRandom rand;
          for (int i = 0; i < PTS; ++i) {
              fColors[i] = rand.nextU() | (0xFF << 24);
          }
  
          fName.set("verts");
          if (fFlags & kTexture_VertFlag) {
              fName.append("_textures");
          }
          if (fFlags & kColors_VertFlag) {
              fName.append("_colors");
          }
          if (fFlags & kPersp_VertFlag) {
              fName.append("_persp");
          }
      }
  
  protected:
      const char* onGetName() override { return fName.c_str(); }
      void onDraw(int loops, SkCanvas* canvas) override {
          SkPaint paint;
          this->setupPaint(&paint);
          paint.setShader(fShader);
  
          if (fFlags & kPersp_VertFlag) {
              tiny_persp_effect(canvas);
          }
  
          const SkPoint* texs = (fFlags & kTexture_VertFlag) ? fPts    : nullptr;
          const SkColor* cols = (fFlags & kColors_VertFlag)  ? fColors : nullptr;
          auto verts = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, PTS,
                                            fPts, texs, cols, IDX, fIdx);
          for (int i = 0; i < loops; i++) {
              canvas->drawVertices(verts, SkBlendMode::kModulate, paint);
          }
      }
  private:
      using INHERITED = Benchmark;
  };
  DEF_BENCH(return new VertBench(kTexture_VertFlag | kPersp_VertFlag);)
  DEF_BENCH(return new VertBench(kColors_VertFlag  | kPersp_VertFlag);)
  DEF_BENCH(return new VertBench(kTexture_VertFlag);)
  DEF_BENCH(return new VertBench(kColors_VertFlag);)
  DEF_BENCH(return new VertBench(kColors_VertFlag | kTexture_VertFlag);)
  
  /////////////////////////////////////////////////////////////////////////////////////////////////
  
  #include "include/core/SkRSXform.h"
  #include "include/utils/SkRandom.h"
  #include "tools/Resources.h"
  
  enum AtlasFlags {
      kColors_Flag = 1 << 0,
      kRotate_Flag = 1 << 1,
      kPersp_Flag  = 1 << 2,
  };
  
  class AtlasBench : public Benchmark {
      unsigned fFlags;
      SkString fName;
      enum {
          W = 640,
          H = 480,
          N = 10*1000,
      };
  
      sk_sp<SkImage>  fAtlas;
      SkRSXform       fXforms[N];
      SkRect          fRects[N];
      SkColor         fColors[N];
  
  public:
      AtlasBench(unsigned flags) : fFlags(flags) {
          fName.printf("drawAtlas");
          if (flags & kColors_Flag) {
              fName.append("_colors");
          }
          if (flags & kRotate_Flag) {
              fName.append("_rotated");
          }
          if (flags & kPersp_Flag) {
              fName.append("_persp");
          }
      }
      ~AtlasBench() override {}
  
  protected:
      const char* onGetName() override { return fName.c_str(); }
      void onDelayedSetup() override {
          fAtlas = GetResourceAsImage("images/mandrill_256.png");
          if (fAtlas) {
              fAtlas = fAtlas->makeRasterImage();
          }
  
          const SkScalar imageW = fAtlas->width();
          const SkScalar imageH = fAtlas->height();
          SkScalar scos = 1;
          SkScalar ssin = 0;
          if (fFlags & kRotate_Flag) {
              scos = 0.866025403784439f;  // sqrt(3)/2
              ssin = 0.5f;
          }
  
          SkRandom rand;
          for (int i = 0; i < N; ++i) {
              fRects[i] = SkRect::MakeXYWH(rand.nextF() * (imageW - 8),
                                           rand.nextF() * (imageH - 8), 8, 8);
              fColors[i] = rand.nextU() | 0xFF000000;
              fXforms[i] = SkRSXform::Make(scos, ssin, rand.nextF() * W, rand.nextF() * H);
          }
      }
      void onDraw(int loops, SkCanvas* canvas) override {
          const SkRect* cullRect = nullptr;
          const SkPaint* paintPtr = nullptr;
          const SkColor* colors = nullptr;
          if (fFlags & kColors_Flag) {
              colors = fColors;
          }
          if (fFlags & kPersp_Flag) {
              tiny_persp_effect(canvas);
          }
          for (int i = 0; i < loops; i++) {
              canvas->drawAtlas(fAtlas.get(), fXforms, fRects, colors, N, SkBlendMode::kModulate,
                                SkSamplingOptions(), cullRect, paintPtr);
          }
      }
  private:
      using INHERITED = Benchmark;
  };
  //DEF_BENCH(return new AtlasBench(0);)
  //DEF_BENCH(return new AtlasBench(kColors_Flag);)
  DEF_BENCH(return new AtlasBench(0);)
  DEF_BENCH(return new AtlasBench(kRotate_Flag);)
  DEF_BENCH(return new AtlasBench(kPersp_Flag);)
  DEF_BENCH(return new AtlasBench(kColors_Flag);)
  DEF_BENCH(return new AtlasBench(kColors_Flag | kRotate_Flag);)
  
  