1/*
2 * Copyright 2020 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
8#include "include/core/SkCanvas.h"
9#include "include/core/SkFont.h"
10#include "include/core/SkSurface.h"
11#include "samplecode/Sample.h"
12#include <chrono>
13
14struct TimingSample : public Sample {
15    inline static constexpr int W = 24,
16                                H = 16;
17    sk_sp<SkImage> fImg;
18
19    SkString name() override { return SkString("Timing"); }
20
21    void onOnceBeforeDraw() override {
22        sk_sp<SkSurface> surf = SkSurface::MakeRasterN32Premul(W,H);
23        surf->getCanvas()->drawString("abc", 2,H-4, SkFont{}, SkPaint{});
24        fImg = surf->makeImageSnapshot();
25    }
26
27    void onDrawContent(SkCanvas* canvas) override {
28        canvas->scale(8,8);
29
30        // Draw normally.
31        canvas->drawImage(fImg, 0,0);
32
33        canvas->translate(0,H);
34
35        // Draw one pixel at a time with drawImageRect(),
36        // timing how long each drawImageRect() call takes.
37        double cost[H][W];
38        double min = +INFINITY,
39               max = -INFINITY;
40        for (int y = 0; y < H; y++)
41        for (int x = 0; x < W; x++) {
42            auto start = std::chrono::steady_clock::now();
43            canvas->drawImageRect(fImg.get(),
44                                  SkRect::MakeXYWH(x,y,1,1), SkRect::MakeXYWH(x,y,1,1),
45                                  SkSamplingOptions(), /*paint=*/nullptr,
46                                  SkCanvas::kStrict_SrcRectConstraint);
47            auto elapsed = std::chrono::steady_clock::now() - start;
48
49            cost[y][x] = elapsed.count();
50            min = std::min(min, cost[y][x]);
51            max = std::max(max, cost[y][x]);
52        }
53
54        canvas->translate(0,H);
55
56        // Draw using those per-pixel timings,
57        // with the slowest pixel scaled to alpha=1, the fastest to alpha=0.
58        for (int y = 0; y < H; y++)
59        for (int x = 0; x < W; x++) {
60            SkPaint p;
61            p.setAlphaf( (cost[y][x] - min) / (max - min) );
62            canvas->drawRect(SkRect::MakeXYWH(x,y,1,1), p);
63        }
64
65        canvas->translate(0,H);
66
67        // Draw each pixel into offscreen, timing each draw.
68        SkImageInfo info = canvas->imageInfo().makeWH(1024,1024);
69        if (sk_sp<SkSurface> offscreen = canvas->makeSurface(info)) {
70            min = +INFINITY;
71            max = -INFINITY;
72            for (int y = 0; y < H; y++)
73            for (int x = 0; x < W; x++) {
74                auto start = std::chrono::steady_clock::now();
75                offscreen->getCanvas()->drawImageRect(fImg,
76                                                      SkRect::MakeXYWH(x,y,1,1),
77                                                      SkRect::MakeXYWH(0,0,1024,1024),
78                                                      SkSamplingOptions(),
79                                                      /*paint=*/nullptr,
80                                                      SkCanvas::kStrict_SrcRectConstraint);
81                auto elapsed = std::chrono::steady_clock::now() - start;
82
83                cost[y][x] = elapsed.count();
84                min = std::min(min, cost[y][x]);
85                max = std::max(max, cost[y][x]);
86            }
87            for (int y = 0; y < H; y++)
88            for (int x = 0; x < W; x++) {
89                SkPaint p;
90                p.setAlphaf( (cost[y][x] - min) / (max - min) );
91                canvas->drawRect(SkRect::MakeXYWH(x,y,1,1), p);
92            }
93        }
94    }
95};
96DEF_SAMPLE( return new TimingSample; )
97