| Index: bench/nanobench.cpp
|
| diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
|
| index 920979cbf9e66c865f2aa21922344ebaccc4e262..a1d5d1de129afcbb1f9aae0aa413fff80a29a31b 100644
|
| --- a/bench/nanobench.cpp
|
| +++ b/bench/nanobench.cpp
|
| @@ -7,6 +7,8 @@
|
|
|
| #include <ctype.h>
|
|
|
| +#include "nanobench.h"
|
| +
|
| #include "Benchmark.h"
|
| #include "CrashHandler.h"
|
| #include "DecodingBench.h"
|
| @@ -32,6 +34,10 @@
|
| #include "SkSurface.h"
|
| #include "SkTaskGroup.h"
|
|
|
| +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
|
| + #include "nanobenchAndroid.h"
|
| +#endif
|
| +
|
| #if SK_SUPPORT_GPU
|
| #include "gl/GrGLDefines.h"
|
| #include "GrContextFactory.h"
|
| @@ -86,24 +92,100 @@ static SkString humanize(double ms) {
|
| }
|
| #define HUMANIZE(ms) humanize(ms).c_str()
|
|
|
| -static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContext* gl) {
|
| +bool Target::init(SkImageInfo info, Benchmark* bench) {
|
| + if (Benchmark::kRaster_Backend == config.backend) {
|
| + this->surface.reset(SkSurface::NewRaster(info));
|
| + if (!this->surface.get()) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +bool Target::capturePixels(SkBitmap* bmp) {
|
| + if (!this->surface.get()) {
|
| + return false;
|
| + }
|
| + SkCanvas* canvas = this->surface->getCanvas();
|
| + if (!canvas) {
|
| + return false;
|
| + }
|
| + bmp->setInfo(canvas->imageInfo());
|
| + if (!canvas->readPixels(bmp, 0, 0)) {
|
| + SkDebugf("Can't read canvas pixels.\n");
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +#if SK_SUPPORT_GPU
|
| +struct GPUTarget : public Target {
|
| + explicit GPUTarget(const Config& c) : Target(c), gl(NULL) { }
|
| + SkGLContext* gl;
|
| +
|
| + void setup() override {
|
| + this->gl->makeCurrent();
|
| + // Make sure we're done with whatever came before.
|
| + SK_GL(*this->gl, Finish());
|
| + }
|
| + void endTiming() override {
|
| + if (this->gl) {
|
| + SK_GL(*this->gl, Flush());
|
| + this->gl->swapBuffers();
|
| + }
|
| + }
|
| + void fence() override {
|
| + SK_GL(*this->gl, Finish());
|
| + }
|
| +
|
| + bool needsFrameTiming() const override { return true; }
|
| + bool init(SkImageInfo info, Benchmark* bench) override {
|
| + uint32_t flags = this->config.useDFText ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
|
| + SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
|
| + this->surface.reset(SkSurface::NewRenderTarget(gGrFactory->get(this->config.ctxType),
|
| + SkSurface::kNo_Budgeted, info,
|
| + this->config.samples, &props));
|
| + this->gl = gGrFactory->getGLContext(this->config.ctxType);
|
| + if (!this->surface.get()) {
|
| + return false;
|
| + }
|
| + return true;
|
| + }
|
| + void fillOptions(ResultsWriter* log) override {
|
| + const GrGLubyte* version;
|
| + SK_GL_RET(*this->gl, version, GetString(GR_GL_VERSION));
|
| + log->configOption("GL_VERSION", (const char*)(version));
|
| +
|
| + SK_GL_RET(*this->gl, version, GetString(GR_GL_RENDERER));
|
| + log->configOption("GL_RENDERER", (const char*) version);
|
| +
|
| + SK_GL_RET(*this->gl, version, GetString(GR_GL_VENDOR));
|
| + log->configOption("GL_VENDOR", (const char*) version);
|
| +
|
| + SK_GL_RET(*this->gl, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
|
| + log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
|
| + }
|
| +};
|
| +
|
| +#endif
|
| +
|
| +static double time(int loops, Benchmark* bench, SkCanvas* canvas, Target* target) {
|
| if (canvas) {
|
| canvas->clear(SK_ColorWHITE);
|
| }
|
| WallTimer timer;
|
| timer.start();
|
| + if (target) {
|
| + canvas = target->beginTiming(canvas);
|
| + }
|
| if (bench) {
|
| bench->draw(loops, canvas);
|
| }
|
| if (canvas) {
|
| canvas->flush();
|
| }
|
| -#if SK_SUPPORT_GPU
|
| - if (gl) {
|
| - SK_GL(*gl, Flush());
|
| - gl->swapBuffers();
|
| + if (target) {
|
| + target->endTiming();
|
| }
|
| -#endif
|
| timer.end();
|
| return timer.fWall;
|
| }
|
| @@ -137,19 +219,22 @@ static int clamp_loops(int loops) {
|
| return loops;
|
| }
|
|
|
| -static bool write_canvas_png(SkCanvas* canvas, const SkString& filename) {
|
| +static bool write_canvas_png(Target* target, const SkString& filename) {
|
| +
|
| if (filename.isEmpty()) {
|
| return false;
|
| }
|
| - if (kUnknown_SkColorType == canvas->imageInfo().colorType()) {
|
| + if (target->surface.get() && target->surface->getCanvas() &&
|
| + kUnknown_SkColorType == target->surface->getCanvas()->imageInfo().colorType()) {
|
| return false;
|
| }
|
| +
|
| SkBitmap bmp;
|
| - bmp.setInfo(canvas->imageInfo());
|
| - if (!canvas->readPixels(&bmp, 0, 0)) {
|
| - SkDebugf("Can't read canvas pixels.\n");
|
| +
|
| + if (!target->capturePixels(&bmp)) {
|
| return false;
|
| }
|
| +
|
| SkString dir = SkOSPath::Dirname(filename.c_str());
|
| if (!sk_mkdir(dir.c_str())) {
|
| SkDebugf("Can't make dir %s.\n", dir.c_str());
|
| @@ -215,14 +300,7 @@ static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas,
|
| return loops;
|
| }
|
|
|
| -#if SK_SUPPORT_GPU
|
| -static void setup_gl(SkGLContext* gl) {
|
| - gl->makeCurrent();
|
| - // Make sure we're done with whatever came before.
|
| - SK_GL(*gl, Finish());
|
| -}
|
| -
|
| -static int gpu_bench(SkGLContext* gl,
|
| +static int gpu_bench(Target* target,
|
| Benchmark* bench,
|
| SkCanvas* canvas,
|
| double* samples) {
|
| @@ -242,7 +320,7 @@ static int gpu_bench(SkGLContext* gl,
|
| // _this_ round, not still timing last round. We force this by looping
|
| // more times than any reasonable GPU will allow frames to lag.
|
| for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
|
| - elapsed = time(loops, bench, canvas, gl);
|
| + elapsed = time(loops, bench, canvas, target);
|
| }
|
| } while (elapsed < FLAGS_gpuMs);
|
|
|
| @@ -250,8 +328,8 @@ static int gpu_bench(SkGLContext* gl,
|
| loops = (int)ceil(loops * FLAGS_gpuMs / elapsed);
|
| loops = clamp_loops(loops);
|
|
|
| - // Might as well make sure we're not still timing our calibration.
|
| - SK_GL(*gl, Finish());
|
| + // Make sure we're not still timing our calibration.
|
| + target->fence();
|
| } else {
|
| loops = detect_forever_loops(loops);
|
| }
|
| @@ -259,16 +337,16 @@ static int gpu_bench(SkGLContext* gl,
|
| // Pretty much the same deal as the calibration: do some warmup to make
|
| // sure we're timing steady-state pipelined frames.
|
| for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
|
| - time(loops, bench, canvas, gl);
|
| + time(loops, bench, canvas, target);
|
| }
|
|
|
| // Now, actually do the timing!
|
| for (int i = 0; i < FLAGS_samples; i++) {
|
| - samples[i] = time(loops, bench, canvas, gl) / loops;
|
| + samples[i] = time(loops, bench, canvas, target) / loops;
|
| }
|
| +
|
| return loops;
|
| }
|
| -#endif
|
|
|
| static SkString to_lower(const char* str) {
|
| SkString lower(str);
|
| @@ -278,30 +356,6 @@ static SkString to_lower(const char* str) {
|
| return lower;
|
| }
|
|
|
| -struct Config {
|
| - const char* name;
|
| - Benchmark::Backend backend;
|
| - SkColorType color;
|
| - SkAlphaType alpha;
|
| - int samples;
|
| -#if SK_SUPPORT_GPU
|
| - GrContextFactory::GLContextType ctxType;
|
| - bool useDFText;
|
| -#else
|
| - int bogusInt;
|
| - bool bogusBool;
|
| -#endif
|
| -};
|
| -
|
| -struct Target {
|
| - explicit Target(const Config& c) : config(c) {}
|
| - const Config config;
|
| - SkAutoTDelete<SkSurface> surface;
|
| -#if SK_SUPPORT_GPU
|
| - SkGLContext* gl;
|
| -#endif
|
| -};
|
| -
|
| static bool is_cpu_config_allowed(const char* name) {
|
| for (int i = 0; i < FLAGS_config.count(); i++) {
|
| if (to_lower(FLAGS_config[i]).equals(name)) {
|
| @@ -373,6 +427,14 @@ static void create_configs(SkTDArray<Config>* configs) {
|
| #endif
|
| }
|
| #endif
|
| +
|
| +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
|
| + if (is_cpu_config_allowed("hwui")) {
|
| + Config config = { "hwui", Benchmark::kHWUI_Backend, kRGBA_8888_SkColorType,
|
| + kPremul_SkAlphaType, 0, kBogusGLContextType, false };
|
| + configs->push(config);
|
| + }
|
| +#endif
|
| }
|
|
|
| // If bench is enabled for config, returns a Target* for it, otherwise NULL.
|
| @@ -384,23 +446,25 @@ static Target* is_enabled(Benchmark* bench, const Config& config) {
|
| SkImageInfo info = SkImageInfo::Make(bench->getSize().fX, bench->getSize().fY,
|
| config.color, config.alpha);
|
|
|
| - Target* target = new Target(config);
|
| + Target* target = NULL;
|
|
|
| - if (Benchmark::kRaster_Backend == config.backend) {
|
| - target->surface.reset(SkSurface::NewRaster(info));
|
| - }
|
| + switch (config.backend) {
|
| #if SK_SUPPORT_GPU
|
| - else if (Benchmark::kGPU_Backend == config.backend) {
|
| - uint32_t flags = config.useDFText ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
|
| - SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
|
| - target->surface.reset(SkSurface::NewRenderTarget(gGrFactory->get(config.ctxType),
|
| - SkSurface::kNo_Budgeted, info,
|
| - config.samples, &props));
|
| - target->gl = gGrFactory->getGLContext(config.ctxType);
|
| - }
|
| + case Benchmark::kGPU_Backend:
|
| + target = new GPUTarget(config);
|
| + break;
|
| +#endif
|
| +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
|
| + case Benchmark::kHWUI_Backend:
|
| + target = new HWUITarget(config, bench);
|
| + break;
|
| #endif
|
| + default:
|
| + target = new Target(config);
|
| + break;
|
| + }
|
|
|
| - if (Benchmark::kNonRendering_Backend != config.backend && !target->surface.get()) {
|
| + if (!target->init(info, bench)) {
|
| delete target;
|
| return NULL;
|
| }
|
| @@ -418,22 +482,6 @@ static void create_targets(SkTDArray<Target*>* targets, Benchmark* b,
|
| }
|
| }
|
|
|
| -#if SK_SUPPORT_GPU
|
| -static void fill_gpu_options(ResultsWriter* log, SkGLContext* ctx) {
|
| - const GrGLubyte* version;
|
| - SK_GL_RET(*ctx, version, GetString(GR_GL_VERSION));
|
| - log->configOption("GL_VERSION", (const char*)(version));
|
| -
|
| - SK_GL_RET(*ctx, version, GetString(GR_GL_RENDERER));
|
| - log->configOption("GL_RENDERER", (const char*) version);
|
| -
|
| - SK_GL_RET(*ctx, version, GetString(GR_GL_VENDOR));
|
| - log->configOption("GL_VENDOR", (const char*) version);
|
| -
|
| - SK_GL_RET(*ctx, version, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
|
| - log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
|
| -}
|
| -#endif
|
|
|
| class BenchmarkStream {
|
| public:
|
| @@ -790,32 +838,26 @@ int nanobench_main() {
|
| bench->preDraw();
|
| }
|
| for (int j = 0; j < targets.count(); j++) {
|
| + // During HWUI output this canvas may be NULL.
|
| SkCanvas* canvas = targets[j]->surface.get() ? targets[j]->surface->getCanvas() : NULL;
|
| const char* config = targets[j]->config.name;
|
|
|
| -#if SK_SUPPORT_GPU
|
| - if (Benchmark::kGPU_Backend == targets[j]->config.backend) {
|
| - setup_gl(targets[j]->gl);
|
| - }
|
| -#endif
|
| -
|
| + targets[j]->setup();
|
| bench->perCanvasPreDraw(canvas);
|
|
|
| const int loops =
|
| -#if SK_SUPPORT_GPU
|
| - Benchmark::kGPU_Backend == targets[j]->config.backend
|
| - ? gpu_bench(targets[j]->gl, bench.get(), canvas, samples.get())
|
| - :
|
| -#endif
|
| - cpu_bench( overhead, bench.get(), canvas, samples.get());
|
| + targets[j]->needsFrameTiming()
|
| + ? gpu_bench(targets[j], bench.get(), canvas, samples.get())
|
| + : cpu_bench(overhead, bench.get(), canvas, samples.get());
|
|
|
| bench->perCanvasPostDraw(canvas);
|
|
|
| - if (canvas && !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
|
| + if (Benchmark::kNonRendering_Backend != targets[j]->config.backend &&
|
| + !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
|
| SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config);
|
| pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName());
|
| pngFilename.append(".png");
|
| - write_canvas_png(canvas, pngFilename);
|
| + write_canvas_png(targets[j], pngFilename);
|
| }
|
|
|
| if (kFailedLoops == loops) {
|
| @@ -827,11 +869,7 @@ int nanobench_main() {
|
| log->config(config);
|
| log->configOption("name", bench->getName());
|
| benchStream.fillCurrentOptions(log.get());
|
| -#if SK_SUPPORT_GPU
|
| - if (Benchmark::kGPU_Backend == targets[j]->config.backend) {
|
| - fill_gpu_options(log.get(), targets[j]->gl);
|
| - }
|
| -#endif
|
| + targets[j]->fillOptions(log.get());
|
| log->metric("min_ms", stats.min);
|
| if (runs++ % FLAGS_flushEvery == 0) {
|
| log->flush();
|
|
|