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