40#if defined(SK_ENABLE_SVG)
69static DEFINE_bool(ddl,
false,
"record the skp into DDLs before rendering");
70static DEFINE_int(ddlNumRecordingThreads, 0,
"number of DDL recording threads (0=num_cores)");
71static DEFINE_int(ddlTilingWidthHeight, 0,
"number of tiles along one edge when in DDL mode");
73static DEFINE_bool(comparableDDL,
false,
"render in a way that is comparable to 'comparableSKP'");
74static DEFINE_bool(comparableSKP,
false,
"report in a way that is comparable to 'comparableDDL'");
77static DEFINE_int(sampleMs, 50,
"minimum duration of a sample");
78static DEFINE_bool(gpuClock,
false,
"time on the gpu clock (gpu work only)");
81 "path to a single .skp or .svg file, or 'warmup' for a builtin warmup run");
82static DEFINE_string(png,
"",
"if set, save a .png proof to disk at this file location");
83static DEFINE_int(verbosity, 4,
"level of verbosity (0=none to 5=debug)");
84static DEFINE_bool(suppressHeader,
false,
"don't print a header row before the results");
85static DEFINE_double(
scale, 1,
"Scale the size of the canvas and the zoom level by this factor.");
86static DEFINE_bool(dumpSamples,
false,
"print the individual samples to stdout");
89" accum median max min stddev samples sample_ms clock metric config bench";
92"%8.4g %8.4g %8.4g %8.4g %6.3g%% %7zu %9i %-5s %-6s %-9s %s";
101 double ms()
const {
return std::chrono::duration<double, std::milli>(
fDuration).count(); }
103 static const char*
metric() {
return FLAGS_fps ?
"fps" :
"ms"; }
119 enum { kMaxFrameLag = 3 };
121 int fCurrentFlushIdx = 0;
171 MultiFrameSkp(
const std::vector<SkDocumentPage>& frames) : fFrames(frames){}
176 if (!
stream) {
return nullptr; }
179 auto deserialContext = std::make_unique<SkSharingDeserialContext>();
190 std::vector<SkDocumentPage> frames(
page_count);
195 return std::make_unique<MultiFrameSkp>(frames);
202 for (
int i=0;
i<this->
count();
i++){
205 return this->
count();
210 int count()
const {
return fFrames.size(); }
212 std::vector<SkDocumentPage> fFrames;
217 std::chrono::high_resolution_clock::time_point* startStopTime,
219 using clock = std::chrono::high_resolution_clock;
221 clock::time_point
start = *startStopTime;
223 if (FLAGS_comparableDDL) {
231 }
else if (FLAGS_comparableSKP) {
236 tiles->kickOffThreadedWork(recordingTaskGroup, gpuTaskGroup, dContext,
picture);
237 recordingTaskGroup->
wait();
241 gpuTaskGroup->
add([&]{
244 gpuTaskGroup->
wait();
249 *startStopTime = clock::now();
261 std::vector<Sample>* samples) {
262 using clock = std::chrono::high_resolution_clock;
263 const Sample::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
264 const clock::duration benchDuration = std::chrono::milliseconds(FLAGS_duration);
281 FLAGS_ddlTilingWidthHeight, FLAGS_ddlTilingWidthHeight,
284 tiles.createBackendTextures(
nullptr, dContext);
288 std::unique_ptr<SkExecutor> gpuThread;
289 std::unique_ptr<SkTaskGroup> gpuTaskGroup;
290 std::unique_ptr<SkExecutor> recordingThreadPool;
291 std::unique_ptr<SkTaskGroup> recordingTaskGroup;
292 if (!FLAGS_comparableDDL && !FLAGS_comparableSKP) {
294 gpuTaskGroup = std::make_unique<SkTaskGroup>(*gpuThread);
296 recordingTaskGroup = std::make_unique<SkTaskGroup>(*recordingThreadPool);
298 gpuTaskGroup->add([=]{ testContext->
makeCurrent(); });
301 clock::time_point startStopTime = clock::now();
304 ddl_sample(dContext, &
tiles, gpuSync,
nullptr, recordingTaskGroup.get(),
305 gpuTaskGroup.get(), &startStopTime, newSKP.
get());
310 samples->emplace_back();
311 Sample& sample = samples->back();
314 tiles.resetAllTiles();
315 ddl_sample(dContext, &
tiles, gpuSync, &sample, recordingTaskGroup.get(),
316 gpuTaskGroup.get(), &startStopTime, newSKP.
get());
317 }
while (sample.
fDuration < sampleDuration);
320 }
while (cumulativeDuration < benchDuration || 0 == samples->
size() % 2);
324 gpuTaskGroup->add([=]{
327 gpuTaskGroup->wait();
331 if (!FLAGS_png.isEmpty()) {
337 tiles.resetAllTiles();
346 tiles.deleteBackendTextures(
nullptr, dContext);
352 std::vector<Sample>* samples) {
353 using clock = std::chrono::high_resolution_clock;
354 const Sample::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
355 const clock::duration benchDuration = std::chrono::milliseconds(FLAGS_duration);
363 clock::time_point now = clock::now();
364 const clock::time_point endTime = now + benchDuration;
367 clock::time_point sampleStart = now;
368 samples->emplace_back();
369 Sample& sample = samples->back();
375 }
while (sample.
fDuration < sampleDuration);
376 }
while (now < endTime || 0 == samples->
size() % 2);
388 std::vector<Sample>* samples) {
390 using clock = std::chrono::steady_clock;
391 const clock::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
392 const clock::duration benchDuration = std::chrono::milliseconds(FLAGS_duration);
395 fprintf(stderr,
"WARNING: GPU timer cannot detect disjoint operations; "
396 "results may be unreliable\n");
409 clock::time_point now = clock::now();
410 const clock::time_point endTime = now + benchDuration;
413 const clock::time_point sampleEndTime = now + sampleDuration;
414 samples->emplace_back();
415 Sample& sample = samples->back();
427 case QueryStatus::kPending:
430 case QueryStatus::kDisjoint:
431 if (FLAGS_verbosity >= 4) {
432 fprintf(stderr,
"discarding timer query due to disjoint operations.\n");
435 case QueryStatus::kAccurate:
443 }
while (now < sampleEndTime || 0 == sample.
fFrames);
444 }
while (now < endTime || 0 == samples->
size() % 2);
455 if (0 == (samples.size() % 2)) {
459 if (FLAGS_dumpSamples) {
461 for (
const Sample& sample : samples) {
462 printf(
"%" PRId64
" ",
static_cast<int64_t
>(sample.fDuration.count()));
468 std::vector<double>
values;
469 values.reserve(samples.size());
470 for (
const Sample& sample : samples) {
471 accum.
fFrames += sample.fFrames;
473 values.push_back(sample.value());
477 const double accumValue = accum.
value();
483 variance /=
values.size();
485 const double stddev = 100 *
sqrt(variance) / accumValue;
496 "Use skpbench.py instead. "
497 "You usually don't want to use this program directly.");
500 if (!FLAGS_suppressHeader) {
503 if (FLAGS_duration <= 0) {
511 if (
configs.size() != 1 || !(config =
configs[0]->asConfigGpu())) {
513 join(FLAGS_config).c_str());
517 if (FLAGS_src.size() != 1) {
519 "invalid input '%s': must specify a single .skp or .svg file, or 'warmup'",
520 join(FLAGS_src).c_str());
526 std::unique_ptr<MultiFrameSkp> mskp;
528 if (0 == strcmp(FLAGS_src[0],
"warmup")) {
539 }
else if (srcfile.
endsWith(
".mskp")) {
542 skp = mskp->frame(0);
553 if (FLAGS_verbosity >= 3 &&
555 fprintf(stderr,
"%s is too large (%ix%i), cropping to %ix%i.\n",
559 if (FLAGS_scale != 1) {
560 width *= FLAGS_scale;
562 if (FLAGS_verbosity >= 3) {
563 fprintf(stderr,
"Scale factor of %.2f: scaling to %ix%i.\n",
593 int supportedSampleCount = ctx->priv().caps()->getRenderTargetSampleCount(
595 if (supportedSampleCount != config->
getSamples()) {
619 std::vector<Sample> samples;
620 if (FLAGS_sampleMs > 0) {
622 samples.reserve(1 + (FLAGS_duration + FLAGS_sampleMs - 1) / FLAGS_sampleMs);
624 samples.reserve(2 * FLAGS_duration);
628 if (FLAGS_scale != 1) {
629 canvas->
scale(FLAGS_scale, FLAGS_scale);
631 if (!FLAGS_gpuClock) {
635 auto s = std::make_unique<StaticSkp>(
skp);
652 if (!FLAGS_png.isEmpty()) {
655 if (!
surface->getCanvas()->readPixels(bmp, 0, 0)) {
676 context->
flush(flushInfo);
682 auto canvas =
surface->getCanvas();
683 canvas->drawPicture(
skp);
712#if defined(SK_ENABLE_SVG)
726 svg->render(recording);
743 for (
int i = 0;
i < stringArray.
size(); ++
i) {
744 joined.
appendf(
i ?
" %s" :
"%s", stringArray[
i]);
762 if (fFinishTrackers[fCurrentFlushIdx]) {
775 fCurrentFlushIdx = (fCurrentFlushIdx + 1) %
std::size(fFinishTrackers);
void ParseConfigs(const CommandLineFlags::StringArray &configs, SkCommandLineConfigArray *outResult)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define SK_PRINTF_LIKE(A, B)
constexpr SkColor SK_ColorWHITE
bool sk_mkdir(const char *path)
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
static void bench(NanoJSONResultsWriter *log, const char *name, int bytes)
#define SkScalarCeilToInt(x)
static void Parse(int argc, const char *const *argv)
static void SetUsage(const char *usage)
sk_sp< SkPicture > recreateSKP(GrDirectContext *, SkPicture *)
void deleteAllFromGPU(SkTaskGroup *, GrDirectContext *)
void uploadAllToGPU(SkTaskGroup *, GrDirectContext *)
sk_gpu_test::FlushFinishTracker * newFlushTracker(GrDirectContext *context)
bool submit(GrSyncCpu sync=GrSyncCpu::kNo)
void flushAndSubmit(GrSyncCpu sync=GrSyncCpu::kNo)
GrSemaphoresSubmitted flush(const GrFlushInfo &info)
int drawAndFlushAndSync(GrDirectContext *context, SkSurface *surface, GpuSync &gpuSync) override
MultiFrameSkp(const std::vector< SkDocumentPage > &frames)
static std::unique_ptr< MultiFrameSkp > MakeFromFile(const SkString &path)
sk_sp< SkPicture > frame(int n) const
void allocPixels(const SkImageInfo &info, size_t rowBytes)
void drawRect(const SkRect &rect, const SkPaint &paint)
void translate(SkScalar dx, SkScalar dy)
virtual SkISize getBaseLayerSize() const
void clear(SkColor color)
void drawPath(const SkPath &path, const SkPaint &paint)
void scale(SkScalar sx, SkScalar sy)
SurfType getSurfType() const
ContextType getContextType() const
ContextOverrides getContextOverrides() const
SkColorType getColorType() const
SkAlphaType getAlphaType() const
uint32_t getSurfaceFlags() const
sk_sp< SkColorSpace > refColorSpace() const
const SkString & getTag() const
static std::unique_ptr< SkExecutor > MakeFIFOThreadPool(int threads=0, bool allowBorrowing=true)
static SkString Basename(const char *fullPath)
static SkString Dirname(const char *fullPath)
@ kStroke_Style
set to stroke geometry
void setShader(sk_sp< SkShader > shader)
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
static sk_sp< SkPicture > MakeFromStream(SkStream *stream, const SkDeserialProcs *procs=nullptr)
static std::unique_ptr< SkStreamAsset > MakeFromFile(const char path[])
bool endsWith(const char suffixStr[]) const
const char * c_str() const
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
bool characterize(GrSurfaceCharacterization *characterization) const
virtual SkImageInfo imageInfo() const
void add(std::function< void(void)> fn)
virtual int drawAndFlushAndSync(GrDirectContext *, SkSurface *surface, GpuSync &gpuSync)=0
StaticSkp(sk_sp< SkPicture > skp)
int drawAndFlushAndSync(GrDirectContext *context, SkSurface *surface, GpuSync &gpuSync) override
GrDirectContext * directContext() const
TestContext * testContext() const
static void FlushFinished(void *finishedContext)
void waitTillFinished(std::function< void()> tick={})
virtual std::chrono::nanoseconds getTimeElapsed(PlatformTimerQuery)=0
PlatformTimerQuery queueStop()
virtual QueryStatus checkQueryStatus(PlatformTimerQuery)=0
bool disjointSupport() const
virtual void deleteQuery(PlatformTimerQuery)=0
ContextInfo getContextInfo(ContextType type, ContextOverrides=ContextOverrides::kNone)
bool gpuTimingSupport() const
GpuTimer * gpuTimer() const
void makeNotCurrent() const
bool fenceSyncSupport() const
void reset(T *ptr=nullptr)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
static float max(float r, float g, float b)
static float min(float r, float g, float b)
void SetCtxOptions(struct GrContextOptions *)
SK_API bool Read(SkStreamSeekable *src, SkDocumentPage *dstArray, int dstArrayCount, const SkDeserialProcs *=nullptr)
SK_API int ReadPageCount(SkStreamSeekable *src)
Optional< SkRect > bounds
sk_sp< const SkPicture > picture
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
SK_API sk_sp< SkShader > MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize *tileSize=nullptr)
sk_sp< Factory > BestAvailable()
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
DlVertices::Builder Builder
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
DEF_SWITCHES_START aot vmservice shared library name
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
const myers::Point & get(const myers::Segment &)
uint64_t PlatformTimerQuery
SK_API bool DrawDDL(SkSurface *, sk_sp< const GrDeferredDisplayList > ddl)
SkYUVAPixmapInfo::SupportedDataTypes SupportedTextureFormats(const GrImageContext &context)
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
static double time(int loops, Benchmark *bench, Target *target)
constexpr struct @263 tiles[]
static const char header[]
static DEFINE_bool(ddl, false, "record the skp into DDLs before rendering")
static DEFINE_string(src, "", "path to a single .skp or .svg file, or 'warmup' for a builtin warmup run")
int main(int argc, char **argv)
static bool mkdir_p(const SkString &name)
static SkString join(const CommandLineFlags::StringArray &)
static void exitf(ExitErr, const char *format,...)
static void flush_with_sync(GrDirectContext *, GpuSync &)
static void draw_skp_and_flush_with_sync(GrDirectContext *, SkSurface *, const SkPicture *, GpuSync &)
static void ddl_sample(GrDirectContext *dContext, DDLTileHelper *tiles, GpuSync &gpuSync, Sample *sample, SkTaskGroup *recordingTaskGroup, SkTaskGroup *gpuTaskGroup, std::chrono::high_resolution_clock::time_point *startStopTime, SkPicture *picture)
static DEFINE_double(scale, 1, "Scale the size of the canvas and the zoom level by this factor.")
static void run_benchmark(GrDirectContext *context, sk_sp< SkSurface > surface, SkpProducer *skpp, std::vector< Sample > *samples)
void print_result(const std::vector< Sample > &samples, const char *config, const char *bench)
static void run_gpu_time_benchmark(sk_gpu_test::GpuTimer *gpuTimer, GrDirectContext *context, sk_sp< SkSurface > surface, const SkPicture *skp, std::vector< Sample > *samples)
static void run_ddl_benchmark(sk_gpu_test::TestContext *testContext, GrDirectContext *dContext, sk_sp< SkSurface > dstSurface, SkPicture *inputPicture, std::vector< Sample > *samples)
static DEFINE_int(ddlNumRecordingThreads, 0, "number of DDL recording threads (0=num_cores)")
static sk_sp< SkPicture > create_skp_from_svg(SkStream *, const char *filename)
static constexpr int kNumFlushesToPrimeCache
static sk_sp< SkPicture > create_warmup_skp()
static const char resultFormat[]
GrGpuFinishedContext fFinishedContext
GrGpuFinishedProc fFinishedProc
static const char * metric()
std::chrono::nanoseconds duration
SkDeserialImageProc fImageProc
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static sk_sp< SkImage > deserializeImage(const void *data, size_t length, void *ctx)
static constexpr SkSize Make(SkScalar w, SkScalar h)