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