1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 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 "bench/SKPBench.h"
9cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
11cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
12cb93a386Sopenharmony_ci#include "tools/flags/CommandLineFlags.h"
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci// These CPU tile sizes are not good per se, but they are similar to what Chrome uses.
16cb93a386Sopenharmony_cistatic DEFINE_int(CPUbenchTileW, 256, "Tile width  used for CPU SKP playback.");
17cb93a386Sopenharmony_cistatic DEFINE_int(CPUbenchTileH, 256, "Tile height used for CPU SKP playback.");
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_cistatic DEFINE_int(GPUbenchTileW, 1600, "Tile width  used for GPU SKP playback.");
20cb93a386Sopenharmony_cistatic DEFINE_int(GPUbenchTileH, 512, "Tile height used for GPU SKP playback.");
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ciSKPBench::SKPBench(const char* name, const SkPicture* pic, const SkIRect& clip, SkScalar scale,
23cb93a386Sopenharmony_ci                   bool doLooping)
24cb93a386Sopenharmony_ci    : fPic(SkRef(pic))
25cb93a386Sopenharmony_ci    , fClip(clip)
26cb93a386Sopenharmony_ci    , fScale(scale)
27cb93a386Sopenharmony_ci    , fName(name)
28cb93a386Sopenharmony_ci    , fDoLooping(doLooping) {
29cb93a386Sopenharmony_ci    fUniqueName.printf("%s_%.2g", name, scale);  // Scale makes this unqiue for perf.skia.org traces.
30cb93a386Sopenharmony_ci}
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ciSKPBench::~SKPBench() {
33cb93a386Sopenharmony_ci    for (int i = 0; i < fSurfaces.count(); ++i) {
34cb93a386Sopenharmony_ci        fSurfaces[i]->unref();
35cb93a386Sopenharmony_ci    }
36cb93a386Sopenharmony_ci}
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ciconst char* SKPBench::onGetName() {
39cb93a386Sopenharmony_ci    return fName.c_str();
40cb93a386Sopenharmony_ci}
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ciconst char* SKPBench::onGetUniqueName() {
43cb93a386Sopenharmony_ci    return fUniqueName.c_str();
44cb93a386Sopenharmony_ci}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_civoid SKPBench::onPerCanvasPreDraw(SkCanvas* canvas) {
47cb93a386Sopenharmony_ci    SkIRect bounds = canvas->getDeviceClipBounds();
48cb93a386Sopenharmony_ci    bounds.intersect(fClip);
49cb93a386Sopenharmony_ci    bounds.intersect(fPic->cullRect().roundOut());
50cb93a386Sopenharmony_ci    SkAssertResult(!bounds.isEmpty());
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    const bool gpu = canvas->recordingContext() != nullptr;
53cb93a386Sopenharmony_ci    int tileW = gpu ? FLAGS_GPUbenchTileW : FLAGS_CPUbenchTileW,
54cb93a386Sopenharmony_ci        tileH = gpu ? FLAGS_GPUbenchTileH : FLAGS_CPUbenchTileH;
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    tileW = std::min(tileW, bounds.width());
57cb93a386Sopenharmony_ci    tileH = std::min(tileH, bounds.height());
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci    int xTiles = SkScalarCeilToInt(bounds.width()  / SkIntToScalar(tileW));
60cb93a386Sopenharmony_ci    int yTiles = SkScalarCeilToInt(bounds.height() / SkIntToScalar(tileH));
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    fSurfaces.reserve_back(xTiles * yTiles);
63cb93a386Sopenharmony_ci    fTileRects.setReserve(xTiles * yTiles);
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci    SkImageInfo ii = canvas->imageInfo().makeWH(tileW, tileH);
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    for (int y = bounds.fTop; y < bounds.fBottom; y += tileH) {
68cb93a386Sopenharmony_ci        for (int x = bounds.fLeft; x < bounds.fRight; x += tileW) {
69cb93a386Sopenharmony_ci            const SkIRect tileRect = SkIRect::MakeXYWH(x, y, tileW, tileH);
70cb93a386Sopenharmony_ci            *fTileRects.append() = tileRect;
71cb93a386Sopenharmony_ci            fSurfaces.emplace_back(canvas->makeSurface(ii));
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ci            // Never want the contents of a tile to include stuff the parent
74cb93a386Sopenharmony_ci            // canvas clips out
75cb93a386Sopenharmony_ci            SkRect clip = SkRect::Make(bounds);
76cb93a386Sopenharmony_ci            clip.offset(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop));
77cb93a386Sopenharmony_ci            fSurfaces.back()->getCanvas()->clipRect(clip);
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci            fSurfaces.back()->getCanvas()->setMatrix(canvas->getLocalToDevice());
80cb93a386Sopenharmony_ci            fSurfaces.back()->getCanvas()->scale(fScale, fScale);
81cb93a386Sopenharmony_ci        }
82cb93a386Sopenharmony_ci    }
83cb93a386Sopenharmony_ci}
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_civoid SKPBench::onPerCanvasPostDraw(SkCanvas* canvas) {
86cb93a386Sopenharmony_ci    // Draw the last set of tiles into the main canvas in case we're
87cb93a386Sopenharmony_ci    // saving the images
88cb93a386Sopenharmony_ci    for (int i = 0; i < fTileRects.count(); ++i) {
89cb93a386Sopenharmony_ci        sk_sp<SkImage> image(fSurfaces[i]->makeImageSnapshot());
90cb93a386Sopenharmony_ci        canvas->drawImage(image,
91cb93a386Sopenharmony_ci                          SkIntToScalar(fTileRects[i].fLeft), SkIntToScalar(fTileRects[i].fTop));
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci    fSurfaces.reset();
95cb93a386Sopenharmony_ci    fTileRects.rewind();
96cb93a386Sopenharmony_ci}
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_cibool SKPBench::isSuitableFor(Backend backend) {
99cb93a386Sopenharmony_ci    return backend != kNonRendering_Backend;
100cb93a386Sopenharmony_ci}
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ciSkIPoint SKPBench::onGetSize() {
103cb93a386Sopenharmony_ci    return SkIPoint::Make(fClip.width(), fClip.height());
104cb93a386Sopenharmony_ci}
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_civoid SKPBench::onDraw(int loops, SkCanvas* canvas) {
107cb93a386Sopenharmony_ci    SkASSERT(fDoLooping || 1 == loops);
108cb93a386Sopenharmony_ci    while (1) {
109cb93a386Sopenharmony_ci        this->drawPicture();
110cb93a386Sopenharmony_ci        if (0 == --loops) {
111cb93a386Sopenharmony_ci            break;
112cb93a386Sopenharmony_ci        }
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ci        auto direct = canvas->recordingContext() ? canvas->recordingContext()->asDirectContext()
115cb93a386Sopenharmony_ci                                                 : nullptr;
116cb93a386Sopenharmony_ci        // Ensure the GrContext doesn't combine ops across draw loops.
117cb93a386Sopenharmony_ci        if (direct) {
118cb93a386Sopenharmony_ci            direct->flushAndSubmit();
119cb93a386Sopenharmony_ci        }
120cb93a386Sopenharmony_ci    }
121cb93a386Sopenharmony_ci}
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_civoid SKPBench::drawMPDPicture() {
124cb93a386Sopenharmony_ci    // TODO: remove me
125cb93a386Sopenharmony_ci}
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_civoid SKPBench::drawPicture() {
128cb93a386Sopenharmony_ci    for (int j = 0; j < fTileRects.count(); ++j) {
129cb93a386Sopenharmony_ci        const SkMatrix trans = SkMatrix::Translate(-fTileRects[j].fLeft / fScale,
130cb93a386Sopenharmony_ci                                                   -fTileRects[j].fTop / fScale);
131cb93a386Sopenharmony_ci        fSurfaces[j]->getCanvas()->drawPicture(fPic.get(), &trans, nullptr);
132cb93a386Sopenharmony_ci    }
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    for (int j = 0; j < fTileRects.count(); ++j) {
135cb93a386Sopenharmony_ci        fSurfaces[j]->flush();
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci}
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci#include "src/gpu/GrGpu.h"
140cb93a386Sopenharmony_cistatic void draw_pic_for_stats(SkCanvas* canvas,
141cb93a386Sopenharmony_ci                               GrDirectContext* dContext,
142cb93a386Sopenharmony_ci                               const SkPicture* picture,
143cb93a386Sopenharmony_ci                               SkTArray<SkString>* keys,
144cb93a386Sopenharmony_ci                               SkTArray<double>* values) {
145cb93a386Sopenharmony_ci    dContext->priv().resetGpuStats();
146cb93a386Sopenharmony_ci    dContext->priv().resetContextStats();
147cb93a386Sopenharmony_ci    canvas->drawPicture(picture);
148cb93a386Sopenharmony_ci    dContext->flush();
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci    dContext->priv().dumpGpuStatsKeyValuePairs(keys, values);
151cb93a386Sopenharmony_ci    dContext->priv().dumpCacheStatsKeyValuePairs(keys, values);
152cb93a386Sopenharmony_ci    dContext->priv().dumpContextStatsKeyValuePairs(keys, values);
153cb93a386Sopenharmony_ci}
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_civoid SKPBench::getGpuStats(SkCanvas* canvas, SkTArray<SkString>* keys, SkTArray<double>* values) {
156cb93a386Sopenharmony_ci    // we do a special single draw and then dump the key / value pairs
157cb93a386Sopenharmony_ci    auto direct = canvas->recordingContext() ? canvas->recordingContext()->asDirectContext()
158cb93a386Sopenharmony_ci                                             : nullptr;
159cb93a386Sopenharmony_ci    if (!direct) {
160cb93a386Sopenharmony_ci        return;
161cb93a386Sopenharmony_ci    }
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci    // TODO refactor this out if we want to test other subclasses of skpbench
164cb93a386Sopenharmony_ci    direct->flushAndSubmit();
165cb93a386Sopenharmony_ci    direct->freeGpuResources();
166cb93a386Sopenharmony_ci    direct->resetContext();
167cb93a386Sopenharmony_ci    direct->priv().getGpu()->resetShaderCacheForTesting();
168cb93a386Sopenharmony_ci    draw_pic_for_stats(canvas, direct, fPic.get(), keys, values);
169cb93a386Sopenharmony_ci}
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_cibool SKPBench::getDMSAAStats(GrRecordingContext* rContext) {
172cb93a386Sopenharmony_ci    if (!rContext || !rContext->asDirectContext()) {
173cb93a386Sopenharmony_ci        return false;
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci    // Clear the current DMSAA stats then do a single tiled draw that resets them to the specific
176cb93a386Sopenharmony_ci    // values for our SKP.
177cb93a386Sopenharmony_ci    rContext->asDirectContext()->flushAndSubmit();
178cb93a386Sopenharmony_ci    rContext->priv().dmsaaStats() = {};
179cb93a386Sopenharmony_ci    this->drawPicture();  // Draw tiled for DMSAA stats.
180cb93a386Sopenharmony_ci    rContext->asDirectContext()->flush();
181cb93a386Sopenharmony_ci    return true;
182cb93a386Sopenharmony_ci}
183