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