| /* | 
 |  * Copyright 2020 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "include/core/SkCanvas.h" | 
 | #include "include/core/SkFont.h" | 
 | #include "include/core/SkSurface.h" | 
 | #include "samplecode/Sample.h" | 
 | #include <chrono> | 
 |  | 
 | struct TimingSample : public Sample { | 
 |     static constexpr int W = 24, | 
 |                          H = 16; | 
 |     sk_sp<SkImage> fImg; | 
 |  | 
 |     SkString name() override { return SkString("Timing"); } | 
 |  | 
 |     void onOnceBeforeDraw() override { | 
 |         sk_sp<SkSurface> surf = SkSurface::MakeRasterN32Premul(W,H); | 
 |         surf->getCanvas()->drawString("abc", 2,H-4, SkFont{}, SkPaint{}); | 
 |         fImg = surf->makeImageSnapshot(); | 
 |     } | 
 |  | 
 |     void onDrawContent(SkCanvas* canvas) override { | 
 |         canvas->scale(8,8); | 
 |  | 
 |         // Draw normally. | 
 |         canvas->drawImage(fImg, 0,0); | 
 |  | 
 |         canvas->translate(0,H); | 
 |  | 
 |         // Draw one pixel at a time with drawImageRect(), | 
 |         // timing how long each drawImageRect() call takes. | 
 |         double cost[H][W]; | 
 |         double min = +INFINITY, | 
 |                max = -INFINITY; | 
 |         for (int y = 0; y < H; y++) | 
 |         for (int x = 0; x < W; x++) { | 
 |             auto start = std::chrono::steady_clock::now(); | 
 |             canvas->drawImageRect(fImg, SkRect::MakeXYWH(x,y,1,1) | 
 |                                       , SkRect::MakeXYWH(x,y,1,1) | 
 |                                       , /*paint=*/nullptr); | 
 |             auto elapsed = std::chrono::steady_clock::now() - start; | 
 |  | 
 |             cost[y][x] = elapsed.count(); | 
 |             min = std::min(min, cost[y][x]); | 
 |             max = std::max(max, cost[y][x]); | 
 |         } | 
 |  | 
 |         canvas->translate(0,H); | 
 |  | 
 |         // Draw using those per-pixel timings, | 
 |         // with the slowest pixel scaled to alpha=1, the fastest to alpha=0. | 
 |         for (int y = 0; y < H; y++) | 
 |         for (int x = 0; x < W; x++) { | 
 |             SkPaint p; | 
 |             p.setAlphaf( (cost[y][x] - min) / (max - min) ); | 
 |             canvas->drawRect(SkRect::MakeXYWH(x,y,1,1), p); | 
 |         } | 
 |  | 
 |         canvas->translate(0,H); | 
 |  | 
 |         // Draw each pixel into offscreen, timing each draw. | 
 |         SkImageInfo info = canvas->imageInfo().makeWH(1024,1024); | 
 |         if (sk_sp<SkSurface> offscreen = canvas->makeSurface(info)) { | 
 |             min = +INFINITY; | 
 |             max = -INFINITY; | 
 |             for (int y = 0; y < H; y++) | 
 |             for (int x = 0; x < W; x++) { | 
 |                 auto start = std::chrono::steady_clock::now(); | 
 |                 offscreen->getCanvas()->drawImageRect(fImg, SkRect::MakeXYWH(x,y,1,1) | 
 |                                                           , SkRect::MakeXYWH(0,0,1024,1024) | 
 |                                                           , /*paint=*/nullptr); | 
 |                 auto elapsed = std::chrono::steady_clock::now() - start; | 
 |  | 
 |                 cost[y][x] = elapsed.count(); | 
 |                 min = std::min(min, cost[y][x]); | 
 |                 max = std::max(max, cost[y][x]); | 
 |             } | 
 |             for (int y = 0; y < H; y++) | 
 |             for (int x = 0; x < W; x++) { | 
 |                 SkPaint p; | 
 |                 p.setAlphaf( (cost[y][x] - min) / (max - min) ); | 
 |                 canvas->drawRect(SkRect::MakeXYWH(x,y,1,1), p); | 
 |             } | 
 |         } | 
 |     } | 
 | }; | 
 | DEF_SAMPLE( return new TimingSample; ) |