diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/skia/bench | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/skia/bench')
108 files changed, 17849 insertions, 0 deletions
diff --git a/chromium/third_party/skia/bench/AAClipBench.cpp b/chromium/third_party/skia/bench/AAClipBench.cpp new file mode 100644 index 00000000000..4cc9abe9fc9 --- /dev/null +++ b/chromium/third_party/skia/bench/AAClipBench.cpp @@ -0,0 +1,257 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkAAClip.h" +#include "SkCanvas.h" +#include "SkPath.h" +#include "SkRandom.h" +#include "SkRegion.h" +#include "SkString.h" + +//////////////////////////////////////////////////////////////////////////////// +// This bench tests out AA/BW clipping via canvas' clipPath and clipRect calls +class AAClipBench : public Benchmark { + SkString fName; + SkPath fClipPath; + SkRect fClipRect; + SkRect fDrawRect; + bool fDoPath; + bool fDoAA; + +public: + AAClipBench(bool doPath, bool doAA) + : fDoPath(doPath) + , fDoAA(doAA) { + + fName.printf("aaclip_%s_%s", + doPath ? "path" : "rect", + doAA ? "AA" : "BW"); + + fClipRect.set(10.5f, 10.5f, + 50.5f, 50.5f); + fClipPath.addRoundRect(fClipRect, SkIntToScalar(10), SkIntToScalar(10)); + fDrawRect.set(SkIntToScalar(0), SkIntToScalar(0), + SkIntToScalar(100), SkIntToScalar(100)); + + SkASSERT(fClipPath.isConvex()); + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + virtual void onDraw(const int loops, SkCanvas* canvas) { + + SkPaint paint; + this->setupPaint(&paint); + + for (int i = 0; i < loops; ++i) { + // jostle the clip regions each time to prevent caching + fClipRect.offset((i % 2) == 0 ? SkIntToScalar(10) : SkIntToScalar(-10), 0); + fClipPath.reset(); + fClipPath.addRoundRect(fClipRect, + SkIntToScalar(5), SkIntToScalar(5)); + SkASSERT(fClipPath.isConvex()); + + canvas->save(); +#if 1 + if (fDoPath) { + canvas->clipPath(fClipPath, SkRegion::kReplace_Op, fDoAA); + } else { + canvas->clipRect(fClipRect, SkRegion::kReplace_Op, fDoAA); + } + + canvas->drawRect(fDrawRect, paint); +#else + // this path tests out directly draw the clip primitive + // use it to comparing just drawing the clip vs. drawing using + // the clip + if (fDoPath) { + canvas->drawPath(fClipPath, paint); + } else { + canvas->drawRect(fClipRect, paint); + } +#endif + canvas->restore(); + } + } +private: + typedef Benchmark INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// +// This bench tests out nested clip stacks. It is intended to simulate +// how WebKit nests clips. +class NestedAAClipBench : public Benchmark { + SkString fName; + bool fDoAA; + SkRect fDrawRect; + SkRandom fRandom; + + static const int kNestingDepth = 3; + static const int kImageSize = 400; + + SkPoint fSizes[kNestingDepth+1]; + +public: + NestedAAClipBench(bool doAA) : fDoAA(doAA) { + fName.printf("nested_aaclip_%s", doAA ? "AA" : "BW"); + + fDrawRect = SkRect::MakeLTRB(0, 0, + SkIntToScalar(kImageSize), + SkIntToScalar(kImageSize)); + + fSizes[0].set(SkIntToScalar(kImageSize), SkIntToScalar(kImageSize)); + + for (int i = 1; i < kNestingDepth+1; ++i) { + fSizes[i].set(fSizes[i-1].fX/2, fSizes[i-1].fY/2); + } + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + + + void recurse(SkCanvas* canvas, + int depth, + const SkPoint& offset) { + + canvas->save(); + + SkRect temp = SkRect::MakeLTRB(0, 0, + fSizes[depth].fX, fSizes[depth].fY); + temp.offset(offset); + + SkPath path; + path.addRoundRect(temp, SkIntToScalar(3), SkIntToScalar(3)); + SkASSERT(path.isConvex()); + + canvas->clipPath(path, + 0 == depth ? SkRegion::kReplace_Op : + SkRegion::kIntersect_Op, + fDoAA); + + if (kNestingDepth == depth) { + // we only draw the draw rect at the lowest nesting level + SkPaint paint; + paint.setColor(0xff000000 | fRandom.nextU()); + canvas->drawRect(fDrawRect, paint); + } else { + SkPoint childOffset = offset; + this->recurse(canvas, depth+1, childOffset); + + childOffset += fSizes[depth+1]; + this->recurse(canvas, depth+1, childOffset); + + childOffset.fX = offset.fX + fSizes[depth+1].fX; + childOffset.fY = offset.fY; + this->recurse(canvas, depth+1, childOffset); + + childOffset.fX = offset.fX; + childOffset.fY = offset.fY + fSizes[depth+1].fY; + this->recurse(canvas, depth+1, childOffset); + } + + canvas->restore(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + + for (int i = 0; i < loops; ++i) { + SkPoint offset = SkPoint::Make(0, 0); + this->recurse(canvas, 0, offset); + } + } + +private: + typedef Benchmark INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// +class AAClipBuilderBench : public Benchmark { + SkString fName; + SkPath fPath; + SkRect fRect; + SkRegion fRegion; + bool fDoPath; + bool fDoAA; + +public: + AAClipBuilderBench(bool doPath, bool doAA) { + fDoPath = doPath; + fDoAA = doAA; + + fName.printf("aaclip_build_%s_%s", doPath ? "path" : "rect", + doAA ? "AA" : "BW"); + + fRegion.setRect(0, 0, 640, 480); + fRect.set(fRegion.getBounds()); + fRect.inset(SK_Scalar1/4, SK_Scalar1/4); + fPath.addRoundRect(fRect, SkIntToScalar(20), SkIntToScalar(20)); + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + virtual void onDraw(const int loops, SkCanvas*) { + SkPaint paint; + this->setupPaint(&paint); + + for (int i = 0; i < loops; ++i) { + SkAAClip clip; + if (fDoPath) { + clip.setPath(fPath, &fRegion, fDoAA); + } else { + clip.setRect(fRect, fDoAA); + } + } + } +private: + typedef Benchmark INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// +class AAClipRegionBench : public Benchmark { +public: + AAClipRegionBench() { + SkPath path; + // test conversion of a complex clip to a aaclip + path.addCircle(0, 0, SkIntToScalar(200)); + path.addCircle(0, 0, SkIntToScalar(180)); + // evenodd means we've constructed basically a stroked circle + path.setFillType(SkPath::kEvenOdd_FillType); + + SkIRect bounds; + path.getBounds().roundOut(&bounds); + fRegion.setPath(path, SkRegion(bounds)); + } + +protected: + virtual const char* onGetName() { return "aaclip_setregion"; } + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; ++i) { + SkAAClip clip; + clip.setRegion(fRegion); + } + } + +private: + SkRegion fRegion; + typedef Benchmark INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return SkNEW_ARGS(AAClipBuilderBench, (false, false)); ) +DEF_BENCH( return SkNEW_ARGS(AAClipBuilderBench, (false, true)); ) +DEF_BENCH( return SkNEW_ARGS(AAClipBuilderBench, (true, false)); ) +DEF_BENCH( return SkNEW_ARGS(AAClipBuilderBench, (true, true)); ) +DEF_BENCH( return SkNEW_ARGS(AAClipRegionBench, ()); ) +DEF_BENCH( return SkNEW_ARGS(AAClipBench, (false, false)); ) +DEF_BENCH( return SkNEW_ARGS(AAClipBench, (false, true)); ) +DEF_BENCH( return SkNEW_ARGS(AAClipBench, (true, false)); ) +DEF_BENCH( return SkNEW_ARGS(AAClipBench, (true, true)); ) +DEF_BENCH( return SkNEW_ARGS(NestedAAClipBench, (false)); ) +DEF_BENCH( return SkNEW_ARGS(NestedAAClipBench, (true)); ) diff --git a/chromium/third_party/skia/bench/BenchGpuTimer_gl.cpp b/chromium/third_party/skia/bench/BenchGpuTimer_gl.cpp new file mode 100644 index 00000000000..349fc1529de --- /dev/null +++ b/chromium/third_party/skia/bench/BenchGpuTimer_gl.cpp @@ -0,0 +1,74 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "BenchGpuTimer_gl.h" +#include "gl/SkGLContextHelper.h" +#include "gl/GrGLUtil.h" + +BenchGpuTimer::BenchGpuTimer(const SkGLContextHelper* glctx) { + fContext = glctx; + glctx->ref(); + glctx->makeCurrent(); + fStarted = false; + fSupported = GrGLGetVersion(glctx->gl()) > GR_GL_VER(3,3) || + glctx->hasExtension("GL_ARB_timer_query") || + glctx->hasExtension("GL_EXT_timer_query"); + + if (fSupported) { + SK_GL(*glctx, GenQueries(1, &fQuery)); + } +} + +BenchGpuTimer::~BenchGpuTimer() { + if (fSupported) { + fContext->makeCurrent(); + SK_GL(*fContext, DeleteQueries(1, &fQuery)); + } + fContext->unref(); +} + +void BenchGpuTimer::startGpu() { + if (fSupported) { + fContext->makeCurrent(); + fStarted = true; + SK_GL(*fContext, BeginQuery(GR_GL_TIME_ELAPSED, fQuery)); + } +} + +/** + * It is important to stop the cpu clocks first, + * as this will cpu wait for the gpu to finish. + */ +double BenchGpuTimer::endGpu() { + if (fSupported) { + fStarted = false; + fContext->makeCurrent(); + SK_GL(*fContext, EndQuery(GR_GL_TIME_ELAPSED)); + + GrGLint available = 0; + while (!available) { + SK_GL_NOERRCHECK(*fContext, GetQueryObjectiv(fQuery, + GR_GL_QUERY_RESULT_AVAILABLE, + &available)); + // If GetQueryObjectiv is erroring out we need some alternative + // means of breaking out of this loop + GrGLenum error; + SK_GL_RET_NOERRCHECK(*fContext, error, GetError()); + if (GR_GL_NO_ERROR != error) { + break; + } + } + GrGLuint64 totalGPUTimeElapsed = 0; + SK_GL(*fContext, GetQueryObjectui64v(fQuery, + GR_GL_QUERY_RESULT, + &totalGPUTimeElapsed)); + + return totalGPUTimeElapsed / 1000000.0; + } else { + return 0; + } +} diff --git a/chromium/third_party/skia/bench/BenchGpuTimer_gl.h b/chromium/third_party/skia/bench/BenchGpuTimer_gl.h new file mode 100644 index 00000000000..e472a4c5144 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchGpuTimer_gl.h @@ -0,0 +1,26 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBenchGpuTimer_DEFINED +#define SkBenchGpuTimer_DEFINED + +class SkGLContextHelper; + +class BenchGpuTimer { +public: + BenchGpuTimer(const SkGLContextHelper* glctx); + ~BenchGpuTimer(); + void startGpu(); + double endGpu(); +private: + unsigned fQuery; + int fStarted; + const SkGLContextHelper* fContext; + bool fSupported; +}; + +#endif diff --git a/chromium/third_party/skia/bench/BenchLogger.cpp b/chromium/third_party/skia/bench/BenchLogger.cpp new file mode 100644 index 00000000000..98423d01507 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchLogger.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "BenchLogger.h" + +#include "SkStream.h" + +BenchLogger::BenchLogger() +: fFileStream(NULL) {} + +BenchLogger::~BenchLogger() { + if (fFileStream) { + SkDELETE(fFileStream); + } +} + +bool BenchLogger::SetLogFile(const char *file) { + fFileStream = SkNEW_ARGS(SkFILEWStream, (file)); + return fFileStream->isValid(); +} + +void BenchLogger::fileWrite(const char msg[], size_t size) { + if (fFileStream && fFileStream->isValid()) { + fFileStream->write(msg, size); + } +} diff --git a/chromium/third_party/skia/bench/BenchLogger.h b/chromium/third_party/skia/bench/BenchLogger.h new file mode 100644 index 00000000000..a7c283ad505 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchLogger.h @@ -0,0 +1,76 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef BenchLogger_DEFINED +#define BenchLogger_DEFINED + +#include <stdio.h> +#include "SkString.h" +#include "SkTypes.h" + +class SkFILEWStream; + +/** + * Class that allows logging to a file while simultaneously logging to stdout/stderr. + */ +class BenchLogger { +public: + BenchLogger(); + + /** + * Not virtual, since this class is not intended to be subclassed. + */ + ~BenchLogger(); + + /** + * Specify a file to write progress logs to. Unless this is called with a valid file path, + * BenchLogger will only write to stdout/stderr. + */ + bool SetLogFile(const char file[]); + + /** + * Log an error to stderr, taking a C style string as input. + */ + void logError(const char msg[]) { this->nativeLogError(msg); } + + /** + * Log an error to stderr, taking an SkString as input. + */ + void logError(const SkString& str) { this->nativeLogError(str.c_str()); } + + /** + * Log the progress of the bench tool to both stdout and the log file specified by SetLogFile, + * if any, taking a C style string as input. + */ + void logProgress(const char msg[]) { + this->nativeLogProgress(msg); + this->fileWrite(msg, strlen(msg)); + } + + /** + * Log the progress of the bench tool to both stdout and the log file specified by SetLogFile, + * if any, taking an SkString as input. + */ + void logProgress(const SkString& str) { + this->nativeLogProgress(str.c_str()); + this->fileWrite(str.c_str(), str.size()); + } + +private: +#ifdef SK_BUILD_FOR_ANDROID + void nativeLogError(const char msg[]) { SkDebugf("%s", msg); } +#else + void nativeLogError(const char msg[]) { fprintf(stderr, "%s", msg); } +#endif + void nativeLogProgress(const char msg[]) { SkDebugf("%s", msg); } + + void fileWrite(const char msg[], size_t size); + + SkFILEWStream* fFileStream; +}; + +#endif // BenchLogger_DEFINED diff --git a/chromium/third_party/skia/bench/BenchSysTimer_c.cpp b/chromium/third_party/skia/bench/BenchSysTimer_c.cpp new file mode 100644 index 00000000000..f4cbd39d737 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_c.cpp @@ -0,0 +1,27 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "BenchSysTimer_c.h" + +//Time +#include <time.h> + +void BenchSysTimer::startWall() { + this->fStartWall = time(); +} +void BenchSysTimer::startCpu() { + this->fStartCpu = clock(); +} + +double BenchSysTimer::endCpu() { + clock_t end_cpu = clock(); + this->fCpu = (end_cpu - this->fStartCpu) * CLOCKS_PER_SEC / 1000.0; +} +double BenchSysTimer::endWall() { + time_t end_wall = time(); + this->fWall = difftime(end_wall, this->fstartWall) / 1000.0; +} diff --git a/chromium/third_party/skia/bench/BenchSysTimer_c.h b/chromium/third_party/skia/bench/BenchSysTimer_c.h new file mode 100644 index 00000000000..586f0b4ff09 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_c.h @@ -0,0 +1,26 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBenchSysTimer_DEFINED +#define SkBenchSysTimer_DEFINED + +//Time +#include <time.h> + +// Beware: this timer uses standard (as opposed to high precision) clocks +class BenchSysTimer { +public: + void startWall(); + void startCpu(); + double endCpu(); + double endWall(); +private: + clock_t start_cpu; + time_t fStartWall; +}; + +#endif diff --git a/chromium/third_party/skia/bench/BenchSysTimer_mach.cpp b/chromium/third_party/skia/bench/BenchSysTimer_mach.cpp new file mode 100644 index 00000000000..1f0a6b98615 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_mach.cpp @@ -0,0 +1,76 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "BenchSysTimer_mach.h" + +//Time +#include <mach/mach.h> +#include <mach/mach_time.h> + +static time_value_t macCpuTime() { + mach_port_t task = mach_task_self(); + if (task == MACH_PORT_NULL) { + time_value_t none = {0, 0}; + return none; + } + + task_thread_times_info thread_info_data; + mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT; + if (KERN_SUCCESS != task_info(task, + TASK_THREAD_TIMES_INFO, + reinterpret_cast<task_info_t>(&thread_info_data), + &thread_info_count)) + { + time_value_t none = {0, 0}; + return none; + } + + time_value_add(&thread_info_data.user_time, &thread_info_data.system_time) + return thread_info_data.user_time; +} + +static double intervalInMSec(const time_value_t start_clock + , const time_value_t end_clock) +{ + double duration_clock; + if ((end_clock.microseconds - start_clock.microseconds) < 0) { + duration_clock = (end_clock.seconds - start_clock.seconds-1)*1000; + duration_clock += (1000000 + + end_clock.microseconds + - start_clock.microseconds) / 1000.0; + } else { + duration_clock = (end_clock.seconds - start_clock.seconds)*1000; + duration_clock += (end_clock.microseconds - start_clock.microseconds) + / 1000.0; + } + return duration_clock; +} + +void BenchSysTimer::startWall() { + this->fStartWall = mach_absolute_time(); +} +void BenchSysTimer::startCpu() { + this->fStartCpu = macCpuTime(); +} + +double BenchSysTimer::endCpu() { + time_value_t end_cpu = macCpuTime(); + return intervalInMSec(this->fStartCpu, end_cpu); +} +double BenchSysTimer::endWall() { + uint64_t end_wall = mach_absolute_time(); + + uint64_t elapsed = end_wall - this->fStartWall; + mach_timebase_info_data_t sTimebaseInfo; + if (KERN_SUCCESS != mach_timebase_info(&sTimebaseInfo)) { + return 0; + } else { + uint64_t elapsedNano = elapsed * sTimebaseInfo.numer + / sTimebaseInfo.denom; + return elapsedNano / 1000000.0; + } +} diff --git a/chromium/third_party/skia/bench/BenchSysTimer_mach.h b/chromium/third_party/skia/bench/BenchSysTimer_mach.h new file mode 100644 index 00000000000..44d0e5eb49a --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_mach.h @@ -0,0 +1,26 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBenchSysTimer_DEFINED +#define SkBenchSysTimer_DEFINED + +//Time +#include <mach/mach.h> +#include <mach/mach_time.h> + +class BenchSysTimer { +public: + void startWall(); + void startCpu(); + double endCpu(); + double endWall(); +private: + time_value_t fStartCpu; + uint64_t fStartWall; +}; + +#endif diff --git a/chromium/third_party/skia/bench/BenchSysTimer_posix.cpp b/chromium/third_party/skia/bench/BenchSysTimer_posix.cpp new file mode 100644 index 00000000000..e6767e5af22 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_posix.cpp @@ -0,0 +1,57 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "BenchSysTimer_posix.h" + +//Time +#include <time.h> + +static double intervalInMSec(const timespec start_clock + , const timespec end_clock) +{ + double duration_clock; + if ((end_clock.tv_nsec - start_clock.tv_nsec) < 0) { + duration_clock = (end_clock.tv_sec - start_clock.tv_sec-1)*1000; + duration_clock += (1000000000 + end_clock.tv_nsec - start_clock.tv_nsec) + / 1000000.0; + } else { + duration_clock = (end_clock.tv_sec - start_clock.tv_sec)*1000; + duration_clock += (end_clock.tv_nsec - start_clock.tv_nsec) / 1000000.0; + } + return duration_clock; +} + +void BenchSysTimer::startWall() { + if (-1 == clock_gettime(CLOCK_MONOTONIC, &this->fWall)) { + timespec none = {0, 0}; + this->fWall = none; + } +} +void BenchSysTimer::startCpu() { + if (-1 == clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &this->fCpu)) { + timespec none = {0, 0}; + this->fCpu = none; + } +} + +double BenchSysTimer::endCpu() { + timespec end_cpu; + if (-1 == clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_cpu)) { + timespec none = {0, 0}; + end_cpu = none; + } + return intervalInMSec(this->fCpu, end_cpu); +} + +double BenchSysTimer::endWall() { + timespec end_wall; + if (-1 == clock_gettime(CLOCK_MONOTONIC, &end_wall)) { + timespec none = {0, 0}; + end_wall = none; + } + return intervalInMSec(this->fWall, end_wall); +} diff --git a/chromium/third_party/skia/bench/BenchSysTimer_posix.h b/chromium/third_party/skia/bench/BenchSysTimer_posix.h new file mode 100644 index 00000000000..8fd97061b6c --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_posix.h @@ -0,0 +1,25 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBenchSysTimer_DEFINED +#define SkBenchSysTimer_DEFINED + +//Time +#include <time.h> + +class BenchSysTimer { +public: + void startWall(); + void startCpu(); + double endCpu(); + double endWall(); +private: + timespec fCpu; + timespec fWall; +}; + +#endif diff --git a/chromium/third_party/skia/bench/BenchSysTimer_windows.cpp b/chromium/third_party/skia/bench/BenchSysTimer_windows.cpp new file mode 100644 index 00000000000..fab657a8c36 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_windows.cpp @@ -0,0 +1,64 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "BenchSysTimer_windows.h" + +//Time +#define WIN32_LEAN_AND_MEAN 1 +#include <windows.h> + +static ULONGLONG winCpuTime() { + FILETIME createTime; + FILETIME exitTime; + FILETIME usrTime; + FILETIME sysTime; + if (0 == GetProcessTimes(GetCurrentProcess() + , &createTime, &exitTime + , &sysTime, &usrTime)) + { + return 0; + } + ULARGE_INTEGER start_cpu_sys; + ULARGE_INTEGER start_cpu_usr; + start_cpu_sys.LowPart = sysTime.dwLowDateTime; + start_cpu_sys.HighPart = sysTime.dwHighDateTime; + start_cpu_usr.LowPart = usrTime.dwLowDateTime; + start_cpu_usr.HighPart = usrTime.dwHighDateTime; + return start_cpu_sys.QuadPart + start_cpu_usr.QuadPart; +} + +void BenchSysTimer::startWall() { + if (0 == ::QueryPerformanceCounter(&this->fStartWall)) { + this->fStartWall.QuadPart = 0; + } +} +void BenchSysTimer::startCpu() { + this->fStartCpu = winCpuTime(); +} + +double BenchSysTimer::endCpu() { + ULONGLONG end_cpu = winCpuTime(); + return static_cast<double>((end_cpu - this->fStartCpu)) / 10000.0L; +} +double BenchSysTimer::endWall() { + LARGE_INTEGER end_wall; + if (0 == ::QueryPerformanceCounter(&end_wall)) { + end_wall.QuadPart = 0; + } + + LARGE_INTEGER ticks_elapsed; + ticks_elapsed.QuadPart = end_wall.QuadPart - this->fStartWall.QuadPart; + + LARGE_INTEGER frequency; + if (0 == ::QueryPerformanceFrequency(&frequency)) { + return 0.0L; + } else { + return static_cast<double>(ticks_elapsed.QuadPart) + / static_cast<double>(frequency.QuadPart) + * 1000.0L; + } +} diff --git a/chromium/third_party/skia/bench/BenchSysTimer_windows.h b/chromium/third_party/skia/bench/BenchSysTimer_windows.h new file mode 100644 index 00000000000..469332e4ed0 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchSysTimer_windows.h @@ -0,0 +1,26 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBenchSysTimer_DEFINED +#define SkBenchSysTimer_DEFINED + +//Time +#define WIN32_LEAN_AND_MEAN 1 +#include <windows.h> + +class BenchSysTimer { +public: + void startWall(); + void startCpu(); + double endCpu(); + double endWall(); +private: + ULONGLONG fStartCpu; + LARGE_INTEGER fStartWall; +}; + +#endif diff --git a/chromium/third_party/skia/bench/BenchTimer.cpp b/chromium/third_party/skia/bench/BenchTimer.cpp new file mode 100644 index 00000000000..f3e8e3b0ec6 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchTimer.cpp @@ -0,0 +1,94 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "BenchTimer.h" +#if defined(SK_BUILD_FOR_WIN32) + #include "BenchSysTimer_windows.h" +#elif defined(SK_BUILD_FOR_MAC) + #include "BenchSysTimer_mach.h" +#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID) + #include "BenchSysTimer_posix.h" +#else + #include "BenchSysTimer_c.h" +#endif + +#if SK_SUPPORT_GPU +#include "BenchGpuTimer_gl.h" +#endif + +BenchTimer::BenchTimer(SkGLContextHelper* gl) + : fCpu(-1.0) + , fWall(-1.0) + , fTruncatedCpu(-1.0) + , fTruncatedWall(-1.0) + , fGpu(-1.0) +{ + fSysTimer = new BenchSysTimer(); + fTruncatedSysTimer = new BenchSysTimer(); +#if SK_SUPPORT_GPU + if (gl) { + fGpuTimer = new BenchGpuTimer(gl); + } else { + fGpuTimer = NULL; + } +#endif +} + +BenchTimer::~BenchTimer() { + delete fSysTimer; + delete fTruncatedSysTimer; +#if SK_SUPPORT_GPU + delete fGpuTimer; +#endif +} + +void BenchTimer::start(double durationScale) { + fDurationScale = durationScale; + + fSysTimer->startWall(); + fTruncatedSysTimer->startWall(); +#if SK_SUPPORT_GPU + if (fGpuTimer) { + fGpuTimer->startGpu(); + } +#endif + fSysTimer->startCpu(); + fTruncatedSysTimer->startCpu(); +} + +void BenchTimer::end() { + fCpu = fSysTimer->endCpu() * fDurationScale; +#if SK_SUPPORT_GPU + //It is important to stop the cpu clocks first, + //as the following will cpu wait for the gpu to finish. + if (fGpuTimer) { + fGpu = fGpuTimer->endGpu() * fDurationScale; + } +#endif + fWall = fSysTimer->endWall() * fDurationScale; +} + +void BenchTimer::truncatedEnd() { + fTruncatedCpu = fTruncatedSysTimer->endCpu() * fDurationScale; + fTruncatedWall = fTruncatedSysTimer->endWall() * fDurationScale; +} + +WallTimer::WallTimer() : fWall(-1.0), fSysTimer(new BenchSysTimer) {} + +WallTimer::~WallTimer() { + delete fSysTimer; +} + +void WallTimer::start(double durationScale) { + fDurationScale = durationScale; + fSysTimer->startWall(); +} + +void WallTimer::end() { + fWall = fSysTimer->endWall() * fDurationScale; +} + diff --git a/chromium/third_party/skia/bench/BenchTimer.h b/chromium/third_party/skia/bench/BenchTimer.h new file mode 100644 index 00000000000..2abf10b80f9 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchTimer.h @@ -0,0 +1,67 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBenchTimer_DEFINED +#define SkBenchTimer_DEFINED + +#include <SkTypes.h> + + +class BenchSysTimer; +class BenchGpuTimer; + +class SkGLContextHelper; + +/** + * SysTimers and GpuTimers are implemented orthogonally. + * This class combines 2 SysTimers and a GpuTimer into one single, + * platform specific Timer with a simple interface. The truncated + * timer doesn't include the time required for the GPU to finish + * its rendering. It should always be <= the un-truncated system + * times and (for GPU configurations) can be used to roughly (very + * roughly) gauge the GPU load/backlog. + */ +class BenchTimer { +public: + BenchTimer(SkGLContextHelper* gl = NULL); + ~BenchTimer(); + void start(double durationScale = 1); + void end(); + void truncatedEnd(); + double fCpu; + double fWall; + double fTruncatedCpu; + double fTruncatedWall; + double fGpu; + +private: + BenchSysTimer* fSysTimer; + BenchSysTimer* fTruncatedSysTimer; +#if SK_SUPPORT_GPU + BenchGpuTimer* fGpuTimer; +#endif + double fDurationScale; // for this start/end session +}; + +// Same as BenchTimer above, supporting only fWall but with much lower overhead. +// (Typically, ~30ns instead of BenchTimer's ~1us.) +class WallTimer { +public: + WallTimer(); + ~WallTimer(); + + void start(double durationScale = 1); + void end(); + + double fWall; + +private: + BenchSysTimer* fSysTimer; + double fDurationScale; +}; + +#endif diff --git a/chromium/third_party/skia/bench/BenchTool/BenchTool.xcodeproj/project.pbxproj b/chromium/third_party/skia/bench/BenchTool/BenchTool.xcodeproj/project.pbxproj new file mode 100644 index 00000000000..4bb4b9cdc49 --- /dev/null +++ b/chromium/third_party/skia/bench/BenchTool/BenchTool.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 272FB43A0F11A19C00CA935D /* RectBench.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 272FB4390F11A19C00CA935D /* RectBench.cpp */; }; + 272FB4F30F11B40300CA935D /* Benchmark.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 272FB4F20F11B40300CA935D /* Benchmark.cpp */; }; + 2752A08A0F14CE1300BBDC03 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2752A0890F14CE1300BBDC03 /* main.cpp */; }; + 27739F4D0F11439200F233EA /* libmaccore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27739F240F11404A00F233EA /* libmaccore.a */; }; + 27739F4E0F11439300F233EA /* libcore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27739F1A0F11403B00F233EA /* libcore.a */; }; + 27739F520F1143C000F233EA /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27739F510F1143C000F233EA /* Carbon.framework */; }; + 8DD76F6A0486A84900D96B5E /* BenchTool.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859E8B029090EE04C91782 /* BenchTool.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 27739F190F11403B00F233EA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 27739F120F11403B00F233EA /* core.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2AAC046055464E500DB518D; + remoteInfo = core; + }; + 27739F230F11404A00F233EA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 27739F1C0F11404A00F233EA /* maccore.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2AAC046055464E500DB518D; + remoteInfo = maccore; + }; + 27739F3C0F11424800F233EA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 27739F1C0F11404A00F233EA /* maccore.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = D2AAC045055464E500DB518D; + remoteInfo = maccore; + }; + 27739F3E0F11424C00F233EA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 27739F120F11403B00F233EA /* core.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = D2AAC045055464E500DB518D; + remoteInfo = core; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F690486A84900D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 8DD76F6A0486A84900D96B5E /* BenchTool.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 272FB4390F11A19C00CA935D /* RectBench.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RectBench.cpp; path = ../RectBench.cpp; sourceTree = SOURCE_ROOT; }; + 272FB4F20F11B40300CA935D /* Benchmark.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Benchmark.cpp; path = ../Benchmark.cpp; sourceTree = SOURCE_ROOT; }; + 2752A0890F14CE1300BBDC03 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../main.cpp; sourceTree = SOURCE_ROOT; }; + 27739F120F11403B00F233EA /* core.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = core.xcodeproj; path = ../../xcode/core/core.xcodeproj; sourceTree = SOURCE_ROOT; }; + 27739F1C0F11404A00F233EA /* maccore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = maccore.xcodeproj; path = ../../xcode/maccore/maccore.xcodeproj; sourceTree = SOURCE_ROOT; }; + 27739F510F1143C000F233EA /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; }; + 8DD76F6C0486A84900D96B5E /* BenchTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BenchTool; sourceTree = BUILT_PRODUCTS_DIR; }; + C6859E8B029090EE04C91782 /* BenchTool.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = BenchTool.1; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F660486A84900D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 27739F4D0F11439200F233EA /* libmaccore.a in Frameworks */, + 27739F4E0F11439300F233EA /* libcore.a in Frameworks */, + 27739F520F1143C000F233EA /* Carbon.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* BenchTool */ = { + isa = PBXGroup; + children = ( + 27739F510F1143C000F233EA /* Carbon.framework */, + 27739F1C0F11404A00F233EA /* maccore.xcodeproj */, + 27739F120F11403B00F233EA /* core.xcodeproj */, + 08FB7795FE84155DC02AAC07 /* Source */, + C6859E8C029090F304C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = BenchTool; + sourceTree = "<group>"; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 2752A0890F14CE1300BBDC03 /* main.cpp */, + 272FB4F20F11B40300CA935D /* Benchmark.cpp */, + 272FB4390F11A19C00CA935D /* RectBench.cpp */, + ); + name = Source; + sourceTree = "<group>"; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76F6C0486A84900D96B5E /* BenchTool */, + ); + name = Products; + sourceTree = "<group>"; + }; + 27739F130F11403B00F233EA /* Products */ = { + isa = PBXGroup; + children = ( + 27739F1A0F11403B00F233EA /* libcore.a */, + ); + name = Products; + sourceTree = "<group>"; + }; + 27739F1D0F11404A00F233EA /* Products */ = { + isa = PBXGroup; + children = ( + 27739F240F11404A00F233EA /* libmaccore.a */, + ); + name = Products; + sourceTree = "<group>"; + }; + C6859E8C029090F304C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6859E8B029090EE04C91782 /* BenchTool.1 */, + ); + name = Documentation; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F620486A84900D96B5E /* BenchTool */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "BenchTool" */; + buildPhases = ( + 8DD76F640486A84900D96B5E /* Sources */, + 8DD76F660486A84900D96B5E /* Frameworks */, + 8DD76F690486A84900D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 27739F3D0F11424800F233EA /* PBXTargetDependency */, + 27739F3F0F11424C00F233EA /* PBXTargetDependency */, + ); + name = BenchTool; + productInstallPath = "$(HOME)/bin"; + productName = BenchTool; + productReference = 8DD76F6C0486A84900D96B5E /* BenchTool */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "BenchTool" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* BenchTool */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 27739F130F11403B00F233EA /* Products */; + ProjectRef = 27739F120F11403B00F233EA /* core.xcodeproj */; + }, + { + ProductGroup = 27739F1D0F11404A00F233EA /* Products */; + ProjectRef = 27739F1C0F11404A00F233EA /* maccore.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 8DD76F620486A84900D96B5E /* BenchTool */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 27739F1A0F11403B00F233EA /* libcore.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcore.a; + remoteRef = 27739F190F11403B00F233EA /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 27739F240F11404A00F233EA /* libmaccore.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libmaccore.a; + remoteRef = 27739F230F11404A00F233EA /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F640486A84900D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 272FB43A0F11A19C00CA935D /* RectBench.cpp in Sources */, + 272FB4F30F11B40300CA935D /* Benchmark.cpp in Sources */, + 2752A08A0F14CE1300BBDC03 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 27739F3D0F11424800F233EA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = maccore; + targetProxy = 27739F3C0F11424800F233EA /* PBXContainerItemProxy */; + }; + 27739F3F0F11424C00F233EA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = core; + targetProxy = 27739F3E0F11424C00F233EA /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1DEB923208733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "_GLIBCXX_DEBUG=1", + "_GLIBCXX_DEBUG_PEDANTIC=1", + ); + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = BenchTool; + }; + name = Debug; + }; + 1DEB923308733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = BenchTool; + }; + name = Release; + }; + 1DEB923608733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + GCC_ENABLE_CPP_RTTI = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_THREADSAFE_STATICS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + USER_HEADER_SEARCH_PATHS = ".. ../../include/**"; + }; + name = Debug; + }; + 1DEB923708733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + GCC_ENABLE_CPP_RTTI = NO; + GCC_THREADSAFE_STATICS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + USER_HEADER_SEARCH_PATHS = ".. ../../include/**"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "BenchTool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923208733DC60010E9CD /* Debug */, + 1DEB923308733DC60010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "BenchTool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923608733DC60010E9CD /* Debug */, + 1DEB923708733DC60010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/chromium/third_party/skia/bench/Benchmark.cpp b/chromium/third_party/skia/bench/Benchmark.cpp new file mode 100644 index 00000000000..ae614f04f9c --- /dev/null +++ b/chromium/third_party/skia/bench/Benchmark.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" + +#include "SkPaint.h" +#include "SkParse.h" + +const char* SkTriState::Name[] = { "default", "true", "false" }; + +template BenchRegistry* BenchRegistry::gHead; + +Benchmark::Benchmark() { + fForceAlpha = 0xFF; + fForceAA = true; + fForceFilter = false; + fDither = SkTriState::kDefault; + fOrMask = fClearMask = 0; +} + +const char* Benchmark::getName() { + return this->onGetName(); +} + +SkIPoint Benchmark::getSize() { + return this->onGetSize(); +} + +void Benchmark::preDraw() { + this->onPreDraw(); +} + +void Benchmark::draw(const int loops, SkCanvas* canvas) { + this->onDraw(loops, canvas); +} + +void Benchmark::setupPaint(SkPaint* paint) { + paint->setAlpha(fForceAlpha); + paint->setAntiAlias(fForceAA); + paint->setFilterLevel(fForceFilter ? SkPaint::kLow_FilterLevel + : SkPaint::kNone_FilterLevel); + + paint->setFlags((paint->getFlags() & ~fClearMask) | fOrMask); + + if (SkTriState::kDefault != fDither) { + paint->setDither(SkTriState::kTrue == fDither); + } +} + +SkIPoint Benchmark::onGetSize() { + return SkIPoint::Make(640, 480); +} diff --git a/chromium/third_party/skia/bench/Benchmark.h b/chromium/third_party/skia/bench/Benchmark.h new file mode 100644 index 00000000000..db70bbe49ca --- /dev/null +++ b/chromium/third_party/skia/bench/Benchmark.h @@ -0,0 +1,128 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef Benchmark_DEFINED +#define Benchmark_DEFINED + +#include "SkPoint.h" +#include "SkRefCnt.h" +#include "SkString.h" +#include "SkTRegistry.h" + +#define DEF_BENCH(code) \ +namespace { \ +static Benchmark* SK_MACRO_APPEND_LINE(factory)(void*) { code; } \ +BenchRegistry SK_MACRO_APPEND_LINE(g_R_)(SK_MACRO_APPEND_LINE(factory)); \ +} + +/* + * With the above macros, you can register benches as follows (at the bottom + * of your .cpp) + * + * DEF_BENCH(return new MyBenchmark(...)) + * DEF_BENCH(return new MyBenchmark(...)) + * DEF_BENCH(return new MyBenchmark(...)) + */ + + +class SkCanvas; +class SkPaint; + +class SkTriState { +public: + enum State { + kDefault, + kTrue, + kFalse + }; + static const char* Name[]; +}; + +class Benchmark : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(Benchmark) + + Benchmark(); + + const char* getName(); + SkIPoint getSize(); + + enum Backend { + kNonRendering_Backend, + kRaster_Backend, + kGPU_Backend, + kPDF_Backend, + }; + + // Call to determine whether the benchmark is intended for + // the rendering mode. + virtual bool isSuitableFor(Backend backend) { + return backend != kNonRendering_Backend; + } + + // Call before draw, allows the benchmark to do setup work outside of the + // timer. When a benchmark is repeatedly drawn, this should be called once + // before the initial draw. + void preDraw(); + + // Bench framework can tune loops to be large enough for stable timing. + void draw(const int loops, SkCanvas*); + + void setForceAlpha(int alpha) { + fForceAlpha = alpha; + } + + void setForceAA(bool aa) { + fForceAA = aa; + } + + void setForceFilter(bool filter) { + fForceFilter = filter; + } + + void setDither(SkTriState::State state) { + fDither = state; + } + + /** Assign masks for paint-flags. These will be applied when setupPaint() + * is called. + * + * Performs the following on the paint: + * uint32_t flags = paint.getFlags(); + * flags &= ~clearMask; + * flags |= orMask; + * paint.setFlags(flags); + */ + void setPaintMasks(uint32_t orMask, uint32_t clearMask) { + fOrMask = orMask; + fClearMask = clearMask; + } + +protected: + virtual void setupPaint(SkPaint* paint); + + virtual const char* onGetName() = 0; + virtual void onPreDraw() {} + // Each bench should do its main work in a loop like this: + // for (int i = 0; i < loops; i++) { <work here> } + virtual void onDraw(const int loops, SkCanvas*) = 0; + + virtual SkIPoint onGetSize(); + +private: + int fForceAlpha; + bool fForceAA; + bool fForceFilter; + SkTriState::State fDither; + uint32_t fOrMask, fClearMask; + + typedef SkRefCnt INHERITED; +}; + +typedef SkTRegistry<Benchmark*(*)(void*)> BenchRegistry; + +#endif diff --git a/chromium/third_party/skia/bench/BicubicBench.cpp b/chromium/third_party/skia/bench/BicubicBench.cpp new file mode 100644 index 00000000000..9d03dd15740 --- /dev/null +++ b/chromium/third_party/skia/bench/BicubicBench.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBicubicImageFilter.h" +#include "SkCanvas.h" +#include "SkShader.h" +#include "SkString.h" + +// This bench exercises SkBicubicImageFilter, upsampling a 40x40 input to +// 100x100, 400x100, 100x400, and 400x400. + +class BicubicBench : public Benchmark { + SkSize fScale; + SkString fName; + +public: + BicubicBench(float x, float y) + : fScale(SkSize::Make(x, y)) { + fName.printf("bicubic_%gx%g", + SkScalarToFloat(fScale.fWidth), SkScalarToFloat(fScale.fHeight)); + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + + paint.setAntiAlias(true); + + SkRect r = SkRect::MakeWH(40, 40); + SkAutoTUnref<SkImageFilter> bicubic(SkBicubicImageFilter::CreateMitchell(fScale)); + paint.setImageFilter(bicubic); + + for (int i = 0; i < loops; i++) { + canvas->save(); + canvas->clipRect(r); + canvas->drawOval(r, paint); + canvas->restore(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new BicubicBench(10.0f, 10.0f); ) +DEF_BENCH( return new BicubicBench(2.5f, 10.0f); ) +DEF_BENCH( return new BicubicBench(10.0f, 2.5f); ) +DEF_BENCH( return new BicubicBench(2.5f, 2.5f); ) diff --git a/chromium/third_party/skia/bench/BitmapBench.cpp b/chromium/third_party/skia/bench/BitmapBench.cpp new file mode 100644 index 00000000000..a269e906f6c --- /dev/null +++ b/chromium/third_party/skia/bench/BitmapBench.cpp @@ -0,0 +1,381 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" +#include "sk_tool_utils.h" + +static int conv6ToByte(int x) { + return x * 0xFF / 5; +} + +static int convByteTo6(int x) { + return x * 5 / 255; +} + +static uint8_t compute666Index(SkPMColor c) { + int r = SkGetPackedR32(c); + int g = SkGetPackedG32(c); + int b = SkGetPackedB32(c); + + return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b); +} + +static void convertToIndex666(const SkBitmap& src, SkBitmap* dst, SkAlphaType aType) { + SkPMColor storage[216]; + SkPMColor* colors = storage; + // rrr ggg bbb + for (int r = 0; r < 6; r++) { + int rr = conv6ToByte(r); + for (int g = 0; g < 6; g++) { + int gg = conv6ToByte(g); + for (int b = 0; b < 6; b++) { + int bb = conv6ToByte(b); + *colors++ = SkPreMultiplyARGB(0xFF, rr, gg, bb); + } + } + } + SkColorTable* ctable = new SkColorTable(storage, 216, aType); + dst->allocPixels(SkImageInfo::Make(src.width(), src.height(), kIndex_8_SkColorType, aType), + NULL, ctable); + ctable->unref(); + + SkAutoLockPixels alps(src); + SkAutoLockPixels alpd(*dst); + + for (int y = 0; y < src.height(); y++) { + const SkPMColor* srcP = src.getAddr32(0, y); + uint8_t* dstP = dst->getAddr8(0, y); + for (int x = src.width() - 1; x >= 0; --x) { + *dstP++ = compute666Index(*srcP++); + } + } +} + +/* Variants for bitmaps + + - src depth (32 w+w/o alpha), 565, 4444, index, a8 + - paint options: filtering, dither, alpha + - matrix options: translate, scale, rotate, persp + - tiling: none, repeat, mirror, clamp + + */ + +class BitmapBench : public Benchmark { + const SkColorType fColorType; + const SkAlphaType fAlphaType; + const bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache + const bool fIsVolatile; + + SkBitmap fBitmap; + SkPaint fPaint; + SkString fName; + + enum { W = 128 }; + enum { H = 128 }; +public: + BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate = false, bool isVolatile = false) + : fColorType(ct) + , fAlphaType(at) + , fForceUpdate(forceUpdate) + , fIsVolatile(isVolatile) + {} + +protected: + virtual const char* onGetName() { + fName.set("bitmap"); + fName.appendf("_%s%s", sk_tool_utils::colortype_name(fColorType), + kOpaque_SkAlphaType == fAlphaType ? "" : "_A"); + if (fForceUpdate) + fName.append("_update"); + if (fIsVolatile) + fName.append("_volatile"); + + return fName.c_str(); + } + + virtual void onPreDraw() { + SkBitmap bm; + + if (kIndex_8_SkColorType == fColorType) { + bm.setInfo(SkImageInfo::MakeN32(W, H, fAlphaType)); + } else { + bm.setInfo(SkImageInfo::Make(W, H, fColorType, fAlphaType)); + } + + bm.allocPixels(); + bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0); + + onDrawIntoBitmap(bm); + + if (kIndex_8_SkColorType == fColorType) { + convertToIndex666(bm, &fBitmap, fAlphaType); + } else { + fBitmap = bm; + } + + fBitmap.setIsVolatile(fIsVolatile); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkIPoint dim = this->getSize(); + SkRandom rand; + + SkPaint paint(fPaint); + this->setupPaint(&paint); + + const SkBitmap& bitmap = fBitmap; + const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2); + const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2); + + for (int i = 0; i < loops; i++) { + SkScalar x = x0 + rand.nextUScalar1() * dim.fX; + SkScalar y = y0 + rand.nextUScalar1() * dim.fY; + + if (fForceUpdate) + bitmap.notifyPixelsChanged(); + + canvas->drawBitmap(bitmap, x, y, &paint); + } + } + + virtual void onDrawIntoBitmap(const SkBitmap& bm) { + const int w = bm.width(); + const int h = bm.height(); + + SkCanvas canvas(bm); + SkPaint p; + p.setAntiAlias(true); + p.setColor(SK_ColorRED); + canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2, + SkIntToScalar(SkMin32(w, h))*3/8, p); + + SkRect r; + r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(4)); + p.setColor(SK_ColorBLUE); + canvas.drawRect(r, p); + } + +private: + typedef Benchmark INHERITED; +}; + +/** Explicitly invoke some filter types to improve coverage of acceleration + procs. */ + +enum Flags { + kScale_Flag = 1 << 0, + kRotate_Flag = 1 << 1, + kBilerp_Flag = 1 << 2, + kBicubic_Flag = 1 << 3, +}; + +static bool isBilerp(uint32_t flags) { + return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag); +} + +static bool isBicubic(uint32_t flags) { + return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag); +} + +class FilterBitmapBench : public BitmapBench { + uint32_t fFlags; + SkString fFullName; +public: + FilterBitmapBench(SkColorType ct, SkAlphaType at, + bool forceUpdate, bool isVolitile, uint32_t flags) + : INHERITED(ct, at, forceUpdate, isVolitile) + , fFlags(flags) { + } + +protected: + virtual const char* onGetName() { + fFullName.set(INHERITED::onGetName()); + if (fFlags & kScale_Flag) { + fFullName.append("_scale"); + } + if (fFlags & kRotate_Flag) { + fFullName.append("_rotate"); + } + if (isBilerp(fFlags)) { + fFullName.append("_bilerp"); + } else if (isBicubic(fFlags)) { + fFullName.append("_bicubic"); + } + + return fFullName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkISize dim = canvas->getDeviceSize(); + if (fFlags & kScale_Flag) { + const SkScalar x = SkIntToScalar(dim.fWidth) / 2; + const SkScalar y = SkIntToScalar(dim.fHeight) / 2; + + canvas->translate(x, y); + // just enough so we can't take the sprite case + canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); + canvas->translate(-x, -y); + } + if (fFlags & kRotate_Flag) { + const SkScalar x = SkIntToScalar(dim.fWidth) / 2; + const SkScalar y = SkIntToScalar(dim.fHeight) / 2; + + canvas->translate(x, y); + canvas->rotate(SkIntToScalar(35)); + canvas->translate(-x, -y); + } + INHERITED::onDraw(loops, canvas); + } + + virtual void setupPaint(SkPaint* paint) SK_OVERRIDE { + this->INHERITED::setupPaint(paint); + + int index = 0; + if (fFlags & kBilerp_Flag) { + index |= 1; + } + if (fFlags & kBicubic_Flag) { + index |= 2; + } + static const SkPaint::FilterLevel gLevels[] = { + SkPaint::kNone_FilterLevel, + SkPaint::kLow_FilterLevel, + SkPaint::kMedium_FilterLevel, + SkPaint::kHigh_FilterLevel + }; + paint->setFilterLevel(gLevels[index]); +} + +private: + typedef BitmapBench INHERITED; +}; + +/** Verify optimizations that test source alpha values. */ + +class SourceAlphaBitmapBench : public BitmapBench { +public: + enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha, + kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha}; +private: + SkString fFullName; + SourceAlpha fSourceAlpha; +public: + SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct, + bool forceUpdate = false, bool bitmapVolatile = false) + : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile) + , fSourceAlpha(alpha) { + } + +protected: + virtual const char* onGetName() { + fFullName.set(INHERITED::onGetName()); + + if (fSourceAlpha == kOpaque_SourceAlpha) { + fFullName.append("_source_opaque"); + } else if (fSourceAlpha == kTransparent_SourceAlpha) { + fFullName.append("_source_transparent"); + } else if (fSourceAlpha == kTwoStripes_SourceAlpha) { + fFullName.append("_source_stripes_two"); + } else if (fSourceAlpha == kThreeStripes_SourceAlpha) { + fFullName.append("_source_stripes_three"); + } + + return fFullName.c_str(); + } + + virtual void onDrawIntoBitmap(const SkBitmap& bm) SK_OVERRIDE { + const int w = bm.width(); + const int h = bm.height(); + + if (kOpaque_SourceAlpha == fSourceAlpha) { + bm.eraseColor(SK_ColorBLACK); + } else if (kTransparent_SourceAlpha == fSourceAlpha) { + bm.eraseColor(0); + } else if (kTwoStripes_SourceAlpha == fSourceAlpha) { + bm.eraseColor(0); + + SkCanvas canvas(bm); + SkPaint p; + p.setAntiAlias(false); + p.setStyle(SkPaint::kFill_Style); + p.setColor(SK_ColorRED); + + // Draw red vertical stripes on transparent background + SkRect r; + for (int x = 0; x < w; x+=2) + { + r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h)); + canvas.drawRect(r, p); + } + + } else if (kThreeStripes_SourceAlpha == fSourceAlpha) { + bm.eraseColor(0); + + SkCanvas canvas(bm); + SkPaint p; + p.setAntiAlias(false); + p.setStyle(SkPaint::kFill_Style); + + // Draw vertical stripes on transparent background with a pattern + // where the first pixel is fully transparent, the next is semi-transparent + // and the third is fully opaque. + SkRect r; + for (int x = 0; x < w; x++) + { + if (x % 3 == 0) { + continue; // Keep transparent + } else if (x % 3 == 1) { + p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent + } else if (x % 3 == 2) { + p.setColor(SK_ColorRED); // Opaque + } + r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h)); + canvas.drawRect(r, p); + } + } + } + +private: + typedef BitmapBench INHERITED; +}; + +DEF_BENCH( return new BitmapBench(kN32_SkColorType, kPremul_SkAlphaType); ) +DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType); ) +DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType); ) +DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kPremul_SkAlphaType); ) +DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kOpaque_SkAlphaType); ) +DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true); ) +DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false); ) + +// scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2 +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); ) +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); ) +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kBilerp_Flag); ) +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kBilerp_Flag); ) + +// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3} +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); ) +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); ) +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); ) +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); ) + +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); ) +DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag | kBicubic_Flag); ) + +// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon} +DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, kN32_SkColorType); ) +DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, kN32_SkColorType); ) +DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, kN32_SkColorType); ) +DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, kN32_SkColorType); ) diff --git a/chromium/third_party/skia/bench/BitmapRectBench.cpp b/chromium/third_party/skia/bench/BitmapRectBench.cpp new file mode 100644 index 00000000000..2ad7bdf9b5f --- /dev/null +++ b/chromium/third_party/skia/bench/BitmapRectBench.cpp @@ -0,0 +1,113 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" + +static void draw_into_bitmap(const SkBitmap& bm) { + const int w = bm.width(); + const int h = bm.height(); + + SkCanvas canvas(bm); + SkPaint p; + p.setAntiAlias(true); + p.setColor(SK_ColorRED); + canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2, + SkIntToScalar(SkMin32(w, h))*3/8, p); + + SkRect r; + r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(4)); + p.setColor(SK_ColorBLUE); + canvas.drawRect(r, p); +} + +/* Variants for bitmaprect + src : entire bitmap, subset, fractional subset + dst : same size as src, diff size + paint : filter-p + */ + +class BitmapRectBench : public Benchmark { + SkBitmap fBitmap; + bool fSlightMatrix; + uint8_t fAlpha; + SkPaint::FilterLevel fFilterLevel; + SkString fName; + SkRect fSrcR, fDstR; + + static const int kWidth = 128; + static const int kHeight = 128; +public: + BitmapRectBench(U8CPU alpha, SkPaint::FilterLevel filterLevel, + bool slightMatrix) { + fAlpha = SkToU8(alpha); + fFilterLevel = filterLevel; + fSlightMatrix = slightMatrix; + + fBitmap.setInfo(SkImageInfo::MakeN32Premul(kWidth, kHeight)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + fName.printf("bitmaprect_%02X_%sfilter_%s", + fAlpha, + SkPaint::kNone_FilterLevel == fFilterLevel ? "no" : "", + fSlightMatrix ? "trans" : "identity"); + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + fBitmap.allocPixels(); + fBitmap.setAlphaType(kOpaque_SkAlphaType); + fBitmap.eraseColor(SK_ColorBLACK); + draw_into_bitmap(fBitmap); + + fSrcR.iset(0, 0, kWidth, kHeight); + fDstR.iset(0, 0, kWidth, kHeight); + + if (fSlightMatrix) { + // want fractional translate + fDstR.offset(SK_Scalar1 / 3, SK_Scalar1 * 5 / 7); + // want enough to create a scale matrix, but not enough to scare + // off our sniffer which tries to see if the matrix is "effectively" + // translate-only. + fDstR.fRight += SK_Scalar1 / (kWidth * 60); + } + } + + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom rand; + + SkPaint paint; + this->setupPaint(&paint); + paint.setFilterLevel(fFilterLevel); + paint.setAlpha(fAlpha); + + for (int i = 0; i < loops; i++) { + canvas->drawBitmapRectToRect(fBitmap, &fSrcR, fDstR, &paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new BitmapRectBench(0xFF, SkPaint::kNone_FilterLevel, false)) +DEF_BENCH(return new BitmapRectBench(0x80, SkPaint::kNone_FilterLevel, false)) +DEF_BENCH(return new BitmapRectBench(0xFF, SkPaint::kLow_FilterLevel, false)) +DEF_BENCH(return new BitmapRectBench(0x80, SkPaint::kLow_FilterLevel, false)) + +DEF_BENCH(return new BitmapRectBench(0xFF, SkPaint::kNone_FilterLevel, true)) +DEF_BENCH(return new BitmapRectBench(0xFF, SkPaint::kLow_FilterLevel, true)) diff --git a/chromium/third_party/skia/bench/BitmapScaleBench.cpp b/chromium/third_party/skia/bench/BitmapScaleBench.cpp new file mode 100644 index 00000000000..fad741aebc7 --- /dev/null +++ b/chromium/third_party/skia/bench/BitmapScaleBench.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBlurMask.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +class BitmapScaleBench: public Benchmark { + int fLoopCount; + int fInputSize; + int fOutputSize; + SkString fName; + +public: + BitmapScaleBench( int is, int os) { + fInputSize = is; + fOutputSize = os; + + fLoopCount = 20; + } + +protected: + + SkBitmap fInputBitmap, fOutputBitmap; + SkMatrix fMatrix; + + virtual const char* onGetName() { + return fName.c_str(); + } + + int inputSize() const { + return fInputSize; + } + + int outputSize() const { + return fOutputSize; + } + + float scale() const { + return float(outputSize())/inputSize(); + } + + SkIPoint onGetSize() SK_OVERRIDE { + return SkIPoint::Make( fOutputSize, fOutputSize ); + } + + void setName(const char * name) { + fName.printf( "bitmap_scale_%s_%d_%d", name, fInputSize, fOutputSize ); + } + + virtual void onPreDraw() { + fInputBitmap.allocN32Pixels(fInputSize, fInputSize, true); + fInputBitmap.eraseColor(SK_ColorWHITE); + + fOutputBitmap.allocN32Pixels(fOutputSize, fOutputSize, true); + + fMatrix.setScale( scale(), scale() ); + } + + virtual void onDraw(const int loops, SkCanvas*) { + SkPaint paint; + this->setupPaint(&paint); + + preBenchSetup(); + + for (int i = 0; i < loops; i++) { + doScaleImage(); + } + } + + virtual void doScaleImage() = 0; + virtual void preBenchSetup() {} +private: + typedef Benchmark INHERITED; +}; + +class BitmapFilterScaleBench: public BitmapScaleBench { + public: + BitmapFilterScaleBench( int is, int os) : INHERITED(is, os) { + setName( "filter" ); + } +protected: + virtual void doScaleImage() SK_OVERRIDE { + SkCanvas canvas( fOutputBitmap ); + SkPaint paint; + + paint.setFilterLevel(SkPaint::kHigh_FilterLevel); + fInputBitmap.notifyPixelsChanged(); + canvas.drawBitmapMatrix( fInputBitmap, fMatrix, &paint ); + } +private: + typedef BitmapScaleBench INHERITED; +}; + +DEF_BENCH(return new BitmapFilterScaleBench(10, 90);) +DEF_BENCH(return new BitmapFilterScaleBench(30, 90);) +DEF_BENCH(return new BitmapFilterScaleBench(80, 90);) +DEF_BENCH(return new BitmapFilterScaleBench(90, 90);) +DEF_BENCH(return new BitmapFilterScaleBench(90, 80);) +DEF_BENCH(return new BitmapFilterScaleBench(90, 30);) +DEF_BENCH(return new BitmapFilterScaleBench(90, 10);) +DEF_BENCH(return new BitmapFilterScaleBench(256, 64);) +DEF_BENCH(return new BitmapFilterScaleBench(64, 256);) diff --git a/chromium/third_party/skia/bench/BlurBench.cpp b/chromium/third_party/skia/bench/BlurBench.cpp new file mode 100644 index 00000000000..cafc6f3a2a3 --- /dev/null +++ b/chromium/third_party/skia/bench/BlurBench.cpp @@ -0,0 +1,109 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBlurMask.h" +#include "SkBlurMaskFilter.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +#define SMALL SkIntToScalar(2) +#define REAL 1.5f +#define BIG SkIntToScalar(10) +#define REALBIG 100.5f + +static const char* gStyleName[] = { + "normal", + "solid", + "outer", + "inner" +}; + +class BlurBench : public Benchmark { + SkScalar fRadius; + SkBlurStyle fStyle; + uint32_t fFlags; + SkString fName; + +public: + BlurBench(SkScalar rad, SkBlurStyle bs, uint32_t flags = 0) { + fRadius = rad; + fStyle = bs; + fFlags = flags; + const char* name = rad > 0 ? gStyleName[bs] : "none"; + const char* quality = flags & SkBlurMaskFilter::kHighQuality_BlurFlag ? "high_quality" + : "low_quality"; + if (SkScalarFraction(rad) != 0) { + fName.printf("blur_%.2f_%s_%s", SkScalarToFloat(rad), name, quality); + } else { + fName.printf("blur_%d_%s_%s", SkScalarRoundToInt(rad), name, quality); + } + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + + paint.setAntiAlias(true); + + SkRandom rand; + for (int i = 0; i < loops; i++) { + SkRect r = SkRect::MakeWH(rand.nextUScalar1() * 400, + rand.nextUScalar1() * 400); + r.offset(fRadius, fRadius); + + if (fRadius > 0) { + SkMaskFilter* mf = SkBlurMaskFilter::Create(fStyle, + SkBlurMask::ConvertRadiusToSigma(fRadius), + fFlags); + paint.setMaskFilter(mf)->unref(); + } + canvas->drawOval(r, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new BlurBench(SMALL, kNormal_SkBlurStyle);) +DEF_BENCH(return new BlurBench(SMALL, kSolid_SkBlurStyle);) +DEF_BENCH(return new BlurBench(SMALL, kOuter_SkBlurStyle);) +DEF_BENCH(return new BlurBench(SMALL, kInner_SkBlurStyle);) + +DEF_BENCH(return new BlurBench(BIG, kNormal_SkBlurStyle);) +DEF_BENCH(return new BlurBench(BIG, kSolid_SkBlurStyle);) +DEF_BENCH(return new BlurBench(BIG, kOuter_SkBlurStyle);) +DEF_BENCH(return new BlurBench(BIG, kInner_SkBlurStyle);) + +DEF_BENCH(return new BlurBench(REALBIG, kNormal_SkBlurStyle);) +DEF_BENCH(return new BlurBench(REALBIG, kSolid_SkBlurStyle);) +DEF_BENCH(return new BlurBench(REALBIG, kOuter_SkBlurStyle);) +DEF_BENCH(return new BlurBench(REALBIG, kInner_SkBlurStyle);) + +DEF_BENCH(return new BlurBench(REAL, kNormal_SkBlurStyle);) +DEF_BENCH(return new BlurBench(REAL, kSolid_SkBlurStyle);) +DEF_BENCH(return new BlurBench(REAL, kOuter_SkBlurStyle);) +DEF_BENCH(return new BlurBench(REAL, kInner_SkBlurStyle);) + +DEF_BENCH(return new BlurBench(SMALL, kNormal_SkBlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag);) + +DEF_BENCH(return new BlurBench(BIG, kNormal_SkBlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag);) + +DEF_BENCH(return new BlurBench(REALBIG, kNormal_SkBlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag);) + +DEF_BENCH(return new BlurBench(REAL, kNormal_SkBlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag);) + +DEF_BENCH(return new BlurBench(0, kNormal_SkBlurStyle);) diff --git a/chromium/third_party/skia/bench/BlurImageFilterBench.cpp b/chromium/third_party/skia/bench/BlurImageFilterBench.cpp new file mode 100644 index 00000000000..786611b1504 --- /dev/null +++ b/chromium/third_party/skia/bench/BlurImageFilterBench.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBitmapDevice.h" +#include "SkBlurImageFilter.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +#define FILTER_WIDTH_SMALL 32 +#define FILTER_HEIGHT_SMALL 32 +#define FILTER_WIDTH_LARGE 256 +#define FILTER_HEIGHT_LARGE 256 +#define BLUR_SIGMA_SMALL 1.0f +#define BLUR_SIGMA_LARGE 10.0f +#define BLUR_SIGMA_HUGE 80.0f + +class BlurImageFilterBench : public Benchmark { +public: + BlurImageFilterBench(SkScalar sigmaX, SkScalar sigmaY, bool small) : + fIsSmall(small), fInitialized(false), fSigmaX(sigmaX), fSigmaY(sigmaY) { + fName.printf("blur_image_filter_%s_%.2f_%.2f", fIsSmall ? "small" : "large", + SkScalarToFloat(sigmaX), SkScalarToFloat(sigmaY)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + if (!fInitialized) { + make_checkerboard(); + fInitialized = true; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + paint.setImageFilter(SkBlurImageFilter::Create(fSigmaX, fSigmaY))->unref(); + + for (int i = 0; i < loops; i++) { + canvas->drawBitmap(fCheckerboard, 0, 0, &paint); + } + } + +private: + void make_checkerboard() { + const int w = fIsSmall ? FILTER_WIDTH_SMALL : FILTER_WIDTH_LARGE; + const int h = fIsSmall ? FILTER_HEIGHT_LARGE : FILTER_HEIGHT_LARGE; + fCheckerboard.allocN32Pixels(w, h); + SkCanvas canvas(fCheckerboard); + canvas.clear(0x00000000); + SkPaint darkPaint; + darkPaint.setColor(0xFF804020); + SkPaint lightPaint; + lightPaint.setColor(0xFF244484); + for (int y = 0; y < h; y += 16) { + for (int x = 0; x < w; x += 16) { + canvas.save(); + canvas.translate(SkIntToScalar(x), SkIntToScalar(y)); + canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint); + canvas.restore(); + } + } + } + + SkString fName; + bool fIsSmall; + bool fInitialized; + SkBitmap fCheckerboard; + SkScalar fSigmaX, fSigmaY; + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_LARGE, 0, false);) +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_SMALL, 0, false);) +DEF_BENCH(return new BlurImageFilterBench(0, BLUR_SIGMA_LARGE, false);) +DEF_BENCH(return new BlurImageFilterBench(0, BLUR_SIGMA_SMALL, false);) +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_SMALL, BLUR_SIGMA_SMALL, true);) +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_SMALL, BLUR_SIGMA_SMALL, false);) +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_LARGE, BLUR_SIGMA_LARGE, true);) +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_LARGE, BLUR_SIGMA_LARGE, false);) +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_HUGE, BLUR_SIGMA_HUGE, true);) +DEF_BENCH(return new BlurImageFilterBench(BLUR_SIGMA_HUGE, BLUR_SIGMA_HUGE, false);) diff --git a/chromium/third_party/skia/bench/BlurRectBench.cpp b/chromium/third_party/skia/bench/BlurRectBench.cpp new file mode 100644 index 00000000000..cdcdfe57f34 --- /dev/null +++ b/chromium/third_party/skia/bench/BlurRectBench.cpp @@ -0,0 +1,228 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBlurMask.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +#define SMALL SkIntToScalar(2) +#define REAL 1.5f +static const SkScalar kMedium = SkIntToScalar(5); +#define BIG SkIntToScalar(10) +static const SkScalar kMedBig = SkIntToScalar(20); +#define REALBIG 30.5f + +class BlurRectBench: public Benchmark { + int fLoopCount; + SkScalar fRadius; + SkString fName; + +public: + BlurRectBench(SkScalar rad) { + fRadius = rad; + + if (fRadius > SkIntToScalar(25)) { + fLoopCount = 100; + } else if (fRadius > SkIntToScalar(5)) { + fLoopCount = 1000; + } else { + fLoopCount = 10000; + } + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + SkScalar radius() const { + return fRadius; + } + + void setName(const SkString& name) { + fName = name; + } + + virtual void onDraw(const int loops, SkCanvas*) { + SkPaint paint; + this->setupPaint(&paint); + + paint.setAntiAlias(true); + + SkScalar pad = fRadius*3/2 + SK_Scalar1; + SkRect r = SkRect::MakeWH(2 * pad + SK_Scalar1, 2 * pad + SK_Scalar1); + + preBenchSetup(r); + + for (int i = 0; i < loops; i++) { + makeBlurryRect(r); + } + } + + virtual void makeBlurryRect(const SkRect&) = 0; + virtual void preBenchSetup(const SkRect&) {} +private: + typedef Benchmark INHERITED; +}; + + +class BlurRectDirectBench: public BlurRectBench { + public: + BlurRectDirectBench(SkScalar rad) : INHERITED(rad) { + SkString name; + + if (SkScalarFraction(rad) != 0) { + name.printf("blurrect_direct_%.2f", SkScalarToFloat(rad)); + } else { + name.printf("blurrect_direct_%d", SkScalarRoundToInt(rad)); + } + + this->setName(name); + } +protected: + virtual void makeBlurryRect(const SkRect& r) SK_OVERRIDE { + SkMask mask; + SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()), + &mask, r, kNormal_SkBlurStyle); + SkMask::FreeImage(mask.fImage); + } +private: + typedef BlurRectBench INHERITED; +}; + +class BlurRectSeparableBench: public BlurRectBench { + +public: + BlurRectSeparableBench(SkScalar rad) : INHERITED(rad) { + fSrcMask.fImage = NULL; + } + + ~BlurRectSeparableBench() { + SkMask::FreeImage(fSrcMask.fImage); + } + +protected: + virtual void preBenchSetup(const SkRect& r) SK_OVERRIDE { + SkMask::FreeImage(fSrcMask.fImage); + + r.roundOut(&fSrcMask.fBounds); + fSrcMask.fFormat = SkMask::kA8_Format; + fSrcMask.fRowBytes = fSrcMask.fBounds.width(); + fSrcMask.fImage = SkMask::AllocImage(fSrcMask.computeTotalImageSize()); + + memset(fSrcMask.fImage, 0xff, fSrcMask.computeTotalImageSize()); + } + + SkMask fSrcMask; +private: + typedef BlurRectBench INHERITED; +}; + +class BlurRectBoxFilterBench: public BlurRectSeparableBench { +public: + BlurRectBoxFilterBench(SkScalar rad) : INHERITED(rad) { + SkString name; + + if (SkScalarFraction(rad) != 0) { + name.printf("blurrect_boxfilter_%.2f", SkScalarToFloat(rad)); + } else { + name.printf("blurrect_boxfilter_%d", SkScalarRoundToInt(rad)); + } + + this->setName(name); + } + +protected: + + virtual void makeBlurryRect(const SkRect&) SK_OVERRIDE { + SkMask mask; + mask.fImage = NULL; + SkBlurMask::BoxBlur(&mask, fSrcMask, SkBlurMask::ConvertRadiusToSigma(this->radius()), + kNormal_SkBlurStyle, kHigh_SkBlurQuality); + SkMask::FreeImage(mask.fImage); + } +private: + typedef BlurRectSeparableBench INHERITED; +}; + +class BlurRectGaussianBench: public BlurRectSeparableBench { +public: + BlurRectGaussianBench(SkScalar rad) : INHERITED(rad) { + SkString name; + + if (SkScalarFraction(rad) != 0) { + name.printf("blurrect_gaussian_%.2f", SkScalarToFloat(rad)); + } else { + name.printf("blurrect_gaussian_%d", SkScalarRoundToInt(rad)); + } + + this->setName(name); + } + +protected: + + virtual void makeBlurryRect(const SkRect&) SK_OVERRIDE { + SkMask mask; + mask.fImage = NULL; + SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()), + &mask, fSrcMask, kNormal_SkBlurStyle); + SkMask::FreeImage(mask.fImage); + } +private: + typedef BlurRectSeparableBench INHERITED; +}; + +DEF_BENCH(return new BlurRectBoxFilterBench(SMALL);) +DEF_BENCH(return new BlurRectBoxFilterBench(BIG);) +DEF_BENCH(return new BlurRectBoxFilterBench(REALBIG);) +DEF_BENCH(return new BlurRectBoxFilterBench(REAL);) +DEF_BENCH(return new BlurRectGaussianBench(SMALL);) +DEF_BENCH(return new BlurRectGaussianBench(BIG);) +DEF_BENCH(return new BlurRectGaussianBench(REALBIG);) +DEF_BENCH(return new BlurRectGaussianBench(REAL);) +DEF_BENCH(return new BlurRectDirectBench(SMALL);) +DEF_BENCH(return new BlurRectDirectBench(BIG);) +DEF_BENCH(return new BlurRectDirectBench(REALBIG);) +DEF_BENCH(return new BlurRectDirectBench(REAL);) + +DEF_BENCH(return new BlurRectDirectBench(kMedium);) +DEF_BENCH(return new BlurRectDirectBench(kMedBig);) + +DEF_BENCH(return new BlurRectBoxFilterBench(kMedium);) +DEF_BENCH(return new BlurRectBoxFilterBench(kMedBig);) + +#if 0 +// disable Gaussian benchmarks; the algorithm works well enough +// and serves as a baseline for ground truth, but it's too slow +// to use in production for non-trivial radii, so no real point +// in having the bots benchmark it all the time. + +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(1));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(2));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(3));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(4));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(5));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(6));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(7));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(8));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(9));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(10));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(11));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(12));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(13));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(14));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(15));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(16));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(17));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(18));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(19));) +DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(20));) +#endif diff --git a/chromium/third_party/skia/bench/BlurRoundRectBench.cpp b/chromium/third_party/skia/bench/BlurRoundRectBench.cpp new file mode 100644 index 00000000000..52de22a4dc0 --- /dev/null +++ b/chromium/third_party/skia/bench/BlurRoundRectBench.cpp @@ -0,0 +1,93 @@ +/* +* Copyright 2013 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "Benchmark.h" +#include "SkBlurMask.h" +#include "SkBlurMaskFilter.h" +#include "SkCanvas.h" +#include "SkColorFilter.h" +#include "SkLayerDrawLooper.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkRRect.h" +#include "SkRect.h" +#include "SkString.h" +#include "SkXfermode.h" + +// Large blurred RR appear frequently on web pages. This benchmark measures our +// performance in this case. +class BlurRoundRectBench : public Benchmark { +public: + BlurRoundRectBench(int width, int height, int cornerRadius) + : fName("blurroundrect") { + fName.appendf("_WH[%ix%i]_cr[%i]", width, height, cornerRadius); + SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); + fRRect.setRectXY(r, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius)); + } + + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual SkIPoint onGetSize() SK_OVERRIDE { + return SkIPoint::Make(SkScalarCeilToInt(fRRect.rect().width()), + SkScalarCeilToInt(fRRect.rect().height())); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkLayerDrawLooper::Builder looperBuilder; + { + SkLayerDrawLooper::LayerInfo info; + info.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit + | SkLayerDrawLooper::kColorFilter_Bit; + info.fColorMode = SkXfermode::kSrc_Mode; + info.fOffset = SkPoint::Make(SkIntToScalar(-1), SkIntToScalar(0)); + info.fPostTranslate = false; + SkPaint* paint = looperBuilder.addLayerOnTop(info); + SkMaskFilter* maskFilter = SkBlurMaskFilter::Create( + kNormal_SkBlurStyle, + SkBlurMask::ConvertRadiusToSigma(SK_ScalarHalf), + SkBlurMaskFilter::kHighQuality_BlurFlag); + paint->setMaskFilter(maskFilter)->unref(); + SkColorFilter* colorFilter = SkColorFilter::CreateModeFilter(SK_ColorLTGRAY, + SkXfermode::kSrcIn_Mode); + paint->setColorFilter(colorFilter)->unref(); + paint->setColor(SK_ColorGRAY); + } + { + SkLayerDrawLooper::LayerInfo info; + looperBuilder.addLayerOnTop(info); + } + SkPaint dullPaint; + dullPaint.setAntiAlias(true); + + SkPaint loopedPaint; + loopedPaint.setLooper(looperBuilder.detachLooper())->unref(); + loopedPaint.setAntiAlias(true); + loopedPaint.setColor(SK_ColorCYAN); + + for (int i = 0; i < loops; i++) { + canvas->drawRect(fRRect.rect(), dullPaint); + canvas->drawRRect(fRRect, loopedPaint); + } + } + +private: + SkString fName; + SkRRect fRRect; + + typedef Benchmark INHERITED; +}; + +// Create one with dimensions/rounded corners based on the skp +DEF_BENCH(return new BlurRoundRectBench(600, 5514, 6);) +// Same radii, much smaller rectangle +DEF_BENCH(return new BlurRoundRectBench(100, 100, 6);) +// Other radii options +DEF_BENCH(return new BlurRoundRectBench(100, 100, 30);) +DEF_BENCH(return new BlurRoundRectBench(100, 100, 90);) diff --git a/chromium/third_party/skia/bench/ChartBench.cpp b/chromium/third_party/skia/bench/ChartBench.cpp new file mode 100644 index 00000000000..f33d2da3985 --- /dev/null +++ b/chromium/third_party/skia/bench/ChartBench.cpp @@ -0,0 +1,192 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" + +/** + * This is a conversion of samplecode/SampleChart.cpp into a bench. It sure would be nice to be able + * to write one subclass that can be a GM, bench, and/or Sample. + */ + +// Generates y values for the chart plots. +static void gen_data(SkScalar yAvg, SkScalar ySpread, int count, + SkRandom* random, SkTDArray<SkScalar>* dataPts) { + dataPts->setCount(count); + for (int i = 0; i < count; ++i) { + (*dataPts)[i] = random->nextRangeScalar(yAvg - SkScalarHalf(ySpread), + yAvg + SkScalarHalf(ySpread)); + } +} + +// Generates a path to stroke along the top of each plot and a fill path for the area below each +// plot. The fill path is bounded below by the bottomData plot points or a horizontal line at +// yBase if bottomData == NULL. +// The plots are animated by rotating the data points by leftShift. +static void gen_paths(const SkTDArray<SkScalar>& topData, + const SkTDArray<SkScalar>* bottomData, + SkScalar yBase, + SkScalar xLeft, SkScalar xDelta, + int leftShift, + SkPath* plot, SkPath* fill) { + plot->rewind(); + fill->rewind(); + plot->incReserve(topData.count()); + if (NULL == bottomData) { + fill->incReserve(topData.count() + 2); + } else { + fill->incReserve(2 * topData.count()); + } + + leftShift %= topData.count(); + SkScalar x = xLeft; + + // Account for the leftShift using two loops + int shiftToEndCount = topData.count() - leftShift; + plot->moveTo(x, topData[leftShift]); + fill->moveTo(x, topData[leftShift]); + + for (int i = 1; i < shiftToEndCount; ++i) { + plot->lineTo(x, topData[i + leftShift]); + fill->lineTo(x, topData[i + leftShift]); + x += xDelta; + } + + for (int i = 0; i < leftShift; ++i) { + plot->lineTo(x, topData[i]); + fill->lineTo(x, topData[i]); + x += xDelta; + } + + if (NULL != bottomData) { + SkASSERT(bottomData->count() == topData.count()); + // iterate backwards over the previous graph's data to generate the bottom of the filled + // area (and account for leftShift). + for (int i = 0; i < leftShift; ++i) { + x -= xDelta; + fill->lineTo(x, (*bottomData)[leftShift - 1 - i]); + } + for (int i = 0; i < shiftToEndCount; ++i) { + x -= xDelta; + fill->lineTo(x, (*bottomData)[bottomData->count() - 1 - i]); + } + } else { + fill->lineTo(x - xDelta, yBase); + fill->lineTo(xLeft, yBase); + } +} + +// A set of scrolling line plots with the area between each plot filled. Stresses out GPU path +// filling +class ChartBench : public Benchmark { +public: + ChartBench(bool aa) { + fShift = 0; + fAA = aa; + fSize.fWidth = -1; + fSize.fHeight = -1; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + if (fAA) { + return "chart_aa"; + } else { + return "chart_bw"; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + bool sizeChanged = false; + if (canvas->getDeviceSize() != fSize) { + fSize = canvas->getDeviceSize(); + sizeChanged = true; + } + + SkScalar ySpread = SkIntToScalar(fSize.fHeight / 20); + + SkScalar height = SkIntToScalar(fSize.fHeight); + if (sizeChanged) { + int dataPointCount = SkMax32(fSize.fWidth / kPixelsPerTick + 1, 2); + + SkRandom random; + for (int i = 0; i < kNumGraphs; ++i) { + SkScalar y = (kNumGraphs - i) * (height - ySpread) / (kNumGraphs + 1); + fData[i].reset(); + gen_data(y, ySpread, dataPointCount, &random, fData + i); + } + } + + SkRandom colorRand; + SkColor colors[kNumGraphs]; + for (int i = 0; i < kNumGraphs; ++i) { + colors[i] = colorRand.nextU() | 0xff000000; + } + + for (int frame = 0; frame < loops; ++frame) { + + canvas->clear(0xFFE0F0E0); + + SkPath plotPath; + SkPath fillPath; + + static const SkScalar kStrokeWidth = SkIntToScalar(2); + SkPaint plotPaint; + SkPaint fillPaint; + plotPaint.setAntiAlias(fAA); + plotPaint.setStyle(SkPaint::kStroke_Style); + plotPaint.setStrokeWidth(kStrokeWidth); + plotPaint.setStrokeCap(SkPaint::kRound_Cap); + plotPaint.setStrokeJoin(SkPaint::kRound_Join); + fillPaint.setAntiAlias(fAA); + fillPaint.setStyle(SkPaint::kFill_Style); + + SkTDArray<SkScalar>* prevData = NULL; + for (int i = 0; i < kNumGraphs; ++i) { + gen_paths(fData[i], + prevData, + height, + 0, + SkIntToScalar(kPixelsPerTick), + fShift, + &plotPath, + &fillPath); + + // Make the fills partially transparent + fillPaint.setColor((colors[i] & 0x00ffffff) | 0x80000000); + canvas->drawPath(fillPath, fillPaint); + + plotPaint.setColor(colors[i]); + canvas->drawPath(plotPath, plotPaint); + + prevData = fData + i; + } + + fShift += kShiftPerFrame; + } + } + +private: + enum { + kNumGraphs = 5, + kPixelsPerTick = 3, + kShiftPerFrame = 1, + }; + int fShift; + SkISize fSize; + SkTDArray<SkScalar> fData[kNumGraphs]; + bool fAA; + + typedef Benchmark INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new ChartBench(true); ) +DEF_BENCH( return new ChartBench(false); ) diff --git a/chromium/third_party/skia/bench/ChecksumBench.cpp b/chromium/third_party/skia/bench/ChecksumBench.cpp new file mode 100644 index 00000000000..7d3ec9ff9f4 --- /dev/null +++ b/chromium/third_party/skia/bench/ChecksumBench.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkChecksum.h" +#include "SkMD5.h" +#include "SkRandom.h" +#include "SkSHA1.h" +#include "SkTemplates.h" + +enum ChecksumType { + kChecksum_ChecksumType, + kMD5_ChecksumType, + kSHA1_ChecksumType, + kMurmur3_ChecksumType, +}; + +class ComputeChecksumBench : public Benchmark { + enum { + U32COUNT = 256, + SIZE = U32COUNT * 4, + }; + uint32_t fData[U32COUNT]; + ChecksumType fType; + +public: + ComputeChecksumBench(ChecksumType type) : fType(type) { + SkRandom rand; + for (int i = 0; i < U32COUNT; ++i) { + fData[i] = rand.nextU(); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + switch (fType) { + case kChecksum_ChecksumType: return "compute_checksum"; + case kMD5_ChecksumType: return "compute_md5"; + case kSHA1_ChecksumType: return "compute_sha1"; + case kMurmur3_ChecksumType: return "compute_murmur3"; + + default: SK_CRASH(); return ""; + } + } + + virtual void onDraw(const int loops, SkCanvas*) { + switch (fType) { + case kChecksum_ChecksumType: { + for (int i = 0; i < loops; i++) { + volatile uint32_t result = SkChecksum::Compute(fData, sizeof(fData)); + sk_ignore_unused_variable(result); + } + } break; + case kMD5_ChecksumType: { + for (int i = 0; i < loops; i++) { + SkMD5 md5; + md5.update(reinterpret_cast<uint8_t*>(fData), sizeof(fData)); + SkMD5::Digest digest; + md5.finish(digest); + } + } break; + case kSHA1_ChecksumType: { + for (int i = 0; i < loops; i++) { + SkSHA1 sha1; + sha1.update(reinterpret_cast<uint8_t*>(fData), sizeof(fData)); + SkSHA1::Digest digest; + sha1.finish(digest); + } + } break; + case kMurmur3_ChecksumType: { + for (int i = 0; i < loops; i++) { + volatile uint32_t result = SkChecksum::Murmur3(fData, sizeof(fData)); + sk_ignore_unused_variable(result); + } + }break; + } + + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new ComputeChecksumBench(kChecksum_ChecksumType); ) +DEF_BENCH( return new ComputeChecksumBench(kMD5_ChecksumType); ) +DEF_BENCH( return new ComputeChecksumBench(kSHA1_ChecksumType); ) +DEF_BENCH( return new ComputeChecksumBench(kMurmur3_ChecksumType); ) diff --git a/chromium/third_party/skia/bench/ChromeBench.cpp b/chromium/third_party/skia/bench/ChromeBench.cpp new file mode 100644 index 00000000000..493878526a5 --- /dev/null +++ b/chromium/third_party/skia/bench/ChromeBench.cpp @@ -0,0 +1,496 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkString.h" + +/** + Benchmarks that try to emulate a particular Skia call pattern observed in Chrome. +*/ + +/// blitRect() calls emitted by Chrome while scrolling through gmail: count, width, height. +int gmailScrollingRectSpec [431*3] = { + 1, 1254, 1160, + 1, 64, 112, + 1, 1034, 261, + 1, 1166, 1, + 1, 1166, 20, + 1, 1254, 40, + 1, 140, 20, + 1, 22, 30, + 1, 22, 39, + 1, 294, 29, + 1, 336, 25, + 1, 336, 5, + 1, 37, 3, + 1, 37, 4, + 1, 37, 5, + 1, 41, 29, + 1, 57, 15, + 1, 72, 5, + 1, 72, 8, + 1, 76, 29, + 1, 981, 88, + 1, 990, 2, + 1, 990, 6, + 2, 220, 88, + 2, 294, 1, + 2, 37, 6, + 2, 391, 55, + 2, 57, 11, + 2, 57, 14, + 2, 57, 7, + 2, 981, 30, + 2, 990, 15, + 2, 990, 19, + 3, 114, 16, + 3, 1166, 39, + 3, 1254, 154, + 3, 12, 12, + 3, 162, 7, + 3, 164, 479, + 3, 167, 449, + 3, 16, 24, + 3, 204, 497, + 3, 205, 434, + 3, 220, 1127, + 3, 220, 1132, + 3, 220, 931, + 3, 220, 933, + 3, 220, 934, + 3, 297, 8, + 3, 72, 25, + 3, 87, 30, + 3, 981, 1, + 3, 981, 126, + 3, 990, 27, + 3, 990, 36, + 3, 991, 29, + 4, 1254, 306, + 4, 1254, 36, + 4, 1, 1, + 4, 1, 14, + 4, 1, 19, + 4, 1, 7, + 4, 21, 21, + 4, 220, 30, + 4, 46, 949, + 4, 509, 30, + 4, 57, 2, + 4, 57, 6, + 4, 990, 11, + 5, 13, 8, + 5, 198, 24, + 5, 24, 24, + 5, 25, 24, + 5, 2, 24, + 5, 37, 33, + 5, 57, 4, + 5, 599, 24, + 5, 90, 24, + 5, 981, 19, + 5, 990, 23, + 5, 990, 8, + 6, 101, 29, + 6, 117, 29, + 6, 1254, 88, + 6, 139, 29, + 6, 13, 12, + 6, 15, 15, + 6, 164, 25, + 6, 16, 16, + 6, 198, 7, + 6, 1, 12, + 6, 1, 15, + 6, 1, 27, + 6, 220, 936, + 6, 24, 7, + 6, 25, 7, + 6, 2, 7, + 6, 326, 29, + 6, 336, 29, + 6, 599, 7, + 6, 86, 29, + 6, 90, 7, + 6, 96, 29, + 6, 991, 31, + 7, 198, 12, + 7, 198, 20, + 7, 198, 33, + 7, 198, 35, + 7, 24, 12, + 7, 24, 20, + 7, 24, 33, + 7, 24, 35, + 7, 25, 12, + 7, 25, 20, + 7, 25, 33, + 7, 25, 35, + 7, 2, 12, + 7, 2, 20, + 7, 2, 33, + 7, 2, 35, + 7, 304, 1, + 7, 38, 29, + 7, 51, 29, + 7, 599, 12, + 7, 599, 20, + 7, 599, 33, + 7, 599, 35, + 7, 90, 12, + 7, 90, 20, + 7, 90, 33, + 7, 90, 35, + 8, 13, 5, + 8, 198, 13, + 8, 198, 23, + 8, 220, 1, + 8, 24, 13, + 8, 24, 23, + 8, 25, 13, + 8, 25, 23, + 8, 2, 13, + 8, 2, 23, + 8, 329, 28, + 8, 57, 10, + 8, 599, 13, + 8, 599, 23, + 8, 90, 13, + 8, 90, 23, + 9, 198, 17, + 9, 198, 19, + 9, 198, 37, + 9, 198, 5, + 9, 198, 8, + 9, 24, 17, + 9, 24, 19, + 9, 24, 37, + 9, 24, 5, + 9, 24, 8, + 9, 25, 17, + 9, 25, 19, + 9, 25, 37, + 9, 25, 5, + 9, 25, 8, + 9, 2, 17, + 9, 2, 19, + 9, 2, 37, + 9, 2, 5, + 9, 2, 8, + 9, 599, 17, + 9, 599, 19, + 9, 599, 37, + 9, 599, 5, + 9, 599, 8, + 9, 72, 29, + 9, 90, 17, + 9, 90, 19, + 9, 90, 37, + 9, 90, 5, + 9, 90, 8, + 10, 13, 11, + 10, 13, 9, + 10, 198, 26, + 10, 198, 28, + 10, 1, 23, + 10, 1, 4, + 10, 1, 6, + 10, 24, 26, + 10, 24, 28, + 10, 25, 26, + 10, 25, 28, + 10, 26, 24, + 10, 2, 26, + 10, 2, 28, + 10, 599, 26, + 10, 599, 28, + 10, 90, 26, + 10, 90, 28, + 11, 198, 27, + 11, 24, 27, + 11, 25, 27, + 11, 2, 27, + 11, 599, 27, + 11, 90, 27, + 12, 198, 14, + 12, 198, 21, + 12, 198, 3, + 12, 1, 11, + 12, 1, 2, + 12, 1, 8, + 12, 24, 14, + 12, 24, 21, + 12, 24, 3, + 12, 25, 14, + 12, 25, 21, + 12, 25, 3, + 12, 26, 7, + 12, 2, 14, + 12, 2, 21, + 12, 2, 3, + 12, 329, 14, + 12, 38, 2, + 12, 599, 14, + 12, 599, 21, + 12, 599, 3, + 12, 90, 14, + 12, 90, 21, + 12, 90, 3, + 13, 198, 11, + 13, 198, 15, + 13, 198, 31, + 13, 24, 11, + 13, 24, 15, + 13, 24, 31, + 13, 25, 11, + 13, 25, 15, + 13, 25, 31, + 13, 2, 11, + 13, 2, 15, + 13, 2, 31, + 13, 57, 13, + 13, 599, 11, + 13, 599, 15, + 13, 599, 31, + 13, 71, 29, + 13, 90, 11, + 13, 90, 15, + 13, 90, 31, + 14, 13, 2, + 14, 198, 10, + 14, 24, 10, + 14, 25, 10, + 14, 26, 12, + 14, 26, 20, + 14, 26, 33, + 14, 26, 35, + 14, 2, 10, + 14, 336, 1, + 14, 45, 29, + 14, 599, 10, + 14, 63, 29, + 14, 90, 10, + 15, 13, 3, + 15, 198, 2, + 15, 198, 29, + 15, 198, 34, + 15, 24, 2, + 15, 24, 29, + 15, 24, 34, + 15, 25, 2, + 15, 25, 29, + 15, 25, 34, + 15, 2, 2, + 15, 2, 29, + 15, 2, 34, + 15, 599, 2, + 15, 599, 29, + 15, 599, 34, + 15, 90, 2, + 15, 90, 29, + 15, 90, 34, + 16, 13, 4, + 16, 13, 6, + 16, 198, 16, + 16, 198, 9, + 16, 1, 10, + 16, 24, 16, + 16, 24, 9, + 16, 25, 16, + 16, 25, 9, + 16, 26, 13, + 16, 26, 23, + 16, 2, 16, + 16, 2, 9, + 16, 599, 16, + 16, 599, 9, + 16, 90, 16, + 16, 90, 9, + 17, 13, 7, + 17, 198, 18, + 17, 24, 18, + 17, 25, 18, + 17, 2, 18, + 17, 599, 18, + 17, 90, 18, + 18, 198, 22, + 18, 198, 32, + 18, 198, 36, + 18, 198, 4, + 18, 24, 22, + 18, 24, 32, + 18, 24, 36, + 18, 24, 4, + 18, 25, 22, + 18, 25, 32, + 18, 25, 36, + 18, 25, 4, + 18, 26, 17, + 18, 26, 19, + 18, 26, 37, + 18, 26, 5, + 18, 26, 8, + 18, 2, 22, + 18, 2, 32, + 18, 2, 36, + 18, 2, 4, + 18, 599, 22, + 18, 599, 32, + 18, 599, 36, + 18, 599, 4, + 18, 90, 22, + 18, 90, 32, + 18, 90, 36, + 18, 90, 4, + 19, 13, 10, + 20, 1254, 30, + 20, 16, 1007, + 20, 26, 26, + 20, 26, 28, + 21, 198, 6, + 21, 24, 6, + 21, 25, 6, + 21, 2, 6, + 21, 599, 6, + 21, 90, 6, + 22, 198, 38, + 22, 22, 40, + 22, 24, 38, + 22, 25, 38, + 22, 26, 27, + 22, 2, 38, + 22, 599, 38, + 22, 90, 38, + 23, 1254, 1160, + 24, 220, 930, + 24, 26, 14, + 24, 26, 21, + 24, 26, 3, + 26, 11, 11, + 26, 1, 13, + 26, 26, 11, + 26, 26, 15, + 26, 26, 31, + 28, 26, 10, + 30, 176, 60, + 30, 26, 2, + 30, 26, 29, + 30, 26, 34, + 32, 26, 16, + 32, 26, 9, + 34, 26, 18, + 36, 26, 22, + 36, 26, 32, + 36, 26, 36, + 36, 26, 4, + 36, 37, 26, + 42, 26, 6, + 43, 115, 29, + 44, 198, 25, + 44, 24, 25, + 44, 25, 25, + 44, 26, 38, + 44, 2, 25, + 44, 599, 25, + 44, 90, 25, + 46, 22, 1, + 47, 198, 30, + 47, 25, 30, + 47, 2, 30, + 47, 599, 30, + 47, 90, 30, + 48, 24, 30, + 52, 176, 30, + 58, 140, 24, + 58, 4, 30, + 63, 990, 29, + 64, 1254, 1, + 88, 26, 25, + 92, 198, 39, + 92, 25, 39, + 92, 2, 39, + 92, 599, 39, + 92, 90, 39, + 93, 24, 39, + 94, 26, 30, + 108, 1254, 1051, + 117, 140, 1, + 119, 160, 1, + 126, 1, 29, + 132, 135, 16, + 147, 72, 16, + 184, 26, 39, + 238, 990, 1, + 376, 11, 1007, + 380, 11, 487, + 1389, 1034, 1007, + 1870, 57, 16, + 4034, 1, 16, + 8521, 198, 40, + 8521, 25, 40, + 8521, 2, 40, + 8521, 599, 40, + 8521, 90, 40, + 8543, 24, 40, + 8883, 13, 13, + 17042, 26, 40, + 17664, 198, 1, + 17664, 25, 1, + 17664, 2, 1, + 17664, 599, 1, + 17664, 90, 1, + 17710, 24, 1, + 35328, 26, 1, +}; + +/// Emulates the mix of rects blitted by gmail during scrolling +class ScrollGmailBench : public Benchmark { + enum { + W = 1254, + H = 1160, + N = 431 + }; +public: + ScrollGmailBench() { } + +protected: + + virtual const char* onGetName() { return "chrome_scrollGmail"; } + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkDEBUGCODE(this->validateBounds(canvas)); + SkPaint paint; + this->setupPaint(&paint); + for (int i = 0; i < N; i++) { + SkRect current; + setRectangle(current, i); + for (int j = 0; j < loops * gmailScrollingRectSpec[i*3]; j++) { + canvas->drawRect(current, paint); + } + } + } + virtual SkIPoint onGetSize() { return SkIPoint::Make(W, H); } + + void setRectangle(SkRect& current, int i) { + current.set(0, 0, + SkIntToScalar(gmailScrollingRectSpec[i*3+1]), SkIntToScalar(gmailScrollingRectSpec[i*3+2])); + } + void validateBounds(SkCanvas* canvas) { + SkIRect bounds; + canvas->getClipDeviceBounds(&bounds); + SkASSERT(bounds.right()-bounds.left() >= W); + SkASSERT(bounds.bottom()-bounds.top() >= H); + } + + +private: + typedef Benchmark INHERITED; +}; + +// Disabled this benchmark: it takes 15x longer than any other benchmark +// and is probably not giving us important information. +// DEF_BENCH(return SkNEW(ScrollGmailBench)); diff --git a/chromium/third_party/skia/bench/CmapBench.cpp b/chromium/third_party/skia/bench/CmapBench.cpp new file mode 100644 index 00000000000..db4ed74951b --- /dev/null +++ b/chromium/third_party/skia/bench/CmapBench.cpp @@ -0,0 +1,102 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkTypeface.h" + +enum { + NGLYPHS = 100 +}; + +static SkTypeface::Encoding paint2Encoding(const SkPaint& paint) { + SkPaint::TextEncoding enc = paint.getTextEncoding(); + SkASSERT(SkPaint::kGlyphID_TextEncoding != enc); + return (SkTypeface::Encoding)enc; +} + +typedef void (*TypefaceProc)(int loops, const SkPaint&, const void* text, size_t len, + int glyphCount); + +static void containsText_proc(int loops, const SkPaint& paint, const void* text, size_t len, + int glyphCount) { + for (int i = 0; i < loops; ++i) { + paint.containsText(text, len); + } +} + +static void textToGlyphs_proc(int loops, const SkPaint& paint, const void* text, size_t len, + int glyphCount) { + uint16_t glyphs[NGLYPHS]; + SkASSERT(glyphCount <= NGLYPHS); + + for (int i = 0; i < loops; ++i) { + paint.textToGlyphs(text, len, glyphs); + } +} + +static void charsToGlyphs_proc(int loops, const SkPaint& paint, const void* text, + size_t len, int glyphCount) { + SkTypeface::Encoding encoding = paint2Encoding(paint); + uint16_t glyphs[NGLYPHS]; + SkASSERT(glyphCount <= NGLYPHS); + + SkTypeface* face = paint.getTypeface(); + for (int i = 0; i < loops; ++i) { + face->charsToGlyphs(text, encoding, glyphs, glyphCount); + } +} + +static void charsToGlyphsNull_proc(int loops, const SkPaint& paint, const void* text, + size_t len, int glyphCount) { + SkTypeface::Encoding encoding = paint2Encoding(paint); + + SkTypeface* face = paint.getTypeface(); + for (int i = 0; i < loops; ++i) { + face->charsToGlyphs(text, encoding, NULL, glyphCount); + } +} + +class CMAPBench : public Benchmark { + TypefaceProc fProc; + SkString fName; + char fText[NGLYPHS]; + SkPaint fPaint; + +public: + CMAPBench(TypefaceProc proc, const char name[]) { + fProc = proc; + fName.printf("cmap_%s", name); + + for (int i = 0; i < NGLYPHS; ++i) { + // we're jamming values into utf8, so we must keep it legal utf8 + fText[i] = 'A' + (i & 31); + } + fPaint.setTypeface(SkTypeface::RefDefault())->unref(); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + fProc(loops, fPaint, fText, sizeof(fText), NGLYPHS); + } + +private: + + typedef Benchmark INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new CMAPBench(containsText_proc, "paint_containsText"); ) +DEF_BENCH( return new CMAPBench(textToGlyphs_proc, "paint_textToGlyphs"); ) +DEF_BENCH( return new CMAPBench(charsToGlyphs_proc, "face_charsToGlyphs"); ) +DEF_BENCH( return new CMAPBench(charsToGlyphsNull_proc, "face_charsToGlyphs_null"); ) diff --git a/chromium/third_party/skia/bench/ColorFilterBench.cpp b/chromium/third_party/skia/bench/ColorFilterBench.cpp new file mode 100644 index 00000000000..7eae21aa757 --- /dev/null +++ b/chromium/third_party/skia/bench/ColorFilterBench.cpp @@ -0,0 +1,367 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkColorFilterImageFilter.h" +#include "SkColorMatrixFilter.h" +#include "SkLumaColorFilter.h" +#include "SkTableColorFilter.h" + +#define FILTER_WIDTH_SMALL SkIntToScalar(32) +#define FILTER_HEIGHT_SMALL SkIntToScalar(32) +#define FILTER_WIDTH_LARGE SkIntToScalar(256) +#define FILTER_HEIGHT_LARGE SkIntToScalar(256) + +class ColorFilterBaseBench : public Benchmark { + +public: + ColorFilterBaseBench(bool small) : fIsSmall(small) { } + +protected: + SkRect getFilterRect() const { + return isSmall() ? SkRect::MakeWH(FILTER_WIDTH_SMALL, FILTER_HEIGHT_SMALL) : + SkRect::MakeWH(FILTER_WIDTH_LARGE, FILTER_HEIGHT_LARGE); + } + + static SkImageFilter* make_brightness(float amount, SkImageFilter* input = NULL) { + SkScalar amount255 = SkScalarMul(amount, SkIntToScalar(255)); + SkScalar matrix[20] = { 1, 0, 0, 0, amount255, + 0, 1, 0, 0, amount255, + 0, 0, 1, 0, amount255, + 0, 0, 0, 1, 0 }; + SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix)); + return SkColorFilterImageFilter::Create(filter, input); + } + + static SkImageFilter* make_grayscale(SkImageFilter* input = NULL) { + SkScalar matrix[20]; + memset(matrix, 0, 20 * sizeof(SkScalar)); + matrix[0] = matrix[5] = matrix[10] = 0.2126f; + matrix[1] = matrix[6] = matrix[11] = 0.7152f; + matrix[2] = matrix[7] = matrix[12] = 0.0722f; + matrix[18] = 1.0f; + SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix)); + return SkColorFilterImageFilter::Create(filter, input); + } + + static SkImageFilter* make_mode_blue(SkImageFilter* input = NULL) { + SkAutoTUnref<SkColorFilter> filter( + SkColorFilter::CreateModeFilter(SK_ColorBLUE, SkXfermode::kSrcIn_Mode)); + return SkColorFilterImageFilter::Create(filter, input); + } + + inline bool isSmall() const { return fIsSmall; } +private: + bool fIsSmall; + + typedef Benchmark INHERITED; +}; + +class ColorFilterDimBrightBench : public ColorFilterBaseBench { + +public: + ColorFilterDimBrightBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_dim_bright_small" : "colorfilter_dim_bright_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + + for (int i = 0; i < loops; i++) { + for (float brightness = -1.0f; brightness <= 1.0f; brightness += 0.4f) { + SkAutoTUnref<SkImageFilter> dim(make_brightness(-brightness)); + SkAutoTUnref<SkImageFilter> bright(make_brightness(brightness, dim)); + paint.setImageFilter(bright); + canvas->drawRect(r, paint); + } + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class ColorFilterBrightGrayBench : public ColorFilterBaseBench { + +public: + ColorFilterBrightGrayBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_bright_gray_small" : "colorfilter_bright_gray_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkImageFilter> brightness(make_brightness(0.9f)); + SkAutoTUnref<SkImageFilter> grayscale(make_grayscale(brightness)); + paint.setImageFilter(grayscale); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class ColorFilterGrayBrightBench : public ColorFilterBaseBench { + +public: + ColorFilterGrayBrightBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_gray_bright_small" : "colorfilter_gray_bright_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkImageFilter> grayscale(make_grayscale()); + SkAutoTUnref<SkImageFilter> brightness(make_brightness(0.9f, grayscale)); + paint.setImageFilter(brightness); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class ColorFilterBlueBrightBench : public ColorFilterBaseBench { + +public: + ColorFilterBlueBrightBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_blue_bright_small" : "colorfilter_blue_bright_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkImageFilter> blue(make_mode_blue()); + SkAutoTUnref<SkImageFilter> brightness(make_brightness(1.0f, blue)); + paint.setImageFilter(brightness); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class ColorFilterBrightBlueBench : public ColorFilterBaseBench { + +public: + ColorFilterBrightBlueBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_bright_blue_small" : "colorfilter_bright_blue_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkImageFilter> brightness(make_brightness(1.0f)); + SkAutoTUnref<SkImageFilter> blue(make_mode_blue(brightness)); + paint.setImageFilter(blue); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class ColorFilterBrightBench : public ColorFilterBaseBench { + +public: + ColorFilterBrightBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_bright_small" : "colorfilter_bright_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkImageFilter> brightness(make_brightness(1.0f)); + paint.setImageFilter(brightness); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class ColorFilterBlueBench : public ColorFilterBaseBench { + +public: + ColorFilterBlueBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_blue_small" : "colorfilter_blue_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkImageFilter> blue(make_mode_blue()); + paint.setImageFilter(blue); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class ColorFilterGrayBench : public ColorFilterBaseBench { + +public: + ColorFilterGrayBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "colorfilter_gray_small" : "colorfilter_gray_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkImageFilter> grayscale(make_grayscale()); + paint.setImageFilter(grayscale); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +class TableColorFilterBench : public ColorFilterBaseBench { + +public: + TableColorFilterBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "table_colorfilter_small" : "table_colorfilter_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkColorFilter> table_filter(make_table_filter()); + paint.setColorFilter(table_filter); + canvas->drawRect(r, paint); + } + } + +private: + static void fill_table_data(uint8_t table[]) { + for (int i = 0; i < 256; ++i) { + int n = i >> 5; + table[i] = (n << 5) | (n << 2) | (n >> 1); + } + } + + static SkColorFilter* make_table_filter() { + uint8_t table[256]; fill_table_data(table); + return SkTableColorFilter::Create(table); + } + + typedef ColorFilterBaseBench INHERITED; +}; + +class LumaColorFilterBench : public ColorFilterBaseBench { + +public: + LumaColorFilterBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "luma_colorfilter_small" : "luma_colorfilter_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = getFilterRect(); + SkPaint paint; + paint.setColor(SK_ColorRED); + + for (int i = 0; i < loops; i++) { + SkAutoTUnref<SkColorFilter> luma_filter(SkLumaColorFilter::Create()); + paint.setColorFilter(luma_filter); + canvas->drawRect(r, paint); + } + } + +private: + typedef ColorFilterBaseBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new ColorFilterDimBrightBench(true); ) +DEF_BENCH( return new ColorFilterBrightGrayBench(true); ) +DEF_BENCH( return new ColorFilterGrayBrightBench(true); ) +DEF_BENCH( return new ColorFilterBlueBrightBench(true); ) +DEF_BENCH( return new ColorFilterBrightBlueBench(true); ) +DEF_BENCH( return new ColorFilterBrightBench(true); ) +DEF_BENCH( return new ColorFilterBlueBench(true); ) +DEF_BENCH( return new ColorFilterGrayBench(true); ) +DEF_BENCH( return new TableColorFilterBench(true); ) +DEF_BENCH( return new LumaColorFilterBench(true); ) + +DEF_BENCH( return new ColorFilterDimBrightBench(false); ) +DEF_BENCH( return new ColorFilterBrightGrayBench(false); ) +DEF_BENCH( return new ColorFilterGrayBrightBench(false); ) +DEF_BENCH( return new ColorFilterBlueBrightBench(false); ) +DEF_BENCH( return new ColorFilterBrightBlueBench(false); ) +DEF_BENCH( return new ColorFilterBrightBench(false); ) +DEF_BENCH( return new ColorFilterBlueBench(false); ) +DEF_BENCH( return new ColorFilterGrayBench(false); ) +DEF_BENCH( return new TableColorFilterBench(false); ) +DEF_BENCH( return new LumaColorFilterBench(false); ) diff --git a/chromium/third_party/skia/bench/ColorPrivBench.cpp b/chromium/third_party/skia/bench/ColorPrivBench.cpp new file mode 100644 index 00000000000..01810ed2399 --- /dev/null +++ b/chromium/third_party/skia/bench/ColorPrivBench.cpp @@ -0,0 +1,81 @@ +#include "Benchmark.h" +#include "SkColorPriv.h" +#include "SkRandom.h" +#include "SkString.h" + +template <bool kFast, bool kScale> +class FourByteInterpBench : public Benchmark { +public: + FourByteInterpBench() { + fName.set("four_byte_interp"); + fName.append(kFast ? "_fast" : "_slow"); + fName.append(kScale ? "_255" : "_256"); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual const char* onGetName() SK_OVERRIDE { return fName.c_str(); } + + virtual void onPreDraw() SK_OVERRIDE { + // A handful of random srcs and dsts. + SkRandom rand; + for (int i = 0; i < kInputs; i++) { + fSrcs[i] = SkPreMultiplyColor(rand.nextU()); + fDsts[i] = SkPreMultiplyColor(rand.nextU()); + } + + // We'll exhaustively test all scales instead of using random numbers. + for (int i = 0; i <= 256; i++) { + fScales[i] = i; + } + if (kScale) fScales[256] = 255; // We'll just do 255 twice if we're limited to [0,255]. + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + // We xor results of FourByteInterp into junk to make sure the function runs. + volatile SkPMColor junk = 0; + + for (int loop = 0; loop < loops; loop++) { + for (int i = 0; i < kInputs; i++) { + for (size_t j = 0; j <= 256; j++) { + // Note: we really want to load src and dst here and not outside in the i-loop. + // If we put the loads there, a clever compiler will do the not-insignificant + // work in the FourByteInterps that depends only on src and dst outside this + // loop, so we'd only be benchmarking the back half of those functions that also + // depends on scale. Even here, these must be volatile arrays to prevent that + // clever compiler from hoisting the loads out of the loop on its own. + const SkPMColor src = fSrcs[i]; + const SkPMColor dst = fDsts[i]; + + const unsigned scale = fScales[j]; + + if (kFast && kScale) { + junk ^= SkFastFourByteInterp(src, dst, scale); + } else if (kFast) { + junk ^= SkFastFourByteInterp256(src, dst, scale); + } else if (kScale) { + junk ^= SkFourByteInterp(src, dst, scale); + } else { + junk ^= SkFourByteInterp256(src, dst, scale); + } + } + } + } + } + +private: + SkString fName; + static const int kInputs = 10; // Arbitrary. + volatile unsigned fSrcs[kInputs]; + volatile unsigned fDsts[kInputs]; + unsigned fScales[257]; // We need space for [0, 256]. +}; + +#define COMMA , +DEF_BENCH( return SkNEW(FourByteInterpBench<true COMMA true>); ) +DEF_BENCH( return SkNEW(FourByteInterpBench<true COMMA false>); ) +DEF_BENCH( return SkNEW(FourByteInterpBench<false COMMA true>); ) +DEF_BENCH( return SkNEW(FourByteInterpBench<false COMMA false>); ) +#undef COMMA diff --git a/chromium/third_party/skia/bench/CoverageBench.cpp b/chromium/third_party/skia/bench/CoverageBench.cpp new file mode 100644 index 00000000000..ecb0ee6fa7c --- /dev/null +++ b/chromium/third_party/skia/bench/CoverageBench.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkDraw.h" +#include "SkMatrix.h" +#include "SkPath.h" +#include "SkRasterClip.h" + +class DrawPathBench : public Benchmark { + SkPaint fPaint; + SkString fName; + SkPath fPath; + SkRasterClip fRC; + SkBitmap fBitmap; + SkMatrix fIdentity; + SkDraw fDraw; + bool fDrawCoverage; +public: + DrawPathBench(bool drawCoverage) : fDrawCoverage(drawCoverage) { + fPaint.setAntiAlias(true); + fName.printf("draw_coverage_%s", drawCoverage ? "true" : "false"); + + fPath.moveTo(0, 0); + fPath.quadTo(500, 0, 500, 500); + fPath.quadTo(250, 0, 0, 500); + + fBitmap.allocPixels(SkImageInfo::MakeA8(500, 500)); + + fIdentity.setIdentity(); + fRC.setRect(fPath.getBounds().round()); + + fDraw.fBitmap = &fBitmap; + fDraw.fMatrix = &fIdentity; + fDraw.fClip = &fRC.bwRgn(); + fDraw.fRC = &fRC; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + if (fDrawCoverage) { + for (int i = 0; i < loops; ++i) { + fDraw.drawPathCoverage(fPath, fPaint); + } + } else { + for (int i = 0; i < loops; ++i) { + fDraw.drawPath(fPath, fPaint); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new DrawPathBench(false) ) +DEF_BENCH( return new DrawPathBench(true) ) diff --git a/chromium/third_party/skia/bench/DashBench.cpp b/chromium/third_party/skia/bench/DashBench.cpp new file mode 100644 index 00000000000..f4d09c66f2e --- /dev/null +++ b/chromium/third_party/skia/bench/DashBench.cpp @@ -0,0 +1,489 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkDashPathEffect.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkRandom.h" +#include "SkString.h" +#include "SkTDArray.h" + + +/* + * Cases to consider: + * + * 1. antialiasing on/off (esp. width <= 1) + * 2. strokewidth == 0, 1, 2 + * 3. hline, vline, diagonal, rect, oval + * 4. dots [1,1] ([N,N] where N=strokeWidth?) or arbitrary (e.g. [2,1] or [1,2,3,2]) + */ +static void path_hline(SkPath* path) { + path->moveTo(SkIntToScalar(10), SkIntToScalar(10)); + path->lineTo(SkIntToScalar(600), SkIntToScalar(10)); +} + +class DashBench : public Benchmark { +protected: + SkString fName; + SkTDArray<SkScalar> fIntervals; + int fWidth; + SkPoint fPts[2]; + bool fDoClip; + +public: + DashBench(const SkScalar intervals[], int count, int width, + bool doClip = false) { + fIntervals.append(count, intervals); + for (int i = 0; i < count; ++i) { + fIntervals[i] *= width; + } + fWidth = width; + fName.printf("dash_%d_%s", width, doClip ? "clipped" : "noclip"); + fDoClip = doClip; + + fPts[0].set(SkIntToScalar(10), SkIntToScalar(10)); + fPts[1].set(SkIntToScalar(600), SkIntToScalar(10)); + } + + virtual void makePath(SkPath* path) { + path_hline(path); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + this->setupPaint(&paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SkIntToScalar(fWidth)); + paint.setAntiAlias(false); + + SkPath path; + this->makePath(&path); + + paint.setPathEffect(SkDashPathEffect::Create(fIntervals.begin(), + fIntervals.count(), 0))->unref(); + + if (fDoClip) { + SkRect r = path.getBounds(); + r.inset(-SkIntToScalar(20), -SkIntToScalar(20)); + // now move it so we don't intersect + r.offset(0, r.height() * 3 / 2); + canvas->clipRect(r); + } + + this->handlePath(canvas, path, paint, loops); + } + + virtual void handlePath(SkCanvas* canvas, const SkPath& path, + const SkPaint& paint, int N) { + for (int i = 0; i < N; ++i) { +// canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, paint); + canvas->drawPath(path, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class RectDashBench : public DashBench { +public: + RectDashBench(const SkScalar intervals[], int count, int width) + : INHERITED(intervals, count, width) { + fName.append("_rect"); + } + +protected: + virtual void handlePath(SkCanvas* canvas, const SkPath& path, + const SkPaint& paint, int N) SK_OVERRIDE { + SkPoint pts[2]; + if (!path.isLine(pts) || pts[0].fY != pts[1].fY) { + this->INHERITED::handlePath(canvas, path, paint, N); + } else { + SkRect rect; + rect.fLeft = pts[0].fX; + rect.fTop = pts[0].fY - paint.getStrokeWidth() / 2; + rect.fRight = rect.fLeft + SkIntToScalar(fWidth); + rect.fBottom = rect.fTop + paint.getStrokeWidth(); + + SkPaint p(paint); + p.setStyle(SkPaint::kFill_Style); + p.setPathEffect(NULL); + + int count = SkScalarRoundToInt((pts[1].fX - pts[0].fX) / (2*fWidth)); + SkScalar dx = SkIntToScalar(2 * fWidth); + + for (int i = 0; i < N*10; ++i) { + SkRect r = rect; + for (int j = 0; j < count; ++j) { + canvas->drawRect(r, p); + r.offset(dx, 0); + } + } + } + } + +private: + typedef DashBench INHERITED; +}; + +static void make_unit_star(SkPath* path, int n) { + SkScalar rad = -SK_ScalarPI / 2; + const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n; + + path->moveTo(0, -SK_Scalar1); + for (int i = 1; i < n; i++) { + rad += drad; + SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV); + path->lineTo(cosV, sinV); + } + path->close(); +} + +static void make_poly(SkPath* path) { + make_unit_star(path, 9); + SkMatrix matrix; + matrix.setScale(SkIntToScalar(100), SkIntToScalar(100)); + path->transform(matrix); +} + +static void make_quad(SkPath* path) { + SkScalar x0 = SkIntToScalar(10); + SkScalar y0 = SkIntToScalar(10); + path->moveTo(x0, y0); + path->quadTo(x0, y0 + 400 * SK_Scalar1, + x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1); +} + +static void make_cubic(SkPath* path) { + SkScalar x0 = SkIntToScalar(10); + SkScalar y0 = SkIntToScalar(10); + path->moveTo(x0, y0); + path->cubicTo(x0, y0 + 400 * SK_Scalar1, + x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1, + x0 + 600 * SK_Scalar1, y0); +} + +class MakeDashBench : public Benchmark { + SkString fName; + SkPath fPath; + SkAutoTUnref<SkPathEffect> fPE; + +public: + MakeDashBench(void (*proc)(SkPath*), const char name[]) { + fName.printf("makedash_%s", name); + proc(&fPath); + + SkScalar vals[] = { SkIntToScalar(4), SkIntToScalar(4) }; + fPE.reset(SkDashPathEffect::Create(vals, 2, 0)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkPath dst; + for (int i = 0; i < loops; ++i) { + SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle); + + fPE->filterPath(&dst, fPath, &rec, NULL); + dst.rewind(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/* + * We try to special case square dashes (intervals are equal to strokewidth). + */ +class DashLineBench : public Benchmark { + SkString fName; + SkScalar fStrokeWidth; + bool fIsRound; + SkAutoTUnref<SkPathEffect> fPE; + +public: + DashLineBench(SkScalar width, bool isRound) { + fName.printf("dashline_%g_%s", SkScalarToFloat(width), isRound ? "circle" : "square"); + fStrokeWidth = width; + fIsRound = isRound; + + SkScalar vals[] = { SK_Scalar1, SK_Scalar1 }; + fPE.reset(SkDashPathEffect::Create(vals, 2, 0)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + this->setupPaint(&paint); + paint.setStrokeWidth(fStrokeWidth); + paint.setStrokeCap(fIsRound ? SkPaint::kRound_Cap : SkPaint::kSquare_Cap); + paint.setPathEffect(fPE); + for (int i = 0; i < loops; ++i) { + canvas->drawLine(10 * SK_Scalar1, 10 * SK_Scalar1, + 640 * SK_Scalar1, 10 * SK_Scalar1, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class DrawPointsDashingBench : public Benchmark { + SkString fName; + int fStrokeWidth; + bool fDoAA; + + SkAutoTUnref<SkPathEffect> fPathEffect; + +public: + DrawPointsDashingBench(int dashLength, int strokeWidth, bool doAA) + { + fName.printf("drawpointsdash_%d_%d%s", dashLength, strokeWidth, doAA ? "_aa" : "_bw"); + fStrokeWidth = strokeWidth; + fDoAA = doAA; + + SkScalar vals[] = { SkIntToScalar(dashLength), SkIntToScalar(dashLength) }; + fPathEffect.reset(SkDashPathEffect::Create(vals, 2, SK_Scalar1)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint p; + this->setupPaint(&p); + p.setColor(SK_ColorBLACK); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(fStrokeWidth)); + p.setPathEffect(fPathEffect); + p.setAntiAlias(fDoAA); + + SkPoint pts[2] = { + { SkIntToScalar(10), 0 }, + { SkIntToScalar(640), 0 } + }; + + for (int i = 0; i < loops; ++i) { + pts[0].fY = pts[1].fY = SkIntToScalar(i % 480); + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p); + } + } + +private: + typedef Benchmark INHERITED; +}; + +// Want to test how we handle dashing when 99% of the dash is clipped out +class GiantDashBench : public Benchmark { + SkString fName; + SkScalar fStrokeWidth; + SkPoint fPts[2]; + SkAutoTUnref<SkPathEffect> fPathEffect; + +public: + enum LineType { + kHori_LineType, + kVert_LineType, + kDiag_LineType, + kLineTypeCount + }; + + static const char* LineTypeName(LineType lt) { + static const char* gNames[] = { "hori", "vert", "diag" }; + SK_COMPILE_ASSERT(kLineTypeCount == SK_ARRAY_COUNT(gNames), names_wrong_size); + return gNames[lt]; + } + + GiantDashBench(LineType lt, SkScalar width) { + fName.printf("giantdashline_%s_%g", LineTypeName(lt), width); + fStrokeWidth = width; + + // deliberately pick intervals that won't be caught by asPoints(), so + // we can test the filterPath code-path. + const SkScalar intervals[] = { 20, 10, 10, 10 }; + fPathEffect.reset(SkDashPathEffect::Create(intervals, + SK_ARRAY_COUNT(intervals), 0)); + + SkScalar cx = 640 / 2; // center X + SkScalar cy = 480 / 2; // center Y + SkMatrix matrix; + + switch (lt) { + case kHori_LineType: + matrix.setIdentity(); + break; + case kVert_LineType: + matrix.setRotate(90, cx, cy); + break; + case kDiag_LineType: + matrix.setRotate(45, cx, cy); + break; + case kLineTypeCount: + // Not a real enum value. + break; + } + + const SkScalar overshoot = 100*1000; + const SkPoint pts[2] = { + { -overshoot, cy }, { 640 + overshoot, cy } + }; + matrix.mapPoints(fPts, pts, 2); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint p; + this->setupPaint(&p); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(fStrokeWidth); + p.setPathEffect(fPathEffect); + + for (int i = 0; i < loops; i++) { + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, p); + } + } + +private: + typedef Benchmark INHERITED; +}; + +// Want to test how we draw a dashed grid (like what is used in spreadsheets) of many +// small dashed lines switching back and forth between horizontal and vertical +class DashGridBench : public Benchmark { + SkString fName; + int fStrokeWidth; + bool fDoAA; + + SkAutoTUnref<SkPathEffect> fPathEffect; + +public: + DashGridBench(int dashLength, int strokeWidth, bool doAA) { + fName.printf("dashgrid_%d_%d%s", dashLength, strokeWidth, doAA ? "_aa" : "_bw"); + fStrokeWidth = strokeWidth; + fDoAA = doAA; + + SkScalar vals[] = { SkIntToScalar(dashLength), SkIntToScalar(dashLength) }; + fPathEffect.reset(SkDashPathEffect::Create(vals, 2, SK_Scalar1)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint p; + this->setupPaint(&p); + p.setColor(SK_ColorBLACK); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(fStrokeWidth)); + p.setPathEffect(fPathEffect); + p.setAntiAlias(fDoAA); + + SkPoint pts[4] = { + { SkIntToScalar(0), 20.5f }, + { SkIntToScalar(20), 20.5f }, + { 20.5f, SkIntToScalar(0) }, + { 20.5f, SkIntToScalar(20) } + }; + + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < 10; ++j) { + for (int k = 0; k < 10; ++k) { + // Horizontal line + SkPoint horPts[2]; + horPts[0].fX = pts[0].fX + k * 22.f; + horPts[0].fY = pts[0].fY + j * 22.f; + horPts[1].fX = pts[1].fX + k * 22.f; + horPts[1].fY = pts[1].fY + j * 22.f; + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, horPts, p); + + // Vertical line + SkPoint vertPts[2]; + vertPts[0].fX = pts[2].fX + k * 22.f; + vertPts[0].fY = pts[2].fY + j * 22.f; + vertPts[1].fX = pts[3].fX + k * 22.f; + vertPts[1].fY = pts[3].fY + j * 22.f; + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, vertPts, p); + } + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static const SkScalar gDots[] = { SK_Scalar1, SK_Scalar1 }; + +#define PARAM(array) array, SK_ARRAY_COUNT(array) + +DEF_BENCH( return new DashBench(PARAM(gDots), 0); ) +DEF_BENCH( return new DashBench(PARAM(gDots), 1); ) +DEF_BENCH( return new DashBench(PARAM(gDots), 1, true); ) +DEF_BENCH( return new DashBench(PARAM(gDots), 4); ) +DEF_BENCH( return new MakeDashBench(make_poly, "poly"); ) +DEF_BENCH( return new MakeDashBench(make_quad, "quad"); ) +DEF_BENCH( return new MakeDashBench(make_cubic, "cubic"); ) +DEF_BENCH( return new DashLineBench(0, false); ) +DEF_BENCH( return new DashLineBench(SK_Scalar1, false); ) +DEF_BENCH( return new DashLineBench(2 * SK_Scalar1, false); ) +DEF_BENCH( return new DashLineBench(0, true); ) +DEF_BENCH( return new DashLineBench(SK_Scalar1, true); ) +DEF_BENCH( return new DashLineBench(2 * SK_Scalar1, true); ) + +DEF_BENCH( return new DrawPointsDashingBench(1, 1, false); ) +DEF_BENCH( return new DrawPointsDashingBench(1, 1, true); ) +DEF_BENCH( return new DrawPointsDashingBench(3, 1, false); ) +DEF_BENCH( return new DrawPointsDashingBench(3, 1, true); ) +DEF_BENCH( return new DrawPointsDashingBench(5, 5, false); ) +DEF_BENCH( return new DrawPointsDashingBench(5, 5, true); ) + +/* Disable the GiantDashBench for Android devices until we can better control + * the memory usage. (https://code.google.com/p/skia/issues/detail?id=1430) + */ +#ifndef SK_BUILD_FOR_ANDROID +DEF_BENCH( return new GiantDashBench(GiantDashBench::kHori_LineType, 0); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kVert_LineType, 0); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kDiag_LineType, 0); ) + +// pass 2 to explicitly avoid any 1-is-the-same-as-hairline special casing + +// hori_2 is just too slow to enable at the moment +DEF_BENCH( return new GiantDashBench(GiantDashBench::kHori_LineType, 2); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kVert_LineType, 2); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kDiag_LineType, 2); ) + +DEF_BENCH( return new DashGridBench(1, 1, true); ) +DEF_BENCH( return new DashGridBench(1, 1, false); ) +DEF_BENCH( return new DashGridBench(3, 1, true); ) +DEF_BENCH( return new DashGridBench(3, 1, false); ) +#endif diff --git a/chromium/third_party/skia/bench/DecodeBench.cpp b/chromium/third_party/skia/bench/DecodeBench.cpp new file mode 100644 index 00000000000..a4717f8eb7f --- /dev/null +++ b/chromium/third_party/skia/bench/DecodeBench.cpp @@ -0,0 +1,50 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCommandLineFlags.h" +#include "SkImageDecoder.h" +#include "SkOSFile.h" +#include "SkString.h" +#include "sk_tool_utils.h" + +DEFINE_string(decodeBenchFilename, "resources/CMYK.jpeg", "Path to image for DecodeBench."); + +class DecodeBench : public Benchmark { + const SkColorType fPrefColorType; + SkString fName; +public: + DecodeBench(SkColorType ct) : fPrefColorType(ct) { + SkString fname = SkOSPath::SkBasename(FLAGS_decodeBenchFilename[0]); + fName.printf("decode_%s_%s", sk_tool_utils::colortype_name(ct), fname.c_str()); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; i++) { + SkBitmap bm; + SkImageDecoder::DecodeFile(FLAGS_decodeBenchFilename[0], &bm, fPrefColorType, + SkImageDecoder::kDecodePixels_Mode); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new DecodeBench(kN32_SkColorType); ) +DEF_BENCH( return new DecodeBench(kRGB_565_SkColorType); ) +DEF_BENCH( return new DecodeBench(kARGB_4444_SkColorType); ) diff --git a/chromium/third_party/skia/bench/DeferredCanvasBench.cpp b/chromium/third_party/skia/bench/DeferredCanvasBench.cpp new file mode 100644 index 00000000000..667895c22f7 --- /dev/null +++ b/chromium/third_party/skia/bench/DeferredCanvasBench.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkDeferredCanvas.h" +#include "SkDevice.h" +#include "SkString.h" + +class DeferredCanvasBench : public Benchmark { +public: + DeferredCanvasBench(const char name[]) { + fName.printf("deferred_canvas_%s", name); + } + + enum { + CANVAS_WIDTH = 200, + CANVAS_HEIGHT = 200, + }; +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { +#if 0 // what specifically are we interested in timing here? + SkBaseDevice *device = canvas->getDevice()->createCompatibleDevice( + SkBitmap::kARGB_8888_Config, CANVAS_WIDTH, CANVAS_HEIGHT, false); + + SkAutoTUnref<SkDeferredCanvas> deferredCanvas(SkDeferredCanvas::Create(device)); + device->unref(); + + initDeferredCanvas(deferredCanvas); + drawInDeferredCanvas(loops, deferredCanvas); + finalizeDeferredCanvas(deferredCanvas); + deferredCanvas->flush(); +#endif + } + + virtual void initDeferredCanvas(SkDeferredCanvas* canvas) = 0; + virtual void drawInDeferredCanvas(const int loops, SkDeferredCanvas* canvas) = 0; + virtual void finalizeDeferredCanvas(SkDeferredCanvas* canvas) = 0; + + SkString fName; + +private: + typedef Benchmark INHERITED; +}; + +class SimpleNotificationClient : public SkDeferredCanvas::NotificationClient { +public: + SimpleNotificationClient() : fDummy(false) {} + + //bogus virtual implementations that just do something small + virtual void prepareForDraw() SK_OVERRIDE {fDummy = true;} + virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {fDummy = false;} + virtual void flushedDrawCommands() SK_OVERRIDE {fDummy = !fDummy;} +private: + bool fDummy; + + typedef SkDeferredCanvas::NotificationClient INHERITED; +}; + +// Test that records very simple draw operations. +// This benchmark aims to capture performance fluctuations in the recording +// overhead of SkDeferredCanvas +class DeferredRecordBench : public DeferredCanvasBench { +public: + DeferredRecordBench() + : INHERITED("record") { + } + +protected: + + virtual void initDeferredCanvas(SkDeferredCanvas* canvas) SK_OVERRIDE { + canvas->setNotificationClient(&fNotificationClient); + } + + virtual void drawInDeferredCanvas(const int loops, SkDeferredCanvas* canvas) SK_OVERRIDE { + SkRect rect; + rect.setXYWH(0, 0, 10, 10); + SkPaint paint; + for (int i = 0; i < loops; i++) { + canvas->save(); + canvas->translate(SkIntToScalar(i * 27 % CANVAS_WIDTH), SkIntToScalar(i * 13 % CANVAS_HEIGHT)); + canvas->drawRect(rect, paint); + canvas->restore(); + } + } + + virtual void finalizeDeferredCanvas(SkDeferredCanvas* canvas) SK_OVERRIDE { + canvas->clear(0x0); + canvas->setNotificationClient(NULL); + } + +private: + typedef DeferredCanvasBench INHERITED; + SimpleNotificationClient fNotificationClient; +}; + + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new DeferredRecordBench(); ) diff --git a/chromium/third_party/skia/bench/DeferredSurfaceCopyBench.cpp b/chromium/third_party/skia/bench/DeferredSurfaceCopyBench.cpp new file mode 100644 index 00000000000..f4002b87be4 --- /dev/null +++ b/chromium/third_party/skia/bench/DeferredSurfaceCopyBench.cpp @@ -0,0 +1,82 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkDeferredCanvas.h" +#include "SkDevice.h" +#include "SkImage.h" +#include "SkSurface.h" +#if SK_SUPPORT_GPU +#include "GrRenderTarget.h" +#endif + +class DeferredSurfaceCopyBench : public Benchmark { + enum { + kSurfaceWidth = 1000, + kSurfaceHeight = 1000, + }; +public: + DeferredSurfaceCopyBench(bool discardableContents) { + fDiscardableContents = discardableContents; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fDiscardableContents ? "DeferredSurfaceCopy_discardable" : + "DeferredSurfaceCopy_nonDiscardable"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + // The canvas is not actually used for this test except to provide + // configuration information: gpu, multisampling, size, etc? + SkImageInfo info; + info.fWidth = kSurfaceWidth; + info.fHeight = kSurfaceHeight; + info.fColorType = kN32_SkColorType; + info.fAlphaType = kPremul_SkAlphaType; + const SkRect fullCanvasRect = SkRect::MakeWH( + SkIntToScalar(kSurfaceWidth), SkIntToScalar(kSurfaceHeight)); + SkSurface* surface; +#if SK_SUPPORT_GPU + GrRenderTarget* rt = reinterpret_cast<GrRenderTarget*>( + canvas->getDevice()->accessRenderTarget()); + if (NULL != rt) { + surface = SkSurface::NewRenderTarget(rt->getContext(), info, rt->numSamples()); + } else +#endif + { + surface = SkSurface::NewRaster(info); + } + SkAutoTUnref<SkDeferredCanvas> drawingCanvas(SkDeferredCanvas::Create(surface)); + surface->unref(); + + for (int iteration = 0; iteration < loops; iteration++) { + drawingCanvas->clear(0); + SkAutoTUnref<SkImage> image(drawingCanvas->newImageSnapshot()); + SkPaint paint; + if (!fDiscardableContents) { + // If paint is not opaque, prior canvas contents are + // not discardable because they are needed for compositing. + paint.setAlpha(127); + } + drawingCanvas->drawRect(fullCanvasRect, paint); + // Trigger copy on write, which should be faster in the discardable case. + drawingCanvas->flush(); + } + } + +private: + bool fDiscardableContents; + + typedef Benchmark INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new DeferredSurfaceCopyBench(false); ) +DEF_BENCH( return new DeferredSurfaceCopyBench(true); ) diff --git a/chromium/third_party/skia/bench/DisplacementBench.cpp b/chromium/third_party/skia/bench/DisplacementBench.cpp new file mode 100644 index 00000000000..881ba33b246 --- /dev/null +++ b/chromium/third_party/skia/bench/DisplacementBench.cpp @@ -0,0 +1,174 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmapDevice.h" +#include "SkBitmapSource.h" +#include "SkCanvas.h" +#include "SkDisplacementMapEffect.h" + +#define FILTER_WIDTH_SMALL 32 +#define FILTER_HEIGHT_SMALL 32 +#define FILTER_WIDTH_LARGE 256 +#define FILTER_HEIGHT_LARGE 256 + +class DisplacementBaseBench : public Benchmark { +public: + DisplacementBaseBench(bool small) : + fInitialized(false), fIsSmall(small) { + } + +protected: + virtual void onPreDraw() SK_OVERRIDE { + if (!fInitialized) { + this->makeBitmap(); + this->makeCheckerboard(); + fInitialized = true; + } + } + + void makeBitmap() { + const int w = this->isSmall() ? FILTER_WIDTH_SMALL : FILTER_WIDTH_LARGE; + const int h = this->isSmall() ? FILTER_HEIGHT_LARGE : FILTER_HEIGHT_LARGE; + fBitmap.allocN32Pixels(w, h); + SkCanvas canvas(fBitmap); + canvas.clear(0x00000000); + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(0xFF884422); + paint.setTextSize(SkIntToScalar(96)); + const char* str = "g"; + canvas.drawText(str, strlen(str), SkIntToScalar(15), SkIntToScalar(55), paint); + } + + void makeCheckerboard() { + const int w = this->isSmall() ? FILTER_WIDTH_SMALL : FILTER_WIDTH_LARGE; + const int h = this->isSmall() ? FILTER_HEIGHT_LARGE : FILTER_HEIGHT_LARGE; + fCheckerboard.allocN32Pixels(w, h); + SkCanvas canvas(fCheckerboard); + canvas.clear(0x00000000); + SkPaint darkPaint; + darkPaint.setColor(0xFF804020); + SkPaint lightPaint; + lightPaint.setColor(0xFF244484); + for (int y = 0; y < h; y += 16) { + for (int x = 0; x < w; x += 16) { + canvas.save(); + canvas.translate(SkIntToScalar(x), SkIntToScalar(y)); + canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint); + canvas.restore(); + } + } + } + + void drawClippedBitmap(SkCanvas* canvas, int x, int y, const SkPaint& paint) { + canvas->save(); + canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), + SkIntToScalar(fBitmap.width()), + SkIntToScalar(fBitmap.height()))); + canvas->drawBitmap(fBitmap, SkIntToScalar(x), SkIntToScalar(y), &paint); + canvas->restore(); + } + + inline bool isSmall() const { return fIsSmall; } + + SkBitmap fBitmap, fCheckerboard; +private: + bool fInitialized; + bool fIsSmall; + typedef Benchmark INHERITED; +}; + +class DisplacementZeroBench : public DisplacementBaseBench { +public: + DisplacementZeroBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return this->isSmall() ? "displacement_zero_small" : "displacement_zero_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + SkAutoTUnref<SkImageFilter> displ(SkBitmapSource::Create(fCheckerboard)); + // No displacement effect + paint.setImageFilter(SkDisplacementMapEffect::Create( + SkDisplacementMapEffect::kR_ChannelSelectorType, + SkDisplacementMapEffect::kG_ChannelSelectorType, 0.0f, displ))->unref(); + + for (int i = 0; i < loops; i++) { + this->drawClippedBitmap(canvas, 0, 0, paint); + } + } + +private: + typedef DisplacementBaseBench INHERITED; +}; + +class DisplacementAlphaBench : public DisplacementBaseBench { +public: + DisplacementAlphaBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "displacement_alpha_small" : "displacement_alpha_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + SkAutoTUnref<SkImageFilter> displ(SkBitmapSource::Create(fCheckerboard)); + // Displacement, with 1 alpha component (which isn't pre-multiplied) + paint.setImageFilter(SkDisplacementMapEffect::Create( + SkDisplacementMapEffect::kB_ChannelSelectorType, + SkDisplacementMapEffect::kA_ChannelSelectorType, 16.0f, displ))->unref(); + for (int i = 0; i < loops; i++) { + drawClippedBitmap(canvas, 100, 0, paint); + } + } + +private: + typedef DisplacementBaseBench INHERITED; +}; + +class DisplacementFullBench : public DisplacementBaseBench { +public: + DisplacementFullBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return isSmall() ? "displacement_full_small" : "displacement_full_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + SkAutoTUnref<SkImageFilter> displ(SkBitmapSource::Create(fCheckerboard)); + // Displacement, with 2 non-alpha components + paint.setImageFilter(SkDisplacementMapEffect::Create( + SkDisplacementMapEffect::kR_ChannelSelectorType, + SkDisplacementMapEffect::kB_ChannelSelectorType, 32.0f, displ))->unref(); + for (int i = 0; i < loops; ++i) { + this->drawClippedBitmap(canvas, 200, 0, paint); + } + } + +private: + typedef DisplacementBaseBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new DisplacementZeroBench(true); ) +DEF_BENCH( return new DisplacementAlphaBench(true); ) +DEF_BENCH( return new DisplacementFullBench(true); ) +DEF_BENCH( return new DisplacementZeroBench(false); ) +DEF_BENCH( return new DisplacementAlphaBench(false); ) +DEF_BENCH( return new DisplacementFullBench(false); ) diff --git a/chromium/third_party/skia/bench/ETCBitmapBench.cpp b/chromium/third_party/skia/bench/ETCBitmapBench.cpp new file mode 100644 index 00000000000..aaa2ce7a660 --- /dev/null +++ b/chromium/third_party/skia/bench/ETCBitmapBench.cpp @@ -0,0 +1,235 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "Resources.h" +#include "SkCanvas.h" +#include "SkData.h" +#include "SkDecodingImageGenerator.h" +#include "SkImageDecoder.h" +#include "SkOSFile.h" +#include "SkPixelRef.h" + +#ifndef SK_IGNORE_ETC1_SUPPORT + +#include "etc1.h" + +// This takes the etc1 data pointed to by orig, and copies it `factor` times in each +// dimension. The return value is the new data or NULL on error. +static etc1_byte* create_expanded_etc1_bitmap(const uint8_t* orig, int factor) { + SkASSERT(NULL != orig); + SkASSERT(factor > 1); + + const etc1_byte* origData = reinterpret_cast<const etc1_byte*>(orig); + if (!etc1_pkm_is_valid(orig)) { + return NULL; + } + + etc1_uint32 origWidth = etc1_pkm_get_width(origData); + etc1_uint32 origHeight = etc1_pkm_get_height(origData); + + // The width and height must be aligned along block boundaries + static const etc1_uint32 kETC1BlockWidth = 4; + static const etc1_uint32 kETC1BlockHeight = 4; + if ((origWidth % kETC1BlockWidth) != 0 || + (origHeight % kETC1BlockHeight) != 0) { + return NULL; + } + + // The picture must be at least as large as a block. + if (origWidth <= kETC1BlockWidth || origHeight <= kETC1BlockHeight) { + return NULL; + } + + etc1_uint32 newWidth = origWidth * factor; + etc1_uint32 newHeight = origHeight * factor; + + etc1_uint32 newDataSz = etc1_get_encoded_data_size(newWidth, newHeight); + etc1_byte* newData = reinterpret_cast<etc1_byte *>( + sk_malloc_throw(newDataSz + ETC_PKM_HEADER_SIZE)); + etc1_pkm_format_header(newData, newWidth, newHeight); + + etc1_byte* copyInto = newData; + + copyInto += ETC_PKM_HEADER_SIZE; + origData += ETC_PKM_HEADER_SIZE; + + etc1_uint32 origBlocksX = (origWidth >> 2); + etc1_uint32 origBlocksY = (origHeight >> 2); + etc1_uint32 newBlocksY = (newHeight >> 2); + etc1_uint32 origRowSzInBytes = origBlocksX * ETC1_ENCODED_BLOCK_SIZE; + + for (etc1_uint32 j = 0; j < newBlocksY; ++j) { + const etc1_byte* rowStart = origData + ((j % origBlocksY) * origRowSzInBytes); + for(etc1_uint32 i = 0; i < newWidth; i += origWidth) { + memcpy(copyInto, rowStart, origRowSzInBytes); + copyInto += origRowSzInBytes; + } + } + return newData; +} + +// This is the base class for all of the benches in this file. In general +// the ETC1 benches should all be working on the same data. Due to the +// simplicity of the PKM file, that data is the 128x128 mandrill etc1 +// compressed texture repeated by some factor (currently 8 -> 1024x1024) +class ETCBitmapBenchBase : public Benchmark { +public: + ETCBitmapBenchBase() : fPKMData(loadPKM()) { + if (NULL == fPKMData) { + SkDebugf("Could not load PKM data!"); + } + } + +protected: + SkAutoDataUnref fPKMData; + +private: + SkData *loadPKM() { + SkString resourcePath = GetResourcePath(); + SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), + "mandrill_128.pkm"); + + // Expand the data + SkAutoDataUnref fileData(SkData::NewFromFileName(filename.c_str())); + if (NULL == fileData) { + SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n"); + return NULL; + } + + const etc1_uint32 kExpansionFactor = 8; + etc1_byte* expandedETC1 = + create_expanded_etc1_bitmap(fileData->bytes(), kExpansionFactor); + if (NULL == expandedETC1) { + SkDebugf("Error expanding ETC1 data by factor of %d\n", kExpansionFactor); + return NULL; + } + + etc1_uint32 width = etc1_pkm_get_width(expandedETC1); + etc1_uint32 height = etc1_pkm_get_width(expandedETC1); + etc1_uint32 dataSz = ETC_PKM_HEADER_SIZE + etc1_get_encoded_data_size(width, height); + return SkData::NewFromMalloc(expandedETC1, dataSz); + } + + typedef Benchmark INHERITED; +}; + +// This is the rendering benchmark. Prior to rendering the data, create a +// bitmap using the etc1 data. +class ETCBitmapBench : public ETCBitmapBenchBase { +public: + ETCBitmapBench(bool decompress, Backend backend) + : fDecompress(decompress), fBackend(backend) { } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == this->fBackend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + if (kGPU_Backend == this->fBackend) { + if (this->fDecompress) { + return "etc1bitmap_render_gpu_decompressed"; + } else { + return "etc1bitmap_render_gpu_compressed"; + } + } else { + SkASSERT(kRaster_Backend == this->fBackend); + if (this->fDecompress) { + return "etc1bitmap_render_raster_decompressed"; + } else { + return "etc1bitmap_render_raster_compressed"; + } + } + } + + virtual void onPreDraw() SK_OVERRIDE { + if (NULL == fPKMData) { + SkDebugf("Failed to load PKM data!\n"); + return; + } + + // Install pixel ref + if (!SkInstallDiscardablePixelRef( + SkDecodingImageGenerator::Create( + fPKMData, SkDecodingImageGenerator::Options()), &(this->fBitmap))) { + SkDebugf("Could not install discardable pixel ref.\n"); + return; + } + + // Decompress it if necessary + if (this->fDecompress) { + this->fBitmap.lockPixels(); + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + canvas->drawBitmap(this->fBitmap, 0, 0, NULL); + } + } + +protected: + SkBitmap fBitmap; + bool decompress() const { return fDecompress; } + Backend backend() const { return fBackend; } +private: + const bool fDecompress; + const Backend fBackend; + typedef ETCBitmapBenchBase INHERITED; +}; + +// This benchmark is identical to the previous benchmark, but it explicitly forces +// an upload to the GPU before each draw call. We do this by notifying the bitmap +// that the pixels have changed (even though they haven't). +class ETCBitmapUploadBench : public ETCBitmapBench { +public: + ETCBitmapUploadBench(bool decompress, Backend backend) + : ETCBitmapBench(decompress, backend) { } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + if (kGPU_Backend == this->backend()) { + if (this->decompress()) { + return "etc1bitmap_upload_gpu_decompressed"; + } else { + return "etc1bitmap_upload_gpu_compressed"; + } + } else { + SkASSERT(kRaster_Backend == this->backend()); + if (this->decompress()) { + return "etc1bitmap_upload_raster_decompressed"; + } else { + return "etc1bitmap_upload_raster_compressed"; + } + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + this->fBitmap.pixelRef()->notifyPixelsChanged(); + canvas->drawBitmap(this->fBitmap, 0, 0, NULL); + } + } + +private: + typedef ETCBitmapBench INHERITED; +}; + +DEF_BENCH(return new ETCBitmapBench(false, Benchmark::kRaster_Backend);) +DEF_BENCH(return new ETCBitmapBench(true, Benchmark::kRaster_Backend);) + +DEF_BENCH(return new ETCBitmapBench(false, Benchmark::kGPU_Backend);) +DEF_BENCH(return new ETCBitmapBench(true, Benchmark::kGPU_Backend);) + +DEF_BENCH(return new ETCBitmapUploadBench(false, Benchmark::kRaster_Backend);) +DEF_BENCH(return new ETCBitmapUploadBench(true, Benchmark::kRaster_Backend);) + +DEF_BENCH(return new ETCBitmapUploadBench(false, Benchmark::kGPU_Backend);) +DEF_BENCH(return new ETCBitmapUploadBench(true, Benchmark::kGPU_Backend);) + +#endif // SK_IGNORE_ETC1_SUPPORT diff --git a/chromium/third_party/skia/bench/FSRectBench.cpp b/chromium/third_party/skia/bench/FSRectBench.cpp new file mode 100644 index 00000000000..3c5304294d1 --- /dev/null +++ b/chromium/third_party/skia/bench/FSRectBench.cpp @@ -0,0 +1,63 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" + +/** + * Draws full screen opaque rectangles. It is designed to test any optimizations in the GPU backend + * to turn such draws into clears. + */ +class FSRectBench : public Benchmark { +public: + FSRectBench() : fInit(false) { } + +protected: + virtual const char* onGetName() SK_OVERRIDE { return "fullscreen_rects"; } + + virtual void onPreDraw() SK_OVERRIDE { + if (!fInit) { + SkRandom rand; + static const SkScalar kMinOffset = 0; + static const SkScalar kMaxOffset = 100 * SK_Scalar1; + static const SkScalar kOffsetRange = kMaxOffset - kMinOffset; + for (int i = 0; i < N; ++i) { + fRects[i].fLeft = -kMinOffset - SkScalarMul(rand.nextUScalar1(), kOffsetRange); + fRects[i].fTop = -kMinOffset - SkScalarMul(rand.nextUScalar1(), kOffsetRange); + fRects[i].fRight = W + kMinOffset + SkScalarMul(rand.nextUScalar1(), kOffsetRange); + fRects[i].fBottom = H + kMinOffset + SkScalarMul(rand.nextUScalar1(), kOffsetRange); + fColors[i] = rand.nextU() | 0xFF000000; + } + fInit = true; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + for (int i = 0; i < loops; ++i) { + paint.setColor(fColors[i % N]); + canvas->drawRect(fRects[i % N], paint); + } + } + +private: + enum { + W = 640, + H = 480, + N = 300, + }; + SkRect fRects[N]; + SkColor fColors[N]; + bool fInit; + + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return SkNEW_ARGS(FSRectBench, ()); ) diff --git a/chromium/third_party/skia/bench/FontCacheBench.cpp b/chromium/third_party/skia/bench/FontCacheBench.cpp new file mode 100644 index 00000000000..0e75c9cb174 --- /dev/null +++ b/chromium/third_party/skia/bench/FontCacheBench.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkFontHost.h" +#include "SkPaint.h" +#include "SkString.h" +#include "SkTemplates.h" + +#include "gUniqueGlyphIDs.h" +#define gUniqueGlyphIDs_Sentinel 0xFFFF + +static int count_glyphs(const uint16_t start[]) { + const uint16_t* curr = start; + while (*curr != gUniqueGlyphIDs_Sentinel) { + curr += 1; + } + return static_cast<int>(curr - start); +} + +class FontCacheBench : public Benchmark { +public: + FontCacheBench() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "fontcache"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + this->setupPaint(&paint); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + + const uint16_t* array = gUniqueGlyphIDs; + while (*array != gUniqueGlyphIDs_Sentinel) { + int count = count_glyphs(array); + for (int i = 0; i < loops; ++i) { + paint.measureText(array, count * sizeof(uint16_t)); + } + array += count + 1; // skip the sentinel + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static uint32_t rotr(uint32_t value, unsigned bits) { + return (value >> bits) | (value << (32 - bits)); +} + +typedef uint32_t (*HasherProc)(uint32_t); + +static uint32_t hasher0(uint32_t value) { + value = value ^ (value >> 16); + return value ^ (value >> 8); +} + +static uint32_t hasher2(uint32_t h) { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + h ^= (h >> 8); + return h; +} + +static const struct { + const char* fName; + HasherProc fHasher; +} gRec[] = { + { "hasher0", hasher0 }, + { "hasher2", hasher2 }, +}; + +#define kMaxHashBits 12 +#define kMaxHashCount (1 << kMaxHashBits) + +static int count_collisions(const uint16_t array[], int count, HasherProc proc, + unsigned hashMask) { + char table[kMaxHashCount]; + sk_bzero(table, sizeof(table)); + + int collisions = 0; + for (int i = 0; i < count; ++i) { + int index = proc(array[i]) & hashMask; + collisions += table[index]; + table[index] = 1; + } + return collisions; +} + +static void dump_array(const uint16_t array[], int count) { + for (int i = 0; i < count; ++i) { + SkDebugf(" %d,", array[i]); + } + SkDebugf("\n"); +} + +class FontCacheEfficiency : public Benchmark { +public: + FontCacheEfficiency() { + if (false) dump_array(NULL, 0); + if (false) rotr(0, 0); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "fontefficiency"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + static bool gDone; + if (gDone) { + return; + } + gDone = true; + + for (int hashBits = 6; hashBits <= 12; hashBits += 1) { + int hashMask = ((1 << hashBits) - 1); + for (int limit = 32; limit <= 1024; limit <<= 1) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { + int collisions = 0; + int glyphs = 0; + const uint16_t* array = gUniqueGlyphIDs; + while (*array != gUniqueGlyphIDs_Sentinel) { + int count = SkMin32(count_glyphs(array), limit); + collisions += count_collisions(array, count, gRec[i].fHasher, hashMask); + glyphs += count; + array += count + 1; // skip the sentinel + } + SkDebugf("hashBits [%d] limit [%d] collisions [%d / %d = %1.2g%%] using %s\n", hashBits, limit, collisions, glyphs, + collisions * 100.0 / glyphs, gRec[i].fName); + } + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new FontCacheBench(); ) + +// undefine this to run the efficiency test +//DEF_BENCH( return new FontCacheEfficiency(); ) diff --git a/chromium/third_party/skia/bench/FontScalerBench.cpp b/chromium/third_party/skia/bench/FontScalerBench.cpp new file mode 100644 index 00000000000..0326a0cce6a --- /dev/null +++ b/chromium/third_party/skia/bench/FontScalerBench.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkGraphics.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" + +class FontScalerBench : public Benchmark { + SkString fName; + SkString fText; + bool fDoLCD; +public: + FontScalerBench(bool doLCD) { + fName.printf("fontscaler_%s", doLCD ? "lcd" : "aa"); + fText.set("abcdefghijklmnopqrstuvwxyz01234567890"); + fDoLCD = doLCD; + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + paint.setLCDRenderText(fDoLCD); + + for (int i = 0; i < loops; i++) { + // this is critical - we want to time the creation process, so we + // explicitly flush our cache before each run + SkGraphics::PurgeFontCache(); + + for (int ps = 9; ps <= 24; ps += 2) { + paint.setTextSize(SkIntToScalar(ps)); + canvas->drawText(fText.c_str(), fText.size(), + 0, SkIntToScalar(20), paint); + } + } + } +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return SkNEW_ARGS(FontScalerBench, (false)); ) +DEF_BENCH( return SkNEW_ARGS(FontScalerBench, (true)); ) diff --git a/chromium/third_party/skia/bench/GMBench.cpp b/chromium/third_party/skia/bench/GMBench.cpp new file mode 100644 index 00000000000..41a8e8c5f4c --- /dev/null +++ b/chromium/third_party/skia/bench/GMBench.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GMBench.h" + +GMBench::GMBench(skiagm::GM* gm) : fGM(gm) { + fName.printf("GM:%s", gm->getName()); +} + +GMBench::~GMBench() { delete fGM; } + +const char* GMBench::onGetName() { + return fName.c_str(); +} + +bool GMBench::isSuitableFor(Backend backend) { + uint32_t flags = fGM->getFlags(); + switch (backend) { + case kGPU_Backend: + return !(skiagm::GM::kSkipGPU_Flag & flags); + case kPDF_Backend: + return !(skiagm::GM::kSkipPDF_Flag & flags); + case kRaster_Backend: + // GM doesn't have an equivalent flag. If the GM has known issues with 565 then + // we skip it for ALL raster configs in bench. + return !(skiagm::GM::kSkip565_Flag & flags); + case kNonRendering_Backend: + return false; + default: + SkDEBUGFAIL("Unexpected backend type."); + return false; + } +} + +void GMBench::onDraw(const int loops, SkCanvas* canvas) { + // Do we care about timing the draw of the background (once)? + // Does the GM ever rely on drawBackground to lazily compute something? + fGM->drawBackground(canvas); + for (int i = 0; i < loops; ++i) { + fGM->drawContent(canvas); + } +} + +SkIPoint GMBench::onGetSize() { + SkISize size = fGM->getISize(); + return SkIPoint::Make(size.fWidth, size.fHeight); +} diff --git a/chromium/third_party/skia/bench/GMBench.h b/chromium/third_party/skia/bench/GMBench.h new file mode 100644 index 00000000000..75cee6c0639 --- /dev/null +++ b/chromium/third_party/skia/bench/GMBench.h @@ -0,0 +1,31 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "gm.h" + +/** + * Runs a GM as a benchmark by repeatedly drawing the GM. + */ +class GMBench : public Benchmark { +public: + // Constructor takes ownership of the GM param. + GMBench(skiagm::GM* gm); + virtual ~GMBench(); + +protected: + virtual const char* onGetName() SK_OVERRIDE; + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE; + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE; + virtual SkIPoint onGetSize() SK_OVERRIDE; + +private: + skiagm::GM* fGM; + SkString fName; + typedef Benchmark INHERITED; +}; diff --git a/chromium/third_party/skia/bench/GameBench.cpp b/chromium/third_party/skia/bench/GameBench.cpp new file mode 100644 index 00000000000..c37f46df302 --- /dev/null +++ b/chromium/third_party/skia/bench/GameBench.cpp @@ -0,0 +1,334 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +// This bench simulates the calls Skia sees from various HTML5 canvas +// game bench marks +class GameBench : public Benchmark { +public: + enum Type { + kScale_Type, + kTranslate_Type, + kRotate_Type + }; + + enum Clear { + kFull_Clear, + kPartial_Clear + }; + + GameBench(Type type, Clear clear, + bool aligned = false, bool useAtlas = false, + bool useDrawVertices = false) + : fType(type) + , fClear(clear) + , fAligned(aligned) + , fUseAtlas(useAtlas) + , fUseDrawVertices(useDrawVertices) + , fName("game") + , fNumSaved(0) + , fInitialized(false) { + + switch (fType) { + case kScale_Type: + fName.append("_scale"); + break; + case kTranslate_Type: + fName.append("_trans"); + break; + case kRotate_Type: + fName.append("_rot"); + break; + }; + + if (aligned) { + fName.append("_aligned"); + } + + if (kPartial_Clear == clear) { + fName.append("_partial"); + } else { + fName.append("_full"); + } + + if (useAtlas) { + fName.append("_atlas"); + } + + if (useDrawVertices) { + fName.append("_drawVerts"); + } + + // It's HTML 5 canvas, so always AA + fName.append("_aa"); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + if (!fInitialized) { + this->makeCheckerboard(); + this->makeAtlas(); + fInitialized = true; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom scaleRand; + SkRandom transRand; + SkRandom rotRand; + + int width, height; + if (fUseAtlas) { + width = kAtlasCellWidth; + height = kAtlasCellHeight; + } else { + width = kCheckerboardWidth; + height = kCheckerboardHeight; + } + + SkPaint clearPaint; + clearPaint.setColor(0xFF000000); + clearPaint.setAntiAlias(true); + + SkISize size = canvas->getDeviceSize(); + + SkScalar maxTransX, maxTransY; + + if (kScale_Type == fType) { + maxTransX = size.fWidth - (1.5f * width); + maxTransY = size.fHeight - (1.5f * height); + } else if (kTranslate_Type == fType) { + maxTransX = SkIntToScalar(size.fWidth - width); + maxTransY = SkIntToScalar(size.fHeight - height); + } else { + SkASSERT(kRotate_Type == fType); + // Yes, some rotations will be off the top and left sides + maxTransX = size.fWidth - SK_ScalarSqrt2 * height; + maxTransY = size.fHeight - SK_ScalarSqrt2 * height; + } + + SkMatrix mat; + SkRect dst = { 0, 0, SkIntToScalar(width), SkIntToScalar(height) }; + SkRect clearRect = { -1.0f, -1.0f, width+1.0f, height+1.0f }; + SkPoint verts[4] = { // for drawVertices path + { 0, 0 }, + { 0, SkIntToScalar(height) }, + { SkIntToScalar(width), SkIntToScalar(height) }, + { SkIntToScalar(width), 0 } + }; + uint16_t indices[6] = { 0, 1, 2, 0, 2, 3 }; + + SkPaint p; + p.setColor(0xFF000000); + p.setFilterLevel(SkPaint::kLow_FilterLevel); + + SkPaint p2; // for drawVertices path + p2.setColor(0xFF000000); + p2.setFilterLevel(SkPaint::kLow_FilterLevel); + p2.setShader(SkShader::CreateBitmapShader(fAtlas, + SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode))->unref(); + + for (int i = 0; i < loops; ++i, ++fNumSaved) { + if (0 == i % kNumBeforeClear) { + if (kPartial_Clear == fClear) { + for (int j = 0; j < fNumSaved; ++j) { + canvas->setMatrix(SkMatrix::I()); + mat.setTranslate(fSaved[j][0], fSaved[j][1]); + + if (kScale_Type == fType) { + mat.preScale(fSaved[j][2], fSaved[j][2]); + } else if (kRotate_Type == fType) { + mat.preRotate(fSaved[j][2]); + } + + canvas->concat(mat); + canvas->drawRect(clearRect, clearPaint); + } + } else { + canvas->clear(0xFF000000); + } + + fNumSaved = 0; + } + + SkASSERT(fNumSaved < kNumBeforeClear); + + canvas->setMatrix(SkMatrix::I()); + + fSaved[fNumSaved][0] = transRand.nextRangeScalar(0.0f, maxTransX); + fSaved[fNumSaved][1] = transRand.nextRangeScalar(0.0f, maxTransY); + if (fAligned) { + // make the translations integer aligned + fSaved[fNumSaved][0] = SkScalarFloorToScalar(fSaved[fNumSaved][0]); + fSaved[fNumSaved][1] = SkScalarFloorToScalar(fSaved[fNumSaved][1]); + } + + mat.setTranslate(fSaved[fNumSaved][0], fSaved[fNumSaved][1]); + + if (kScale_Type == fType) { + fSaved[fNumSaved][2] = scaleRand.nextRangeScalar(0.5f, 1.5f); + mat.preScale(fSaved[fNumSaved][2], fSaved[fNumSaved][2]); + } else if (kRotate_Type == fType) { + fSaved[fNumSaved][2] = rotRand.nextRangeScalar(0.0f, 360.0f); + mat.preRotate(fSaved[fNumSaved][2]); + } + + canvas->concat(mat); + if (fUseAtlas) { + const int curCell = i % (kNumAtlasedX * kNumAtlasedY); + SkIRect src = fAtlasRects[curCell % (kNumAtlasedX)][curCell / (kNumAtlasedX)]; + + if (fUseDrawVertices) { + SkPoint uvs[4] = { + { SkIntToScalar(src.fLeft), SkIntToScalar(src.fBottom) }, + { SkIntToScalar(src.fLeft), SkIntToScalar(src.fTop) }, + { SkIntToScalar(src.fRight), SkIntToScalar(src.fTop) }, + { SkIntToScalar(src.fRight), SkIntToScalar(src.fBottom) }, + }; + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, + 4, verts, uvs, NULL, NULL, + indices, 6, p2); + } else { + canvas->drawBitmapRect(fAtlas, &src, dst, &p, + SkCanvas::kBleed_DrawBitmapRectFlag); + } + } else { + canvas->drawBitmapRect(fCheckerboard, NULL, dst, &p); + } + } + } + +private: + static const int kCheckerboardWidth = 64; + static const int kCheckerboardHeight = 128; + + static const int kAtlasCellWidth = 48; + static const int kAtlasCellHeight = 36; + static const int kNumAtlasedX = 5; + static const int kNumAtlasedY = 5; + static const int kAtlasSpacer = 2; + static const int kTotAtlasWidth = kNumAtlasedX * kAtlasCellWidth + + (kNumAtlasedX+1) * kAtlasSpacer; + static const int kTotAtlasHeight = kNumAtlasedY * kAtlasCellHeight + + (kNumAtlasedY+1) * kAtlasSpacer; + static const int kNumBeforeClear = 100; + + Type fType; + Clear fClear; + bool fAligned; + bool fUseAtlas; + bool fUseDrawVertices; + SkString fName; + int fNumSaved; // num draws stored in 'fSaved' + bool fInitialized; + + // 0 & 1 are always x & y translate. 2 is either scale or rotate. + SkScalar fSaved[kNumBeforeClear][3]; + + SkBitmap fCheckerboard; + SkBitmap fAtlas; + SkIRect fAtlasRects[kNumAtlasedX][kNumAtlasedY]; + + // Note: the resulting checker board has transparency + void makeCheckerboard() { + static int kCheckSize = 16; + + fCheckerboard.allocN32Pixels(kCheckerboardWidth, kCheckerboardHeight); + SkAutoLockPixels lock(fCheckerboard); + for (int y = 0; y < kCheckerboardHeight; ++y) { + int even = (y / kCheckSize) % 2; + + SkPMColor* scanline = fCheckerboard.getAddr32(0, y); + + for (int x = 0; x < kCheckerboardWidth; ++x) { + if (even == (x / kCheckSize) % 2) { + *scanline++ = 0xFFFF0000; + } else { + *scanline++ = 0x00000000; + } + } + } + } + + // Note: the resulting atlas has transparency + void makeAtlas() { + SkRandom rand; + + SkColor colors[kNumAtlasedX][kNumAtlasedY]; + + for (int y = 0; y < kNumAtlasedY; ++y) { + for (int x = 0; x < kNumAtlasedX; ++x) { + colors[x][y] = rand.nextU() | 0xff000000; + fAtlasRects[x][y] = SkIRect::MakeXYWH(kAtlasSpacer + x * (kAtlasCellWidth + kAtlasSpacer), + kAtlasSpacer + y * (kAtlasCellHeight + kAtlasSpacer), + kAtlasCellWidth, + kAtlasCellHeight); + } + } + + fAtlas.allocN32Pixels(kTotAtlasWidth, kTotAtlasHeight); + SkAutoLockPixels lock(fAtlas); + + for (int y = 0; y < kTotAtlasHeight; ++y) { + int colorY = y / (kAtlasCellHeight + kAtlasSpacer); + bool inColorY = (y % (kAtlasCellHeight + kAtlasSpacer)) >= kAtlasSpacer; + + SkPMColor* scanline = fAtlas.getAddr32(0, y); + + for (int x = 0; x < kTotAtlasWidth; ++x, ++scanline) { + int colorX = x / (kAtlasCellWidth + kAtlasSpacer); + bool inColorX = (x % (kAtlasCellWidth + kAtlasSpacer)) >= kAtlasSpacer; + + if (inColorX && inColorY) { + SkASSERT(colorX < kNumAtlasedX && colorY < kNumAtlasedY); + *scanline = colors[colorX][colorY]; + } else { + *scanline = 0x00000000; + } + } + } + } + + typedef Benchmark INHERITED; +}; + +// Partial clear +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kScale_Type, + GameBench::kPartial_Clear)); ) +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type, + GameBench::kPartial_Clear)); ) +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type, + GameBench::kPartial_Clear, true)); ) +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kRotate_Type, + GameBench::kPartial_Clear)); ) + +// Full clear +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kScale_Type, + GameBench::kFull_Clear)); ) +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type, + GameBench::kFull_Clear)); ) +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type, + GameBench::kFull_Clear, true)); ) +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kRotate_Type, + GameBench::kFull_Clear)); ) + +// Atlased +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type, + GameBench::kFull_Clear, false, true)); ) +DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type, + GameBench::kFull_Clear, false, true, true)); ) diff --git a/chromium/third_party/skia/bench/GrMemoryPoolBench.cpp b/chromium/third_party/skia/bench/GrMemoryPoolBench.cpp new file mode 100644 index 00000000000..6e6a37e76c8 --- /dev/null +++ b/chromium/third_party/skia/bench/GrMemoryPoolBench.cpp @@ -0,0 +1,178 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// This tests a Gr class +#if SK_SUPPORT_GPU + +#include "Benchmark.h" +#include "GrMemoryPool.h" +#include "SkRandom.h" +#include "SkTDArray.h" +#include "SkTemplates.h" + +// change this to 0 to compare GrMemoryPool to default new / delete +#define OVERRIDE_NEW 1 + +struct A { + int gStuff[10]; +#if OVERRIDE_NEW + void* operator new (size_t size) { return gBenchPool.allocate(size); } + void operator delete (void* mem) { if (mem) { return gBenchPool.release(mem); } } +#endif + static GrMemoryPool gBenchPool; +}; +GrMemoryPool A::gBenchPool(10 * (1 << 10), 10 * (1 << 10)); + +/** + * This benchmark creates and deletes objects in stack order + */ +class GrMemoryPoolBenchStack : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "grmemorypool_stack"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + SkRandom r; + enum { + kMaxObjects = 4 * (1 << 10), + }; + A* objects[kMaxObjects]; + + // We delete if a random [-1, 1] fixed pt is < the thresh. Otherwise, + // we allocate. We start allocate-biased and ping-pong to delete-biased + SkFixed delThresh = -SK_FixedHalf; + const int kSwitchThreshPeriod = loops / (2 * kMaxObjects); + int s = 0; + + int count = 0; + for (int i = 0; i < loops; i++, ++s) { + if (kSwitchThreshPeriod == s) { + delThresh = -delThresh; + s = 0; + } + SkFixed del = r.nextSFixed1(); + if (count && + (kMaxObjects == count || del < delThresh)) { + delete objects[count-1]; + --count; + } else { + objects[count] = new A; + ++count; + } + } + for (int i = 0; i < count; ++i) { + delete objects[i]; + } + } + +private: + typedef Benchmark INHERITED; +}; + +struct B { + int gStuff[10]; +#if OVERRIDE_NEW + void* operator new (size_t size) { return gBenchPool.allocate(size); } + void operator delete (void* mem) { if (mem) { return gBenchPool.release(mem); } } +#endif + static GrMemoryPool gBenchPool; +}; +GrMemoryPool B::gBenchPool(10 * (1 << 10), 10 * (1 << 10)); + +/** + * This benchmark creates objects and deletes them in random order + */ +class GrMemoryPoolBenchRandom : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "grmemorypool_random"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + SkRandom r; + enum { + kMaxObjects = 4 * (1 << 10), + }; + SkAutoTDelete<B> objects[kMaxObjects]; + + for (int i = 0; i < loops; i++) { + uint32_t idx = r.nextRangeU(0, kMaxObjects-1); + if (NULL == objects[idx].get()) { + objects[idx].reset(new B); + } else { + objects[idx].free(); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +struct C { + int gStuff[10]; +#if OVERRIDE_NEW + void* operator new (size_t size) { return gBenchPool.allocate(size); } + void operator delete (void* mem) { if (mem) { return gBenchPool.release(mem); } } +#endif + static GrMemoryPool gBenchPool; +}; +GrMemoryPool C::gBenchPool(10 * (1 << 10), 10 * (1 << 10)); + +/** + * This benchmark creates objects and deletes them in queue order + */ +class GrMemoryPoolBenchQueue : public Benchmark { + enum { + M = 4 * (1 << 10), + }; +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "grmemorypool_queue"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + SkRandom r; + C* objects[M]; + for (int i = 0; i < loops; i++) { + uint32_t count = r.nextRangeU(0, M-1); + for (uint32_t i = 0; i < count; i++) { + objects[i] = new C; + } + for (uint32_t i = 0; i < count; i++) { + delete objects[i]; + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new GrMemoryPoolBenchStack(); ) +DEF_BENCH( return new GrMemoryPoolBenchRandom(); ) +DEF_BENCH( return new GrMemoryPoolBenchQueue(); ) + +#endif diff --git a/chromium/third_party/skia/bench/GrOrderedSetBench.cpp b/chromium/third_party/skia/bench/GrOrderedSetBench.cpp new file mode 100644 index 00000000000..dde1c4a3f0d --- /dev/null +++ b/chromium/third_party/skia/bench/GrOrderedSetBench.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkRandom.h" +#include "SkString.h" +#if SK_SUPPORT_GPU +#include "GrOrderedSet.h" + +static const int NUM_ELEMENTS = 1000; + +// Time how long it takes to build a set +class GrOrderedSetBuildBench : public Benchmark { +public: + GrOrderedSetBuildBench() { + fName.append("ordered_set_build"); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return kNonRendering_Backend == backend; + } + + virtual ~GrOrderedSetBuildBench() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + SkRandom rand; + for (int j = 0; j < NUM_ELEMENTS; ++j) { + fData[j] = rand.nextU() % NUM_ELEMENTS; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + GrOrderedSet<int> set; + for (int j = 0; j < NUM_ELEMENTS; ++j) { + set.insert(fData[j]); + } + set.reset(); + } + } + +private: + SkString fName; + int fData[NUM_ELEMENTS]; + typedef Benchmark INHERITED; +}; + +// Time how long it takes to find elements in a set +class GrOrderedSetFindBench : public Benchmark { +public: + GrOrderedSetFindBench() { + fName.append("ordered_set_find"); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return kNonRendering_Backend == backend; + } + + virtual ~GrOrderedSetFindBench() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + SkRandom rand; + for (int j = 0; j < NUM_ELEMENTS; ++j) { + fData[j] = rand.nextU() % 1500; + fSet.insert(rand.nextU() % NUM_ELEMENTS); + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < NUM_ELEMENTS; ++j) { + fSet.find(fData[j]); + } + } + } + +private: + SkString fName; + int fData[NUM_ELEMENTS]; + GrOrderedSet<int> fSet; + typedef Benchmark INHERITED; +}; + +// Time how long it takes to iterate over and remove all elements from set +class GrOrderedSetRemoveBench : public Benchmark { +public: + GrOrderedSetRemoveBench() { + fName.append("ordered_set_remove"); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return kNonRendering_Backend == backend; + } + + virtual ~GrOrderedSetRemoveBench() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + SkRandom rand; + for (int j = 0; j < NUM_ELEMENTS; ++j) { + fSet.insert(rand.nextU() % NUM_ELEMENTS); + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + typedef GrOrderedSet<int>::Iter SetIter; + for (int i = 0; i < loops; ++i) { + GrOrderedSet<int> testSet; + for (SetIter s = fSet.begin(); fSet.end() != s; ++s) { + testSet.insert(*s); + } + for (int j = 0; j < NUM_ELEMENTS; ++j) { + testSet.remove(testSet.find(j)); + } + } + } + +private: + SkString fName; + GrOrderedSet<int> fSet; + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH(return SkNEW_ARGS(GrOrderedSetBuildBench, ());) +DEF_BENCH(return SkNEW_ARGS(GrOrderedSetFindBench, ());) +DEF_BENCH(return SkNEW_ARGS(GrOrderedSetRemoveBench, ());) +#endif diff --git a/chromium/third_party/skia/bench/GrResourceCacheBench.cpp b/chromium/third_party/skia/bench/GrResourceCacheBench.cpp new file mode 100644 index 00000000000..93ae356a4c1 --- /dev/null +++ b/chromium/third_party/skia/bench/GrResourceCacheBench.cpp @@ -0,0 +1,239 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#if SK_SUPPORT_GPU + +#include "Benchmark.h" +#include "GrCacheable.h" +#include "GrContext.h" +#include "GrResourceCache.h" +#include "GrStencilBuffer.h" +#include "GrTexture.h" +#include "SkCanvas.h" + +enum { + CACHE_SIZE_COUNT = 2048, + CACHE_SIZE_BYTES = 2 * 1024 * 1024, +}; + +class StencilResource : public GrCacheable { +public: + SK_DECLARE_INST_COUNT(StencilResource); + StencilResource(int id) + : fID(id) { + } + + virtual size_t gpuMemorySize() const SK_OVERRIDE { + return 100 + ((fID % 1 == 0) ? -5 : 6); + } + + virtual bool isValidOnGpu() const SK_OVERRIDE { + return true; + } + + static GrResourceKey ComputeKey(int width, int height, int sampleCnt) { + return GrStencilBuffer::ComputeKey(width, height, sampleCnt); + } + + int fID; + +private: + typedef GrCacheable INHERITED; +}; + +class TextureResource : public GrCacheable { +public: + SK_DECLARE_INST_COUNT(TextureResource); + TextureResource(int id) + : fID(id) { + } + + virtual size_t gpuMemorySize() const SK_OVERRIDE { + return 100 + ((fID % 1 == 0) ? -40 : 33); + } + + virtual bool isValidOnGpu() const SK_OVERRIDE { + return true; + } + + static GrResourceKey ComputeKey(const GrTextureDesc& desc) { + return GrTextureImpl::ComputeScratchKey(desc); + } + + int fID; + +private: + typedef GrCacheable INHERITED; +}; + +static void get_stencil(int i, int* w, int* h, int* s) { + *w = i % 1024; + *h = i * 2 % 1024; + *s = i % 1 == 0 ? 0 : 4; +} + +static void get_texture_desc(int i, GrTextureDesc* desc) { + desc->fFlags = kRenderTarget_GrTextureFlagBit | + kNoStencil_GrTextureFlagBit; + desc->fWidth = i % 1024; + desc->fHeight = i * 2 % 1024; + desc->fConfig = static_cast<GrPixelConfig>(i % (kLast_GrPixelConfig + 1)); + desc->fSampleCnt = i % 1 == 0 ? 0 : 4; +} + +static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount) { + for (int i = 0; i < resourceCount; ++i) { + int w, h, s; + get_stencil(i, &w, &h, &s); + GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s); + GrCacheable* resource = SkNEW_ARGS(StencilResource, (i)); + cache->purgeAsNeeded(1, resource->gpuMemorySize()); + cache->addResource(key, resource); + resource->unref(); + } + + for (int i = 0; i < resourceCount; ++i) { + GrTextureDesc desc; + get_texture_desc(i, &desc); + GrResourceKey key = TextureResource::ComputeKey(desc); + GrCacheable* resource = SkNEW_ARGS(TextureResource, (i)); + cache->purgeAsNeeded(1, resource->gpuMemorySize()); + cache->addResource(key, resource); + resource->unref(); + } +} + +static void check_cache_contents_or_die(GrResourceCache* cache, int k) { + // Benchmark find calls that succeed. + { + GrTextureDesc desc; + get_texture_desc(k, &desc); + GrResourceKey key = TextureResource::ComputeKey(desc); + GrCacheable* item = cache->find(key); + if (NULL == item) { + SkFAIL("cache add does not work as expected"); + return; + } + if (static_cast<TextureResource*>(item)->fID != k) { + SkFAIL("cache add does not work as expected"); + return; + } + } + { + int w, h, s; + get_stencil(k, &w, &h, &s); + GrResourceKey key = StencilResource::ComputeKey(w, h, s); + GrCacheable* item = cache->find(key); + if (NULL == item) { + SkFAIL("cache add does not work as expected"); + return; + } + if (static_cast<TextureResource*>(item)->fID != k) { + SkFAIL("cache add does not work as expected"); + return; + } + } + + // Benchmark also find calls that always fail. + { + GrTextureDesc desc; + get_texture_desc(k, &desc); + desc.fHeight |= 1; + GrResourceKey key = TextureResource::ComputeKey(desc); + GrCacheable* item = cache->find(key); + if (NULL != item) { + SkFAIL("cache add does not work as expected"); + return; + } + } + { + int w, h, s; + get_stencil(k, &w, &h, &s); + h |= 1; + GrResourceKey key = StencilResource::ComputeKey(w, h, s); + GrCacheable* item = cache->find(key); + if (NULL != item) { + SkFAIL("cache add does not work as expected"); + return; + } + } +} + +class GrResourceCacheBenchAdd : public Benchmark { + enum { + RESOURCE_COUNT = CACHE_SIZE_COUNT / 2, + DUPLICATE_COUNT = CACHE_SIZE_COUNT / 4, + }; + +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kGPU_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "grresourcecache_add"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + GrGpu* gpu = canvas->getGrContext()->getGpu(); + + for (int i = 0; i < loops; ++i) { + GrResourceCache cache(CACHE_SIZE_COUNT, CACHE_SIZE_BYTES); + populate_cache(&cache, gpu, DUPLICATE_COUNT); + populate_cache(&cache, gpu, RESOURCE_COUNT); + + // Check that cache works. + for (int k = 0; k < RESOURCE_COUNT; k += 33) { + check_cache_contents_or_die(&cache, k); + } + cache.purgeAllUnlocked(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class GrResourceCacheBenchFind : public Benchmark { + enum { + RESOURCE_COUNT = (CACHE_SIZE_COUNT / 2) - 100, + DUPLICATE_COUNT = 100 + }; + +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kGPU_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "grresourcecache_find"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + GrGpu* gpu = canvas->getGrContext()->getGpu(); + GrResourceCache cache(CACHE_SIZE_COUNT, CACHE_SIZE_BYTES); + populate_cache(&cache, gpu, DUPLICATE_COUNT); + populate_cache(&cache, gpu, RESOURCE_COUNT); + + for (int i = 0; i < loops; ++i) { + for (int k = 0; k < RESOURCE_COUNT; ++k) { + check_cache_contents_or_die(&cache, k); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new GrResourceCacheBenchAdd(); ) +DEF_BENCH( return new GrResourceCacheBenchFind(); ) + +#endif diff --git a/chromium/third_party/skia/bench/GradientBench.cpp b/chromium/third_party/skia/bench/GradientBench.cpp new file mode 100644 index 00000000000..f3e783e78fd --- /dev/null +++ b/chromium/third_party/skia/bench/GradientBench.cpp @@ -0,0 +1,390 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkGradientShader.h" +#include "SkPaint.h" +#include "SkShader.h" +#include "SkString.h" + +struct GradData { + int fCount; + const SkColor* fColors; + const SkScalar* fPos; + const char* fName; +}; + +static const SkColor gColors[] = { + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, // 10 lines, 50 colors +}; + +static const SkColor gShallowColors[] = { 0xFF555555, 0xFF444444 }; + +// We have several special-cases depending on the number (and spacing) of colors, so +// try to exercise those here. +static const GradData gGradData[] = { + { 2, gColors, NULL, "" }, + { 50, gColors, NULL, "_hicolor" }, // many color gradient + { 3, gColors, NULL, "_3color" }, + { 2, gShallowColors, NULL, "_shallow" }, +}; + +/// Ignores scale +static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm); +} + +static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + SkPoint center; + center.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + return SkGradientShader::CreateRadial(center, center.fX * scale, + data.fColors, + data.fPos, data.fCount, tm); +} + +/// Ignores scale +static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + SkPoint center; + center.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, + data.fPos, data.fCount); +} + +/// Ignores scale +static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + SkPoint center0, center1; + center0.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), + SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); + return SkGradientShader::CreateTwoPointRadial( + center1, (pts[1].fX - pts[0].fX) / 7, + center0, (pts[1].fX - pts[0].fX) / 2, + data.fColors, data.fPos, data.fCount, tm); +} + +/// Ignores scale +static SkShader* MakeConical(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + SkPoint center0, center1; + center0.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), + SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); + return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, + center0, (pts[1].fX - pts[0].fX) / 2, + data.fColors, data.fPos, data.fCount, tm); +} + +/// Ignores scale +static SkShader* MakeConicalZeroRad(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + SkPoint center0, center1; + center0.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), + SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); + return SkGradientShader::CreateTwoPointConical(center1, 0.0, + center0, (pts[1].fX - pts[0].fX) / 2, + data.fColors, data.fPos, data.fCount, tm); +} + +/// Ignores scale +static SkShader* MakeConicalOutside(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + SkPoint center0, center1; + SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10); + SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3); + center0.set(pts[0].fX + radius0, pts[0].fY + radius0); + center1.set(pts[1].fX - radius1, pts[1].fY - radius1); + return SkGradientShader::CreateTwoPointConical(center0, radius0, + center1, radius1, + data.fColors, data.fPos, + data.fCount, tm); +} + +/// Ignores scale +static SkShader* MakeConicalOutsideZeroRad(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale) { + SkPoint center0, center1; + SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10); + SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3); + center0.set(pts[0].fX + radius0, pts[0].fY + radius0); + center1.set(pts[1].fX - radius1, pts[1].fY - radius1); + return SkGradientShader::CreateTwoPointConical(center0, 0.0, + center1, radius1, + data.fColors, data.fPos, + data.fCount, tm); +} + +typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, float scale); + +static const struct { + GradMaker fMaker; + const char* fName; +} gGrads[] = { + { MakeLinear, "linear" }, + { MakeRadial, "radial1" }, + { MakeSweep, "sweep" }, + { Make2Radial, "radial2" }, + { MakeConical, "conical" }, + { MakeConicalZeroRad, "conicalZero" }, + { MakeConicalOutside, "conicalOut" }, + { MakeConicalOutsideZeroRad, "conicalOutZero" }, +}; + +enum GradType { // these must match the order in gGrads + kLinear_GradType, + kRadial_GradType, + kSweep_GradType, + kRadial2_GradType, + kConical_GradType, + kConicalZero_GradType, + kConicalOut_GradType, + kConicalOutZero_GradType +}; + +enum GeomType { + kRect_GeomType, + kOval_GeomType +}; + +static const char* tilemodename(SkShader::TileMode tm) { + switch (tm) { + case SkShader::kClamp_TileMode: + return "clamp"; + case SkShader::kRepeat_TileMode: + return "repeat"; + case SkShader::kMirror_TileMode: + return "mirror"; + default: + SkDEBUGFAIL("unknown tilemode"); + return "error"; + } +} + +static const char* geomtypename(GeomType gt) { + switch (gt) { + case kRect_GeomType: + return "rectangle"; + case kOval_GeomType: + return "oval"; + default: + SkDEBUGFAIL("unknown geometry type"); + return "error"; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +class GradientBench : public Benchmark { + SkString fName; + SkShader* fShader; + bool fDither; + enum { + W = 400, + H = 400, + kRepeat = 15, + }; +public: + SkShader* makeShader(GradType gradType, GradData data, SkShader::TileMode tm, float scale) { + const SkPoint pts[2] = { + { 0, 0 }, + { SkIntToScalar(W), SkIntToScalar(H) } + }; + + return gGrads[gradType].fMaker(pts, data, tm, scale); + } + + GradientBench(GradType gradType, + GradData data = gGradData[0], + SkShader::TileMode tm = SkShader::kClamp_TileMode, + GeomType geomType = kRect_GeomType, + float scale = 1.0f) { + fName.printf("gradient_%s_%s", gGrads[gradType].fName, + tilemodename(tm)); + if (geomType != kRect_GeomType) { + fName.append("_"); + fName.append(geomtypename(geomType)); + } + + if (scale != 1.f) { + fName.appendf("_scale_%g", scale); + } + + fName.append(data.fName); + + fDither = false; + fShader = this->makeShader(gradType, data, tm, scale); + fGeomType = geomType; + } + + GradientBench(GradType gradType, GradData data, bool dither) { + const char *tmname = tilemodename(SkShader::kClamp_TileMode); + fName.printf("gradient_%s_%s", gGrads[gradType].fName, tmname); + fName.append(data.fName); + + fDither = dither; + if (dither) { + fName.appendf("_dither"); + } + + fShader = this->makeShader(gradType, data, SkShader::kClamp_TileMode, 1.0f); + fGeomType = kRect_GeomType; + } + + virtual ~GradientBench() { + fShader->unref(); + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + + paint.setShader(fShader); + if (fDither) { + paint.setDither(true); + } + + SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; + for (int i = 0; i < loops * kRepeat; i++) { + switch (fGeomType) { + case kRect_GeomType: + canvas->drawRect(r, paint); + break; + case kOval_GeomType: + canvas->drawOval(r, paint); + break; + } + } + } + +private: + typedef Benchmark INHERITED; + + GeomType fGeomType; +}; + +DEF_BENCH( return new GradientBench(kLinear_GradType); ) +DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); ) +DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); ) + +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); ) +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[2]); ) +// Draw a radial gradient of radius 1/2 on a rectangle; half the lines should +// be completely pinned, the other half should pe partially pinned +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); ) + +// Draw a radial gradient on a circle of equal size; all the lines should +// hit the unpinned fast path (so long as GradientBench.W == H) +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); ) + +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); ) +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kRepeat_TileMode); ) +DEF_BENCH( return new GradientBench(kSweep_GradType); ) +DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); ) +DEF_BENCH( return new GradientBench(kRadial2_GradType); ) +DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[0], SkShader::kMirror_TileMode); ) +DEF_BENCH( return new GradientBench(kConical_GradType); ) +DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); ) +DEF_BENCH( return new GradientBench(kConicalZero_GradType); ) +DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[2]); ) +DEF_BENCH( return new GradientBench(kConicalOut_GradType); ) +DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[2]); ) +DEF_BENCH( return new GradientBench(kConicalOutZero_GradType); ) +DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[1]); ) +DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[2]); ) + +// Dithering +DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], true); ) +DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], false); ) +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], true); ) +DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], false); ) +DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], true); ) +DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], false); ) +DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], true); ) +DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], false); ) + +/////////////////////////////////////////////////////////////////////////////// + +class Gradient2Bench : public Benchmark { + SkString fName; + bool fHasAlpha; + +public: + Gradient2Bench(bool hasAlpha) { + fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque"); + fHasAlpha = hasAlpha; + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + + const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) }; + const SkPoint pts[] = { + { 0, 0 }, + { SkIntToScalar(100), SkIntToScalar(100) }, + }; + + for (int i = 0; i < loops; i++) { + const int gray = i % 256; + const int alpha = fHasAlpha ? gray : 0xFF; + SkColor colors[] = { + SK_ColorBLACK, + SkColorSetARGB(alpha, gray, gray, gray), + SK_ColorWHITE }; + SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, + SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode); + paint.setShader(s)->unref(); + canvas->drawRect(r, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new Gradient2Bench(false); ) +DEF_BENCH( return new Gradient2Bench(true); ) diff --git a/chromium/third_party/skia/bench/HairlinePathBench.cpp b/chromium/third_party/skia/bench/HairlinePathBench.cpp new file mode 100644 index 00000000000..e7e2b428e8f --- /dev/null +++ b/chromium/third_party/skia/bench/HairlinePathBench.cpp @@ -0,0 +1,258 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +#if SK_SUPPORT_GPU +#include "GrDrawTargetCaps.h" +#include "GrTest.h" +#endif + +enum Flags { + kBig_Flag = 1 << 0, + kAA_Flag = 1 << 1 +}; + +#define FLAGS00 Flags(0) +#define FLAGS01 Flags(kBig_Flag) +#define FLAGS10 Flags(kAA_Flag) +#define FLAGS11 Flags(kBig_Flag | kAA_Flag) + +static const int points[] = { + 10, 10, 15, 5, 20, 20, + 30, 5, 25, 20, 15, 12, + 21, 21, 30, 30, 12, 4, + 32, 28, 20, 18, 12, 10 +}; + +static const int kMaxPathSize = 10; + +class HairlinePathBench : public Benchmark { +public: + HairlinePathBench(Flags flags) : fFlags(flags) { + fPaint.setStyle(SkPaint::kStroke_Style); + fPaint.setStrokeWidth(SkIntToScalar(0)); + } + + virtual void appendName(SkString*) = 0; + virtual void makePath(SkPath*) = 0; + +protected: + virtual const char* onGetName() SK_OVERRIDE { + fName.printf("path_hairline_%s_%s_", + fFlags & kBig_Flag ? "big" : "small", + fFlags & kAA_Flag ? "AA" : "noAA"); + this->appendName(&fName); + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint(fPaint); + this->setupPaint(&paint); + + paint.setAntiAlias(fFlags & kAA_Flag ? true : false); + + SkPath path; + this->makePath(&path); + if (fFlags & kBig_Flag) { + SkMatrix m; + m.setScale(SkIntToScalar(3), SkIntToScalar(3)); + path.transform(m); + } + + for (int i = 0; i < loops; i++) { + canvas->drawPath(path, paint); + } + } + +private: + SkPaint fPaint; + SkString fName; + Flags fFlags; + typedef Benchmark INHERITED; +}; + +class LinePathBench : public HairlinePathBench { +public: + LinePathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("line"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRandom rand; + int size = SK_ARRAY_COUNT(points); + int hSize = size / 2; + for (int i = 0; i < kMaxPathSize; ++i) { + int xTrans = 10 + 40 * (i%(kMaxPathSize/2)); + int yTrans = 0; + if (i > kMaxPathSize/2 - 1) { + yTrans = 40; + } + int base1 = 2 * rand.nextULessThan(hSize); + int base2 = 2 * rand.nextULessThan(hSize); + int base3 = 2 * rand.nextULessThan(hSize); + path->moveTo(SkIntToScalar(points[base1] + xTrans), + SkIntToScalar(points[base1+1] + yTrans)); + path->lineTo(SkIntToScalar(points[base2] + xTrans), + SkIntToScalar(points[base2+1] + yTrans)); + path->lineTo(SkIntToScalar(points[base3] + xTrans), + SkIntToScalar(points[base3+1] + yTrans)); + } + } +private: + typedef HairlinePathBench INHERITED; +}; + +class QuadPathBench : public HairlinePathBench { +public: + QuadPathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("quad"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRandom rand; + int size = SK_ARRAY_COUNT(points); + int hSize = size / 2; + for (int i = 0; i < kMaxPathSize; ++i) { + int xTrans = 10 + 40 * (i%(kMaxPathSize/2)); + int yTrans = 0; + if (i > kMaxPathSize/2 - 1) { + yTrans = 40; + } + int base1 = 2 * rand.nextULessThan(hSize); + int base2 = 2 * rand.nextULessThan(hSize); + int base3 = 2 * rand.nextULessThan(hSize); + path->moveTo(SkIntToScalar(points[base1] + xTrans), + SkIntToScalar(points[base1+1] + yTrans)); + path->quadTo(SkIntToScalar(points[base2] + xTrans), + SkIntToScalar(points[base2+1] + yTrans), + SkIntToScalar(points[base3] + xTrans), + SkIntToScalar(points[base3+1] + yTrans)); + } + } +private: + typedef HairlinePathBench INHERITED; +}; + +class ConicPathBench : public HairlinePathBench { +public: + ConicPathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("conic"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRandom rand; + SkRandom randWeight; + int size = SK_ARRAY_COUNT(points); + int hSize = size / 2; + for (int i = 0; i < kMaxPathSize; ++i) { + int xTrans = 10 + 40 * (i%(kMaxPathSize/2)); + int yTrans = 0; + if (i > kMaxPathSize/2 - 1) { + yTrans = 40; + } + int base1 = 2 * rand.nextULessThan(hSize); + int base2 = 2 * rand.nextULessThan(hSize); + int base3 = 2 * rand.nextULessThan(hSize); + float weight = randWeight.nextRangeF(0.0f, 2.0f); + path->moveTo(SkIntToScalar(points[base1] + xTrans), + SkIntToScalar(points[base1+1] + yTrans)); + path->conicTo(SkIntToScalar(points[base2] + xTrans), + SkIntToScalar(points[base2+1] + yTrans), + SkIntToScalar(points[base3] + xTrans), + SkIntToScalar(points[base3+1] + yTrans), + weight); + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { +#if SK_SUPPORT_GPU + GrContext* context = canvas->getGrContext(); + // This is a workaround for skbug.com/2078. See also skbug.com/2033. + if (NULL != context) { + GrTestTarget tt; + context->getTestTarget(&tt); + if (tt.target()->caps()->pathRenderingSupport()) { + return; + } + } +#endif + INHERITED::onDraw(loops, canvas); + } + +private: + typedef HairlinePathBench INHERITED; +}; + +class CubicPathBench : public HairlinePathBench { +public: + CubicPathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("cubic"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRandom rand; + int size = SK_ARRAY_COUNT(points); + int hSize = size / 2; + for (int i = 0; i < kMaxPathSize; ++i) { + int xTrans = 10 + 40 * (i%(kMaxPathSize/2)); + int yTrans = 0; + if (i > kMaxPathSize/2 - 1) { + yTrans = 40; + } + int base1 = 2 * rand.nextULessThan(hSize); + int base2 = 2 * rand.nextULessThan(hSize); + int base3 = 2 * rand.nextULessThan(hSize); + int base4 = 2 * rand.nextULessThan(hSize); + path->moveTo(SkIntToScalar(points[base1] + xTrans), + SkIntToScalar(points[base1+1] + yTrans)); + path->cubicTo(SkIntToScalar(points[base2] + xTrans), + SkIntToScalar(points[base2+1] + yTrans), + SkIntToScalar(points[base3] + xTrans), + SkIntToScalar(points[base3+1] + yTrans), + SkIntToScalar(points[base4] + xTrans), + SkIntToScalar(points[base4+1] + yTrans)); + } + } +private: + typedef HairlinePathBench INHERITED; +}; + +// FLAG00 - no AA, small +// FLAG01 - no AA, small +// FLAG10 - AA, big +// FLAG11 - AA, big + +DEF_BENCH( return new LinePathBench(FLAGS00); ) +DEF_BENCH( return new LinePathBench(FLAGS01); ) +DEF_BENCH( return new LinePathBench(FLAGS10); ) +DEF_BENCH( return new LinePathBench(FLAGS11); ) + +DEF_BENCH( return new QuadPathBench(FLAGS00); ) +DEF_BENCH( return new QuadPathBench(FLAGS01); ) +DEF_BENCH( return new QuadPathBench(FLAGS10); ) +DEF_BENCH( return new QuadPathBench(FLAGS11); ) + +// Don't have default path renderer for conics yet on GPU, so must use AA +// DEF_BENCH( return new ConicPathBench(FLAGS00); ) +// DEF_BENCH( return new ConicPathBench(FLAGS01); ) +DEF_BENCH( return new ConicPathBench(FLAGS10); ) +DEF_BENCH( return new ConicPathBench(FLAGS11); ) + +DEF_BENCH( return new CubicPathBench(FLAGS00); ) +DEF_BENCH( return new CubicPathBench(FLAGS01); ) +DEF_BENCH( return new CubicPathBench(FLAGS10); ) +DEF_BENCH( return new CubicPathBench(FLAGS11); ) diff --git a/chromium/third_party/skia/bench/ImageCacheBench.cpp b/chromium/third_party/skia/bench/ImageCacheBench.cpp new file mode 100644 index 00000000000..5f1715fc318 --- /dev/null +++ b/chromium/third_party/skia/bench/ImageCacheBench.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkScaledImageCache.h" + +class ImageCacheBench : public Benchmark { + SkScaledImageCache fCache; + SkBitmap fBM; + + enum { + DIM = 1, + CACHE_COUNT = 500 + }; +public: + ImageCacheBench() : fCache(CACHE_COUNT * 100) { + fBM.allocN32Pixels(DIM, DIM); + } + + void populateCache() { + SkScalar scale = 1; + for (int i = 0; i < CACHE_COUNT; ++i) { + SkBitmap tmp; + tmp.allocN32Pixels(1, 1); + fCache.unlock(fCache.addAndLock(fBM, scale, scale, tmp)); + scale += 1; + } + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "imagecache"; + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + if (fCache.getBytesUsed() == 0) { + this->populateCache(); + } + + SkBitmap tmp; + // search for a miss (-1 scale) + for (int i = 0; i < loops; ++i) { + (void)fCache.findAndLock(fBM, -1, -1, &tmp); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new ImageCacheBench(); ) diff --git a/chromium/third_party/skia/bench/ImageDecodeBench.cpp b/chromium/third_party/skia/bench/ImageDecodeBench.cpp new file mode 100644 index 00000000000..47993cfa7db --- /dev/null +++ b/chromium/third_party/skia/bench/ImageDecodeBench.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkData.h" +#include "SkForceLinking.h" +#include "SkImageDecoder.h" +#include "SkOSFile.h" +#include "SkStream.h" +#include "SkString.h" + +__SK_FORCE_IMAGE_DECODER_LINKING; + +class SkCanvas; + +class ImageDecodeBench : public Benchmark { +public: + ImageDecodeBench(void* p, const char* filename) + : fName("image_decode_") + , fFilename(filename) + , fStream() + , fValid(false) { + fName.append(SkOSPath::SkBasename(filename)); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + SkFILEStream fileStream(fFilename.c_str()); + fValid = fileStream.isValid() && fileStream.getLength() > 0; + if (fValid) { + const size_t size = fileStream.getLength(); + void* data = sk_malloc_throw(size); + if (fileStream.read(data, size) < size) { + fValid = false; + } else { + SkAutoTUnref<SkData> skdata(SkData::NewFromMalloc(data, size)); + fStream.setData(skdata.get()); + } + } + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { +#ifdef SK_DEBUG + if (!fValid) { + SkDebugf("stream was invalid: %s\n", fName.c_str()); + return; + } +#endif + // Decode a bunch of times + SkBitmap bm; + for (int i = 0; i < loops; ++i) { + SkDEBUGCODE(bool success =) SkImageDecoder::DecodeStream(&fStream, &bm); +#ifdef SK_DEBUG + if (!success) { + SkDebugf("failed to decode %s\n", fName.c_str()); + return; + } +#endif + SkDEBUGCODE(success =) fStream.rewind(); +#ifdef SK_DEBUG + if (!success) { + SkDebugf("failed to rewind %s\n", fName.c_str()); + return; + } +#endif + } + } + +private: + SkString fName; + const SkString fFilename; + SkMemoryStream fStream; + bool fValid; + + typedef Benchmark INHERITED; +}; + +// These are files which call decodePalette +//DEF_BENCH( return SkNEW_ARGS(ImageDecodeBench, ("/usr/local/google/home/scroggo/Downloads/images/hal_163x90.png")); ) +//DEF_BENCH( return SkNEW_ARGS(ImageDecodeBench, ("/usr/local/google/home/scroggo/Downloads/images/box_19_top-left.png")); ) diff --git a/chromium/third_party/skia/bench/ImageFilterDAGBench.cpp b/chromium/third_party/skia/bench/ImageFilterDAGBench.cpp new file mode 100644 index 00000000000..29d1da1a612 --- /dev/null +++ b/chromium/third_party/skia/bench/ImageFilterDAGBench.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBlurImageFilter.h" +#include "SkCanvas.h" +#include "SkMergeImageFilter.h" + +enum { kNumInputs = 5 }; + +// Exercise a blur filter connected to 5 inputs of the same merge filter. +// This bench shows an improvement in performance once cacheing of re-used +// nodes is implemented, since the DAG is no longer flattened to a tree. + +class ImageFilterDAGBench : public Benchmark { +public: + ImageFilterDAGBench() { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "image_filter_dag"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(20.0f, 20.0f)); + SkImageFilter* inputs[kNumInputs]; + for (int i = 0; i < kNumInputs; ++i) { + inputs[i] = blur.get(); + } + SkAutoTUnref<SkImageFilter> merge(SkMergeImageFilter::Create(inputs, kNumInputs)); + SkPaint paint; + paint.setImageFilter(merge); + SkRect rect = SkRect::Make(SkIRect::MakeWH(400, 400)); + canvas->drawRect(rect, paint); + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new ImageFilterDAGBench;) diff --git a/chromium/third_party/skia/bench/InterpBench.cpp b/chromium/third_party/skia/bench/InterpBench.cpp new file mode 100644 index 00000000000..b19af8f35fa --- /dev/null +++ b/chromium/third_party/skia/bench/InterpBench.cpp @@ -0,0 +1,163 @@ +#include "Benchmark.h" +#include "SkColorPriv.h" +#include "SkMatrix.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" + +#define TILE(x, width) (((x) & 0xFFFF) * width >> 16) + +class InterpBench : public Benchmark { + enum { + kBuffer = 128, + kLoop = 20000 + }; + SkString fName; + int16_t fDst[kBuffer]; + float fFx, fDx; +public: + InterpBench(const char name[]) { + fName.printf("interp_%s", name); + fFx = 3.3f; + fDx = 0.1257f; + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void performTest(int16_t dst[], float x, float dx, int count) = 0; + +protected: + virtual int mulLoopCount() const { return 1; } + + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) { + int n = loops * this->mulLoopCount(); + for (int i = 0; i < n; i++) { + this->performTest(fDst, fFx, fDx, kBuffer); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class Fixed16D16Interp : public InterpBench { +public: + Fixed16D16Interp() : INHERITED("16.16") {} + +protected: + virtual void performTest(int16_t dst[], float fx, float dx, int count) SK_OVERRIDE { + SkFixed curr = SkFloatToFixed(fx); + SkFixed step = SkFloatToFixed(dx); + for (int i = 0; i < count; i += 4) { + dst[i + 0] = TILE(curr, count); curr += step; + dst[i + 1] = TILE(curr, count); curr += step; + dst[i + 2] = TILE(curr, count); curr += step; + dst[i + 3] = TILE(curr, count); curr += step; + } + } +private: + typedef InterpBench INHERITED; +}; + +class Fixed32D32Interp : public InterpBench { +public: + Fixed32D32Interp() : INHERITED("32.32") {} + +protected: + virtual void performTest(int16_t dst[], float fx, float dx, int count) SK_OVERRIDE { + int64_t curr = (int64_t)(fx * 65536 * 655536); + int64_t step = (int64_t)(dx * 65536 * 655536); + SkFixed tmp; + for (int i = 0; i < count; i += 4) { + tmp = (SkFixed)(curr >> 16); + dst[i + 0] = TILE(tmp, count); + curr += step; + + tmp = (SkFixed)(curr >> 16); + dst[i + 1] = TILE(tmp, count); + curr += step; + + tmp = (SkFixed)(curr >> 16); + dst[i + 2] = TILE(tmp, count); + curr += step; + + tmp = (SkFixed)(curr >> 16); + dst[i + 3] = TILE(tmp, count); + curr += step; + } + } +private: + typedef InterpBench INHERITED; +}; + +class Fixed16D48Interp : public InterpBench { +public: + Fixed16D48Interp() : INHERITED("16.48") {} + +protected: + virtual void performTest(int16_t dst[], float fx, float dx, int count) SK_OVERRIDE { + int64_t curr = (int64_t)(fx * 65536 * 655536 * 65536); + int64_t step = (int64_t)(dx * 65536 * 655536 * 65536); + SkFixed tmp; + for (int i = 0; i < count; i += 4) { + tmp = (SkFixed) (curr >> 32); dst[i + 0] = TILE(tmp, count); curr += step; + tmp = (SkFixed) (curr >> 32); dst[i + 1] = TILE(tmp, count); curr += step; + tmp = (SkFixed) (curr >> 32); dst[i + 2] = TILE(tmp, count); curr += step; + tmp = (SkFixed) (curr >> 32); dst[i + 3] = TILE(tmp, count); curr += step; + } + } +private: + typedef InterpBench INHERITED; +}; + +class FloatInterp : public InterpBench { +public: + FloatInterp() : INHERITED("float") {} + +protected: + virtual void performTest(int16_t dst[], float fx, float dx, int count) SK_OVERRIDE { + SkFixed tmp; + for (int i = 0; i < count; i += 4) { + tmp = SkFloatToFixed(fx); dst[i + 0] = TILE(tmp, count); fx += dx; + tmp = SkFloatToFixed(fx); dst[i + 1] = TILE(tmp, count); fx += dx; + tmp = SkFloatToFixed(fx); dst[i + 2] = TILE(tmp, count); fx += dx; + tmp = SkFloatToFixed(fx); dst[i + 3] = TILE(tmp, count); fx += dx; + } + } +private: + typedef InterpBench INHERITED; +}; + +class DoubleInterp : public InterpBench { +public: + DoubleInterp() : INHERITED("double") {} + +protected: + virtual void performTest(int16_t dst[], float fx, float dx, int count) SK_OVERRIDE { + double ffx = fx; + double ddx = dx; + SkFixed tmp; + for (int i = 0; i < count; i += 4) { + tmp = SkDoubleToFixed(ffx); dst[i + 0] = TILE(tmp, count); ffx += ddx; + tmp = SkDoubleToFixed(ffx); dst[i + 1] = TILE(tmp, count); ffx += ddx; + tmp = SkDoubleToFixed(ffx); dst[i + 2] = TILE(tmp, count); ffx += ddx; + tmp = SkDoubleToFixed(ffx); dst[i + 3] = TILE(tmp, count); ffx += ddx; + } + } +private: + typedef InterpBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new Fixed16D16Interp(); ) +DEF_BENCH( return new Fixed32D32Interp(); ) +DEF_BENCH( return new Fixed16D48Interp(); ) +DEF_BENCH( return new FloatInterp(); ) +DEF_BENCH( return new DoubleInterp(); ) diff --git a/chromium/third_party/skia/bench/LightingBench.cpp b/chromium/third_party/skia/bench/LightingBench.cpp new file mode 100644 index 00000000000..4d234b951f6 --- /dev/null +++ b/chromium/third_party/skia/bench/LightingBench.cpp @@ -0,0 +1,246 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmapSource.h" +#include "SkCanvas.h" +#include "SkDevice.h" +#include "SkLightingImageFilter.h" + +#define FILTER_WIDTH_SMALL SkIntToScalar(32) +#define FILTER_HEIGHT_SMALL SkIntToScalar(32) +#define FILTER_WIDTH_LARGE SkIntToScalar(256) +#define FILTER_HEIGHT_LARGE SkIntToScalar(256) + +class LightingBaseBench : public Benchmark { +public: + LightingBaseBench(bool small) : fIsSmall(small) { } + +protected: + void draw(const int loops, SkCanvas* canvas, SkImageFilter* imageFilter) const { + SkRect r = fIsSmall ? SkRect::MakeWH(FILTER_WIDTH_SMALL, FILTER_HEIGHT_SMALL) : + SkRect::MakeWH(FILTER_WIDTH_LARGE, FILTER_HEIGHT_LARGE); + SkPaint paint; + paint.setImageFilter(imageFilter)->unref(); + for (int i = 0; i < loops; i++) { + canvas->drawRect(r, paint); + } + } + + static SkPoint3 getPointLocation() { + static SkPoint3 pointLocation(0, 0, SkIntToScalar(10)); + return pointLocation; + } + + static SkPoint3 getDistantDirection() { + static SkScalar azimuthRad = SkDegreesToRadians(SkIntToScalar(225)); + static SkScalar elevationRad = SkDegreesToRadians(SkIntToScalar(5)); + static SkPoint3 distantDirection(SkScalarMul(SkScalarCos(azimuthRad), + SkScalarCos(elevationRad)), + SkScalarMul(SkScalarSin(azimuthRad), + SkScalarCos(elevationRad)), + SkScalarSin(elevationRad)); + return distantDirection; + } + + static SkPoint3 getSpotLocation() { + static SkPoint3 spotLocation(SkIntToScalar(-10), SkIntToScalar(-10), SkIntToScalar(20)); + return spotLocation; + } + + static SkPoint3 getSpotTarget() { + static SkPoint3 spotTarget(SkIntToScalar(40), SkIntToScalar(40), 0); + return spotTarget; + } + + static SkScalar getSpotExponent() { + static SkScalar spotExponent = SK_Scalar1; + return spotExponent; + } + + static SkScalar getCutoffAngle() { + static SkScalar cutoffAngle = SkIntToScalar(15); + return cutoffAngle; + } + + static SkScalar getKd() { + static SkScalar kd = SkIntToScalar(2); + return kd; + } + + static SkScalar getKs() { + static SkScalar ks = SkIntToScalar(1); + return ks; + } + + static SkScalar getShininess() { + static SkScalar shininess = SkIntToScalar(8); + return shininess; + } + + static SkScalar getSurfaceScale() { + static SkScalar surfaceScale = SkIntToScalar(1); + return surfaceScale; + } + + static SkColor getWhite() { + static SkColor white(0xFFFFFFFF); + return white; + } + + bool fIsSmall; + typedef Benchmark INHERITED; +}; + +class LightingPointLitDiffuseBench : public LightingBaseBench { +public: + LightingPointLitDiffuseBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "lightingpointlitdiffuse_small" : "lightingpointlitdiffuse_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + draw(loops, canvas, SkLightingImageFilter::CreatePointLitDiffuse(getPointLocation(), + getWhite(), + getSurfaceScale(), + getKd())); + } + +private: + typedef LightingBaseBench INHERITED; +}; + +class LightingDistantLitDiffuseBench : public LightingBaseBench { +public: + LightingDistantLitDiffuseBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "lightingdistantlitdiffuse_small" : "lightingdistantlitdiffuse_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + draw(loops, canvas, SkLightingImageFilter::CreateDistantLitDiffuse(getDistantDirection(), + getWhite(), + getSurfaceScale(), + getKd())); + } + +private: + typedef LightingBaseBench INHERITED; +}; + +class LightingSpotLitDiffuseBench : public LightingBaseBench { +public: + LightingSpotLitDiffuseBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "lightingspotlitdiffuse_small" : "lightingspotlitdiffuse_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + draw(loops, canvas, SkLightingImageFilter::CreateSpotLitDiffuse(getSpotLocation(), + getSpotTarget(), + getSpotExponent(), + getCutoffAngle(), + getWhite(), + getSurfaceScale(), + getKd())); + } + +private: + typedef LightingBaseBench INHERITED; +}; + +class LightingPointLitSpecularBench : public LightingBaseBench { +public: + LightingPointLitSpecularBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "lightingpointlitspecular_small" : "lightingpointlitspecular_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + draw(loops, canvas, SkLightingImageFilter::CreatePointLitSpecular(getPointLocation(), + getWhite(), + getSurfaceScale(), + getKs(), + getShininess())); + } + +private: + typedef LightingBaseBench INHERITED; +}; + +class LightingDistantLitSpecularBench : public LightingBaseBench { +public: + LightingDistantLitSpecularBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "lightingdistantlitspecular_small" : "lightingdistantlitspecular_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + draw(loops, canvas, SkLightingImageFilter::CreateDistantLitSpecular(getDistantDirection(), + getWhite(), + getSurfaceScale(), + getKs(), + getShininess())); + } + +private: + typedef LightingBaseBench INHERITED; +}; + +class LightingSpotLitSpecularBench : public LightingBaseBench { +public: + LightingSpotLitSpecularBench(bool small) : INHERITED(small) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "lightingspotlitspecular_small" : "lightingspotlitspecular_large"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + draw(loops, canvas, SkLightingImageFilter::CreateSpotLitSpecular(getSpotLocation(), + getSpotTarget(), + getSpotExponent(), + getCutoffAngle(), + getWhite(), + getSurfaceScale(), + getKs(), + getShininess())); + } + +private: + typedef LightingBaseBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new LightingPointLitDiffuseBench(true); ) +DEF_BENCH( return new LightingPointLitDiffuseBench(false); ) +DEF_BENCH( return new LightingDistantLitDiffuseBench(true); ) +DEF_BENCH( return new LightingDistantLitDiffuseBench(false); ) +DEF_BENCH( return new LightingSpotLitDiffuseBench(true); ) +DEF_BENCH( return new LightingSpotLitDiffuseBench(false); ) +DEF_BENCH( return new LightingPointLitSpecularBench(true); ) +DEF_BENCH( return new LightingPointLitSpecularBench(false); ) +DEF_BENCH( return new LightingDistantLitSpecularBench(true); ) +DEF_BENCH( return new LightingDistantLitSpecularBench(false); ) +DEF_BENCH( return new LightingSpotLitSpecularBench(true); ) +DEF_BENCH( return new LightingSpotLitSpecularBench(false); ) diff --git a/chromium/third_party/skia/bench/LineBench.cpp b/chromium/third_party/skia/bench/LineBench.cpp new file mode 100644 index 00000000000..bb6215b03fd --- /dev/null +++ b/chromium/third_party/skia/bench/LineBench.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" +#include "SkTArray.h" + + +class LineBench : public Benchmark { + SkScalar fStrokeWidth; + bool fDoAA; + SkString fName; + enum { + PTS = 500, + }; + SkPoint fPts[PTS]; + +public: + LineBench(SkScalar width, bool doAA) { + fStrokeWidth = width; + fDoAA = doAA; + fName.printf("lines_%g_%s", width, doAA ? "AA" : "BW"); + + SkRandom rand; + for (int i = 0; i < PTS; ++i) { + fPts[i].set(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480); + } + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + this->setupPaint(&paint); + + paint.setStyle(SkPaint::kStroke_Style); + paint.setAntiAlias(fDoAA); + paint.setStrokeWidth(fStrokeWidth); + + for (int i = 0; i < loops; i++) { + canvas->drawPoints(SkCanvas::kLines_PointMode, PTS, fPts, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new LineBench(0, false);) +DEF_BENCH(return new LineBench(SK_Scalar1, false);) +DEF_BENCH(return new LineBench(0, true);) +DEF_BENCH(return new LineBench(SK_Scalar1/2, true);) +DEF_BENCH(return new LineBench(SK_Scalar1, true);) diff --git a/chromium/third_party/skia/bench/MagnifierBench.cpp b/chromium/third_party/skia/bench/MagnifierBench.cpp new file mode 100644 index 00000000000..875ec4f465f --- /dev/null +++ b/chromium/third_party/skia/bench/MagnifierBench.cpp @@ -0,0 +1,85 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmapDevice.h" +#include "SkCanvas.h" +#include "SkMagnifierImageFilter.h" +#include "SkRandom.h" + +#define FILTER_WIDTH_SMALL 32 +#define FILTER_HEIGHT_SMALL 32 +#define FILTER_WIDTH_LARGE 256 +#define FILTER_HEIGHT_LARGE 256 + +class MagnifierBench : public Benchmark { +public: + MagnifierBench(bool small) : + fIsSmall(small), fInitialized(false) { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "magnifier_small" : "magnifier_large"; + } + + virtual void onPreDraw() SK_OVERRIDE { + if (!fInitialized) { + make_checkerboard(); + fInitialized = true; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + const int w = fIsSmall ? FILTER_WIDTH_SMALL : FILTER_WIDTH_LARGE; + const int h = fIsSmall ? FILTER_HEIGHT_SMALL : FILTER_HEIGHT_LARGE; + SkPaint paint; + paint.setImageFilter( + SkMagnifierImageFilter::Create( + SkRect::MakeXYWH(SkIntToScalar(w / 4), + SkIntToScalar(h / 4), + SkIntToScalar(w / 2), + SkIntToScalar(h / 2)), 100))->unref(); + + for (int i = 0; i < loops; i++) { + canvas->drawBitmap(fCheckerboard, 0, 0, &paint); + } + } + +private: + void make_checkerboard() { + const int w = fIsSmall ? FILTER_WIDTH_SMALL : FILTER_WIDTH_LARGE; + const int h = fIsSmall ? FILTER_HEIGHT_LARGE : FILTER_HEIGHT_LARGE; + fCheckerboard.allocN32Pixels(w, h); + SkCanvas canvas(fCheckerboard); + canvas.clear(0x00000000); + SkPaint darkPaint; + darkPaint.setColor(0xFF804020); + SkPaint lightPaint; + lightPaint.setColor(0xFF244484); + for (int y = 0; y < h; y += 16) { + for (int x = 0; x < w; x += 16) { + canvas.save(); + canvas.translate(SkIntToScalar(x), SkIntToScalar(y)); + canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint); + canvas.restore(); + } + } + } + + bool fIsSmall; + bool fInitialized; + SkBitmap fCheckerboard; + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new MagnifierBench(true); ) +DEF_BENCH( return new MagnifierBench(false); ) diff --git a/chromium/third_party/skia/bench/MathBench.cpp b/chromium/third_party/skia/bench/MathBench.cpp new file mode 100644 index 00000000000..dbd661f8d38 --- /dev/null +++ b/chromium/third_party/skia/bench/MathBench.cpp @@ -0,0 +1,611 @@ +#include "Benchmark.h" +#include "SkColorPriv.h" +#include "SkMatrix.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" + +static float sk_fsel(float pred, float result_ge, float result_lt) { + return pred >= 0 ? result_ge : result_lt; +} + +static float fast_floor(float x) { +// float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23); + float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23)); + return (x + big) - big; +} + +class MathBench : public Benchmark { + enum { + kBuffer = 100, + }; + SkString fName; + float fSrc[kBuffer], fDst[kBuffer]; +public: + MathBench(const char name[]) { + fName.printf("math_%s", name); + + SkRandom rand; + for (int i = 0; i < kBuffer; ++i) { + fSrc[i] = rand.nextSScalar1(); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void performTest(float* SK_RESTRICT dst, + const float* SK_RESTRICT src, + int count) = 0; + +protected: + virtual int mulLoopCount() const { return 1; } + + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) { + int n = loops * this->mulLoopCount(); + for (int i = 0; i < n; i++) { + this->performTest(fDst, fSrc, kBuffer); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class MathBenchU32 : public MathBench { +public: + MathBenchU32(const char name[]) : INHERITED(name) {} + +protected: + virtual void performITest(uint32_t* SK_RESTRICT dst, + const uint32_t* SK_RESTRICT src, + int count) = 0; + + virtual void performTest(float* SK_RESTRICT dst, + const float* SK_RESTRICT src, + int count) SK_OVERRIDE { + uint32_t* d = SkTCast<uint32_t*>(dst); + const uint32_t* s = SkTCast<const uint32_t*>(src); + this->performITest(d, s, count); + } +private: + typedef MathBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class NoOpMathBench : public MathBench { +public: + NoOpMathBench() : INHERITED("noOp") {} +protected: + virtual void performTest(float* SK_RESTRICT dst, + const float* SK_RESTRICT src, + int count) { + for (int i = 0; i < count; ++i) { + dst[i] = src[i] + 1; + } + } +private: + typedef MathBench INHERITED; +}; + +class SkRSqrtMathBench : public MathBench { +public: + SkRSqrtMathBench() : INHERITED("sk_float_rsqrt") {} +protected: + virtual void performTest(float* SK_RESTRICT dst, + const float* SK_RESTRICT src, + int count) { + for (int i = 0; i < count; ++i) { + dst[i] = sk_float_rsqrt(src[i]); + } + } +private: + typedef MathBench INHERITED; +}; + + +class SlowISqrtMathBench : public MathBench { +public: + SlowISqrtMathBench() : INHERITED("slowIsqrt") {} +protected: + virtual void performTest(float* SK_RESTRICT dst, + const float* SK_RESTRICT src, + int count) { + for (int i = 0; i < count; ++i) { + dst[i] = 1.0f / sk_float_sqrt(src[i]); + } + } +private: + typedef MathBench INHERITED; +}; + +static inline float SkFastInvSqrt(float x) { + float xhalf = 0.5f*x; + int i = *SkTCast<int*>(&x); + i = 0x5f3759df - (i>>1); + x = *SkTCast<float*>(&i); + x = x*(1.5f-xhalf*x*x); +// x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6 + return x; +} + +class FastISqrtMathBench : public MathBench { +public: + FastISqrtMathBench() : INHERITED("fastIsqrt") {} +protected: + virtual void performTest(float* SK_RESTRICT dst, + const float* SK_RESTRICT src, + int count) { + for (int i = 0; i < count; ++i) { + dst[i] = SkFastInvSqrt(src[i]); + } + } +private: + typedef MathBench INHERITED; +}; + +static inline uint32_t QMul64(uint32_t value, U8CPU alpha) { + SkASSERT((uint8_t)alpha == alpha); + const uint32_t mask = 0xFF00FF; + + uint64_t tmp = value; + tmp = (tmp & mask) | ((tmp & ~mask) << 24); + tmp *= alpha; + return (uint32_t) (((tmp >> 8) & mask) | ((tmp >> 32) & ~mask)); +} + +class QMul64Bench : public MathBenchU32 { +public: + QMul64Bench() : INHERITED("qmul64") {} +protected: + virtual void performITest(uint32_t* SK_RESTRICT dst, + const uint32_t* SK_RESTRICT src, + int count) SK_OVERRIDE { + for (int i = 0; i < count; ++i) { + dst[i] = QMul64(src[i], (uint8_t)i); + } + } +private: + typedef MathBenchU32 INHERITED; +}; + +class QMul32Bench : public MathBenchU32 { +public: + QMul32Bench() : INHERITED("qmul32") {} +protected: + virtual void performITest(uint32_t* SK_RESTRICT dst, + const uint32_t* SK_RESTRICT src, + int count) SK_OVERRIDE { + for (int i = 0; i < count; ++i) { + dst[i] = SkAlphaMulQ(src[i], (uint8_t)i); + } + } +private: + typedef MathBenchU32 INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static bool isFinite_int(float x) { + uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts + int exponent = bits << 1 >> 24; + return exponent != 0xFF; +} + +static bool isFinite_float(float x) { + return SkToBool(sk_float_isfinite(x)); +} + +static bool isFinite_mulzero(float x) { + float y = x * 0; + return y == y; +} + +static bool isfinite_and_int(const float data[4]) { + return isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]); +} + +static bool isfinite_and_float(const float data[4]) { + return isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]); +} + +static bool isfinite_and_mulzero(const float data[4]) { + return isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]); +} + +#define mulzeroadd(data) (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0) + +static bool isfinite_plus_int(const float data[4]) { + return isFinite_int(mulzeroadd(data)); +} + +static bool isfinite_plus_float(const float data[4]) { + return !sk_float_isnan(mulzeroadd(data)); +} + +static bool isfinite_plus_mulzero(const float data[4]) { + float x = mulzeroadd(data); + return x == x; +} + +typedef bool (*IsFiniteProc)(const float[]); + +#define MAKEREC(name) { name, #name } + +static const struct { + IsFiniteProc fProc; + const char* fName; +} gRec[] = { + MAKEREC(isfinite_and_int), + MAKEREC(isfinite_and_float), + MAKEREC(isfinite_and_mulzero), + MAKEREC(isfinite_plus_int), + MAKEREC(isfinite_plus_float), + MAKEREC(isfinite_plus_mulzero), +}; + +#undef MAKEREC + +static bool isFinite(const SkRect& r) { + // x * 0 will be NaN iff x is infinity or NaN. + // a + b will be NaN iff either a or b is NaN. + float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0; + + // value is either NaN or it is finite (zero). + // value==value will be true iff value is not NaN + return value == value; +} + +class IsFiniteBench : public Benchmark { + enum { + N = 1000, + }; + float fData[N]; +public: + + IsFiniteBench(int index) { + SkRandom rand; + + for (int i = 0; i < N; ++i) { + fData[i] = rand.nextSScalar1(); + } + + if (index < 0) { + fProc = NULL; + fName = "isfinite_rect"; + } else { + fProc = gRec[index].fProc; + fName = gRec[index].fName; + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual void onDraw(const int loops, SkCanvas*) { + IsFiniteProc proc = fProc; + const float* data = fData; + // do this so the compiler won't throw away the function call + int counter = 0; + + if (proc) { + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < N - 4; ++i) { + counter += proc(&data[i]); + } + } + } else { + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < N - 4; ++i) { + const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]); + if (false) { // avoid bit rot, suppress warning + isFinite(*r); + } + counter += r->isFinite(); + } + } + } + + SkPaint paint; + if (paint.getAlpha() == 0) { + SkDebugf("%d\n", counter); + } + } + + virtual const char* onGetName() { + return fName; + } + +private: + IsFiniteProc fProc; + const char* fName; + + typedef Benchmark INHERITED; +}; + +class FloorBench : public Benchmark { + enum { + ARRAY = 1000, + }; + float fData[ARRAY]; + bool fFast; +public: + + FloorBench(bool fast) : fFast(fast) { + SkRandom rand; + + for (int i = 0; i < ARRAY; ++i) { + fData[i] = rand.nextSScalar1(); + } + + if (fast) { + fName = "floor_fast"; + } else { + fName = "floor_std"; + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void process(float) {} + +protected: + virtual void onDraw(const int loops, SkCanvas*) { + SkRandom rand; + float accum = 0; + const float* data = fData; + + if (fFast) { + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < ARRAY; ++i) { + accum += fast_floor(data[i]); + } + this->process(accum); + } + } else { + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < ARRAY; ++i) { + accum += sk_float_floor(data[i]); + } + this->process(accum); + } + } + } + + virtual const char* onGetName() { + return fName; + } + +private: + const char* fName; + + typedef Benchmark INHERITED; +}; + +class CLZBench : public Benchmark { + enum { + ARRAY = 1000, + }; + uint32_t fData[ARRAY]; + bool fUsePortable; + +public: + CLZBench(bool usePortable) : fUsePortable(usePortable) { + + SkRandom rand; + for (int i = 0; i < ARRAY; ++i) { + fData[i] = rand.nextU(); + } + + if (fUsePortable) { + fName = "clz_portable"; + } else { + fName = "clz_intrinsic"; + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + // just so the compiler doesn't remove our loops + virtual void process(int) {} + +protected: + virtual void onDraw(const int loops, SkCanvas*) { + int accum = 0; + + if (fUsePortable) { + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < ARRAY; ++i) { + accum += SkCLZ_portable(fData[i]); + } + this->process(accum); + } + } else { + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < ARRAY; ++i) { + accum += SkCLZ(fData[i]); + } + this->process(accum); + } + } + } + + virtual const char* onGetName() { + return fName; + } + +private: + const char* fName; + + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class NormalizeBench : public Benchmark { + enum { + ARRAY =1000, + }; + SkVector fVec[ARRAY]; + +public: + NormalizeBench() { + SkRandom rand; + for (int i = 0; i < ARRAY; ++i) { + fVec[i].set(rand.nextSScalar1(), rand.nextSScalar1()); + } + + fName = "point_normalize"; + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + // just so the compiler doesn't remove our loops + virtual void process(int) {} + +protected: + virtual void onDraw(const int loops, SkCanvas*) { + int accum = 0; + + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < ARRAY; ++i) { + accum += fVec[i].normalize(); + } + this->process(accum); + } + } + + virtual const char* onGetName() { + return fName; + } + +private: + const char* fName; + + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class FixedMathBench : public Benchmark { + enum { + N = 1000, + }; + float fData[N]; + SkFixed fResult[N]; +public: + + FixedMathBench() { + SkRandom rand; + for (int i = 0; i < N; ++i) { + fData[i] = rand.nextSScalar1(); + } + + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual void onDraw(const int loops, SkCanvas*) { + for (int j = 0; j < loops; ++j) { + for (int i = 0; i < N - 4; ++i) { + fResult[i] = SkFloatToFixed(fData[i]); + } + } + + SkPaint paint; + if (paint.getAlpha() == 0) { + SkDebugf("%d\n", fResult[0]); + } + } + + virtual const char* onGetName() { + return "float_to_fixed"; + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +template <typename T> +class DivModBench : public Benchmark { + SkString fName; +public: + explicit DivModBench(const char* name) { + fName.printf("divmod_%s", name); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) { + volatile T a = 0, b = 0; + T div = 0, mod = 0; + for (int i = 0; i < loops; i++) { + if ((T)i == 0) continue; // Small T will wrap around. + SkTDivMod((T)(i+1), (T)i, &div, &mod); + a ^= div; + b ^= mod; + } + } +}; +DEF_BENCH(return new DivModBench<uint8_t>("uint8_t")) +DEF_BENCH(return new DivModBench<uint16_t>("uint16_t")) +DEF_BENCH(return new DivModBench<uint32_t>("uint32_t")) +DEF_BENCH(return new DivModBench<uint64_t>("uint64_t")) + +DEF_BENCH(return new DivModBench<int8_t>("int8_t")) +DEF_BENCH(return new DivModBench<int16_t>("int16_t")) +DEF_BENCH(return new DivModBench<int32_t>("int32_t")) +DEF_BENCH(return new DivModBench<int64_t>("int64_t")) + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new NoOpMathBench(); ) +DEF_BENCH( return new SkRSqrtMathBench(); ) +DEF_BENCH( return new SlowISqrtMathBench(); ) +DEF_BENCH( return new FastISqrtMathBench(); ) +DEF_BENCH( return new QMul64Bench(); ) +DEF_BENCH( return new QMul32Bench(); ) + +DEF_BENCH( return new IsFiniteBench(-1); ) +DEF_BENCH( return new IsFiniteBench(0); ) +DEF_BENCH( return new IsFiniteBench(1); ) +DEF_BENCH( return new IsFiniteBench(2); ) +DEF_BENCH( return new IsFiniteBench(3); ) +DEF_BENCH( return new IsFiniteBench(4); ) +DEF_BENCH( return new IsFiniteBench(5); ) + +DEF_BENCH( return new FloorBench(false); ) +DEF_BENCH( return new FloorBench(true); ) + +DEF_BENCH( return new CLZBench(false); ) +DEF_BENCH( return new CLZBench(true); ) + +DEF_BENCH( return new NormalizeBench(); ) + +DEF_BENCH( return new FixedMathBench(); ) diff --git a/chromium/third_party/skia/bench/Matrix44Bench.cpp b/chromium/third_party/skia/bench/Matrix44Bench.cpp new file mode 100644 index 00000000000..8a7c50e6068 --- /dev/null +++ b/chromium/third_party/skia/bench/Matrix44Bench.cpp @@ -0,0 +1,304 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkMatrix44.h" +#include "SkRandom.h" +#include "SkString.h" + +class Matrix44Bench : public Benchmark { + SkString fName; +public: + Matrix44Bench(const char name[]) { + fName.printf("matrix44_%s", name); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void performTest() = 0; + +protected: + virtual int mulLoopCount() const { return 1; } + + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; i++) { + this->performTest(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class EqualsMatrix44Bench : public Matrix44Bench { +public: + EqualsMatrix44Bench() + : INHERITED("equals") + , fM0(SkMatrix44::kIdentity_Constructor) + , fM1(SkMatrix44::kIdentity_Constructor) + , fM2(SkMatrix44::kIdentity_Constructor) + { + fM1.set(0, 0, 0); + fM2.set(3, 3, 0); + } +protected: + virtual void performTest() { + for (int i = 0; i < 10; ++i) { + (void) (fM0 == fM1); + (void) (fM1 == fM2); + (void) (fM2 == fM0); + } + } +private: + SkMatrix44 fM0, fM1, fM2; + typedef Matrix44Bench INHERITED; +}; + +class SetIdentityMatrix44Bench : public Matrix44Bench { +public: + SetIdentityMatrix44Bench() + : INHERITED("setidentity") + , mat(SkMatrix44::kIdentity_Constructor) + { + double rowMajor[16] = + { 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16}; + mat.setRowMajord(rowMajor); + } +protected: + virtual void performTest() { + for (int i = 0; i < 10; ++i) { + mat.setIdentity(); + } + } +private: + SkMatrix44 mat; + typedef Matrix44Bench INHERITED; +}; + +class PreScaleMatrix44Bench : public Matrix44Bench { +public: + PreScaleMatrix44Bench() + : INHERITED("prescale") + , fM0(SkMatrix44::kUninitialized_Constructor) + { + fX = fY = fZ = SkDoubleToMScalar(1.5); + } +protected: + virtual void performTest() { + fM0.reset(); + for (int i = 0; i < 10; ++i) { + fM0.preScale(fX, fY, fZ); + } + } +private: + SkMatrix44 fM0; + SkMScalar fX, fY, fZ; + typedef Matrix44Bench INHERITED; +}; + +class InvertMatrix44Bench : public Matrix44Bench { +public: + InvertMatrix44Bench() + : INHERITED("invert") + , fM0(SkMatrix44::kUninitialized_Constructor) + , fM1(SkMatrix44::kUninitialized_Constructor) + { + fM0.set(0, 0, -1.1); + fM0.set(0, 1, 2.1); + fM0.set(0, 2, -3.1); + fM0.set(0, 3, 4.1); + fM0.set(1, 0, 5.1); + fM0.set(1, 1, -6.1); + fM0.set(1, 2, 7.1); + fM0.set(1, 3, 8.1); + fM0.set(2, 0, -9.1); + fM0.set(2, 1, 10.1); + fM0.set(2, 2, 11.1); + fM0.set(2, 3, -12.1); + fM0.set(3, 0, -13.1); + fM0.set(3, 1, 14.1); + fM0.set(3, 2, -15.1); + fM0.set(3, 3, 16.1); + } +protected: + virtual void performTest() { + for (int i = 0; i < 10; ++i) { + fM0.invert(&fM1); + } + } +private: + SkMatrix44 fM0, fM1; + typedef Matrix44Bench INHERITED; +}; + +class InvertAffineMatrix44Bench : public Matrix44Bench { +public: + InvertAffineMatrix44Bench() + : INHERITED("invertaffine") + , fM0(SkMatrix44::kIdentity_Constructor) + , fM1(SkMatrix44::kUninitialized_Constructor) + { + fM0.set(0, 0, -1.1); + fM0.set(0, 1, 2.1); + fM0.set(0, 2, -3.1); + fM0.set(0, 3, 4.1); + fM0.set(1, 0, 5.1); + fM0.set(1, 1, -6.1); + fM0.set(1, 2, 7.1); + fM0.set(1, 3, 8.1); + fM0.set(2, 0, -9.1); + fM0.set(2, 1, 10.1); + fM0.set(2, 2, 11.1); + fM0.set(2, 3, -12.1); + // bottom row (perspective component) remains (0, 0, 0, 1). + } +protected: + virtual void performTest() { + for (int i = 0; i < 10; ++i) { + fM0.invert(&fM1); + } + } +private: + SkMatrix44 fM0, fM1; + typedef Matrix44Bench INHERITED; +}; + +class InvertScaleTranslateMatrix44Bench : public Matrix44Bench { +public: + InvertScaleTranslateMatrix44Bench() + : INHERITED("invertscaletranslate") + , fM0(SkMatrix44::kIdentity_Constructor) + , fM1(SkMatrix44::kUninitialized_Constructor) + { + fM0.set(0, 0, -1.1); + fM0.set(0, 3, 4.1); + + fM0.set(1, 1, -6.1); + fM0.set(1, 3, 8.1); + + fM0.set(2, 2, 11.1); + fM0.set(2, 3, -12.1); + } +protected: + virtual void performTest() { + for (int i = 0; i < 10; ++i) { + fM0.invert(&fM1); + } + } +private: + SkMatrix44 fM0, fM1; + typedef Matrix44Bench INHERITED; +}; + +class InvertTranslateMatrix44Bench : public Matrix44Bench { +public: + InvertTranslateMatrix44Bench() + : INHERITED("inverttranslate") + , fM0(SkMatrix44::kIdentity_Constructor) + , fM1(SkMatrix44::kUninitialized_Constructor) + { + fM0.set(0, 3, 4.1); + fM0.set(1, 3, 8.1); + fM0.set(2, 3, -12.1); + } +protected: + virtual void performTest() { + for (int i = 0; i < 10; ++i) { + fM0.invert(&fM1); + } + } +private: + SkMatrix44 fM0, fM1; + typedef Matrix44Bench INHERITED; +}; + +class PostScaleMatrix44Bench : public Matrix44Bench { +public: + PostScaleMatrix44Bench() + : INHERITED("postscale") + , fM0(SkMatrix44::kUninitialized_Constructor) + { + fX = fY = fZ = SkDoubleToMScalar(1.5); + } +protected: + virtual void performTest() { + fM0.reset(); + for (int i = 0; i < 10; ++i) { + fM0.postScale(fX, fY, fZ); + } + } +private: + SkMatrix44 fM0; + SkMScalar fX, fY, fZ; + typedef Matrix44Bench INHERITED; +}; + +class SetConcatMatrix44Bench : public Matrix44Bench { +public: + SetConcatMatrix44Bench() + : INHERITED("setconcat") + , fM0(SkMatrix44::kUninitialized_Constructor) + , fM1(SkMatrix44::kUninitialized_Constructor) + , fM2(SkMatrix44::kUninitialized_Constructor) +{ + fX = fY = fZ = SkDoubleToMScalar(1.5); + fM1.setScale(fX, fY, fZ); + fM2.setTranslate(fX, fY, fZ); + } +protected: + virtual void performTest() { + fM0.reset(); // just to normalize this test with prescale/postscale + for (int i = 0; i < 10; ++i) { + fM0.setConcat(fM1, fM2); + } + } +private: + SkMatrix44 fM0, fM1, fM2; + SkMScalar fX, fY, fZ; + typedef Matrix44Bench INHERITED; +}; + +class GetTypeMatrix44Bench : public Matrix44Bench { +public: + GetTypeMatrix44Bench() + : INHERITED("gettype") + , fMatrix(SkMatrix44::kIdentity_Constructor) + {} +protected: + // Putting random generation of the matrix inside performTest() + // would help us avoid anomalous runs, but takes up 25% or + // more of the function time. + virtual void performTest() { + for (int i = 0; i < 20; ++i) { + fMatrix.set(1, 2, 1); // to invalidate the type-cache + fMatrix.getType(); + } + } +private: + SkMatrix44 fMatrix; + typedef Matrix44Bench INHERITED; +}; + +DEF_BENCH( return new SetIdentityMatrix44Bench(); ) +DEF_BENCH( return new EqualsMatrix44Bench(); ) +DEF_BENCH( return new PreScaleMatrix44Bench(); ) +DEF_BENCH( return new PostScaleMatrix44Bench(); ) +DEF_BENCH( return new InvertMatrix44Bench(); ) +DEF_BENCH( return new InvertAffineMatrix44Bench(); ) +DEF_BENCH( return new InvertScaleTranslateMatrix44Bench(); ) +DEF_BENCH( return new InvertTranslateMatrix44Bench(); ) +DEF_BENCH( return new SetConcatMatrix44Bench(); ) +DEF_BENCH( return new GetTypeMatrix44Bench(); ) diff --git a/chromium/third_party/skia/bench/MatrixBench.cpp b/chromium/third_party/skia/bench/MatrixBench.cpp new file mode 100644 index 00000000000..78482d963d4 --- /dev/null +++ b/chromium/third_party/skia/bench/MatrixBench.cpp @@ -0,0 +1,472 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkMatrix.h" +#include "SkMatrixUtils.h" +#include "SkRandom.h" +#include "SkString.h" + +class MatrixBench : public Benchmark { + SkString fName; +public: + MatrixBench(const char name[]) { + fName.printf("matrix_%s", name); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void performTest() = 0; + +protected: + virtual int mulLoopCount() const { return 1; } + + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; i++) { + this->performTest(); + } + } + +private: + typedef Benchmark INHERITED; +}; + + +class EqualsMatrixBench : public MatrixBench { +public: + EqualsMatrixBench() : INHERITED("equals") {} +protected: + virtual void performTest() { + SkMatrix m0, m1, m2; + + m0.reset(); + m1.reset(); + m2.reset(); + + // xor into a volatile prevents these comparisons from being optimized away. + volatile bool junk = false; + junk ^= (m0 == m1); + junk ^= (m1 == m2); + junk ^= (m2 == m0); + } +private: + typedef MatrixBench INHERITED; +}; + +class ScaleMatrixBench : public MatrixBench { +public: + ScaleMatrixBench() : INHERITED("scale") { + fSX = fSY = 1.5f; + fM0.reset(); + fM1.setScale(fSX, fSY); + fM2.setTranslate(fSX, fSY); + } +protected: + virtual void performTest() { + SkMatrix m; + m = fM0; m.preScale(fSX, fSY); + m = fM1; m.preScale(fSX, fSY); + m = fM2; m.preScale(fSX, fSY); + } +private: + SkMatrix fM0, fM1, fM2; + SkScalar fSX, fSY; + typedef MatrixBench INHERITED; +}; + +// having unknown values in our arrays can throw off the timing a lot, perhaps +// handling NaN values is a lot slower. Anyway, this guy is just meant to put +// reasonable values in our arrays. +template <typename T> void init9(T array[9]) { + SkRandom rand; + for (int i = 0; i < 9; i++) { + array[i] = rand.nextSScalar1(); + } +} + +// Test the performance of setConcat() non-perspective case: +// using floating point precision only. +class FloatConcatMatrixBench : public MatrixBench { +public: + FloatConcatMatrixBench() : INHERITED("concat_floatfloat") { + init9(mya); + init9(myb); + init9(myr); + } +protected: + virtual int mulLoopCount() const { return 4; } + + static inline void muladdmul(float a, float b, float c, float d, + float* result) { + *result = a * b + c * d; + } + virtual void performTest() { + const float* a = mya; + const float* b = myb; + float* r = myr; + muladdmul(a[0], b[0], a[1], b[3], &r[0]); + muladdmul(a[0], b[1], a[1], b[4], &r[1]); + muladdmul(a[0], b[2], a[1], b[5], &r[2]); + r[2] += a[2]; + muladdmul(a[3], b[0], a[4], b[3], &r[3]); + muladdmul(a[3], b[1], a[4], b[4], &r[4]); + muladdmul(a[3], b[2], a[4], b[5], &r[5]); + r[5] += a[5]; + r[6] = r[7] = 0.0f; + r[8] = 1.0f; + } +private: + float mya [9]; + float myb [9]; + float myr [9]; + typedef MatrixBench INHERITED; +}; + +static inline float SkDoubleToFloat(double x) { + return static_cast<float>(x); +} + +// Test the performance of setConcat() non-perspective case: +// using floating point precision but casting up to float for +// intermediate results during computations. +class FloatDoubleConcatMatrixBench : public MatrixBench { +public: + FloatDoubleConcatMatrixBench() : INHERITED("concat_floatdouble") { + init9(mya); + init9(myb); + init9(myr); + } +protected: + virtual int mulLoopCount() const { return 4; } + + static inline void muladdmul(float a, float b, float c, float d, + float* result) { + *result = SkDoubleToFloat((double)a * b + (double)c * d); + } + virtual void performTest() { + const float* a = mya; + const float* b = myb; + float* r = myr; + muladdmul(a[0], b[0], a[1], b[3], &r[0]); + muladdmul(a[0], b[1], a[1], b[4], &r[1]); + muladdmul(a[0], b[2], a[1], b[5], &r[2]); + r[2] += a[2]; + muladdmul(a[3], b[0], a[4], b[3], &r[3]); + muladdmul(a[3], b[1], a[4], b[4], &r[4]); + muladdmul(a[3], b[2], a[4], b[5], &r[5]); + r[5] += a[5]; + r[6] = r[7] = 0.0f; + r[8] = 1.0f; + } +private: + float mya [9]; + float myb [9]; + float myr [9]; + typedef MatrixBench INHERITED; +}; + +// Test the performance of setConcat() non-perspective case: +// using double precision only. +class DoubleConcatMatrixBench : public MatrixBench { +public: + DoubleConcatMatrixBench() : INHERITED("concat_double") { + init9(mya); + init9(myb); + init9(myr); + } +protected: + virtual int mulLoopCount() const { return 4; } + + static inline void muladdmul(double a, double b, double c, double d, + double* result) { + *result = a * b + c * d; + } + virtual void performTest() { + const double* a = mya; + const double* b = myb; + double* r = myr; + muladdmul(a[0], b[0], a[1], b[3], &r[0]); + muladdmul(a[0], b[1], a[1], b[4], &r[1]); + muladdmul(a[0], b[2], a[1], b[5], &r[2]); + r[2] += a[2]; + muladdmul(a[3], b[0], a[4], b[3], &r[3]); + muladdmul(a[3], b[1], a[4], b[4], &r[4]); + muladdmul(a[3], b[2], a[4], b[5], &r[5]); + r[5] += a[5]; + r[6] = r[7] = 0.0; + r[8] = 1.0; + } +private: + double mya [9]; + double myb [9]; + double myr [9]; + typedef MatrixBench INHERITED; +}; + +class GetTypeMatrixBench : public MatrixBench { +public: + GetTypeMatrixBench() + : INHERITED("gettype") { + fArray[0] = (float) fRnd.nextS(); + fArray[1] = (float) fRnd.nextS(); + fArray[2] = (float) fRnd.nextS(); + fArray[3] = (float) fRnd.nextS(); + fArray[4] = (float) fRnd.nextS(); + fArray[5] = (float) fRnd.nextS(); + fArray[6] = (float) fRnd.nextS(); + fArray[7] = (float) fRnd.nextS(); + fArray[8] = (float) fRnd.nextS(); + } +protected: + // Putting random generation of the matrix inside performTest() + // would help us avoid anomalous runs, but takes up 25% or + // more of the function time. + virtual void performTest() { + fMatrix.setAll(fArray[0], fArray[1], fArray[2], + fArray[3], fArray[4], fArray[5], + fArray[6], fArray[7], fArray[8]); + // xoring into a volatile prevents the compiler from optimizing these away + volatile int junk = 0; + junk ^= (fMatrix.getType()); + fMatrix.dirtyMatrixTypeCache(); + junk ^= (fMatrix.getType()); + fMatrix.dirtyMatrixTypeCache(); + junk ^= (fMatrix.getType()); + fMatrix.dirtyMatrixTypeCache(); + junk ^= (fMatrix.getType()); + fMatrix.dirtyMatrixTypeCache(); + junk ^= (fMatrix.getType()); + fMatrix.dirtyMatrixTypeCache(); + junk ^= (fMatrix.getType()); + fMatrix.dirtyMatrixTypeCache(); + junk ^= (fMatrix.getType()); + fMatrix.dirtyMatrixTypeCache(); + junk ^= (fMatrix.getType()); + } +private: + SkMatrix fMatrix; + float fArray[9]; + SkRandom fRnd; + typedef MatrixBench INHERITED; +}; + +class ScaleTransMixedMatrixBench : public MatrixBench { + public: + ScaleTransMixedMatrixBench() : INHERITED("scaletrans_mixed") { + fMatrix.setAll(fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(), + fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(), + fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1()); + int i; + for (i = 0; i < kCount; i++) { + fSrc[i].fX = fRandom.nextSScalar1(); + fSrc[i].fY = fRandom.nextSScalar1(); + fDst[i].fX = fRandom.nextSScalar1(); + fDst[i].fY = fRandom.nextSScalar1(); + } + } + protected: + virtual void performTest() { + SkPoint* dst = fDst; + const SkPoint* src = fSrc; + int count = kCount; + float mx = fMatrix[SkMatrix::kMScaleX]; + float my = fMatrix[SkMatrix::kMScaleY]; + float tx = fMatrix[SkMatrix::kMTransX]; + float ty = fMatrix[SkMatrix::kMTransY]; + do { + dst->fY = SkScalarMulAdd(src->fY, my, ty); + dst->fX = SkScalarMulAdd(src->fX, mx, tx); + src += 1; + dst += 1; + } while (--count); + } + private: + enum { + kCount = 16 + }; + SkMatrix fMatrix; + SkPoint fSrc [kCount]; + SkPoint fDst [kCount]; + SkRandom fRandom; + typedef MatrixBench INHERITED; +}; + +class ScaleTransDoubleMatrixBench : public MatrixBench { + public: + ScaleTransDoubleMatrixBench() : INHERITED("scaletrans_double") { + init9(fMatrix); + int i; + for (i = 0; i < kCount; i++) { + fSrc[i].fX = fRandom.nextSScalar1(); + fSrc[i].fY = fRandom.nextSScalar1(); + fDst[i].fX = fRandom.nextSScalar1(); + fDst[i].fY = fRandom.nextSScalar1(); + } + } + protected: + virtual void performTest() { + SkPoint* dst = fDst; + const SkPoint* src = fSrc; + int count = kCount; + // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode + float mx = (float) fMatrix[SkMatrix::kMScaleX]; + float my = (float) fMatrix[SkMatrix::kMScaleY]; + float tx = (float) fMatrix[SkMatrix::kMTransX]; + float ty = (float) fMatrix[SkMatrix::kMTransY]; + do { + dst->fY = src->fY * my + ty; + dst->fX = src->fX * mx + tx; + src += 1; + dst += 1; + } while (--count); + } + private: + enum { + kCount = 16 + }; + double fMatrix [9]; + SkPoint fSrc [kCount]; + SkPoint fDst [kCount]; + SkRandom fRandom; + typedef MatrixBench INHERITED; +}; + +class DecomposeMatrixBench : public MatrixBench { +public: + DecomposeMatrixBench() : INHERITED("decompose") {} + +protected: + virtual void onPreDraw() { + for (int i = 0; i < 10; ++i) { + SkScalar rot0 = (fRandom.nextBool()) ? fRandom.nextRangeF(-180, 180) : 0.0f; + SkScalar sx = fRandom.nextRangeF(-3000.f, 3000.f); + SkScalar sy = (fRandom.nextBool()) ? fRandom.nextRangeF(-3000.f, 3000.f) : sx; + SkScalar rot1 = fRandom.nextRangeF(-180, 180); + fMatrix[i].setRotate(rot0); + fMatrix[i].postScale(sx, sy); + fMatrix[i].postRotate(rot1); + } + } + virtual void performTest() { + SkPoint rotation1, scale, rotation2; + for (int i = 0; i < 10; ++i) { + (void) SkDecomposeUpper2x2(fMatrix[i], &rotation1, &scale, &rotation2); + } + } +private: + SkMatrix fMatrix[10]; + SkRandom fRandom; + typedef MatrixBench INHERITED; +}; + +class InvertMapRectMatrixBench : public MatrixBench { +public: + InvertMapRectMatrixBench(const char* name, int flags) + : INHERITED(name) + , fFlags(flags) { + fMatrix.reset(); + fIteration = 0; + if (flags & kScale_Flag) { + fMatrix.postScale(1.5f, 2.5f); + } + if (flags & kTranslate_Flag) { + fMatrix.postTranslate(1.5f, 2.5f); + } + if (flags & kRotate_Flag) { + fMatrix.postRotate(45.0f); + } + if (flags & kPerspective_Flag) { + fMatrix.setPerspX(1.5f); + fMatrix.setPerspY(2.5f); + } + if (0 == (flags & kUncachedTypeMask_Flag)) { + fMatrix.getType(); + } + } + enum Flag { + kScale_Flag = 0x01, + kTranslate_Flag = 0x02, + kRotate_Flag = 0x04, + kPerspective_Flag = 0x08, + kUncachedTypeMask_Flag = 0x10, + }; +protected: + virtual void performTest() { + if (fFlags & kUncachedTypeMask_Flag) { + // This will invalidate the typemask without + // changing the matrix. + fMatrix.setPerspX(fMatrix.getPerspX()); + } + SkMatrix inv; + bool invertible = fMatrix.invert(&inv); + SkASSERT(invertible); + SkRect transformedRect; + // an arbitrary, small, non-zero rect to transform + SkRect srcRect = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10)); + if (invertible) { + inv.mapRect(&transformedRect, srcRect); + } + } +private: + SkMatrix fMatrix; + int fFlags; + unsigned fIteration; + typedef MatrixBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new EqualsMatrixBench(); ) +DEF_BENCH( return new ScaleMatrixBench(); ) +DEF_BENCH( return new FloatConcatMatrixBench(); ) +DEF_BENCH( return new FloatDoubleConcatMatrixBench(); ) +DEF_BENCH( return new DoubleConcatMatrixBench(); ) +DEF_BENCH( return new GetTypeMatrixBench(); ) +DEF_BENCH( return new DecomposeMatrixBench(); ) + +DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); ) + +DEF_BENCH(return new InvertMapRectMatrixBench( + "invert_maprect_rectstaysrect", + InvertMapRectMatrixBench::kScale_Flag | + InvertMapRectMatrixBench::kTranslate_Flag); ) + +DEF_BENCH(return new InvertMapRectMatrixBench( + "invert_maprect_translate", + InvertMapRectMatrixBench::kTranslate_Flag); ) + +DEF_BENCH(return new InvertMapRectMatrixBench( + "invert_maprect_nonpersp", + InvertMapRectMatrixBench::kScale_Flag | + InvertMapRectMatrixBench::kRotate_Flag | + InvertMapRectMatrixBench::kTranslate_Flag); ) + +DEF_BENCH( return new InvertMapRectMatrixBench( + "invert_maprect_persp", + InvertMapRectMatrixBench::kPerspective_Flag); ) + +DEF_BENCH( return new InvertMapRectMatrixBench( + "invert_maprect_typemask_rectstaysrect", + InvertMapRectMatrixBench::kUncachedTypeMask_Flag | + InvertMapRectMatrixBench::kScale_Flag | + InvertMapRectMatrixBench::kTranslate_Flag); ) + +DEF_BENCH( return new InvertMapRectMatrixBench( + "invert_maprect_typemask_nonpersp", + InvertMapRectMatrixBench::kUncachedTypeMask_Flag | + InvertMapRectMatrixBench::kScale_Flag | + InvertMapRectMatrixBench::kRotate_Flag | + InvertMapRectMatrixBench::kTranslate_Flag); ) + +DEF_BENCH( return new ScaleTransMixedMatrixBench(); ) +DEF_BENCH( return new ScaleTransDoubleMatrixBench(); ) diff --git a/chromium/third_party/skia/bench/MatrixConvolutionBench.cpp b/chromium/third_party/skia/bench/MatrixConvolutionBench.cpp new file mode 100644 index 00000000000..6593ab02597 --- /dev/null +++ b/chromium/third_party/skia/bench/MatrixConvolutionBench.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkMatrixConvolutionImageFilter.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" + +class MatrixConvolutionBench : public Benchmark { +public: + MatrixConvolutionBench(SkMatrixConvolutionImageFilter::TileMode tileMode, bool convolveAlpha) + : fName("matrixconvolution") { + SkISize kernelSize = SkISize::Make(3, 3); + SkScalar kernel[9] = { + SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), + SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1), + SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), + }; + SkScalar gain = 0.3f, bias = SkIntToScalar(100); + SkIPoint kernelOffset = SkIPoint::Make(1, 1); + fFilter = SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, kernelOffset, tileMode, convolveAlpha); + } + + ~MatrixConvolutionBench() { + fFilter->unref(); + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + paint.setAntiAlias(true); + SkRandom rand; + for (int i = 0; i < loops; i++) { + SkRect r = SkRect::MakeWH(rand.nextUScalar1() * 400, + rand.nextUScalar1() * 400); + paint.setImageFilter(fFilter); + canvas->drawOval(r, paint); + } + } + +private: + typedef Benchmark INHERITED; + SkMatrixConvolutionImageFilter* fFilter; + SkString fName; +}; + +DEF_BENCH( return new MatrixConvolutionBench(SkMatrixConvolutionImageFilter::kClamp_TileMode, true); ) +DEF_BENCH( return new MatrixConvolutionBench(SkMatrixConvolutionImageFilter::kRepeat_TileMode, true); ) +DEF_BENCH( return new MatrixConvolutionBench(SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, true); ) +DEF_BENCH( return new MatrixConvolutionBench(SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, false); ) diff --git a/chromium/third_party/skia/bench/MemcpyBench.cpp b/chromium/third_party/skia/bench/MemcpyBench.cpp new file mode 100644 index 00000000000..f5501927519 --- /dev/null +++ b/chromium/third_party/skia/bench/MemcpyBench.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkRandom.h" +#include "SkTemplates.h" +#include "SkUtils.h" + +template <typename Memcpy32> +class Memcpy32Bench : public Benchmark { +public: + explicit Memcpy32Bench(int count, Memcpy32 memcpy32, const char* name) + : fCount(count) + , fMemcpy32(memcpy32) + , fName(SkStringPrintf("%s_%d", name, count)) {} + + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void onPreDraw() SK_OVERRIDE { + fDst.reset(fCount); + fSrc.reset(fCount); + + SkRandom rand; + for (int i = 0; i < fCount; i++) { + fSrc[i] = rand.nextU(); + } + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; i++) { + fMemcpy32(fDst, fSrc, fCount); + } + } + +private: + SkAutoTMalloc<uint32_t> fDst, fSrc; + + int fCount; + Memcpy32 fMemcpy32; + const SkString fName; +}; + +template <typename Memcpy32> +static Memcpy32Bench<Memcpy32>* Bench(int count, Memcpy32 memcpy32, const char* name) { + return new Memcpy32Bench<Memcpy32>(count, memcpy32, name); +} +#define BENCH(memcpy32, count) DEF_BENCH(return Bench(count, memcpy32, #memcpy32); ) + + +// Let the libc developers do what they think is best. +static void memcpy32_memcpy(uint32_t* dst, const uint32_t* src, int count) { + memcpy(dst, src, sizeof(uint32_t) * count); +} +BENCH(memcpy32_memcpy, 10) +BENCH(memcpy32_memcpy, 100) +BENCH(memcpy32_memcpy, 1000) +BENCH(memcpy32_memcpy, 10000) +BENCH(memcpy32_memcpy, 100000) + +// Let the compiler's autovectorizer do what it thinks is best. +static void memcpy32_autovectorize(uint32_t* dst, const uint32_t* src, int count) { + while (count --> 0) { + *dst++ = *src++; + } +} +BENCH(memcpy32_autovectorize, 10) +BENCH(memcpy32_autovectorize, 100) +BENCH(memcpy32_autovectorize, 1000) +BENCH(memcpy32_autovectorize, 10000) +BENCH(memcpy32_autovectorize, 100000) + +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + +// Align dst to 16 bytes, then use aligned stores. src isn't algined, so use unaligned loads. +static void memcpy32_sse2_align(uint32_t* dst, const uint32_t* src, int count) { + if (count >= 16) { + while (uintptr_t(dst) & 0xF) { + *dst++ = *src++; + count--; + } + + __m128i* dst128 = reinterpret_cast<__m128i*>(dst); + const __m128i* src128 = reinterpret_cast<const __m128i*>(src); + dst += 16 * (count / 16); + src += 16 * (count / 16); + while (count >= 16) { + __m128i a = _mm_loadu_si128(src128++); + __m128i b = _mm_loadu_si128(src128++); + __m128i c = _mm_loadu_si128(src128++); + __m128i d = _mm_loadu_si128(src128++); + + _mm_store_si128(dst128++, a); + _mm_store_si128(dst128++, b); + _mm_store_si128(dst128++, c); + _mm_store_si128(dst128++, d); + + count -= 16; + } + } + + while (count --> 0) { + *dst++ = *src++; + } +} +BENCH(memcpy32_sse2_align, 10) +BENCH(memcpy32_sse2_align, 100) +BENCH(memcpy32_sse2_align, 1000) +BENCH(memcpy32_sse2_align, 10000) +BENCH(memcpy32_sse2_align, 100000) + +// Leave both dst and src unaliged, and so use unaligned stores for dst and unaligned loads for src. +static void memcpy32_sse2_unalign(uint32_t* dst, const uint32_t* src, int count) { + __m128i* dst128 = reinterpret_cast<__m128i*>(dst); + const __m128i* src128 = reinterpret_cast<const __m128i*>(src); + dst += 16 * (count / 16); + src += 16 * (count / 16); + while (count >= 16) { + __m128i a = _mm_loadu_si128(src128++); + __m128i b = _mm_loadu_si128(src128++); + __m128i c = _mm_loadu_si128(src128++); + __m128i d = _mm_loadu_si128(src128++); + + _mm_storeu_si128(dst128++, a); + _mm_storeu_si128(dst128++, b); + _mm_storeu_si128(dst128++, c); + _mm_storeu_si128(dst128++, d); + + count -= 16; + } + + while (count --> 0) { + *dst++ = *src++; + } +} +BENCH(memcpy32_sse2_unalign, 10) +BENCH(memcpy32_sse2_unalign, 100) +BENCH(memcpy32_sse2_unalign, 1000) +BENCH(memcpy32_sse2_unalign, 10000) +BENCH(memcpy32_sse2_unalign, 100000) + +// Test our chosen best, from SkUtils.h +BENCH(sk_memcpy32, 10) +BENCH(sk_memcpy32, 100) +BENCH(sk_memcpy32, 1000) +BENCH(sk_memcpy32, 10000) +BENCH(sk_memcpy32, 100000) + +#endif // SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + +#undef BENCH diff --git a/chromium/third_party/skia/bench/MemoryBench.cpp b/chromium/third_party/skia/bench/MemoryBench.cpp new file mode 100644 index 00000000000..3fc46dccf4d --- /dev/null +++ b/chromium/third_party/skia/bench/MemoryBench.cpp @@ -0,0 +1,165 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkChunkAlloc.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" + +class ChunkAllocBench : public Benchmark { + SkString fName; + size_t fMinSize; +public: + ChunkAllocBench(size_t minSize) { + fMinSize = minSize; + fName.printf("chunkalloc_" SK_SIZE_T_SPECIFIER, minSize); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + size_t inc = fMinSize >> 4; + SkASSERT(inc > 0); + size_t total = fMinSize * 64; + + SkChunkAlloc alloc(fMinSize); + + for (int i = 0; i < loops; ++i) { + size_t size = 0; + int calls = 0; + while (size < total) { + alloc.allocThrow(inc); + size += inc; + calls += 1; + } + alloc.reset(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new ChunkAllocBench(64); ) +DEF_BENCH( return new ChunkAllocBench(8*1024); ) + +static int* calloc(size_t num) { + return (int*)sk_calloc_throw(num*sizeof(int)); +} + +static int* malloc_bzero(size_t num) { + const size_t bytes = num*sizeof(int); + int* ints = (int*)sk_malloc_throw(bytes); + sk_bzero(ints, bytes); + return ints; +} + +class ZerosBench : public Benchmark { + size_t fNum; + bool fRead; + bool fWrite; + bool fUseCalloc; + SkString fName; +public: + ZerosBench(size_t num, bool read, bool write, bool useCalloc) + : fNum(num) + , fRead(read) + , fWrite(write) + , fUseCalloc(useCalloc) { + fName.printf("memory_%s", useCalloc ? "calloc" : "malloc_bzero"); + if (read && write) { + fName.appendf("_rw"); + } else if (read) { + fName.appendf("_r"); + } else if (write) { + fName.appendf("_w"); + } + fName.appendf("_"SK_SIZE_T_SPECIFIER, num); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; i++) { + int* zeros = fUseCalloc ? calloc(fNum) : malloc_bzero(fNum); + if (fRead) { + volatile int x = 15; + for (size_t j = 0; j < fNum; j++) { + x ^= zeros[j]; + } + } + if (fWrite) { + for (size_t j = 0; j < fNum; j++) { + zeros[j] = 15; + } + } + sk_free(zeros); + } + } +}; + +// zero count r w useCalloc? +DEF_BENCH(return new ZerosBench(1024*1024, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(1024*1024, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(1024*1024, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(256*1024, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(256*1024, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(256*1024, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(4*1024, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(4*1024, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(4*1024, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(300, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(300, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(300, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(300, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(300, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(300, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(300, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(300, 1, 1, 1)) + +DEF_BENCH(return new ZerosBench(4, 0, 0, 0)) +DEF_BENCH(return new ZerosBench(4, 0, 0, 1)) +DEF_BENCH(return new ZerosBench(4, 0, 1, 0)) +DEF_BENCH(return new ZerosBench(4, 0, 1, 1)) +DEF_BENCH(return new ZerosBench(4, 1, 0, 0)) +DEF_BENCH(return new ZerosBench(4, 1, 0, 1)) +DEF_BENCH(return new ZerosBench(4, 1, 1, 0)) +DEF_BENCH(return new ZerosBench(4, 1, 1, 1)) diff --git a/chromium/third_party/skia/bench/MemsetBench.cpp b/chromium/third_party/skia/bench/MemsetBench.cpp new file mode 100644 index 00000000000..6a1bd24c84c --- /dev/null +++ b/chromium/third_party/skia/bench/MemsetBench.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkString.h" +#include "SkUtils.h" + +class MemsetBench : public Benchmark { + SkString fName; + +protected: + size_t fMinSize; + size_t fMaxSize; + enum { + kBufferSize = 10000, + VALUE32 = 0x12345678, + VALUE16 = 0x1234 + }; + + enum MemsetType { + MEMSET16 = 16, + MEMSET32 = 32 + }; + +public: + MemsetBench(MemsetType type, size_t minSize, size_t maxSize) { + SkASSERT((minSize < maxSize) && (maxSize <= kBufferSize)); + fMinSize = minSize; + fMaxSize = maxSize; + fName.printf("memset%d_" SK_SIZE_T_SPECIFIER "_" SK_SIZE_T_SPECIFIER, + type, minSize, maxSize); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void performTest() = 0; + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + this->performTest(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class Memset32Bench : public MemsetBench { + uint32_t kBuffer[kBufferSize + 3]; +public: + Memset32Bench(size_t minSize, size_t maxSize) + : INHERITED(MEMSET32, minSize, maxSize) {} + +protected: + virtual void performTest() SK_OVERRIDE { + for(size_t j = fMinSize; j < fMaxSize; ++j){ + sk_memset32(kBuffer, VALUE32, j); + sk_memset32(kBuffer + 1, VALUE32, j); + sk_memset32(kBuffer + 2, VALUE32, j); + sk_memset32(kBuffer + 3, VALUE32, j); + } + } +private: + typedef MemsetBench INHERITED; +}; + +class Memset16Bench : public MemsetBench { + uint16_t kBuffer[kBufferSize + 7]; +public: + Memset16Bench(size_t minSize, size_t maxSize) + : INHERITED(MEMSET16, minSize, maxSize) {} + +protected: + virtual void performTest() SK_OVERRIDE { + for(size_t j = fMinSize; j < fMaxSize; ++j){ + sk_memset16(kBuffer, VALUE16, j); + sk_memset16(kBuffer + 1, VALUE16, j); + sk_memset16(kBuffer + 2, VALUE16, j); + sk_memset16(kBuffer + 3, VALUE16, j); + sk_memset16(kBuffer + 4, VALUE16, j); + sk_memset16(kBuffer + 5, VALUE16, j); + sk_memset16(kBuffer + 6, VALUE16, j); + sk_memset16(kBuffer + 7, VALUE16, j); + } + } +private: + typedef MemsetBench INHERITED; +}; + +DEF_BENCH(return new Memset32Bench(1, 600);) +DEF_BENCH(return new Memset32Bench(600, 800);) +DEF_BENCH(return new Memset32Bench(800, 1000);) +DEF_BENCH(return new Memset32Bench(1000, 2000);) +DEF_BENCH(return new Memset32Bench(2000, 3000);) +DEF_BENCH(return new Memset32Bench(3000, 4000);) +DEF_BENCH(return new Memset32Bench(4000, 5000);) + +DEF_BENCH(return new Memset16Bench(1, 600);) +DEF_BENCH(return new Memset16Bench(600, 800);) +DEF_BENCH(return new Memset16Bench(800, 1000);) +DEF_BENCH(return new Memset16Bench(1000, 2000);) +DEF_BENCH(return new Memset16Bench(2000, 3000);) +DEF_BENCH(return new Memset16Bench(3000, 4000);) +DEF_BENCH(return new Memset16Bench(4000, 5000);) diff --git a/chromium/third_party/skia/bench/MergeBench.cpp b/chromium/third_party/skia/bench/MergeBench.cpp new file mode 100644 index 00000000000..a6bb3acfb19 --- /dev/null +++ b/chromium/third_party/skia/bench/MergeBench.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmapDevice.h" +#include "SkBitmapSource.h" +#include "SkCanvas.h" +#include "SkMergeImageFilter.h" + +#define FILTER_WIDTH_SMALL SkIntToScalar(32) +#define FILTER_HEIGHT_SMALL SkIntToScalar(32) +#define FILTER_WIDTH_LARGE SkIntToScalar(256) +#define FILTER_HEIGHT_LARGE SkIntToScalar(256) + +class MergeBench : public Benchmark { +public: + MergeBench(bool small) : fIsSmall(small), fInitialized(false) { } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fIsSmall ? "merge_small" : "merge_large"; + } + + virtual void onPreDraw() SK_OVERRIDE { + if (!fInitialized) { + make_bitmap(); + make_checkerboard(); + fInitialized = true; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r = fIsSmall ? SkRect::MakeWH(FILTER_WIDTH_SMALL, FILTER_HEIGHT_SMALL) : + SkRect::MakeWH(FILTER_WIDTH_LARGE, FILTER_HEIGHT_LARGE); + SkPaint paint; + paint.setImageFilter(mergeBitmaps())->unref(); + for (int i = 0; i < loops; i++) { + canvas->drawRect(r, paint); + } + } + +private: + SkImageFilter* mergeBitmaps() { + SkImageFilter* first = SkBitmapSource::Create(fCheckerboard); + SkImageFilter* second = SkBitmapSource::Create(fBitmap); + SkAutoUnref aur0(first); + SkAutoUnref aur1(second); + return SkMergeImageFilter::Create(first, second); + } + + void make_bitmap() { + fBitmap.allocN32Pixels(80, 80); + SkCanvas canvas(fBitmap); + canvas.clear(0x00000000); + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(0xFF884422); + paint.setTextSize(SkIntToScalar(96)); + const char* str = "g"; + canvas.drawText(str, strlen(str), SkIntToScalar(15), SkIntToScalar(55), paint); + } + + void make_checkerboard() { + fCheckerboard.allocN32Pixels(80, 80); + SkCanvas canvas(fCheckerboard); + canvas.clear(0x00000000); + SkPaint darkPaint; + darkPaint.setColor(0xFF804020); + SkPaint lightPaint; + lightPaint.setColor(0xFF244484); + for (int y = 0; y < 80; y += 16) { + for (int x = 0; x < 80; x += 16) { + canvas.save(); + canvas.translate(SkIntToScalar(x), SkIntToScalar(y)); + canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint); + canvas.restore(); + } + } + } + + bool fIsSmall; + bool fInitialized; + SkBitmap fBitmap, fCheckerboard; + + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new MergeBench(true); ) +DEF_BENCH( return new MergeBench(false); ) diff --git a/chromium/third_party/skia/bench/MorphologyBench.cpp b/chromium/third_party/skia/bench/MorphologyBench.cpp new file mode 100644 index 00000000000..97995e81955 --- /dev/null +++ b/chromium/third_party/skia/bench/MorphologyBench.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkMorphologyImageFilter.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +#define SMALL SkIntToScalar(2) +#define REAL 1.5f +#define BIG SkIntToScalar(10) + +enum MorphologyType { + kErode_MT, + kDilate_MT +}; + +static const char* gStyleName[] = { + "erode", + "dilate" +}; + +class MorphologyBench : public Benchmark { + SkScalar fRadius; + MorphologyType fStyle; + SkString fName; + +public: + MorphologyBench(SkScalar rad, MorphologyType style) + { + fRadius = rad; + fStyle = style; + const char* name = rad > 0 ? gStyleName[style] : "none"; + if (SkScalarFraction(rad) != 0) { + fName.printf("morph_%.2f_%s", SkScalarToFloat(rad), name); + } else { + fName.printf("morph_%d_%s", SkScalarRoundToInt(rad), name); + } + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + + paint.setAntiAlias(true); + + SkRandom rand; + for (int i = 0; i < loops; i++) { + SkRect r = SkRect::MakeWH(rand.nextUScalar1() * 400, + rand.nextUScalar1() * 400); + r.offset(fRadius, fRadius); + + if (fRadius > 0) { + SkMorphologyImageFilter* mf = NULL; + switch (fStyle) { + case kDilate_MT: + mf = SkDilateImageFilter::Create(SkScalarFloorToInt(fRadius), + SkScalarFloorToInt(fRadius)); + break; + case kErode_MT: + mf = SkErodeImageFilter::Create(SkScalarFloorToInt(fRadius), + SkScalarFloorToInt(fRadius)); + break; + } + paint.setImageFilter(mf)->unref(); + } + canvas->drawOval(r, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new MorphologyBench(SMALL, kErode_MT); ) +DEF_BENCH( return new MorphologyBench(SMALL, kDilate_MT); ) + +DEF_BENCH( return new MorphologyBench(BIG, kErode_MT); ) +DEF_BENCH( return new MorphologyBench(BIG, kDilate_MT); ) + +DEF_BENCH( return new MorphologyBench(REAL, kErode_MT); ) +DEF_BENCH( return new MorphologyBench(REAL, kDilate_MT); ) + +DEF_BENCH( return new MorphologyBench(0, kErode_MT); ) diff --git a/chromium/third_party/skia/bench/MutexBench.cpp b/chromium/third_party/skia/bench/MutexBench.cpp new file mode 100644 index 00000000000..67648b5decf --- /dev/null +++ b/chromium/third_party/skia/bench/MutexBench.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkThread.h" + +class MutexBench : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "mutex"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + SK_DECLARE_STATIC_MUTEX(mu); + for (int i = 0; i < loops; i++) { + mu.acquire(); + mu.release(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new MutexBench(); ) diff --git a/chromium/third_party/skia/bench/PathBench.cpp b/chromium/third_party/skia/bench/PathBench.cpp new file mode 100644 index 00000000000..59b3bfa2ef7 --- /dev/null +++ b/chromium/third_party/skia/bench/PathBench.cpp @@ -0,0 +1,1019 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" +#include "SkTArray.h" + +enum Flags { + kStroke_Flag = 1 << 0, + kBig_Flag = 1 << 1 +}; + +#define FLAGS00 Flags(0) +#define FLAGS01 Flags(kStroke_Flag) +#define FLAGS10 Flags(kBig_Flag) +#define FLAGS11 Flags(kStroke_Flag | kBig_Flag) + +class PathBench : public Benchmark { + SkPaint fPaint; + SkString fName; + Flags fFlags; +public: + PathBench(Flags flags) : fFlags(flags) { + fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style : + SkPaint::kFill_Style); + fPaint.setStrokeWidth(SkIntToScalar(5)); + fPaint.setStrokeJoin(SkPaint::kBevel_Join); + } + + virtual void appendName(SkString*) = 0; + virtual void makePath(SkPath*) = 0; + virtual int complexity() { return 0; } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + fName.printf("path_%s_%s_", + fFlags & kStroke_Flag ? "stroke" : "fill", + fFlags & kBig_Flag ? "big" : "small"); + this->appendName(&fName); + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint(fPaint); + this->setupPaint(&paint); + + SkPath path; + this->makePath(&path); + if (fFlags & kBig_Flag) { + SkMatrix m; + m.setScale(SkIntToScalar(10), SkIntToScalar(10)); + path.transform(m); + } + + int count = loops; + if (fFlags & kBig_Flag) { + count >>= 2; + } + count >>= (3 * complexity()); + + for (int i = 0; i < count; i++) { + canvas->drawPath(path, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class TrianglePathBench : public PathBench { +public: + TrianglePathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("triangle"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + static const int gCoord[] = { + 10, 10, 15, 5, 20, 20 + }; + path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1])); + path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3])); + path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5])); + path->close(); + } +private: + typedef PathBench INHERITED; +}; + +class RectPathBench : public PathBench { +public: + RectPathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("rect"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRect r = { 10, 10, 20, 20 }; + path->addRect(r); + } +private: + typedef PathBench INHERITED; +}; + +class OvalPathBench : public PathBench { +public: + OvalPathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("oval"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRect r = { 10, 10, 23, 20 }; + path->addOval(r); + } +private: + typedef PathBench INHERITED; +}; + +class CirclePathBench: public PathBench { +public: + CirclePathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("circle"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + path->addCircle(SkIntToScalar(20), SkIntToScalar(20), + SkIntToScalar(10)); + } +private: + typedef PathBench INHERITED; +}; + +class SawToothPathBench : public PathBench { +public: + SawToothPathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("sawtooth"); + } + virtual void makePath(SkPath* path) { + SkScalar x = SkIntToScalar(20); + SkScalar y = SkIntToScalar(20); + const SkScalar x0 = x; + const SkScalar dx = SK_Scalar1 * 5; + const SkScalar dy = SK_Scalar1 * 10; + + path->moveTo(x, y); + for (int i = 0; i < 32; i++) { + x += dx; + path->lineTo(x, y - dy); + x += dx; + path->lineTo(x, y + dy); + } + path->lineTo(x, y + 2 * dy); + path->lineTo(x0, y + 2 * dy); + path->close(); + } + virtual int complexity() SK_OVERRIDE { return 1; } +private: + typedef PathBench INHERITED; +}; + +class LongCurvedPathBench : public PathBench { +public: + LongCurvedPathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("long_curved"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRandom rand (12); + int i; + for (i = 0; i < 100; i++) { + path->quadTo(SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)), + SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)), + SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)), + SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480))); + } + path->close(); + } + virtual int complexity() SK_OVERRIDE { return 2; } +private: + typedef PathBench INHERITED; +}; + +class LongLinePathBench : public PathBench { +public: + LongLinePathBench(Flags flags) : INHERITED(flags) {} + + virtual void appendName(SkString* name) SK_OVERRIDE { + name->append("long_line"); + } + virtual void makePath(SkPath* path) SK_OVERRIDE { + SkRandom rand; + path->moveTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480); + for (size_t i = 1; i < 100; i++) { + path->lineTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480); + } + } + virtual int complexity() SK_OVERRIDE { return 2; } +private: + typedef PathBench INHERITED; +}; + +class RandomPathBench : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + void createData(int minVerbs, + int maxVerbs, + bool allowMoves = true, + SkRect* bounds = NULL) { + SkRect tempBounds; + if (NULL == bounds) { + tempBounds.setXYWH(0, 0, SK_Scalar1, SK_Scalar1); + bounds = &tempBounds; + } + fVerbCnts.reset(kNumVerbCnts); + for (int i = 0; i < kNumVerbCnts; ++i) { + fVerbCnts[i] = fRandom.nextRangeU(minVerbs, maxVerbs + 1); + } + fVerbs.reset(kNumVerbs); + for (int i = 0; i < kNumVerbs; ++i) { + do { + fVerbs[i] = static_cast<SkPath::Verb>(fRandom.nextULessThan(SkPath::kDone_Verb)); + } while (!allowMoves && SkPath::kMove_Verb == fVerbs[i]); + } + fPoints.reset(kNumPoints); + for (int i = 0; i < kNumPoints; ++i) { + fPoints[i].set(fRandom.nextRangeScalar(bounds->fLeft, bounds->fRight), + fRandom.nextRangeScalar(bounds->fTop, bounds->fBottom)); + } + this->restartMakingPaths(); + } + + void restartMakingPaths() { + fCurrPath = 0; + fCurrVerb = 0; + fCurrPoint = 0; + } + + void makePath(SkPath* path) { + int vCount = fVerbCnts[(fCurrPath++) & (kNumVerbCnts - 1)]; + for (int v = 0; v < vCount; ++v) { + int verb = fVerbs[(fCurrVerb++) & (kNumVerbs - 1)]; + switch (verb) { + case SkPath::kMove_Verb: + path->moveTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]); + break; + case SkPath::kLine_Verb: + path->lineTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]); + break; + case SkPath::kQuad_Verb: + path->quadTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)], + fPoints[(fCurrPoint + 1) & (kNumPoints - 1)]); + fCurrPoint += 2; + break; + case SkPath::kConic_Verb: + path->conicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)], + fPoints[(fCurrPoint + 1) & (kNumPoints - 1)], + SK_ScalarHalf); + fCurrPoint += 2; + break; + case SkPath::kCubic_Verb: + path->cubicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)], + fPoints[(fCurrPoint + 1) & (kNumPoints - 1)], + fPoints[(fCurrPoint + 2) & (kNumPoints - 1)]); + fCurrPoint += 3; + break; + case SkPath::kClose_Verb: + path->close(); + break; + default: + SkDEBUGFAIL("Unexpected path verb"); + break; + } + } + } + + void finishedMakingPaths() { + fVerbCnts.reset(0); + fVerbs.reset(0); + fPoints.reset(0); + } + +private: + enum { + // these should all be pow 2 + kNumVerbCnts = 1 << 5, + kNumVerbs = 1 << 5, + kNumPoints = 1 << 5, + }; + SkAutoTArray<int> fVerbCnts; + SkAutoTArray<SkPath::Verb> fVerbs; + SkAutoTArray<SkPoint> fPoints; + int fCurrPath; + int fCurrVerb; + int fCurrPoint; + SkRandom fRandom; + typedef Benchmark INHERITED; +}; + +class PathCreateBench : public RandomPathBench { +public: + PathCreateBench() { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "path_create"; + } + + virtual void onPreDraw() SK_OVERRIDE { + this->createData(10, 100); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + if (i % 1000 == 0) { + fPath.reset(); // PathRef memory can grow without bound otherwise. + } + this->makePath(&fPath); + } + this->restartMakingPaths(); + } + +private: + SkPath fPath; + + typedef RandomPathBench INHERITED; +}; + +class PathCopyBench : public RandomPathBench { +public: + PathCopyBench() { + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "path_copy"; + } + virtual void onPreDraw() SK_OVERRIDE { + this->createData(10, 100); + fPaths.reset(kPathCnt); + fCopies.reset(kPathCnt); + for (int i = 0; i < kPathCnt; ++i) { + this->makePath(&fPaths[i]); + } + this->finishedMakingPaths(); + } + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + fCopies[idx] = fPaths[idx]; + } + } + +private: + enum { + // must be a pow 2 + kPathCnt = 1 << 5, + }; + SkAutoTArray<SkPath> fPaths; + SkAutoTArray<SkPath> fCopies; + + typedef RandomPathBench INHERITED; +}; + +class PathTransformBench : public RandomPathBench { +public: + PathTransformBench(bool inPlace) : fInPlace(inPlace) {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fInPlace ? "path_transform_in_place" : "path_transform_copy"; + } + + virtual void onPreDraw() SK_OVERRIDE { + fMatrix.setScale(5 * SK_Scalar1, 6 * SK_Scalar1); + this->createData(10, 100); + fPaths.reset(kPathCnt); + for (int i = 0; i < kPathCnt; ++i) { + this->makePath(&fPaths[i]); + } + this->finishedMakingPaths(); + if (!fInPlace) { + fTransformed.reset(kPathCnt); + } + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + if (fInPlace) { + for (int i = 0; i < loops; ++i) { + fPaths[i & (kPathCnt - 1)].transform(fMatrix); + } + } else { + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + fPaths[idx].transform(fMatrix, &fTransformed[idx]); + } + } + } + +private: + enum { + // must be a pow 2 + kPathCnt = 1 << 5, + }; + SkAutoTArray<SkPath> fPaths; + SkAutoTArray<SkPath> fTransformed; + + SkMatrix fMatrix; + bool fInPlace; + typedef RandomPathBench INHERITED; +}; + +class PathEqualityBench : public RandomPathBench { +public: + PathEqualityBench() { } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "path_equality_50%"; + } + + virtual void onPreDraw() SK_OVERRIDE { + fParity = 0; + this->createData(10, 100); + fPaths.reset(kPathCnt); + fCopies.reset(kPathCnt); + for (int i = 0; i < kPathCnt; ++i) { + this->makePath(&fPaths[i]); + fCopies[i] = fPaths[i]; + } + this->finishedMakingPaths(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + fParity ^= (fPaths[idx] == fCopies[idx & ~0x1]); + } + } + +private: + bool fParity; // attempt to keep compiler from optimizing out the == + enum { + // must be a pow 2 + kPathCnt = 1 << 5, + }; + SkAutoTArray<SkPath> fPaths; + SkAutoTArray<SkPath> fCopies; + typedef RandomPathBench INHERITED; +}; + +class SkBench_AddPathTest : public RandomPathBench { +public: + enum AddType { + kAdd_AddType, + kAddTrans_AddType, + kAddMatrix_AddType, + kReverseAdd_AddType, + kReversePathTo_AddType, + }; + + SkBench_AddPathTest(AddType type) : fType(type) { + fMatrix.setRotate(60 * SK_Scalar1); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + switch (fType) { + case kAdd_AddType: + return "path_add_path"; + case kAddTrans_AddType: + return "path_add_path_trans"; + case kAddMatrix_AddType: + return "path_add_path_matrix"; + case kReverseAdd_AddType: + return "path_reverse_add_path"; + case kReversePathTo_AddType: + return "path_reverse_path_to"; + default: + SkDEBUGFAIL("Bad add type"); + return ""; + } + } + + virtual void onPreDraw() SK_OVERRIDE { + // reversePathTo assumes a single contour path. + bool allowMoves = kReversePathTo_AddType != fType; + this->createData(10, 100, allowMoves); + fPaths0.reset(kPathCnt); + fPaths1.reset(kPathCnt); + for (int i = 0; i < kPathCnt; ++i) { + this->makePath(&fPaths0[i]); + this->makePath(&fPaths1[i]); + } + this->finishedMakingPaths(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + switch (fType) { + case kAdd_AddType: + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + SkPath result = fPaths0[idx]; + result.addPath(fPaths1[idx]); + } + break; + case kAddTrans_AddType: + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + SkPath result = fPaths0[idx]; + result.addPath(fPaths1[idx], 2 * SK_Scalar1, 5 * SK_Scalar1); + } + break; + case kAddMatrix_AddType: + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + SkPath result = fPaths0[idx]; + result.addPath(fPaths1[idx], fMatrix); + } + break; + case kReverseAdd_AddType: + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + SkPath result = fPaths0[idx]; + result.reverseAddPath(fPaths1[idx]); + } + break; + case kReversePathTo_AddType: + for (int i = 0; i < loops; ++i) { + int idx = i & (kPathCnt - 1); + SkPath result = fPaths0[idx]; + result.reversePathTo(fPaths1[idx]); + } + break; + } + } + +private: + AddType fType; // or reverseAddPath + enum { + // must be a pow 2 + kPathCnt = 1 << 5, + }; + SkAutoTArray<SkPath> fPaths0; + SkAutoTArray<SkPath> fPaths1; + SkMatrix fMatrix; + typedef RandomPathBench INHERITED; +}; + + +class CirclesBench : public Benchmark { +protected: + SkString fName; + Flags fFlags; + +public: + CirclesBench(Flags flags) : fFlags(flags) { + fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill"); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + + paint.setColor(SK_ColorBLACK); + paint.setAntiAlias(true); + if (fFlags & kStroke_Flag) { + paint.setStyle(SkPaint::kStroke_Style); + } + + SkRandom rand; + + SkRect r; + + for (int i = 0; i < loops; ++i) { + SkScalar radius = rand.nextUScalar1() * 3; + r.fLeft = rand.nextUScalar1() * 300; + r.fTop = rand.nextUScalar1() * 300; + r.fRight = r.fLeft + 2 * radius; + r.fBottom = r.fTop + 2 * radius; + + if (fFlags & kStroke_Flag) { + paint.setStrokeWidth(rand.nextUScalar1() * 5.0f); + } + + SkPath temp; + + // mimic how Chrome does circles + temp.arcTo(r, 0, 0, false); + temp.addOval(r, SkPath::kCCW_Direction); + temp.arcTo(r, 360, 0, true); + temp.close(); + + canvas->drawPath(temp, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + + +// Chrome creates its own round rects with each corner possibly being different. +// In its "zero radius" incarnation it creates degenerate round rects. +// Note: PathTest::test_arb_round_rect_is_convex and +// test_arb_zero_rad_round_rect_is_rect perform almost exactly +// the same test (but with no drawing) +class ArbRoundRectBench : public Benchmark { +protected: + SkString fName; + +public: + ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) { + if (zeroRad) { + fName.printf("zeroradroundrect"); + } else { + fName.printf("arbroundrect"); + } + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + static void add_corner_arc(SkPath* path, const SkRect& rect, + SkScalar xIn, SkScalar yIn, + int startAngle) + { + + SkScalar rx = SkMinScalar(rect.width(), xIn); + SkScalar ry = SkMinScalar(rect.height(), yIn); + + SkRect arcRect; + arcRect.set(-rx, -ry, rx, ry); + switch (startAngle) { + case 0: + arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom); + break; + case 90: + arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom); + break; + case 180: + arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop); + break; + case 270: + arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop); + break; + default: + break; + } + + path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false); + } + + static void make_arb_round_rect(SkPath* path, const SkRect& r, + SkScalar xCorner, SkScalar yCorner) { + // we are lazy here and use the same x & y for each corner + add_corner_arc(path, r, xCorner, yCorner, 270); + add_corner_arc(path, r, xCorner, yCorner, 0); + add_corner_arc(path, r, xCorner, yCorner, 90); + add_corner_arc(path, r, xCorner, yCorner, 180); + path->close(); + + SkASSERT(path->isConvex()); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom rand; + SkRect r; + + for (int i = 0; i < loops; ++i) { + SkPaint paint; + paint.setColor(0xff000000 | rand.nextU()); + paint.setAntiAlias(true); + + SkScalar size = rand.nextUScalar1() * 30; + if (size < SK_Scalar1) { + continue; + } + r.fLeft = rand.nextUScalar1() * 300; + r.fTop = rand.nextUScalar1() * 300; + r.fRight = r.fLeft + 2 * size; + r.fBottom = r.fTop + 2 * size; + + SkPath temp; + + if (fZeroRad) { + make_arb_round_rect(&temp, r, 0, 0); + + SkASSERT(temp.isRect(NULL)); + } else { + make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15); + } + + canvas->drawPath(temp, paint); + } + } + +private: + bool fZeroRad; // should 0 radius rounds rects be tested? + + typedef Benchmark INHERITED; +}; + +class ConservativelyContainsBench : public Benchmark { +public: + enum Type { + kRect_Type, + kRoundRect_Type, + kOval_Type, + }; + + ConservativelyContainsBench(Type type) { + fParity = false; + fName = "conservatively_contains_"; + switch (type) { + case kRect_Type: + fName.append("rect"); + fPath.addRect(kBaseRect); + break; + case kRoundRect_Type: + fName.append("round_rect"); + fPath.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1]); + break; + case kOval_Type: + fName.append("oval"); + fPath.addOval(kBaseRect); + break; + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +private: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + const SkRect& rect = fQueryRects[i % kQueryRectCnt]; + fParity = fParity != fPath.conservativelyContainsRect(rect); + } + } + + virtual void onPreDraw() SK_OVERRIDE { + fQueryRects.setCount(kQueryRectCnt); + + SkRandom rand; + for (int i = 0; i < kQueryRectCnt; ++i) { + SkSize size; + SkPoint xy; + size.fWidth = rand.nextRangeScalar(kQueryMin.fWidth, kQueryMax.fWidth); + size.fHeight = rand.nextRangeScalar(kQueryMin.fHeight, kQueryMax.fHeight); + xy.fX = rand.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth); + xy.fY = rand.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight); + + fQueryRects[i] = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight); + } + } + + enum { + kQueryRectCnt = 400, + }; + static const SkRect kBounds; // bounds for all random query rects + static const SkSize kQueryMin; // minimum query rect size, should be <= kQueryMax + static const SkSize kQueryMax; // max query rect size, should < kBounds + static const SkRect kBaseRect; // rect that is used to construct the path + static const SkScalar kRRRadii[2]; // x and y radii for round rect + + SkString fName; + SkPath fPath; + bool fParity; + SkTDArray<SkRect> fQueryRects; + + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkGeometry.h" + +class ConicBench_Chop5 : public Benchmark { + SkConic fRQ; +public: + ConicBench_Chop5() { + fRQ.fPts[0].set(0, 0); + fRQ.fPts[1].set(100, 0); + fRQ.fPts[2].set(100, 100); + fRQ.fW = SkScalarCos(SK_ScalarPI/4); + } + +private: + virtual const char* onGetName() SK_OVERRIDE { + return "ratquad-chop-0.5"; + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkConic dst[2]; + for (int i = 0; i < loops; ++i) { + fRQ.chopAt(0.5f, dst); + } + } + + typedef Benchmark INHERITED; +}; + +class ConicBench_ChopHalf : public Benchmark { + SkConic fRQ; +public: + ConicBench_ChopHalf() { + fRQ.fPts[0].set(0, 0); + fRQ.fPts[1].set(100, 0); + fRQ.fPts[2].set(100, 100); + fRQ.fW = SkScalarCos(SK_ScalarPI/4); + } + +private: + virtual const char* onGetName() SK_OVERRIDE { + return "ratquad-chop-half"; + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkConic dst[2]; + for (int i = 0; i < loops; ++i) { + fRQ.chop(dst); + } + } + + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static void rand_conic(SkConic* conic, SkRandom& rand) { + for (int i = 0; i < 3; ++i) { + conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100); + } + if (rand.nextUScalar1() > 0.5f) { + conic->fW = rand.nextUScalar1(); + } else { + conic->fW = 1 + rand.nextUScalar1() * 4; + } +} + +class ConicBench : public Benchmark { +public: + ConicBench() { + SkRandom rand; + for (int i = 0; i < CONICS; ++i) { + rand_conic(&fConics[i], rand); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + enum { + CONICS = 100 + }; + SkConic fConics[CONICS]; + +private: + typedef Benchmark INHERITED; +}; + +class ConicBench_ComputeError : public ConicBench { +public: + ConicBench_ComputeError() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "conic-compute-error"; + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkVector err; + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < CONICS; ++j) { + fConics[j].computeAsQuadError(&err); + } + } + } + +private: + typedef ConicBench INHERITED; +}; + +class ConicBench_asQuadTol : public ConicBench { +public: + ConicBench_asQuadTol() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "conic-asQuadTol"; + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < CONICS; ++j) { + fConics[j].asQuadTol(SK_ScalarHalf); + } + } + } + +private: + typedef ConicBench INHERITED; +}; + +class ConicBench_quadPow2 : public ConicBench { +public: + ConicBench_quadPow2() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "conic-quadPow2"; + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < CONICS; ++j) { + fConics[j].computeQuadPOW2(SK_ScalarHalf); + } + } + } + +private: + typedef ConicBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100)); +const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1)); +const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40)); +const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50)); +const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)}; + +DEF_BENCH( return new TrianglePathBench(FLAGS00); ) +DEF_BENCH( return new TrianglePathBench(FLAGS01); ) +DEF_BENCH( return new TrianglePathBench(FLAGS10); ) +DEF_BENCH( return new TrianglePathBench(FLAGS11); ) + +DEF_BENCH( return new RectPathBench(FLAGS00); ) +DEF_BENCH( return new RectPathBench(FLAGS01); ) +DEF_BENCH( return new RectPathBench(FLAGS10); ) +DEF_BENCH( return new RectPathBench(FLAGS11); ) + +DEF_BENCH( return new OvalPathBench(FLAGS00); ) +DEF_BENCH( return new OvalPathBench(FLAGS01); ) +DEF_BENCH( return new OvalPathBench(FLAGS10); ) +DEF_BENCH( return new OvalPathBench(FLAGS11); ) + +DEF_BENCH( return new CirclePathBench(FLAGS00); ) +DEF_BENCH( return new CirclePathBench(FLAGS01); ) +DEF_BENCH( return new CirclePathBench(FLAGS10); ) +DEF_BENCH( return new CirclePathBench(FLAGS11); ) + +DEF_BENCH( return new SawToothPathBench(FLAGS00); ) +DEF_BENCH( return new SawToothPathBench(FLAGS01); ) + +DEF_BENCH( return new LongCurvedPathBench(FLAGS00); ) +DEF_BENCH( return new LongCurvedPathBench(FLAGS01); ) +DEF_BENCH( return new LongLinePathBench(FLAGS00); ) +DEF_BENCH( return new LongLinePathBench(FLAGS01); ) + +DEF_BENCH( return new PathCreateBench(); ) +DEF_BENCH( return new PathCopyBench(); ) +DEF_BENCH( return new PathTransformBench(true); ) +DEF_BENCH( return new PathTransformBench(false); ) +DEF_BENCH( return new PathEqualityBench(); ) + +DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); ) +DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); ) +DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); ) +DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); ) +DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); ) + +DEF_BENCH( return new CirclesBench(FLAGS00); ) +DEF_BENCH( return new CirclesBench(FLAGS01); ) +DEF_BENCH( return new ArbRoundRectBench(false); ) +DEF_BENCH( return new ArbRoundRectBench(true); ) +DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); ) +DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); ) +DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); ) + +DEF_BENCH( return new ConicBench_Chop5() ) +DEF_BENCH( return new ConicBench_ChopHalf() ) +DEF_BENCH( return new ConicBench_ComputeError() ) +DEF_BENCH( return new ConicBench_asQuadTol() ) +DEF_BENCH( return new ConicBench_quadPow2() ) diff --git a/chromium/third_party/skia/bench/PathIterBench.cpp b/chromium/third_party/skia/bench/PathIterBench.cpp new file mode 100644 index 00000000000..b82146d1b23 --- /dev/null +++ b/chromium/third_party/skia/bench/PathIterBench.cpp @@ -0,0 +1,95 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +static int rand_pts(SkRandom& rand, SkPoint pts[4]) { + int n = rand.nextU() & 3; + n += 1; + + for (int i = 0; i < n; ++i) { + pts[i].fX = rand.nextSScalar1(); + pts[i].fY = rand.nextSScalar1(); + } + return n; +} + +class PathIterBench : public Benchmark { + SkString fName; + SkPath fPath; + bool fRaw; + +public: + PathIterBench(bool raw) { + fName.printf("pathiter_%s", raw ? "raw" : "consume"); + fRaw = raw; + + SkRandom rand; + for (int i = 0; i < 1000; ++i) { + SkPoint pts[4]; + int n = rand_pts(rand, pts); + switch (n) { + case 1: + fPath.moveTo(pts[0]); + break; + case 2: + fPath.lineTo(pts[1]); + break; + case 3: + fPath.quadTo(pts[1], pts[2]); + break; + case 4: + fPath.cubicTo(pts[1], pts[2], pts[3]); + break; + } + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + if (fRaw) { + for (int i = 0; i < loops; ++i) { + SkPath::RawIter iter(fPath); + SkPath::Verb verb; + SkPoint pts[4]; + + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { } + } + } else { + for (int i = 0; i < loops; ++i) { + SkPath::Iter iter(fPath, false); + SkPath::Verb verb; + SkPoint pts[4]; + + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { } + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new PathIterBench(false); ) +DEF_BENCH( return new PathIterBench(true); ) diff --git a/chromium/third_party/skia/bench/PathUtilsBench.cpp b/chromium/third_party/skia/bench/PathUtilsBench.cpp new file mode 100644 index 00000000000..6c8086fb9df --- /dev/null +++ b/chromium/third_party/skia/bench/PathUtilsBench.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPathUtils.h" +#include "SkRandom.h" +#include "SkString.h" +#include "SkTime.h" + +#define H 16 +#define W 16 +#define STRIDE 2 + +//this function is redefined for sample, test, and bench. is there anywhere +// I can put it to avoid code duplcation? +static void fillRandomBits( int chars, char* bits ){ + SkRandom rand(SkTime::GetMSecs()); + + for (int i = 0; i < chars; ++i){ + bits[i] = rand.nextU(); + } +} + +static void path_proc(char* bits, SkPath* path) { + SkPathUtils::BitsToPath_Path(path, bits, H, W, STRIDE); +} + +static void region_proc(char* bits, SkPath* path) { + SkPathUtils::BitsToPath_Region(path, bits, H, W, STRIDE); +} + +/// Emulates the mix of rects blitted by gmail during scrolling +class PathUtilsBench : public Benchmark { + typedef void (*Proc)(char*, SkPath*); + + Proc fProc; + SkString fName; + char* bits[H * STRIDE]; + +public: + PathUtilsBench(Proc proc, const char name[]) { + fProc = proc; + fName.printf("pathUtils_%s", name); + + + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + + for (int i = 0; i < loops; ++i){ + //create a random 16x16 bitmap + fillRandomBits(H * STRIDE, (char*) &bits); + + //use passed function pointer to handle it + SkPath path; + fProc( (char*) &bits, &path); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return SkNEW_ARGS(PathUtilsBench, (path_proc, "path")); ) +DEF_BENCH( return SkNEW_ARGS(PathUtilsBench, (region_proc, "region")); ) diff --git a/chromium/third_party/skia/bench/PerlinNoiseBench.cpp b/chromium/third_party/skia/bench/PerlinNoiseBench.cpp new file mode 100644 index 00000000000..560628f4fdd --- /dev/null +++ b/chromium/third_party/skia/bench/PerlinNoiseBench.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPerlinNoiseShader.h" + +class PerlinNoiseBench : public Benchmark { + SkISize fSize; + +public: + PerlinNoiseBench() { + fSize = SkISize::Make(80, 80); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "perlinnoise"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + this->test(loops, canvas, 0, 0, SkPerlinNoiseShader::kFractalNoise_Type, + 0.1f, 0.1f, 3, 0, false); + } + +private: + void drawClippedRect(SkCanvas* canvas, int x, int y, const SkPaint& paint) { + canvas->save(); + canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), + SkIntToScalar(fSize.width()), SkIntToScalar(fSize.height()))); + SkRect r = SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), + SkIntToScalar(fSize.width()), + SkIntToScalar(fSize.height())); + canvas->drawRect(r, paint); + canvas->restore(); + } + + void test(const int loops, SkCanvas* canvas, int x, int y, SkPerlinNoiseShader::Type type, + float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, + bool stitchTiles) { + SkShader* shader = (type == SkPerlinNoiseShader::kFractalNoise_Type) ? + SkPerlinNoiseShader::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, + seed, stitchTiles ? &fSize : NULL) : + SkPerlinNoiseShader::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, + seed, stitchTiles ? &fSize : NULL); + SkPaint paint; + paint.setShader(shader)->unref(); + + for (int i = 0; i < loops; i++) { + this->drawClippedRect(canvas, x, y, paint); + } + } + + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new PerlinNoiseBench(); ) diff --git a/chromium/third_party/skia/bench/PicturePlaybackBench.cpp b/chromium/third_party/skia/bench/PicturePlaybackBench.cpp new file mode 100644 index 00000000000..0109c720fc0 --- /dev/null +++ b/chromium/third_party/skia/bench/PicturePlaybackBench.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkPaint.h" +#include "SkPicture.h" +#include "SkPictureRecorder.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkString.h" + +// This is designed to emulate about 4 screens of textual content + + +class PicturePlaybackBench : public Benchmark { +public: + PicturePlaybackBench(const char name[]) { + fName.printf("picture_playback_%s", name); + fPictureWidth = SkIntToScalar(PICTURE_WIDTH); + fPictureHeight = SkIntToScalar(PICTURE_HEIGHT); + fTextSize = SkIntToScalar(TEXT_SIZE); + } + + enum { + PICTURE_WIDTH = 1000, + PICTURE_HEIGHT = 4000, + TEXT_SIZE = 10 + }; +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + + SkPictureRecorder recorder; + SkCanvas* pCanvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); + this->recordCanvas(pCanvas); + SkAutoTUnref<SkPicture> picture(recorder.endRecording()); + + const SkPoint translateDelta = getTranslateDelta(loops); + + for (int i = 0; i < loops; i++) { + picture->draw(canvas); + canvas->translate(translateDelta.fX, translateDelta.fY); + } + } + + virtual void recordCanvas(SkCanvas* canvas) = 0; + virtual SkPoint getTranslateDelta(int N) { + SkIPoint canvasSize = onGetSize(); + return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/N), + SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/N)); + } + + SkString fName; + SkScalar fPictureWidth; + SkScalar fPictureHeight; + SkScalar fTextSize; +private: + typedef Benchmark INHERITED; +}; + + +class TextPlaybackBench : public PicturePlaybackBench { +public: + TextPlaybackBench() : INHERITED("drawText") { } +protected: + virtual void recordCanvas(SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + paint.setTextSize(fTextSize); + paint.setColor(SK_ColorBLACK); + + const char* text = "Hamburgefons"; + size_t len = strlen(text); + const SkScalar textWidth = paint.measureText(text, len); + + for (SkScalar x = 0; x < fPictureWidth; x += textWidth) { + for (SkScalar y = 0; y < fPictureHeight; y += fTextSize) { + canvas->drawText(text, len, x, y, paint); + } + } + } +private: + typedef PicturePlaybackBench INHERITED; +}; + +class PosTextPlaybackBench : public PicturePlaybackBench { +public: + PosTextPlaybackBench(bool drawPosH) + : INHERITED(drawPosH ? "drawPosTextH" : "drawPosText") + , fDrawPosH(drawPosH) { } +protected: + virtual void recordCanvas(SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + paint.setTextSize(fTextSize); + paint.setColor(SK_ColorBLACK); + + const char* text = "Hamburgefons"; + size_t len = strlen(text); + const SkScalar textWidth = paint.measureText(text, len); + + SkScalar* adv = new SkScalar[len]; + paint.getTextWidths(text, len, adv); + + for (SkScalar x = 0; x < fPictureWidth; x += textWidth) { + for (SkScalar y = 0; y < fPictureHeight; y += fTextSize) { + + SkPoint* pos = new SkPoint[len]; + SkScalar advX = 0; + + for (size_t i = 0; i < len; i++) { + if (fDrawPosH) + pos[i].set(x + advX, y); + else + pos[i].set(x + advX, y + i); + advX += adv[i]; + } + + canvas->drawPosText(text, len, pos, paint); + delete[] pos; + } + } + delete[] adv; + } +private: + bool fDrawPosH; + typedef PicturePlaybackBench INHERITED; +}; + + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new TextPlaybackBench(); ) +DEF_BENCH( return new PosTextPlaybackBench(true); ) +DEF_BENCH( return new PosTextPlaybackBench(false); ) diff --git a/chromium/third_party/skia/bench/PictureRecordBench.cpp b/chromium/third_party/skia/bench/PictureRecordBench.cpp new file mode 100644 index 00000000000..ef5361d20ac --- /dev/null +++ b/chromium/third_party/skia/bench/PictureRecordBench.cpp @@ -0,0 +1,178 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkPaint.h" +#include "SkPicture.h" +#include "SkPictureRecorder.h" +#include "SkPoint.h" +#include "SkRandom.h" +#include "SkRect.h" +#include "SkString.h" + +class PictureRecordBench : public Benchmark { +public: + PictureRecordBench(const char name[]) { + fName.printf("picture_record_%s", name); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + enum { + PICTURE_WIDTH = 1000, + PICTURE_HEIGHT = 4000, + }; +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } +private: + SkString fName; + typedef Benchmark INHERITED; +}; + + +static const int kMaxLoopsPerCanvas = 10000; + +/* + * An SkPicture has internal dictionaries to store bitmaps, matrices, paints, + * and regions. This bench populates those dictionaries to test the speed of + * reading and writing to those particular dictionary data structures. + */ +class DictionaryRecordBench : public PictureRecordBench { +public: + DictionaryRecordBench() : INHERITED("dictionaries") {} + +protected: + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkPictureRecorder recorder; + SkCanvas* canvas = NULL; + + const SkPoint translateDelta = getTranslateDelta(loops); + + for (int i = 0; i < loops; i++) { + if (0 == i % kMaxLoopsPerCanvas) { + SkAutoTUnref<SkPicture> picture(recorder.endRecording()); + canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); + } + + SkColor color = SK_ColorYELLOW + (i % 255); + SkIRect rect = SkIRect::MakeWH(i % PICTURE_WIDTH, i % PICTURE_HEIGHT); + + canvas->save(); + + // set the clip to the given region + SkRegion region; + region.setRect(rect); + canvas->clipRegion(region); + + // fill the clip with a color + SkPaint paint; + paint.setColor(color); + canvas->drawPaint(paint); + + // set a matrix on the canvas + SkMatrix matrix; + matrix.setRotate(SkIntToScalar(i % 360)); + canvas->setMatrix(matrix); + + // create a simple bitmap + SkBitmap bitmap; + bitmap.allocPixels(SkImageInfo::Make(10, 10, + kRGB_565_SkColorType, kOpaque_SkAlphaType)); + + // draw a single color into the bitmap + SkCanvas bitmapCanvas(bitmap); + bitmapCanvas.drawColor(SkColorSetA(color, i % 255)); + + // draw the bitmap onto the canvas + canvas->drawBitmapMatrix(bitmap, matrix); + + canvas->restore(); + canvas->translate(translateDelta.fX, translateDelta.fY); + } + } + + SkPoint getTranslateDelta(int M) { + SkIPoint canvasSize = onGetSize(); + return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/M), + SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/M)); + } +private: + typedef PictureRecordBench INHERITED; +}; + +/* + * Populates the SkPaint dictionary with a large number of unique paint + * objects that differ only by color + */ +class UniquePaintDictionaryRecordBench : public PictureRecordBench { +public: + UniquePaintDictionaryRecordBench() : INHERITED("unique_paint_dictionary") { } + +protected: + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkRandom rand; + SkPaint paint; + SkPictureRecorder recorder; + SkCanvas* canvas = NULL; + for (int i = 0; i < loops; i++) { + if (0 == i % kMaxLoopsPerCanvas) { + SkAutoTUnref<SkPicture> picture(recorder.endRecording()); + canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); + } + paint.setColor(rand.nextU()); + canvas->drawPaint(paint); + } + } + +private: + typedef PictureRecordBench INHERITED; +}; + +/* + * Populates the SkPaint dictionary with a number of unique paint + * objects that get reused repeatedly. + * + * Re-creating the paint objects in the inner loop slows the benchmark down 10%. + * Using setColor(i % objCount) instead of a random color creates a very high rate + * of hash conflicts, slowing us down 12%. + */ +class RecurringPaintDictionaryRecordBench : public PictureRecordBench { +public: + RecurringPaintDictionaryRecordBench() : INHERITED("recurring_paint_dictionary") { + SkRandom rand; + for (int i = 0; i < ObjCount; i++) { + fPaint[i].setColor(rand.nextU()); + } + } + + enum { + ObjCount = 100, // number of unique paint objects + }; +protected: + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkPictureRecorder recorder; + SkCanvas* canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); + for (int i = 0; i < loops; i++) { + canvas->drawPaint(fPaint[i % ObjCount]); + } + } + +private: + SkPaint fPaint [ObjCount]; + typedef PictureRecordBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new DictionaryRecordBench(); ) +DEF_BENCH( return new UniquePaintDictionaryRecordBench(); ) +DEF_BENCH( return new RecurringPaintDictionaryRecordBench(); ) diff --git a/chromium/third_party/skia/bench/PremulAndUnpremulAlphaOpsBench.cpp b/chromium/third_party/skia/bench/PremulAndUnpremulAlphaOpsBench.cpp new file mode 100644 index 00000000000..311bdf2d477 --- /dev/null +++ b/chromium/third_party/skia/bench/PremulAndUnpremulAlphaOpsBench.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkConfig8888.h" +#include "SkString.h" +#include "sk_tool_utils.h" + +class PremulAndUnpremulAlphaOpsBench : public Benchmark { + enum { + W = 256, + H = 256, + }; + SkBitmap fBmp1, fBmp2; + +public: + PremulAndUnpremulAlphaOpsBench(SkColorType ct) { + fColorType = ct; + fName.printf("premul_and_unpremul_alpha_%s", sk_tool_utils::colortype_name(ct)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() { + SkImageInfo info = SkImageInfo::Make(W, H, fColorType, kPremul_SkAlphaType); + fBmp1.allocPixels(info); // used in writePixels + + for (int h = 0; h < H; ++h) { + for (int w = 0; w < W; ++w) { + // SkColor places A in the right slot for either RGBA or BGRA + *fBmp1.getAddr32(w, h) = SkColorSetARGB(h & 0xFF, w & 0xFF, w & 0xFF, w & 0xFF); + } + } + + fBmp2.allocPixels(info); // used in readPixels() + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + canvas->clear(SK_ColorBLACK); + + for (int loop = 0; loop < loops; ++loop) { + // Unpremul -> Premul + canvas->writePixels(fBmp1.info(), fBmp1.getPixels(), fBmp1.rowBytes(), 0, 0); + // Premul -> Unpremul + canvas->readPixels(fBmp2.info(), fBmp2.getPixels(), fBmp2.rowBytes(), 0, 0); + } + } + +private: + SkColorType fColorType; + SkString fName; + + typedef Benchmark INHERITED; +}; + + +DEF_BENCH(return new PremulAndUnpremulAlphaOpsBench(kRGBA_8888_SkColorType)); +DEF_BENCH(return new PremulAndUnpremulAlphaOpsBench(kBGRA_8888_SkColorType)); diff --git a/chromium/third_party/skia/bench/QuadTreeBench.cpp b/chromium/third_party/skia/bench/QuadTreeBench.cpp new file mode 100644 index 00000000000..79078a8ae9b --- /dev/null +++ b/chromium/third_party/skia/bench/QuadTreeBench.cpp @@ -0,0 +1,216 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkQuadTree.h" +#include "SkRandom.h" +#include "SkString.h" + +// confine rectangles to a smallish area, so queries generally hit something, and overlap occurs: +static const int GENERATE_EXTENTS = 1000; +static const int NUM_BUILD_RECTS = 500; +static const int NUM_QUERY_RECTS = 5000; +static const int GRID_WIDTH = 100; +static const SkIRect QUAD_TREE_BOUNDS = SkIRect::MakeLTRB( + -GENERATE_EXTENTS, -GENERATE_EXTENTS, 2 * GENERATE_EXTENTS, 2 * GENERATE_EXTENTS); + +typedef SkIRect (*MakeRectProc)(SkRandom&, int, int); + +// Time how long it takes to build an QuadTree +class QuadTreeBuildBench : public Benchmark { +public: + QuadTreeBuildBench(const char* name, MakeRectProc proc, SkBBoxHierarchy* tree) + : fTree(tree) + , fProc(proc) { + fName.append("quadtree_"); + fName.append(name); + fName.append("_build"); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual ~QuadTreeBuildBench() { + fTree->unref(); + } +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom rand; + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < NUM_BUILD_RECTS; ++j) { + fTree->insert(reinterpret_cast<void*>(j), fProc(rand, j, NUM_BUILD_RECTS), + false); + } + fTree->clear(); + } + } +private: + SkBBoxHierarchy* fTree; + MakeRectProc fProc; + SkString fName; + typedef Benchmark INHERITED; +}; + +// Time how long it takes to perform queries on an QuadTree +class QuadTreeQueryBench : public Benchmark { +public: + enum QueryType { + kSmall_QueryType, // small queries + kLarge_QueryType, // large queries + kRandom_QueryType,// randomly sized queries + kFull_QueryType // queries that cover everything + }; + + QuadTreeQueryBench(const char* name, MakeRectProc proc, + QueryType q, SkBBoxHierarchy* tree) + : fTree(tree) + , fProc(proc) + , fQuery(q) { + fName.append("quadtree_"); + fName.append(name); + fName.append("_query"); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual ~QuadTreeQueryBench() { + fTree->unref(); + } +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + virtual void onPreDraw() SK_OVERRIDE { + SkRandom rand; + for (int j = 0; j < NUM_QUERY_RECTS; ++j) { + fTree->insert(reinterpret_cast<void*>(j), + fProc(rand, j, NUM_QUERY_RECTS), + false); + } + fTree->flushDeferredInserts(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom rand; + for (int i = 0; i < loops; ++i) { + SkTDArray<void*> hits; + SkIRect query; + switch(fQuery) { + case kSmall_QueryType: + query.fLeft = rand.nextU() % GENERATE_EXTENTS; + query.fTop = rand.nextU() % GENERATE_EXTENTS; + query.fRight = query.fLeft + (GENERATE_EXTENTS / 20); + query.fBottom = query.fTop + (GENERATE_EXTENTS / 20); + break; + case kLarge_QueryType: + query.fLeft = rand.nextU() % GENERATE_EXTENTS; + query.fTop = rand.nextU() % GENERATE_EXTENTS; + query.fRight = query.fLeft + (GENERATE_EXTENTS / 2); + query.fBottom = query.fTop + (GENERATE_EXTENTS / 2); + break; + case kFull_QueryType: + query.fLeft = -GENERATE_EXTENTS; + query.fTop = -GENERATE_EXTENTS; + query.fRight = 2 * GENERATE_EXTENTS; + query.fBottom = 2 * GENERATE_EXTENTS; + break; + default: // fallthrough + case kRandom_QueryType: + query.fLeft = rand.nextU() % GENERATE_EXTENTS; + query.fTop = rand.nextU() % GENERATE_EXTENTS; + query.fRight = query.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 2); + query.fBottom = query.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 2); + break; + }; + fTree->search(query, &hits); + } + } +private: + SkBBoxHierarchy* fTree; + MakeRectProc fProc; + SkString fName; + QueryType fQuery; + typedef Benchmark INHERITED; +}; + +static inline SkIRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) { + SkIRect out = {0, 0, index + 1, index + 1}; + return out; +} + +static inline SkIRect make_XYordered_rects(SkRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = index % GRID_WIDTH; + out.fTop = index / GRID_WIDTH; + out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + return out; +} + +static inline SkIRect make_YXordered_rects(SkRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = index / GRID_WIDTH; + out.fTop = index % GRID_WIDTH; + out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + return out; +} + +static inline SkIRect make_random_rects(SkRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = rand.nextS() % GENERATE_EXTENTS; + out.fTop = rand.nextS() % GENERATE_EXTENTS; + out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 5); + out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 5); + return out; +} + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( + return SkNEW_ARGS(QuadTreeBuildBench, ("XYordered", &make_XYordered_rects, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) +DEF_BENCH( + return SkNEW_ARGS(QuadTreeQueryBench, ("XYordered", &make_XYordered_rects, + QuadTreeQueryBench::kRandom_QueryType, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) +DEF_BENCH( + return SkNEW_ARGS(QuadTreeBuildBench, ("YXordered", &make_YXordered_rects, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) +DEF_BENCH( + return SkNEW_ARGS(QuadTreeQueryBench, ("YXordered", &make_YXordered_rects, + QuadTreeQueryBench::kRandom_QueryType, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) +DEF_BENCH( + return SkNEW_ARGS(QuadTreeBuildBench, ("random", &make_random_rects, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) +DEF_BENCH( + return SkNEW_ARGS(QuadTreeQueryBench, ("random", &make_random_rects, + QuadTreeQueryBench::kRandom_QueryType, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) +DEF_BENCH( + return SkNEW_ARGS(QuadTreeBuildBench, ("concentric", &make_concentric_rects_increasing, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) +DEF_BENCH( + return SkNEW_ARGS(QuadTreeQueryBench, ("concentric", &make_concentric_rects_increasing, + QuadTreeQueryBench::kRandom_QueryType, + SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS)))); +) diff --git a/chromium/third_party/skia/bench/RTreeBench.cpp b/chromium/third_party/skia/bench/RTreeBench.cpp new file mode 100644 index 00000000000..95f55c9a8f0 --- /dev/null +++ b/chromium/third_party/skia/bench/RTreeBench.cpp @@ -0,0 +1,269 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkRTree.h" +#include "SkRandom.h" +#include "SkString.h" + +// confine rectangles to a smallish area, so queries generally hit something, and overlap occurs: +static const int GENERATE_EXTENTS = 1000; +static const int NUM_BUILD_RECTS = 500; +static const int NUM_QUERY_RECTS = 5000; +static const int GRID_WIDTH = 100; + +typedef SkIRect (*MakeRectProc)(SkRandom&, int, int); + +// Time how long it takes to build an R-Tree either bulk-loaded or not +class RTreeBuildBench : public Benchmark { +public: + RTreeBuildBench(const char* name, MakeRectProc proc, bool bulkLoad, + SkBBoxHierarchy* tree) + : fTree(tree) + , fProc(proc) + , fBulkLoad(bulkLoad) { + fName.append("rtree_"); + fName.append(name); + fName.append("_build"); + if (fBulkLoad) { + fName.append("_bulk"); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual ~RTreeBuildBench() { + fTree->unref(); + } +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom rand; + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < NUM_BUILD_RECTS; ++j) { + fTree->insert(reinterpret_cast<void*>(j), fProc(rand, j, NUM_BUILD_RECTS), + fBulkLoad); + } + fTree->flushDeferredInserts(); + fTree->clear(); + } + } +private: + SkBBoxHierarchy* fTree; + MakeRectProc fProc; + SkString fName; + bool fBulkLoad; + typedef Benchmark INHERITED; +}; + +// Time how long it takes to perform queries on an R-Tree, bulk-loaded or not +class RTreeQueryBench : public Benchmark { +public: + enum QueryType { + kSmall_QueryType, // small queries + kLarge_QueryType, // large queries + kRandom_QueryType,// randomly sized queries + kFull_QueryType // queries that cover everything + }; + + RTreeQueryBench(const char* name, MakeRectProc proc, bool bulkLoad, + QueryType q, SkBBoxHierarchy* tree) + : fTree(tree) + , fProc(proc) + , fBulkLoad(bulkLoad) + , fQuery(q) { + fName.append("rtree_"); + fName.append(name); + fName.append("_query"); + if (fBulkLoad) { + fName.append("_bulk"); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual ~RTreeQueryBench() { + fTree->unref(); + } +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + virtual void onPreDraw() SK_OVERRIDE { + SkRandom rand; + for (int j = 0; j < NUM_QUERY_RECTS; ++j) { + fTree->insert(reinterpret_cast<void*>(j), + fProc(rand, j, NUM_QUERY_RECTS), + fBulkLoad); + } + fTree->flushDeferredInserts(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom rand; + for (int i = 0; i < loops; ++i) { + SkTDArray<void*> hits; + SkIRect query; + switch(fQuery) { + case kSmall_QueryType: + query.fLeft = rand.nextU() % GENERATE_EXTENTS; + query.fTop = rand.nextU() % GENERATE_EXTENTS; + query.fRight = query.fLeft + (GENERATE_EXTENTS / 20); + query.fBottom = query.fTop + (GENERATE_EXTENTS / 20); + break; + case kLarge_QueryType: + query.fLeft = rand.nextU() % GENERATE_EXTENTS; + query.fTop = rand.nextU() % GENERATE_EXTENTS; + query.fRight = query.fLeft + (GENERATE_EXTENTS / 2); + query.fBottom = query.fTop + (GENERATE_EXTENTS / 2); + break; + case kFull_QueryType: + query.fLeft = -GENERATE_EXTENTS; + query.fTop = -GENERATE_EXTENTS; + query.fRight = 2 * GENERATE_EXTENTS; + query.fBottom = 2 * GENERATE_EXTENTS; + break; + default: // fallthrough + case kRandom_QueryType: + query.fLeft = rand.nextU() % GENERATE_EXTENTS; + query.fTop = rand.nextU() % GENERATE_EXTENTS; + query.fRight = query.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 2); + query.fBottom = query.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 2); + break; + }; + fTree->search(query, &hits); + } + } +private: + SkBBoxHierarchy* fTree; + MakeRectProc fProc; + SkString fName; + bool fBulkLoad; + QueryType fQuery; + typedef Benchmark INHERITED; +}; + +static inline SkIRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) { + SkIRect out = {0, 0, index + 1, index + 1}; + return out; +} + +static inline SkIRect make_XYordered_rects(SkRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = index % GRID_WIDTH; + out.fTop = index / GRID_WIDTH; + out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + return out; +} +static inline SkIRect make_YXordered_rects(SkRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = index / GRID_WIDTH; + out.fTop = index % GRID_WIDTH; + out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + return out; +} + +static inline SkIRect make_random_rects(SkRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = rand.nextS() % GENERATE_EXTENTS; + out.fTop = rand.nextS() % GENERATE_EXTENTS; + out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 5); + out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 5); + return out; +} + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("XYordered", &make_XYordered_rects, false, + SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("XYordered", &make_XYordered_rects, true, + SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)XYordered", &make_XYordered_rects, true, + SkRTree::Create(5, 16, 1, false))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("XYordered", &make_XYordered_rects, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)XYordered", &make_XYordered_rects, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +) + +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("YXordered", &make_YXordered_rects, false, + SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("YXordered", &make_YXordered_rects, true, + SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)YXordered", &make_YXordered_rects, true, + SkRTree::Create(5, 16, 1, false))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("YXordered", &make_YXordered_rects, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)YXordered", &make_YXordered_rects, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +) + +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("random", &make_random_rects, false, + SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("random", &make_random_rects, true, + SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)random", &make_random_rects, true, + SkRTree::Create(5, 16, 1, false))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("random", &make_random_rects, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)random", &make_random_rects, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +) + +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("concentric", + &make_concentric_rects_increasing, true, SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)concentric", + &make_concentric_rects_increasing, true, SkRTree::Create(5, 16, 1, false))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("concentric", &make_concentric_rects_increasing, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); +) +DEF_BENCH( + return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)concentric", &make_concentric_rects_increasing, true, + RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +) diff --git a/chromium/third_party/skia/bench/ReadPixBench.cpp b/chromium/third_party/skia/bench/ReadPixBench.cpp new file mode 100644 index 00000000000..7848ebc7576 --- /dev/null +++ b/chromium/third_party/skia/bench/ReadPixBench.cpp @@ -0,0 +1,67 @@ + +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" + + +/** + * This bench mark tests the use case where the user writes the a canvas + * and then reads small chunks from it repeatedly. This can cause trouble + * for the GPU as readbacks are very expensive. + */ +class ReadPixBench : public Benchmark { +public: + ReadPixBench() {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "readpix"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + canvas->clear(SK_ColorBLACK); + + SkISize size = canvas->getDeviceSize(); + + int offX = (size.width() - kWindowSize) / kNumStepsX; + int offY = (size.height() - kWindowSize) / kNumStepsY; + + SkPaint paint; + + paint.setColor(SK_ColorBLUE); + + canvas->drawCircle(SkIntToScalar(size.width()/2), + SkIntToScalar(size.height()/2), + SkIntToScalar(size.width()/2), + paint); + + SkBitmap bitmap; + + bitmap.setInfo(SkImageInfo::MakeN32Premul(kWindowSize, kWindowSize)); + + for (int i = 0; i < loops; i++) { + for (int x = 0; x < kNumStepsX; ++x) { + for (int y = 0; y < kNumStepsY; ++y) { + canvas->readPixels(&bitmap, x * offX, y * offY); + } + } + } + } + +private: + static const int kNumStepsX = 30; + static const int kNumStepsY = 30; + static const int kWindowSize = 5; + + typedef Benchmark INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new ReadPixBench(); ) diff --git a/chromium/third_party/skia/bench/RectBench.cpp b/chromium/third_party/skia/bench/RectBench.cpp new file mode 100644 index 00000000000..f50324a580b --- /dev/null +++ b/chromium/third_party/skia/bench/RectBench.cpp @@ -0,0 +1,345 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkCommandLineFlags.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +DEFINE_double(strokeWidth, -1.0, "If set, use this stroke width in RectBench."); + +class RectBench : public Benchmark { +public: + int fShift, fStroke; + enum { + W = 640, + H = 480, + N = 300, + }; + SkRect fRects[N]; + SkColor fColors[N]; + + RectBench(int shift, int stroke = 0) + : fShift(shift) + , fStroke(stroke) {} + + SkString fName; + const char* computeName(const char root[]) { + fName.printf("%s_%d", root, fShift); + if (fStroke > 0) { + fName.appendf("_stroke_%d", fStroke); + } + return fName.c_str(); + } + +protected: + virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) { + c->drawRect(r, p); + } + + virtual const char* onGetName() { return computeName("rects"); } + + virtual void onPreDraw() { + SkRandom rand; + const SkScalar offset = SK_Scalar1/3; + for (int i = 0; i < N; i++) { + int x = rand.nextU() % W; + int y = rand.nextU() % H; + int w = rand.nextU() % W; + int h = rand.nextU() % H; + w >>= fShift; + h >>= fShift; + x -= w/2; + y -= h/2; + fRects[i].set(SkIntToScalar(x), SkIntToScalar(y), + SkIntToScalar(x+w), SkIntToScalar(y+h)); + fRects[i].offset(offset, offset); + fColors[i] = rand.nextU() | 0xFF808080; + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + if (fStroke > 0) { + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SkIntToScalar(fStroke)); + } + for (int i = 0; i < loops; i++) { + paint.setColor(fColors[i % N]); + this->setupPaint(&paint); + this->drawThisRect(canvas, fRects[i % N], paint); + } + } +private: + typedef Benchmark INHERITED; +}; + +class SrcModeRectBench : public RectBench { +public: + SrcModeRectBench() : INHERITED(1, 0) { + fMode = SkXfermode::Create(SkXfermode::kSrc_Mode); + } + + virtual ~SrcModeRectBench() { + SkSafeUnref(fMode); + } + +protected: + virtual void setupPaint(SkPaint* paint) SK_OVERRIDE { + this->INHERITED::setupPaint(paint); + // srcmode is most interesting when we're not opaque + paint->setAlpha(0x80); + paint->setXfermode(fMode); + } + + virtual const char* onGetName() SK_OVERRIDE { + fName.set(this->INHERITED::onGetName()); + fName.prepend("srcmode_"); + return fName.c_str(); + } + +private: + SkString fName; + SkXfermode* fMode; + + typedef RectBench INHERITED; +}; + +class OvalBench : public RectBench { +public: + OvalBench(int shift, int stroke = 0) : RectBench(shift, stroke) {} +protected: + virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) { + c->drawOval(r, p); + } + virtual const char* onGetName() { return computeName("ovals"); } +}; + +class RRectBench : public RectBench { +public: + RRectBench(int shift, int stroke = 0) : RectBench(shift, stroke) {} +protected: + virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) { + c->drawRoundRect(r, r.width() / 4, r.height() / 4, p); + } + virtual const char* onGetName() { return computeName("rrects"); } +}; + +class PointsBench : public RectBench { +public: + SkCanvas::PointMode fMode; + const char* fName; + + PointsBench(SkCanvas::PointMode mode, const char* name) + : RectBench(2) + , fMode(mode) { + fName = name; + } + +protected: + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkScalar gSizes[] = { + SkIntToScalar(7), 0 + }; + size_t sizes = SK_ARRAY_COUNT(gSizes); + + if (FLAGS_strokeWidth >= 0) { + gSizes[0] = (SkScalar)FLAGS_strokeWidth; + sizes = 1; + } + + SkPaint paint; + paint.setStrokeCap(SkPaint::kRound_Cap); + + for (int loop = 0; loop < loops; loop++) { + for (size_t i = 0; i < sizes; i++) { + paint.setStrokeWidth(gSizes[i]); + this->setupPaint(&paint); + canvas->drawPoints(fMode, N * 2, SkTCast<SkPoint*>(fRects), paint); + paint.setColor(fColors[i % N]); + } + } + } + virtual const char* onGetName() { return fName; } +}; + +class AARectBench : public Benchmark { +public: + enum { + W = 640, + H = 480, + }; + + AARectBench(bool rotate) : fRotate(rotate) {} + +protected: + + virtual const char* onGetName() { + if (fRotate) { + return "aarects_rotated"; + } + return "aarects"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + static const SkScalar kHalfRectSize = 0.75f; + + SkPaint paint; + this->setupPaint(&paint); + paint.setAntiAlias(true); + paint.setColor(SK_ColorBLACK); + SkRect r = { -kHalfRectSize, -kHalfRectSize, kHalfRectSize, kHalfRectSize }; + int rot = 0; + + for (int i = 0; i < loops; i++) { + // Draw small aa rects in a grid across the screen + for (SkScalar y = kHalfRectSize+SK_Scalar1; y < H; y += 2*kHalfRectSize+2) { + for (SkScalar x = kHalfRectSize+SK_Scalar1; x < W; x += 2*kHalfRectSize+2) { + canvas->save(); + canvas->translate(x, y); + + if (fRotate) { + SkMatrix rotate; + rotate.setRotate(SkIntToScalar(rot)); + canvas->concat(rotate); + rot += 10; + } + + canvas->drawRect(r, paint); + canvas->restore(); + } + } + } + + } +private: + bool fRotate; + typedef Benchmark INHERITED; +}; + +/******************************************************************************* + * to bench BlitMask [Opaque, Black, color, shader] + *******************************************************************************/ + +class BlitMaskBench : public RectBench { +public: + enum kMaskType { + kMaskOpaque = 0, + kMaskBlack, + kMaskColor, + KMaskShader + }; + SkCanvas::PointMode fMode; + const char* fName; + + BlitMaskBench(SkCanvas::PointMode mode, + BlitMaskBench::kMaskType type, const char* name) : + RectBench(2), fMode(mode), _type(type) { + fName = name; + } + +protected: + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkScalar gSizes[] = { + SkIntToScalar(13), SkIntToScalar(24) + }; + size_t sizes = SK_ARRAY_COUNT(gSizes); + + if (FLAGS_strokeWidth >= 0) { + gSizes[0] = (SkScalar)FLAGS_strokeWidth; + sizes = 1; + } + SkRandom rand; + SkColor color = 0xFF000000; + U8CPU alpha = 0xFF; + SkPaint paint; + paint.setStrokeCap(SkPaint::kRound_Cap); + if (_type == KMaskShader) { + SkBitmap srcBM; + srcBM.allocN32Pixels(10, 1); + srcBM.eraseColor(0xFF00FF00); + + SkShader* s; + s = SkShader::CreateBitmapShader(srcBM, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode); + paint.setShader(s)->unref(); + } + for (int loop = 0; loop < loops; loop++) { + for (size_t i = 0; i < sizes; i++) { + switch (_type) { + case kMaskOpaque: + color = fColors[i]; + alpha = 0xFF; + break; + case kMaskBlack: + alpha = 0xFF; + color = 0xFF000000; + break; + case kMaskColor: + color = fColors[i]; + alpha = rand.nextU() & 255; + break; + case KMaskShader: + break; + } + paint.setStrokeWidth(gSizes[i]); + this->setupPaint(&paint); + paint.setColor(color); + paint.setAlpha(alpha); + canvas->drawPoints(fMode, N * 2, SkTCast<SkPoint*>(fRects), paint); + } + } + } + virtual const char* onGetName() { return fName; } +private: + typedef RectBench INHERITED; + kMaskType _type; +}; + + +DEF_BENCH( return SkNEW_ARGS(RectBench, (1)); ) +DEF_BENCH( return SkNEW_ARGS(RectBench, (1, 4)); ) +DEF_BENCH( return SkNEW_ARGS(RectBench, (3)); ) +DEF_BENCH( return SkNEW_ARGS(RectBench, (3, 4)); ) +DEF_BENCH( return SkNEW_ARGS(OvalBench, (1)); ) +DEF_BENCH( return SkNEW_ARGS(OvalBench, (3)); ) +DEF_BENCH( return SkNEW_ARGS(OvalBench, (1, 4)); ) +DEF_BENCH( return SkNEW_ARGS(OvalBench, (3, 4)); ) +DEF_BENCH( return SkNEW_ARGS(RRectBench, (1)); ) +DEF_BENCH( return SkNEW_ARGS(RRectBench, (1, 4)); ) +DEF_BENCH( return SkNEW_ARGS(RRectBench, (3)); ) +DEF_BENCH( return SkNEW_ARGS(RRectBench, (3, 4)); ) +DEF_BENCH( return SkNEW_ARGS(PointsBench, (SkCanvas::kPoints_PointMode, "points")); ) +DEF_BENCH( return SkNEW_ARGS(PointsBench, (SkCanvas::kLines_PointMode, "lines")); ) +DEF_BENCH( return SkNEW_ARGS(PointsBench, (SkCanvas::kPolygon_PointMode, "polygon")); ) + +DEF_BENCH( return SkNEW_ARGS(SrcModeRectBench, ()); ) + +DEF_BENCH( return SkNEW_ARGS(AARectBench, (false)); ) +DEF_BENCH( return SkNEW_ARGS(AARectBench, (true)); ) + +/* init the blitmask bench + */ +DEF_BENCH( return SkNEW_ARGS(BlitMaskBench, + (SkCanvas::kPoints_PointMode, + BlitMaskBench::kMaskOpaque, "maskopaque") + ); ) +DEF_BENCH( return SkNEW_ARGS(BlitMaskBench, + (SkCanvas::kPoints_PointMode, + BlitMaskBench::kMaskBlack, "maskblack") + ); ) +DEF_BENCH( return SkNEW_ARGS(BlitMaskBench, + (SkCanvas::kPoints_PointMode, + BlitMaskBench::kMaskColor, "maskcolor") + ); ) +DEF_BENCH( return SkNEW_ARGS(BlitMaskBench, + (SkCanvas::kPoints_PointMode, + BlitMaskBench::KMaskShader, "maskshader") + ); ) diff --git a/chromium/third_party/skia/bench/RectanizerBench.cpp b/chromium/third_party/skia/bench/RectanizerBench.cpp new file mode 100644 index 00000000000..286b681d386 --- /dev/null +++ b/chromium/third_party/skia/bench/RectanizerBench.cpp @@ -0,0 +1,138 @@ +/* +* Copyright 2014 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "Benchmark.h" +#include "SkRandom.h" +#include "SkSize.h" +#include "SkTDArray.h" + +#if SK_SUPPORT_GPU + +#include "GrRectanizer_pow2.h" +#include "GrRectanizer_skyline.h" + +/** + * This bench exercises Ganesh' GrRectanizer classes. It exercises the following + * rectanizers: + * Pow2 Rectanizer + * Skyline Rectanizer + * in the following cases: + * random rects (e.g., pull-save-layers forward use case) + * random power of two rects + * small constant sized power of 2 rects (e.g., glyph cache use case) + */ +class RectanizerBench : public Benchmark { +public: + static const int kWidth = 1024; + static const int kHeight = 1024; + + enum RectanizerType { + kPow2_RectanizerType, + kSkyline_RectanizerType, + }; + + enum RectType { + kRand_RectType, + kRandPow2_RectType, + kSmallPow2_RectType + }; + + RectanizerBench(RectanizerType rectanizerType, RectType rectType) + : fName("rectanizer_") + , fRectanizerType(rectanizerType) + , fRectType(rectType) { + + if (kPow2_RectanizerType == fRectanizerType) { + fName.append("pow2_"); + } else { + SkASSERT(kSkyline_RectanizerType == fRectanizerType); + fName.append("skyline_"); + } + + if (kRand_RectType == fRectType) { + fName.append("rand"); + } else if (kRandPow2_RectType == fRectType) { + fName.append("rand2"); + } else { + SkASSERT(kSmallPow2_RectType == fRectType); + fName.append("sm2"); + } + } + +protected: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return kNonRendering_Backend == backend; + } + + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + SkASSERT(NULL == fRectanizer.get()); + + if (kPow2_RectanizerType == fRectanizerType) { + fRectanizer.reset(SkNEW_ARGS(GrRectanizerPow2, (kWidth, kHeight))); + } else { + SkASSERT(kSkyline_RectanizerType == fRectanizerType); + fRectanizer.reset(SkNEW_ARGS(GrRectanizerSkyline, (kWidth, kHeight))); + } + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom rand; + SkIPoint16 loc; + SkISize size; + + for (int i = 0; i < loops; ++i) { + if (kRand_RectType == fRectType) { + size = SkISize::Make(rand.nextRangeU(1, kWidth / 2), + rand.nextRangeU(1, kHeight / 2)); + } else if (kRandPow2_RectType == fRectType) { + size = SkISize::Make(GrNextPow2(rand.nextRangeU(1, kWidth / 2)), + GrNextPow2(rand.nextRangeU(1, kHeight / 2))); + } else { + SkASSERT(kSmallPow2_RectType == fRectType); + size = SkISize::Make(128, 128); + } + + if (!fRectanizer->addRect(size.fWidth, size.fHeight, &loc)) { + // insert failed so clear out the rectanizer and give the + // current rect another try + fRectanizer->reset(); + i--; + } + } + + fRectanizer->reset(); + } + +private: + SkString fName; + RectanizerType fRectanizerType; + RectType fRectType; + SkAutoTDelete<GrRectanizer> fRectanizer; + + typedef Benchmark INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH(return new RectanizerBench(RectanizerBench::kPow2_RectanizerType, + RectanizerBench::kRand_RectType);) +DEF_BENCH(return new RectanizerBench(RectanizerBench::kPow2_RectanizerType, + RectanizerBench::kRandPow2_RectType);) +DEF_BENCH(return new RectanizerBench(RectanizerBench::kPow2_RectanizerType, + RectanizerBench::kSmallPow2_RectType);) +DEF_BENCH(return new RectanizerBench(RectanizerBench::kSkyline_RectanizerType, + RectanizerBench::kRand_RectType);) +DEF_BENCH(return new RectanizerBench(RectanizerBench::kSkyline_RectanizerType, + RectanizerBench::kRandPow2_RectType);) +DEF_BENCH(return new RectanizerBench(RectanizerBench::kSkyline_RectanizerType, + RectanizerBench::kSmallPow2_RectType);) + +#endif diff --git a/chromium/third_party/skia/bench/RectoriBench.cpp b/chromium/third_party/skia/bench/RectoriBench.cpp new file mode 100644 index 00000000000..5c115115e3d --- /dev/null +++ b/chromium/third_party/skia/bench/RectoriBench.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBlurMaskFilter.h" +#include "SkCanvas.h" +#include "SkLayerDrawLooper.h" +#include "SkPaint.h" +#include "SkRandom.h" + +// This bench replicates a problematic use case of a draw looper used +// to create an inner blurred rect +class RectoriBench : public Benchmark { +public: + RectoriBench() {} + +protected: + + virtual const char* onGetName() { + return "rectori"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRandom Random; + + for (int i = 0; i < loops; i++) { + SkScalar blurSigma = Random.nextRangeScalar(1.5f, 25.0f); + SkScalar size = Random.nextRangeScalar(20*blurSigma, 50*blurSigma); + + SkScalar x = Random.nextRangeScalar(0.0f, W - size); + SkScalar y = Random.nextRangeScalar(0.0f, H - size); + + SkRect inner = { x, y, x + size, y + size }; + + SkRect outer(inner); + // outer is always outset either 2x or 4x the blur radius (we go with 2x) + outer.outset(2*blurSigma, 2*blurSigma); + + SkPath p; + + p.addRect(outer); + p.addRect(inner); + p.setFillType(SkPath::kEvenOdd_FillType); + + // This will be used to translate the normal draw outside the + // clip rect and translate the blurred version back inside + SkScalar translate = 2.0f * size; + + SkPaint paint; + paint.setLooper(this->createLooper(-translate, blurSigma))->unref(); + paint.setColor(0xff000000 | Random.nextU()); + paint.setAntiAlias(true); + + canvas->save(); + // clip always equals inner rect so we get the inside blur + canvas->clipRect(inner); + canvas->translate(translate, 0); + canvas->drawPath(p, paint); + canvas->restore(); + } + } + +private: + enum { + W = 640, + H = 480, + }; + + SkLayerDrawLooper* createLooper(SkScalar xOff, SkScalar sigma) { + SkLayerDrawLooper::Builder looperBuilder; + + //----------------------------------------------- + SkLayerDrawLooper::LayerInfo info; + + // TODO: add a color filter to better match what is seen in the wild + info.fPaintBits = /* SkLayerDrawLooper::kColorFilter_Bit |*/ + SkLayerDrawLooper::kMaskFilter_Bit; + info.fColorMode = SkXfermode::kDst_Mode; + info.fOffset.set(xOff, 0); + info.fPostTranslate = false; + + SkPaint* paint = looperBuilder.addLayer(info); + + SkMaskFilter* mf = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, + sigma, + SkBlurMaskFilter::kHighQuality_BlurFlag); + paint->setMaskFilter(mf)->unref(); + + //----------------------------------------------- + info.fPaintBits = 0; + info.fOffset.set(0, 0); + + paint = looperBuilder.addLayer(info); + return looperBuilder.detachLooper(); + } + + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return SkNEW_ARGS(RectoriBench, ()); ) diff --git a/chromium/third_party/skia/bench/RefCntBench.cpp b/chromium/third_party/skia/bench/RefCntBench.cpp new file mode 100644 index 00000000000..351513b8318 --- /dev/null +++ b/chromium/third_party/skia/bench/RefCntBench.cpp @@ -0,0 +1,200 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include <memory> +#include "Benchmark.h" +#include "SkRefCnt.h" +#include "SkThread.h" +#include "SkWeakRefCnt.h" + +enum { + M = 2 +}; + +class RefCntBench_Stack : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "ref_cnt_stack"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; ++i) { + SkRefCnt ref; + for (int j = 0; j < M; ++j) { + ref.ref(); + ref.unref(); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +class PlacedRefCnt : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(PlacedRefCnt) + + PlacedRefCnt() : SkRefCnt() { } + void operator delete(void*) { } + +private: + typedef SkRefCnt INHERITED; +}; + +class RefCntBench_Heap : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "ref_cnt_heap"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + char memory[sizeof(PlacedRefCnt)]; + for (int i = 0; i < loops; ++i) { + PlacedRefCnt* ref = new (memory) PlacedRefCnt(); + for (int j = 0; j < M; ++j) { + ref->ref(); + ref->unref(); + } + ref->unref(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class RefCntBench_New : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "ref_cnt_new"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; ++i) { + SkRefCnt* ref = new SkRefCnt(); + for (int j = 0; j < M; ++j) { + ref->ref(); + ref->unref(); + } + ref->unref(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class WeakRefCntBench_Stack : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "ref_cnt_stack_weak"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; ++i) { + SkWeakRefCnt ref; + for (int j = 0; j < M; ++j) { + ref.ref(); + ref.unref(); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +class PlacedWeakRefCnt : public SkWeakRefCnt { +public: + PlacedWeakRefCnt() : SkWeakRefCnt() { } + void operator delete(void*) { } +}; + +class WeakRefCntBench_Heap : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "ref_cnt_heap_weak"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + char memory[sizeof(PlacedWeakRefCnt)]; + for (int i = 0; i < loops; ++i) { + PlacedWeakRefCnt* ref = new (memory) PlacedWeakRefCnt(); + for (int j = 0; j < M; ++j) { + ref->ref(); + ref->unref(); + } + ref->unref(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class WeakRefCntBench_New : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { + return "ref_cnt_new_weak"; + } + + virtual void onDraw(const int loops, SkCanvas*) { + for (int i = 0; i < loops; ++i) { + SkWeakRefCnt* ref = new SkWeakRefCnt(); + for (int j = 0; j < M; ++j) { + ref->ref(); + ref->unref(); + } + ref->unref(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new RefCntBench_Stack(); ) +DEF_BENCH( return new RefCntBench_Heap(); ) +DEF_BENCH( return new RefCntBench_New(); ) + +DEF_BENCH( return new WeakRefCntBench_Stack(); ) +DEF_BENCH( return new WeakRefCntBench_Heap(); ) +DEF_BENCH( return new WeakRefCntBench_New(); ) diff --git a/chromium/third_party/skia/bench/RegionBench.cpp b/chromium/third_party/skia/bench/RegionBench.cpp new file mode 100644 index 00000000000..b3722d4caa4 --- /dev/null +++ b/chromium/third_party/skia/bench/RegionBench.cpp @@ -0,0 +1,188 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkRandom.h" +#include "SkRegion.h" +#include "SkString.h" + +static bool union_proc(SkRegion& a, SkRegion& b) { + SkRegion result; + return result.op(a, b, SkRegion::kUnion_Op); +} + +static bool sect_proc(SkRegion& a, SkRegion& b) { + SkRegion result; + return result.op(a, b, SkRegion::kIntersect_Op); +} + +static bool diff_proc(SkRegion& a, SkRegion& b) { + SkRegion result; + return result.op(a, b, SkRegion::kDifference_Op); +} + +static bool diffrect_proc(SkRegion& a, SkRegion& b) { + SkRegion result; + return result.op(a, b.getBounds(), SkRegion::kDifference_Op); +} + +static bool diffrectbig_proc(SkRegion& a, SkRegion& b) { + SkRegion result; + return result.op(a, a.getBounds(), SkRegion::kDifference_Op); +} + +static bool containsrect_proc(SkRegion& a, SkRegion& b) { + SkIRect r = a.getBounds(); + r.inset(r.width()/4, r.height()/4); + (void)a.contains(r); + + r = b.getBounds(); + r.inset(r.width()/4, r.height()/4); + return b.contains(r); +} + +static bool sectsrgn_proc(SkRegion& a, SkRegion& b) { + return a.intersects(b); +} + +static bool sectsrect_proc(SkRegion& a, SkRegion& b) { + SkIRect r = a.getBounds(); + r.inset(r.width()/4, r.height()/4); + return a.intersects(r); +} + +static bool containsxy_proc(SkRegion& a, SkRegion& b) { + const SkIRect& r = a.getBounds(); + const int dx = r.width() / 8; + const int dy = r.height() / 8; + for (int y = r.fTop; y < r.fBottom; y += dy) { + for (int x = r.fLeft; x < r.fRight; x += dx) { + (void)a.contains(x, y); + } + } + return true; +} + +class RegionBench : public Benchmark { +public: + typedef bool (*Proc)(SkRegion& a, SkRegion& b); + + SkRegion fA, fB; + Proc fProc; + SkString fName; + + enum { + W = 1024, + H = 768, + }; + + SkIRect randrect(SkRandom& rand) { + int x = rand.nextU() % W; + int y = rand.nextU() % H; + int w = rand.nextU() % W; + int h = rand.nextU() % H; + return SkIRect::MakeXYWH(x, y, w >> 1, h >> 1); + } + + RegionBench(int count, Proc proc, const char name[]) { + fProc = proc; + fName.printf("region_%s_%d", name, count); + + SkRandom rand; + for (int i = 0; i < count; i++) { + fA.op(randrect(rand), SkRegion::kXOR_Op); + fB.op(randrect(rand), SkRegion::kXOR_Op); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + Proc proc = fProc; + for (int i = 0; i < loops; ++i) { + proc(fA, fB); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class RectSectBench : public Benchmark { + enum { + N = 1000 + }; + SkRect fArray0[N]; + SkRect fArray1[N]; + SkString fName; + bool fNewWay; + +public: + static void RandRect(SkRect* r, SkRandom& rand) { + r->set(rand.nextSScalar1(), rand.nextSScalar1(), + rand.nextSScalar1(), rand.nextSScalar1()); + r->sort(); + } + + RectSectBench(bool newWay) : fNewWay(newWay) { + fName.printf("rect_intersect_%s", newWay ? "new" : "old"); + + SkRandom rand; + for (int i = 0; i < N; i++) { + RandRect(&fArray0[i], rand); + RandRect(&fArray1[i], rand); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + for (int i = 0; i < loops; ++i) { + if (fNewWay) { + for (int j = 0; j < N; ++j) { + SkRect r = fArray0[j]; + r.intersect2(fArray1[j]); + } + } else { + for (int j = 0; j < N; ++j) { + SkRect r = fArray0[j]; + r.intersect(fArray1[j]); + } + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#define SMALL 16 + +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, union_proc, "union")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, sect_proc, "intersect")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, diff_proc, "difference")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, diffrect_proc, "differencerect")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, diffrectbig_proc, "differencerectbig")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, containsrect_proc, "containsrect")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, sectsrgn_proc, "intersectsrgn")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, sectsrect_proc, "intersectsrect")); ) +DEF_BENCH( return SkNEW_ARGS(RegionBench, (SMALL, containsxy_proc, "containsxy")); ) + +DEF_BENCH( return SkNEW_ARGS(RectSectBench, (false)); ) +DEF_BENCH( return SkNEW_ARGS(RectSectBench, (true)); ) diff --git a/chromium/third_party/skia/bench/RegionContainBench.cpp b/chromium/third_party/skia/bench/RegionContainBench.cpp new file mode 100644 index 00000000000..a47ab3395f8 --- /dev/null +++ b/chromium/third_party/skia/bench/RegionContainBench.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkRandom.h" +#include "SkRegion.h" +#include "SkString.h" + +static bool sect_proc(SkRegion& a, SkRegion& b) { + SkRegion result; + return result.op(a, b, SkRegion::kIntersect_Op); +} + +class RegionContainBench : public Benchmark { +public: + typedef bool (*Proc)(SkRegion& a, SkRegion& b); + SkRegion fA, fB; + Proc fProc; + SkString fName; + + enum { + W = 200, + H = 200, + COUNT = 10, + }; + + SkIRect randrect(SkRandom& rand, int i) { + int w = rand.nextU() % W; + return SkIRect::MakeXYWH(0, i*H/COUNT, w, H/COUNT); + } + + RegionContainBench(Proc proc, const char name[]) { + fProc = proc; + fName.printf("region_contains_%s", name); + + SkRandom rand; + for (int i = 0; i < COUNT; i++) { + fA.op(randrect(rand, i), SkRegion::kXOR_Op); + } + + fB.setRect(0, 0, H, W); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + + virtual void onDraw(const int loops, SkCanvas*) { + Proc proc = fProc; + + for (int i = 0; i < loops; ++i) { + proc(fA, fB); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return SkNEW_ARGS(RegionContainBench, (sect_proc, "sect")); ) diff --git a/chromium/third_party/skia/bench/RepeatTileBench.cpp b/chromium/third_party/skia/bench/RepeatTileBench.cpp new file mode 100644 index 00000000000..cf29b6a460e --- /dev/null +++ b/chromium/third_party/skia/bench/RepeatTileBench.cpp @@ -0,0 +1,146 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkPaint.h" +#include "SkShader.h" +#include "SkString.h" +#include "sk_tool_utils.h" + +static void draw_into_bitmap(const SkBitmap& bm) { + const int w = bm.width(); + const int h = bm.height(); + + SkCanvas canvas(bm); + SkPaint p; + p.setAntiAlias(true); + p.setColor(SK_ColorRED); + canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2, + SkIntToScalar(SkMin32(w, h))*3/8, p); + + SkRect r; + r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(4)); + p.setColor(SK_ColorBLUE); + canvas.drawRect(r, p); +} + +static int conv_6_to_byte(int x) { + return x * 0xFF / 5; +} + +static int conv_byte_to_6(int x) { + return x * 5 / 255; +} + +static uint8_t compute_666_index(SkPMColor c) { + int r = SkGetPackedR32(c); + int g = SkGetPackedG32(c); + int b = SkGetPackedB32(c); + + return conv_byte_to_6(r) * 36 + conv_byte_to_6(g) * 6 + conv_byte_to_6(b); +} + +static void convert_to_index666(const SkBitmap& src, SkBitmap* dst) { + SkPMColor storage[216]; + SkPMColor* colors = storage; + // rrr ggg bbb + for (int r = 0; r < 6; r++) { + int rr = conv_6_to_byte(r); + for (int g = 0; g < 6; g++) { + int gg = conv_6_to_byte(g); + for (int b = 0; b < 6; b++) { + int bb = conv_6_to_byte(b); + *colors++ = SkPreMultiplyARGB(0xFF, rr, gg, bb); + } + } + } + SkColorTable* ctable = new SkColorTable(storage, 216, kOpaque_SkAlphaType); + dst->allocPixels(SkImageInfo::Make(src.width(), src.height(), + kIndex_8_SkColorType, kOpaque_SkAlphaType), + NULL, ctable); + ctable->unref(); + + SkAutoLockPixels alps(src); + SkAutoLockPixels alpd(*dst); + + for (int y = 0; y < src.height(); y++) { + const SkPMColor* srcP = src.getAddr32(0, y); + uint8_t* dstP = dst->getAddr8(0, y); + for (int x = src.width() - 1; x >= 0; --x) { + *dstP++ = compute_666_index(*srcP++); + } + } +} + +class RepeatTileBench : public Benchmark { + const SkColorType fColorType; + const SkAlphaType fAlphaType; + SkPaint fPaint; + SkString fName; + SkBitmap fBitmap; +public: + RepeatTileBench(SkColorType ct, SkAlphaType at = kPremul_SkAlphaType) + : fColorType(ct), fAlphaType(at) + { + const int w = 50; + const int h = 50; + + if (kIndex_8_SkColorType == ct) { + fBitmap.setInfo(SkImageInfo::MakeN32(w, h, at)); + } else { + fBitmap.setInfo(SkImageInfo::Make(w, h, ct, at)); + } + fName.printf("repeatTile_%s_%c", + sk_tool_utils::colortype_name(ct), kOpaque_SkAlphaType == at ? 'X' : 'A'); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + fBitmap.allocPixels(); + fBitmap.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorWHITE : 0); + + draw_into_bitmap(fBitmap); + + if (kIndex_8_SkColorType == fColorType) { + SkBitmap tmp; + convert_to_index666(fBitmap, &tmp); + fBitmap = tmp; + } + + SkShader* s = SkShader::CreateBitmapShader(fBitmap, + SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); + fPaint.setShader(s)->unref(); + } + + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint(fPaint); + this->setupPaint(&paint); + + for (int i = 0; i < loops; i++) { + canvas->drawPaint(paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new RepeatTileBench(kN32_SkColorType, kOpaque_SkAlphaType)) +DEF_BENCH(return new RepeatTileBench(kN32_SkColorType, kPremul_SkAlphaType)) +DEF_BENCH(return new RepeatTileBench(kRGB_565_SkColorType, kOpaque_SkAlphaType)) +DEF_BENCH(return new RepeatTileBench(kIndex_8_SkColorType, kPremul_SkAlphaType)) diff --git a/chromium/third_party/skia/bench/ResultsWriter.cpp b/chromium/third_party/skia/bench/ResultsWriter.cpp new file mode 100644 index 00000000000..08f11c190fb --- /dev/null +++ b/chromium/third_party/skia/bench/ResultsWriter.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Helper functions for result writing operations. + */ + +#include "ResultsWriter.h" + +Json::Value* SkFindNamedNode(Json::Value* root, const char name[]) { + Json::Value* search_results = NULL; + for(Json::Value::iterator iter = root->begin(); + iter!= root->end(); ++iter) { + if(SkString(name).equals((*iter)["name"].asCString())) { + search_results = &(*iter); + break; + } + } + + if(search_results != NULL) { + return search_results; + } else { + Json::Value* new_val = &(root->append(Json::Value())); + (*new_val)["name"] = name; + return new_val; + } +} + diff --git a/chromium/third_party/skia/bench/ResultsWriter.h b/chromium/third_party/skia/bench/ResultsWriter.h new file mode 100644 index 00000000000..ed10afa3caa --- /dev/null +++ b/chromium/third_party/skia/bench/ResultsWriter.h @@ -0,0 +1,198 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Classes for writing out bench results in various formats. + */ + +#ifndef SkResultsWriter_DEFINED +#define SkResultsWriter_DEFINED + +#include "BenchLogger.h" +#include "SkJSONCPP.h" +#include "SkStream.h" +#include "SkString.h" +#include "SkTArray.h" +#include "SkTypes.h" + +/** + * Base class for writing out the bench results. + * + * TODO(jcgregorio) Add info if tests fail to converge? + */ +class ResultsWriter : SkNoncopyable { +public: + virtual ~ResultsWriter() {}; + + // Records one option set for this run. All options must be set before + // calling bench(). + virtual void option(const char name[], const char value[]) = 0; + + // Denotes the start of a specific benchmark. Once bench is called, + // then config and timer can be called multiple times to record runs. + virtual void bench(const char name[], int32_t x, int32_t y) = 0; + + // Records the specific configuration a bench is run under, such as "8888". + virtual void config(const char name[]) = 0; + + // Records a single test metric. + virtual void timer(const char name[], double ms) = 0; + + // Call when all results are finished. + virtual void end() = 0; +}; + +/** + * This ResultsWriter handles writing out the human readable format of the + * bench results. + */ +class LoggerResultsWriter : public ResultsWriter { +public: + explicit LoggerResultsWriter(BenchLogger& logger, const char* timeFormat) + : fLogger(logger) + , fTimeFormat(timeFormat) { + fLogger.logProgress("skia bench:"); + } + virtual void option(const char name[], const char value[]) { + fLogger.logProgress(SkStringPrintf(" %s=%s", name, value)); + } + virtual void bench(const char name[], int32_t x, int32_t y) { + fLogger.logProgress(SkStringPrintf( + "\nrunning bench [%3d %3d] %40s", x, y, name)); + } + virtual void config(const char name[]) { + fLogger.logProgress(SkStringPrintf(" %s:", name)); + } + virtual void timer(const char name[], double ms) { + fLogger.logProgress(SkStringPrintf(" %s = ", name)); + fLogger.logProgress(SkStringPrintf(fTimeFormat, ms)); + } + virtual void end() { + fLogger.logProgress("\n"); + } +private: + BenchLogger& fLogger; + const char* fTimeFormat; +}; + +/** + * This ResultsWriter handles writing out the results in JSON. + * + * The output looks like (except compressed to a single line): + * + * { + * "options" : { + * "alpha" : "0xFF", + * "scale" : "0", + * ... + * "system" : "UNIX" + * }, + * "results" : [ + * { + * "name" : "Xfermode_Luminosity_640_480", + * "results" : [ + * { + * "name": "565", + * "cmsecs" : 143.188128906250, + * "msecs" : 143.835957031250 + * }, + * ... + */ + +Json::Value* SkFindNamedNode(Json::Value* root, const char name[]); +class JSONResultsWriter : public ResultsWriter { +public: + explicit JSONResultsWriter(const char filename[]) + : fFilename(filename) + , fRoot() + , fResults(fRoot["results"]) + , fBench(NULL) + , fConfig(NULL) { + } + virtual void option(const char name[], const char value[]) { + fRoot["options"][name] = value; + } + virtual void bench(const char name[], int32_t x, int32_t y) { + SkString sk_name(name); + sk_name.append("_"); + sk_name.appendS32(x); + sk_name.append("_"); + sk_name.appendS32(y); + Json::Value* bench_node = SkFindNamedNode(&fResults, sk_name.c_str()); + fBench = &(*bench_node)["results"]; + } + virtual void config(const char name[]) { + SkASSERT(NULL != fBench); + fConfig = SkFindNamedNode(fBench, name); + } + virtual void timer(const char name[], double ms) { + SkASSERT(NULL != fConfig); + (*fConfig)[name] = ms; + } + virtual void end() { + SkFILEWStream stream(fFilename.c_str()); + stream.writeText(Json::FastWriter().write(fRoot).c_str()); + stream.flush(); + } +private: + + SkString fFilename; + Json::Value fRoot; + Json::Value& fResults; + Json::Value* fBench; + Json::Value* fConfig; +}; + +/** + * This ResultsWriter writes out to multiple ResultsWriters. + */ +class MultiResultsWriter : public ResultsWriter { +public: + MultiResultsWriter() : writers() { + }; + void add(ResultsWriter* writer) { + writers.push_back(writer); + } + virtual void option(const char name[], const char value[]) { + for (int i = 0; i < writers.count(); ++i) { + writers[i]->option(name, value); + } + } + virtual void bench(const char name[], int32_t x, int32_t y) { + for (int i = 0; i < writers.count(); ++i) { + writers[i]->bench(name, x, y); + } + } + virtual void config(const char name[]) { + for (int i = 0; i < writers.count(); ++i) { + writers[i]->config(name); + } + } + virtual void timer(const char name[], double ms) { + for (int i = 0; i < writers.count(); ++i) { + writers[i]->timer(name, ms); + } + } + virtual void end() { + for (int i = 0; i < writers.count(); ++i) { + writers[i]->end(); + } + } +private: + SkTArray<ResultsWriter *> writers; +}; + +/** + * Calls the end() method of T on destruction. + */ +template <typename T> class CallEnd : SkNoncopyable { +public: + CallEnd(T& obj) : fObj(obj) {} + ~CallEnd() { fObj.end(); } +private: + T& fObj; +}; + +#endif diff --git a/chromium/third_party/skia/bench/ScalarBench.cpp b/chromium/third_party/skia/bench/ScalarBench.cpp new file mode 100644 index 00000000000..e09fa7533b3 --- /dev/null +++ b/chromium/third_party/skia/bench/ScalarBench.cpp @@ -0,0 +1,168 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkFloatBits.h" +#include "SkRandom.h" +#include "SkRect.h" +#include "SkString.h" + +class ScalarBench : public Benchmark { + SkString fName; +public: + ScalarBench(const char name[]) { + fName.printf("scalar_%s", name); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + + virtual void performTest() = 0; + +protected: + virtual int mulLoopCount() const { return 1; } + + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + for (int i = 0; i < loops; i++) { + this->performTest(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +// having unknown values in our arrays can throw off the timing a lot, perhaps +// handling NaN values is a lot slower. Anyway, this guy is just meant to put +// reasonable values in our arrays. +template <typename T> void init9(T array[9]) { + SkRandom rand; + for (int i = 0; i < 9; i++) { + array[i] = rand.nextSScalar1(); + } +} + +class FloatComparisonBench : public ScalarBench { +public: + FloatComparisonBench() : INHERITED("compare_float") { + init9(fArray); + } +protected: + virtual int mulLoopCount() const { return 4; } + virtual void performTest() { + // xoring into a volatile prevents the compiler from optimizing these checks away. + volatile bool junk = false; + junk ^= (fArray[6] != 0.0f || fArray[7] != 0.0f || fArray[8] != 1.0f); + junk ^= (fArray[2] != 0.0f || fArray[5] != 0.0f); + } +private: + float fArray[9]; + typedef ScalarBench INHERITED; +}; + +class ForcedIntComparisonBench : public ScalarBench { +public: + ForcedIntComparisonBench() + : INHERITED("compare_forced_int") { + init9(fArray); + } +protected: + virtual int mulLoopCount() const { return 4; } + virtual void performTest() { + // xoring into a volatile prevents the compiler from optimizing these checks away. + volatile int32_t junk = 0; + junk ^= (SkScalarAs2sCompliment(fArray[6]) | + SkScalarAs2sCompliment(fArray[7]) | + (SkScalarAs2sCompliment(fArray[8]) - kPersp1Int)); + junk ^= (SkScalarAs2sCompliment(fArray[2]) | + SkScalarAs2sCompliment(fArray[5])); + } +private: + static const int32_t kPersp1Int = 0x3f800000; + SkScalar fArray[9]; + typedef ScalarBench INHERITED; +}; + +class IsFiniteScalarBench : public ScalarBench { +public: + IsFiniteScalarBench() : INHERITED("isfinite") { + SkRandom rand; + for (size_t i = 0; i < ARRAY_N; ++i) { + fArray[i] = rand.nextSScalar1(); + } + } +protected: + virtual int mulLoopCount() const { return 1; } + virtual void performTest() SK_OVERRIDE { + int sum = 0; + for (size_t i = 0; i < ARRAY_N; ++i) { + // We pass -fArray[i], so the compiler can't cheat and treat the + // value as an int (even though we tell it that it is a float) + sum += SkScalarIsFinite(-fArray[i]); + } + // we do this so the compiler won't optimize our loop away... + this->doSomething(fArray, sum); + } + + virtual void doSomething(SkScalar array[], int sum) {} +private: + enum { + ARRAY_N = 64 + }; + SkScalar fArray[ARRAY_N]; + + typedef ScalarBench INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class RectBoundsBench : public Benchmark { + enum { + PTS = 100, + }; + SkPoint fPts[PTS]; + +public: + RectBoundsBench() { + SkRandom rand; + for (int i = 0; i < PTS; ++i) { + fPts[i].fX = rand.nextSScalar1(); + fPts[i].fY = rand.nextSScalar1(); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "rect_bounds"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkRect r; + for (int i = 0; i < loops; ++i) { + r.set(fPts, PTS); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new FloatComparisonBench(); ) +DEF_BENCH( return new ForcedIntComparisonBench(); ) +DEF_BENCH( return new RectBoundsBench(); ) +DEF_BENCH( return new IsFiniteScalarBench(); ) diff --git a/chromium/third_party/skia/bench/ShaderMaskBench.cpp b/chromium/third_party/skia/bench/ShaderMaskBench.cpp new file mode 100644 index 00000000000..aa3dadff2ff --- /dev/null +++ b/chromium/third_party/skia/bench/ShaderMaskBench.cpp @@ -0,0 +1,98 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkColorShader.h" +#include "SkFontHost.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" +#include "SkTemplates.h" + +#define STR "Hamburgefons" + +enum FontQuality { + kBW, + kAA, + kLCD +}; + +static const char* fontQualityName(const SkPaint& paint) { + if (!paint.isAntiAlias()) { + return "BW"; + } + if (paint.isLCDRenderText()) { + return "LCD"; + } + return "AA"; +} + +class ShaderMaskBench : public Benchmark { + SkPaint fPaint; + SkString fText; + SkString fName; + FontQuality fFQ; +public: + ShaderMaskBench(bool isOpaque, FontQuality fq) { + fFQ = fq; + fText.set(STR); + + fPaint.setAntiAlias(kBW != fq); + fPaint.setLCDRenderText(kLCD == fq); + fPaint.setShader(new SkColorShader(isOpaque ? 0xFFFFFFFF : 0x80808080))->unref(); + } + +protected: + virtual const char* onGetName() { + fName.printf("shadermask"); + fName.appendf("_%s", fontQualityName(fPaint)); + fName.appendf("_%02X", fPaint.getAlpha()); + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + const SkIPoint dim = this->getSize(); + SkRandom rand; + + SkPaint paint(fPaint); + this->setupPaint(&paint); + // explicitly need these + paint.setAlpha(fPaint.getAlpha()); + paint.setAntiAlias(kBW != fFQ); + paint.setLCDRenderText(kLCD == fFQ); + + const SkScalar x0 = SkIntToScalar(-10); + const SkScalar y0 = SkIntToScalar(-10); + + paint.setTextSize(SkIntToScalar(12)); + for (int i = 0; i < loops; i++) { + SkScalar x = x0 + rand.nextUScalar1() * dim.fX; + SkScalar y = y0 + rand.nextUScalar1() * dim.fY; + canvas->drawText(fText.c_str(), fText.size(), x, y, paint); + } + + paint.setTextSize(SkIntToScalar(48)); + for (int i = 0; i < loops / 4 ; i++) { + SkScalar x = x0 + rand.nextUScalar1() * dim.fX; + SkScalar y = y0 + rand.nextUScalar1() * dim.fY; + canvas->drawText(fText.c_str(), fText.size(), x, y, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new ShaderMaskBench(true, kBW); ) +DEF_BENCH( return new ShaderMaskBench(false, kBW); ) +DEF_BENCH( return new ShaderMaskBench(true, kAA); ) +DEF_BENCH( return new ShaderMaskBench(false, kAA); ) +DEF_BENCH( return new ShaderMaskBench(true, kLCD); ) +DEF_BENCH( return new ShaderMaskBench(false, kLCD); ) diff --git a/chromium/third_party/skia/bench/SkipZeroesBench.cpp b/chromium/third_party/skia/bench/SkipZeroesBench.cpp new file mode 100644 index 00000000000..30d9377a5ef --- /dev/null +++ b/chromium/third_party/skia/bench/SkipZeroesBench.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "Resources.h" +#include "SkBitmap.h" +#include "SkData.h" +#include "SkForceLinking.h" +#include "SkImageDecoder.h" +#include "SkOSFile.h" +#include "SkStream.h" +#include "SkString.h" + +__SK_FORCE_IMAGE_DECODER_LINKING; + +class SkCanvas; + +class SkipZeroesBench : public Benchmark { +public: + SkipZeroesBench(const char* filename, bool skipZeroes) + : fName("SkipZeroes_") + , fDecoder(NULL) + , fFilename(filename) + , fStream() + , fSkipZeroes(skipZeroes) + , fValid(false) { + fName.append(filename); + if (skipZeroes) { + fName.append("_skip_zeroes"); + } else { + fName.append("_write_zeroes"); + } + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onPreDraw() SK_OVERRIDE { + SkString resourcePath = GetResourcePath(); + if (resourcePath.isEmpty()) { + fValid = false; + return; + } + + SkString fullPath = SkOSPath::SkPathJoin(resourcePath.c_str(), + fFilename.c_str()); + SkFILEStream fileStream(fullPath.c_str()); + fValid = fileStream.isValid() && fileStream.getLength() > 0; + if (fValid) { + const size_t size = fileStream.getLength(); + void* data = sk_malloc_throw(size); + if (fileStream.read(data, size) < size) { + fValid = false; + } else { + SkAutoTUnref<SkData> skdata(SkData::NewFromMalloc(data, size)); + fStream.setData(skdata.get()); + fDecoder.reset(SkImageDecoder::Factory(&fStream)); + if (fDecoder.get()) { + fDecoder->setSkipWritingZeroes(fSkipZeroes); + } else { + fValid = false; + } + } + } + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + if (!fValid) { +#ifdef SK_DEBUG + SkDebugf("stream was invalid: %s\n", fFilename.c_str()); +#endif + return; + } + // Decode a bunch of times + SkBitmap bm; + for (int i = 0; i < loops; ++i) { + SkDEBUGCODE(bool success =) fDecoder->decode(&fStream, &bm, + SkImageDecoder::kDecodePixels_Mode); +#ifdef SK_DEBUG + if (!success) { + SkDebugf("failed to decode %s\n", fFilename.c_str()); + return; + } +#endif + SkDEBUGCODE(success =) fStream.rewind(); +#ifdef SK_DEBUG + if (!success) { + SkDebugf("failed to rewind %s\n", fFilename.c_str()); + return; + } +#endif + } + } + +private: + SkString fName; + SkAutoTDelete<SkImageDecoder> fDecoder; + const SkString fFilename; + SkMemoryStream fStream; + bool fSkipZeroes; + bool fValid; + + typedef Benchmark INHERITED; +}; + +// Enable the true version once the feature is checked in. +DEF_BENCH( return SkNEW_ARGS(SkipZeroesBench, ("arrow.png", true))); +DEF_BENCH( return SkNEW_ARGS(SkipZeroesBench, ("arrow.png", false))); diff --git a/chromium/third_party/skia/bench/SortBench.cpp b/chromium/third_party/skia/bench/SortBench.cpp new file mode 100644 index 00000000000..a7e8c2cd0bc --- /dev/null +++ b/chromium/third_party/skia/bench/SortBench.cpp @@ -0,0 +1,172 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkRandom.h" +#include "SkString.h" +#include "SkTSort.h" + +static const int N = 1000; + +static void rand_proc(int array[N]) { + SkRandom rand; + for (int i = 0; i < N; ++i) { + array[i] = rand.nextS(); + } +} + +static void randN_proc(int array[N]) { + SkRandom rand; + int mod = N / 10; + for (int i = 0; i < N; ++i) { + array[i] = rand.nextU() % mod; + } +} + +static void forward_proc(int array[N]) { + for (int i = 0; i < N; ++i) { + array[i] = i; + } +} + +static void backward_proc(int array[N]) { + for (int i = 0; i < N; ++i) { + array[i] = -i; + } +} + +static void same_proc(int array[N]) { + for (int i = 0; i < N; ++i) { + array[i] = N; + } +} + +typedef void (*SortProc)(int array[N]); + +enum Type { + kRand, kRandN, kFore, kBack, kSame +}; + +static const struct { + const char* fName; + SortProc fProc; +} gRec[] = { + { "rand", rand_proc }, + { "rand10", randN_proc }, + { "forward", forward_proc }, + { "backward", backward_proc }, + { "repeated", same_proc }, +}; + +static void skqsort_sort(int array[N]) { + // End is inclusive for SkTQSort! + SkTQSort<int>(array, array + N - 1); +} + +static void skheap_sort(int array[N]) { + SkTHeapSort<int>(array, N); +} + +extern "C" { + static int int_compare(const void* a, const void* b) { + const int ai = *(const int*)a; + const int bi = *(const int*)b; + return ai < bi ? -1 : (ai > bi); + } +} + +static void qsort_sort(int array[N]) { + qsort(array, N, sizeof(int), int_compare); +} + +enum SortType { + kSKQSort, kSKHeap, kQSort +}; + +static const struct { + const char* fName; + SortProc fProc; +} gSorts[] = { + { "skqsort", skqsort_sort }, + { "skheap", skheap_sort }, + { "qsort", qsort_sort }, +}; + +class SortBench : public Benchmark { + SkString fName; + const Type fType; + const SortProc fSortProc; + SkAutoTMalloc<int> fUnsorted; + +public: + SortBench(Type t, SortType s) : fType(t), fSortProc(gSorts[s].fProc) { + fName.printf("sort_%s_%s", gSorts[s].fName, gRec[t].fName); + } + + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + // Delayed initialization only done if onDraw will be called. + virtual void onPreDraw() SK_OVERRIDE { + fUnsorted.reset(N); + gRec[fType].fProc(fUnsorted.get()); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkAutoTMalloc<int> sorted(N); + for (int i = 0; i < loops; i++) { + memcpy(sorted.get(), fUnsorted.get(), N*sizeof(int)); + fSortProc(sorted.get()); +#ifdef SK_DEBUG + for (int j = 1; j < N; ++j) { + SkASSERT(sorted[j - 1] <= sorted[j]); + } +#endif + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static Benchmark* NewSkQSort(Type t) { + return new SortBench(t, kSKQSort); +} +static Benchmark* NewSkHeap(Type t) { + return new SortBench(t, kSKHeap); +} +static Benchmark* NewQSort(Type t) { + return new SortBench(t, kQSort); +} + +DEF_BENCH( return NewSkQSort(kRand); ) +DEF_BENCH( return NewSkHeap(kRand); ) +DEF_BENCH( return NewQSort(kRand); ) + +DEF_BENCH( return NewSkQSort(kRandN); ) +DEF_BENCH( return NewSkHeap(kRandN); ) +DEF_BENCH( return NewQSort(kRandN); ) + +DEF_BENCH( return NewSkQSort(kFore); ) +DEF_BENCH( return NewSkHeap(kFore); ) +DEF_BENCH( return NewQSort(kFore); ) + +DEF_BENCH( return NewSkQSort(kBack); ) +DEF_BENCH( return NewSkHeap(kBack); ) +DEF_BENCH( return NewQSort(kBack); ) + +DEF_BENCH( return NewSkQSort(kSame); ) +DEF_BENCH( return NewSkHeap(kSame); ) +DEF_BENCH( return NewQSort(kSame); ) diff --git a/chromium/third_party/skia/bench/StackBench.cpp b/chromium/third_party/skia/bench/StackBench.cpp new file mode 100644 index 00000000000..3b41cb65ceb --- /dev/null +++ b/chromium/third_party/skia/bench/StackBench.cpp @@ -0,0 +1,179 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkRandom.h" + +#include "SkChunkAlloc.h" +#include "SkDeque.h" +#include "SkTArray.h" +#include "SkTDArray.h" + +// This file has several benchmarks using various data structures to do stack-like things: +// - push +// - push, immediately pop +// - push many, pop all of them +// - serial access +// - random access +// When a data structure doesn't suppport an operation efficiently, we leave that combination out. +// Where possible we hint to the data structure to allocate in 4K pages. +// +// These benchmarks may help you decide which data structure to use for a dynamically allocated +// ordered list of allocations that grows on one end. +// +// Current overall winner (01/2014): SkTDArray. +// It wins every benchmark on every machine I tried (Desktop, Nexus S, Laptop). + +template <typename Impl> +struct StackBench : public Benchmark { + virtual bool isSuitableFor(Backend b) SK_OVERRIDE { return b == kNonRendering_Backend; } + virtual const char* onGetName() SK_OVERRIDE { return Impl::kName; } + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { Impl::bench(loops); } +}; + +#define BENCH(name) \ + struct name { static const char* const kName; static void bench(int); }; \ + const char* const name::kName = #name; \ + DEF_BENCH(return new StackBench<name>();) \ + void name::bench(int loops) + +static const int K = 2049; + +// Add K items, then iterate through them serially many times. + +BENCH(Deque_Serial) { + SkDeque s(sizeof(int), 1024); + for (int i = 0; i < K; i++) *(int*)s.push_back() = i; + + volatile int junk = 0; + for (int j = 0; j < loops; j++) { + SkDeque::Iter it(s, SkDeque::Iter::kFront_IterStart); + while(void* p = it.next()) { + junk += *(int*)p; + } + } +} + +BENCH(TArray_Serial) { + SkTArray<int, true> s; + for (int i = 0; i < K; i++) s.push_back(i); + + volatile int junk = 0; + for (int j = 0; j < loops; j++) { + for (int i = 0; i < s.count(); i++) junk += s[i]; + } +} + +BENCH(TDArray_Serial) { + SkTDArray<int> s; + for (int i = 0; i < K; i++) s.push(i); + + volatile int junk = 0; + for (int j = 0; j < loops; j++) { + for (int i = 0; i < s.count(); i++) junk += s[i]; + } +} + +// Add K items, then randomly access them many times. + +BENCH(TArray_RandomAccess) { + SkTArray<int, true> s; + for (int i = 0; i < K; i++) s.push_back(i); + + SkRandom rand; + volatile int junk = 0; + for (int i = 0; i < K*loops; i++) { + junk += s[rand.nextULessThan(K)]; + } +} + +BENCH(TDArray_RandomAccess) { + SkTDArray<int> s; + for (int i = 0; i < K; i++) s.push(i); + + SkRandom rand; + volatile int junk = 0; + for (int i = 0; i < K*loops; i++) { + junk += s[rand.nextULessThan(K)]; + } +} + +// Push many times. + +BENCH(ChunkAlloc_Push) { + SkChunkAlloc s(4096); + for (int i = 0; i < K*loops; i++) s.allocThrow(sizeof(int)); +} + +BENCH(Deque_Push) { + SkDeque s(sizeof(int), 1024); + for (int i = 0; i < K*loops; i++) *(int*)s.push_back() = i; +} + +BENCH(TArray_Push) { + SkTArray<int, true> s; + for (int i = 0; i < K*loops; i++) s.push_back(i); +} + +BENCH(TDArray_Push) { + SkTDArray<int> s; + for (int i = 0; i < K*loops; i++) s.push(i); +} + +// Push then immediately pop many times. + +BENCH(ChunkAlloc_PushPop) { + SkChunkAlloc s(4096); + for (int i = 0; i < K*loops; i++) { + void* p = s.allocThrow(sizeof(int)); + s.unalloc(p); + } +} + +BENCH(Deque_PushPop) { + SkDeque s(sizeof(int), 1024); + for (int i = 0; i < K*loops; i++) { + *(int*)s.push_back() = i; + s.pop_back(); + } +} + +BENCH(TArray_PushPop) { + SkTArray<int, true> s; + for (int i = 0; i < K*loops; i++) { + s.push_back(i); + s.pop_back(); + } +} + +BENCH(TDArray_PushPop) { + SkTDArray<int> s; + for (int i = 0; i < K*loops; i++) { + s.push(i); + s.pop(); + } +} + +// Push many items, then pop them all. + +BENCH(Deque_PushAllPopAll) { + SkDeque s(sizeof(int), 1024); + for (int i = 0; i < K*loops; i++) *(int*)s.push_back() = i; + for (int i = 0; i < K*loops; i++) s.pop_back(); +} + +BENCH(TArray_PushAllPopAll) { + SkTArray<int, true> s; + for (int i = 0; i < K*loops; i++) s.push_back(i); + for (int i = 0; i < K*loops; i++) s.pop_back(); +} + +BENCH(TDArray_PushAllPopAll) { + SkTDArray<int> s; + for (int i = 0; i < K*loops; i++) s.push(i); + for (int i = 0; i < K*loops; i++) s.pop(); +} diff --git a/chromium/third_party/skia/bench/StrokeBench.cpp b/chromium/third_party/skia/bench/StrokeBench.cpp new file mode 100644 index 00000000000..24e0cabbb03 --- /dev/null +++ b/chromium/third_party/skia/bench/StrokeBench.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRRect.h" +#include "SkString.h" + +struct RRectRec { + SkCanvas* fCanvas; + SkRRect fRRect; + SkPaint fPaint; +}; + +typedef const char* (*DrawProc)(const RRectRec*, int); + +static const char* draw_rect(const RRectRec* rec, int count) { + if (rec) { + const SkRect& r = rec->fRRect.getBounds(); + for (int i = 0; i < count; ++i) { + rec->fCanvas->drawRect(r, rec->fPaint); + } + } + return "rect"; +} + +static const char* draw_rrect(const RRectRec* rec, int count) { + if (rec) { + for (int i = 0; i < count; ++i) { + rec->fCanvas->drawRRect(rec->fRRect, rec->fPaint); + } + } + return "rrect"; +} + +static const char* draw_oval(const RRectRec* rec, int count) { + if (rec) { + const SkRect& r = rec->fRRect.getBounds(); + for (int i = 0; i < count; ++i) { + rec->fCanvas->drawOval(r, rec->fPaint); + } + } + return "oval"; +} + +// Handles rect, rrect, and oval +// +// Test drawing a small stroked version to see the effect of special-casing +// our stroke code for these convex single-contour shapes. +// +class StrokeRRectBench : public Benchmark { + SkString fName; + SkPaint::Join fJoin; + RRectRec fRec; + DrawProc fProc; +public: + StrokeRRectBench(SkPaint::Join j, DrawProc proc) { + static const char* gJoinName[] = { + "miter", "round", "bevel" + }; + + fJoin = j; + fProc = proc; + fName.printf("draw_stroke_%s_%s", proc(NULL, 0), gJoinName[j]); + + SkRect r = { 20, 20, 40, 40 }; + SkScalar rad = 4; + fRec.fRRect.setRectXY(r, rad, rad); + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + fRec.fCanvas = canvas; + this->setupPaint(&fRec.fPaint); + fRec.fPaint.setStyle(SkPaint::kStroke_Style); + fRec.fPaint.setStrokeJoin(fJoin); + fRec.fPaint.setStrokeWidth(5); + fProc(&fRec, loops); + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new StrokeRRectBench(SkPaint::kRound_Join, draw_rect); ) +DEF_BENCH( return new StrokeRRectBench(SkPaint::kBevel_Join, draw_rect); ) +DEF_BENCH( return new StrokeRRectBench(SkPaint::kMiter_Join, draw_rect); ) + +DEF_BENCH( return new StrokeRRectBench(SkPaint::kRound_Join, draw_rrect); ) +DEF_BENCH( return new StrokeRRectBench(SkPaint::kBevel_Join, draw_rrect); ) +DEF_BENCH( return new StrokeRRectBench(SkPaint::kMiter_Join, draw_rrect); ) + +DEF_BENCH( return new StrokeRRectBench(SkPaint::kRound_Join, draw_oval); ) +DEF_BENCH( return new StrokeRRectBench(SkPaint::kBevel_Join, draw_oval); ) +DEF_BENCH( return new StrokeRRectBench(SkPaint::kMiter_Join, draw_oval); ) diff --git a/chromium/third_party/skia/bench/TableBench.cpp b/chromium/third_party/skia/bench/TableBench.cpp new file mode 100644 index 00000000000..a99e03b513f --- /dev/null +++ b/chromium/third_party/skia/bench/TableBench.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkRect.h" + +static const SkScalar kCellWidth = SkIntToScalar(20); +static const SkScalar kCellHeight = SkIntToScalar(10); + +// This bench draws a table in the manner of Google spreadsheet and sahadan.com. +// ____________ ___ +// | 1 | 2 | +// |____________|___| +// | 3 | 4 | +// |____________|___| +// +// Areas 1-4 are first all draw white. Areas 3&4 are then drawn grey. Areas +// 2&4 are then drawn grey. Areas 2&3 are thus double drawn while area 4 is +// triple drawn. +// This trio of drawRects is then repeat for the next cell. +class TableBench : public Benchmark { +public: + static const int kNumRows = 48; + static const int kNumCols = 32; + +protected: + virtual const char* onGetName() { + return "tablebench"; + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint cellPaint; + cellPaint.setColor(0xFFFFFFF); + + SkPaint borderPaint; + borderPaint.setColor(0xFFCCCCCC); + + for (int i = 0; i < loops; ++i) { + for (int row = 0; row < kNumRows; ++row) { + for (int col = 0; col < kNumCols; ++col) { + SkRect cell = SkRect::MakeLTRB(col * kCellWidth, + row * kCellHeight, + (col+1) * kCellWidth, + (row+1) * kCellHeight); + canvas->drawRect(cell, cellPaint); + + SkRect bottom = SkRect::MakeLTRB(col * kCellWidth, + row * kCellHeight + (kCellHeight-SK_Scalar1), + (col+1) * kCellWidth, + (row+1) * kCellHeight); + canvas->drawRect(bottom, borderPaint); + + SkRect right = SkRect::MakeLTRB(col * kCellWidth + (kCellWidth-SK_Scalar1), + row * kCellHeight, + (col+1) * kCellWidth, + (row+1) * kCellHeight); + canvas->drawRect(right, borderPaint); + } + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH( return new TableBench(); ) diff --git a/chromium/third_party/skia/bench/TextBench.cpp b/chromium/third_party/skia/bench/TextBench.cpp new file mode 100644 index 00000000000..f150be2188d --- /dev/null +++ b/chromium/third_party/skia/bench/TextBench.cpp @@ -0,0 +1,145 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkFontHost.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" +#include "SkTemplates.h" + +enum FontQuality { + kBW, + kAA, + kLCD +}; + +static const char* fontQualityName(const SkPaint& paint) { + if (!paint.isAntiAlias()) { + return "BW"; + } + if (paint.isLCDRenderText()) { + return "LCD"; + } + return "AA"; +} + +/* Some considerations for performance: + short -vs- long strings (measuring overhead) + tiny -vs- large pointsize (measure blit -vs- overhead) + 1 -vs- many point sizes (measure cache lookup) + normal -vs- subpixel -vs- lineartext (minor) + force purge after each draw to measure scaler + textencoding? + text -vs- postext - pathtext + */ +class TextBench : public Benchmark { + SkPaint fPaint; + SkString fText; + SkString fName; + FontQuality fFQ; + bool fDoPos; + SkPoint* fPos; +public: + TextBench(const char text[], int ps, + SkColor color, FontQuality fq, bool doPos = false) { + fPos = NULL; + fFQ = fq; + fDoPos = doPos; + fText.set(text); + + fPaint.setAntiAlias(kBW != fq); + fPaint.setLCDRenderText(kLCD == fq); + fPaint.setTextSize(SkIntToScalar(ps)); + fPaint.setColor(color); + + if (doPos) { + size_t len = strlen(text); + SkScalar* adv = new SkScalar[len]; + fPaint.getTextWidths(text, len, adv); + fPos = new SkPoint[len]; + SkScalar x = 0; + for (size_t i = 0; i < len; ++i) { + fPos[i].set(x, SkIntToScalar(50)); + x += adv[i]; + } + delete[] adv; + } + } + + virtual ~TextBench() { + delete[] fPos; + } + +protected: + virtual const char* onGetName() { + fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize())); + if (fDoPos) { + fName.append("_pos"); + } + fName.appendf("_%s", fontQualityName(fPaint)); + if (SK_ColorBLACK != fPaint.getColor()) { + fName.appendf("_%02X", fPaint.getAlpha()); + } else { + fName.append("_BK"); + } + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + const SkIPoint dim = this->getSize(); + SkRandom rand; + + SkPaint paint(fPaint); + this->setupPaint(&paint); + // explicitly need these + paint.setColor(fPaint.getColor()); + paint.setAntiAlias(kBW != fFQ); + paint.setLCDRenderText(kLCD == fFQ); + + const SkScalar x0 = SkIntToScalar(-10); + const SkScalar y0 = SkIntToScalar(-10); + + if (fDoPos) { + // realistically, the matrix is often at least translated, so we + // do that since it exercises different code in drawPosText. + canvas->translate(SK_Scalar1, SK_Scalar1); + } + + for (int i = 0; i < loops; i++) { + if (fDoPos) { + canvas->drawPosText(fText.c_str(), fText.size(), fPos, paint); + } else { + SkScalar x = x0 + rand.nextUScalar1() * dim.fX; + SkScalar y = y0 + rand.nextUScalar1() * dim.fY; + canvas->drawText(fText.c_str(), fText.size(), x, y, paint); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#define STR "Hamburgefons" + +DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kBW); ) +DEF_BENCH( return new TextBench(STR, 16, 0xFFFF0000, kBW); ) +DEF_BENCH( return new TextBench(STR, 16, 0x88FF0000, kBW); ) + +DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kAA); ) +DEF_BENCH( return new TextBench(STR, 16, 0xFFFF0000, kAA); ) +DEF_BENCH( return new TextBench(STR, 16, 0x88FF0000, kAA); ) + +DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kLCD); ) +DEF_BENCH( return new TextBench(STR, 16, 0xFFFF0000, kLCD); ) +DEF_BENCH( return new TextBench(STR, 16, 0x88FF0000, kLCD); ) + +DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kAA, true); ) diff --git a/chromium/third_party/skia/bench/TileBench.cpp b/chromium/third_party/skia/bench/TileBench.cpp new file mode 100644 index 00000000000..7487b1b8ea6 --- /dev/null +++ b/chromium/third_party/skia/bench/TileBench.cpp @@ -0,0 +1,131 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkShader.h" +#include "SkString.h" + +static void create_gradient(SkBitmap* bm) { + SkASSERT(1 == bm->width()); + const int height = bm->height(); + + float deltaB = 255.0f / height; + float blue = 255.0f; + + SkAutoLockPixels lock(*bm); + for (int y = 0; y < height; y++) { + *bm->getAddr32(0, y) = SkColorSetRGB(0, 0, (U8CPU) blue); + blue -= deltaB; + } +} + +// Test out the special case of a tiled 1xN texture. Test out opacity, +// filtering and the different tiling modes +class ConstXTileBench : public Benchmark { + SkPaint fPaint; + SkString fName; + bool fDoFilter; + bool fDoTrans; + bool fDoScale; + static const int kWidth = 1; + static const int kHeight = 300; + +public: + ConstXTileBench(SkShader::TileMode xTile, + SkShader::TileMode yTile, + bool doFilter, + bool doTrans, + bool doScale) + : fDoFilter(doFilter) + , fDoTrans(doTrans) + , fDoScale(doScale) { + SkBitmap bm; + + bm.allocN32Pixels(kWidth, kHeight, true); + bm.eraseColor(SK_ColorWHITE); + + create_gradient(&bm); + + SkShader* s = SkShader::CreateBitmapShader(bm, xTile, yTile); + fPaint.setShader(s)->unref(); + + fName.printf("constXTile_"); + + static const char* gTileModeStr[SkShader::kTileModeCount] = { "C", "R", "M" }; + fName.append(gTileModeStr[xTile]); + fName.append(gTileModeStr[yTile]); + + if (doFilter) { + fName.append("_filter"); + } + + if (doTrans) { + fName.append("_trans"); + } + + if (doScale) { + fName.append("_scale"); + } + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint(fPaint); + this->setupPaint(&paint); + paint.setFilterLevel(fDoFilter ? SkPaint::kLow_FilterLevel + : SkPaint::kNone_FilterLevel); + if (fDoTrans) { + paint.setColor(SkColorSetARGBMacro(0x80, 0xFF, 0xFF, 0xFF)); + } + + SkRect r; + + if (fDoScale) { + r = SkRect::MakeWH(SkIntToScalar(2 * 640), SkIntToScalar(2 * 480)); + canvas->scale(SK_ScalarHalf, SK_ScalarHalf); + } else { + r = SkRect::MakeWH(SkIntToScalar(640), SkIntToScalar(480)); + } + + SkPaint bgPaint; + bgPaint.setColor(SK_ColorWHITE); + + for (int i = 0; i < loops; i++) { + if (fDoTrans) { + canvas->drawRect(r, bgPaint); + } + + canvas->drawRect(r, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +DEF_BENCH(return new ConstXTileBench(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, false, false, true)) +DEF_BENCH(return new ConstXTileBench(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, false, false, false)) +DEF_BENCH(return new ConstXTileBench(SkShader::kMirror_TileMode, SkShader::kMirror_TileMode, false, false, true)) + +DEF_BENCH(return new ConstXTileBench(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, true, false, false)) +DEF_BENCH(return new ConstXTileBench(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, true, false, true)) +DEF_BENCH(return new ConstXTileBench(SkShader::kMirror_TileMode, SkShader::kMirror_TileMode, true, false, false)) + +DEF_BENCH(return new ConstXTileBench(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, false, true, true)) +DEF_BENCH(return new ConstXTileBench(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, false, true, false)) +DEF_BENCH(return new ConstXTileBench(SkShader::kMirror_TileMode, SkShader::kMirror_TileMode, false, true, true)) + +DEF_BENCH(return new ConstXTileBench(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, true, true, false)) +DEF_BENCH(return new ConstXTileBench(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, true, true, true)) +DEF_BENCH(return new ConstXTileBench(SkShader::kMirror_TileMode, SkShader::kMirror_TileMode, true, true, false)) diff --git a/chromium/third_party/skia/bench/TimerData.cpp b/chromium/third_party/skia/bench/TimerData.cpp new file mode 100644 index 00000000000..0cb000280b9 --- /dev/null +++ b/chromium/third_party/skia/bench/TimerData.cpp @@ -0,0 +1,224 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "TimerData.h" + +#include "BenchTimer.h" +#include <limits> + +using namespace std; + +TimerData::TimerData(int maxNumTimings) +: fMaxNumTimings(maxNumTimings) +, fCurrTiming(0) +, fWallTimes(maxNumTimings) +, fTruncatedWallTimes(maxNumTimings) +, fCpuTimes(maxNumTimings) +, fTruncatedCpuTimes(maxNumTimings) +, fGpuTimes(maxNumTimings){ +} + +bool TimerData::appendTimes(BenchTimer* timer) { + SkASSERT(timer != NULL); + if (fCurrTiming >= fMaxNumTimings) { + return false; + } + + fWallTimes[fCurrTiming] = timer->fWall; + fTruncatedWallTimes[fCurrTiming] = timer->fTruncatedWall; + fCpuTimes[fCurrTiming] = timer->fCpu; + fTruncatedCpuTimes[fCurrTiming] = timer->fTruncatedCpu; + fGpuTimes[fCurrTiming] = timer->fGpu; + + ++fCurrTiming; + + return true; +} + +SkString TimerData::getResult(const char* doubleFormat, + Result result, + const char *configName, + uint32_t timerFlags, + int itersPerTiming) { + SkASSERT(itersPerTiming >= 1); + + if (!fCurrTiming) { + return SkString(""); + } + + int numTimings = fCurrTiming; + + SkString wallStr(" msecs = "); + SkString truncWallStr(" Wmsecs = "); + SkString cpuStr(" cmsecs = "); + SkString truncCpuStr(" Cmsecs = "); + SkString gpuStr(" gmsecs = "); + + double wallMin = std::numeric_limits<double>::max(); + double truncWallMin = std::numeric_limits<double>::max(); + double cpuMin = std::numeric_limits<double>::max(); + double truncCpuMin = std::numeric_limits<double>::max(); + double gpuMin = std::numeric_limits<double>::max(); + + double wallSum = 0; + double truncWallSum = 0; + double cpuSum = 0; + double truncCpuSum = 0; + double gpuSum = 0; + + for (int i = 0; i < numTimings; ++i) { + if (kPerIter_Result == result) { + wallStr.appendf(doubleFormat, fWallTimes[i] / itersPerTiming); + truncWallStr.appendf(doubleFormat, fTruncatedWallTimes[i] / itersPerTiming); + cpuStr.appendf(doubleFormat, fCpuTimes[i] / itersPerTiming); + truncCpuStr.appendf(doubleFormat, fTruncatedCpuTimes[i] / itersPerTiming); + gpuStr.appendf(doubleFormat, fGpuTimes[i] / itersPerTiming); + + if (i != numTimings - 1) { + static const char kSep[] = ", "; + wallStr.append(kSep); + truncWallStr.append(kSep); + cpuStr.append(kSep); + truncCpuStr.append(kSep); + gpuStr.append(kSep); + } + } else if (kMin_Result == result) { + wallMin = SkTMin(wallMin, fWallTimes[i]); + truncWallMin = SkTMin(truncWallMin, fTruncatedWallTimes[i]); + cpuMin = SkTMin(cpuMin, fCpuTimes[i]); + truncCpuMin = SkTMin(truncCpuMin, fTruncatedCpuTimes[i]); + gpuMin = SkTMin(gpuMin, fGpuTimes[i]); + } else { + SkASSERT(kAvg_Result == result); + wallSum += fWallTimes[i]; + truncWallSum += fTruncatedWallTimes[i]; + cpuSum += fCpuTimes[i]; + truncCpuSum += fTruncatedCpuTimes[i]; + } + + // We always track the GPU sum because whether it is non-zero indicates if valid gpu times + // were recorded at all. + gpuSum += fGpuTimes[i]; + } + + if (kMin_Result == result) { + wallStr.appendf(doubleFormat, wallMin / itersPerTiming); + truncWallStr.appendf(doubleFormat, truncWallMin / itersPerTiming); + cpuStr.appendf(doubleFormat, cpuMin / itersPerTiming); + truncCpuStr.appendf(doubleFormat, truncCpuMin / itersPerTiming); + gpuStr.appendf(doubleFormat, gpuMin / itersPerTiming); + } else if (kAvg_Result == result) { + int divisor = numTimings * itersPerTiming; + wallStr.appendf(doubleFormat, wallSum / divisor); + truncWallStr.appendf(doubleFormat, truncWallSum / divisor); + cpuStr.appendf(doubleFormat, cpuSum / divisor); + truncCpuStr.appendf(doubleFormat, truncCpuSum / divisor); + gpuStr.appendf(doubleFormat, gpuSum / divisor); + } + + SkString str; + str.printf(" %4s:", configName); + if (timerFlags & kWall_Flag) { + str += wallStr; + } + if (timerFlags & kTruncatedWall_Flag) { + str += truncWallStr; + } + if (timerFlags & kCpu_Flag) { + str += cpuStr; + } + if (timerFlags & kTruncatedCpu_Flag) { + str += truncCpuStr; + } + if ((timerFlags & kGpu_Flag) && gpuSum > 0) { + str += gpuStr; + } + return str; +} + +Json::Value TimerData::getJSON(uint32_t timerFlags, + Result result, + int itersPerTiming) { + SkASSERT(itersPerTiming >= 1); + Json::Value dataNode; + Json::Value wallNode, truncWall, cpuNode, truncCpu, gpuNode; + if (!fCurrTiming) { + return dataNode; + } + + int numTimings = fCurrTiming; + + double wallMin = std::numeric_limits<double>::max(); + double truncWallMin = std::numeric_limits<double>::max(); + double cpuMin = std::numeric_limits<double>::max(); + double truncCpuMin = std::numeric_limits<double>::max(); + double gpuMin = std::numeric_limits<double>::max(); + + double wallSum = 0; + double truncWallSum = 0; + double cpuSum = 0; + double truncCpuSum = 0; + double gpuSum = 0; + + for (int i = 0; i < numTimings; ++i) { + if (kPerIter_Result == result) { + wallNode.append(fWallTimes[i] / itersPerTiming); + truncWall.append(fTruncatedWallTimes[i] / itersPerTiming); + cpuNode.append(fCpuTimes[i] / itersPerTiming); + truncCpu.append(fTruncatedCpuTimes[i] / itersPerTiming); + gpuNode.append(fGpuTimes[i] / itersPerTiming); + } else if (kMin_Result == result) { + wallMin = SkTMin(wallMin, fWallTimes[i]); + truncWallMin = SkTMin(truncWallMin, fTruncatedWallTimes[i]); + cpuMin = SkTMin(cpuMin, fCpuTimes[i]); + truncCpuMin = SkTMin(truncCpuMin, fTruncatedCpuTimes[i]); + gpuMin = SkTMin(gpuMin, fGpuTimes[i]); + } else { + SkASSERT(kAvg_Result == result); + wallSum += fWallTimes[i]; + truncWallSum += fTruncatedWallTimes[i]; + cpuSum += fCpuTimes[i]; + truncCpuSum += fTruncatedCpuTimes[i]; + } + + // We always track the GPU sum because whether it is non-zero indicates if valid gpu times + // were recorded at all. + gpuSum += fGpuTimes[i]; + } + + if (kMin_Result == result) { + wallNode.append(wallMin / itersPerTiming); + truncWall.append(truncWallMin / itersPerTiming); + cpuNode.append(cpuMin / itersPerTiming); + truncCpu.append(truncCpuMin / itersPerTiming); + gpuNode.append(gpuMin / itersPerTiming); + } else if (kAvg_Result == result) { + int divisor = numTimings * itersPerTiming; + wallNode.append(wallSum / divisor); + truncWall.append(truncWallSum / divisor); + cpuNode.append(cpuSum / divisor); + truncCpu.append(truncCpuSum / divisor); + gpuNode.append(gpuSum / divisor); + } + + if (timerFlags & kWall_Flag) { + dataNode["wall"] = wallNode; + } + if (timerFlags & kTruncatedWall_Flag) { + dataNode["truncWall"] = truncWall; + } + if (timerFlags & kCpu_Flag) { + dataNode["cpu"] = cpuNode; + } + if (timerFlags & kTruncatedCpu_Flag) { + dataNode["trucCpu"] = truncCpu; + } + if ((timerFlags & kGpu_Flag) && gpuSum > 0) { + dataNode["gpu"] = gpuNode; + } + return dataNode; +} diff --git a/chromium/third_party/skia/bench/TimerData.h b/chromium/third_party/skia/bench/TimerData.h new file mode 100644 index 00000000000..fb84df1a9eb --- /dev/null +++ b/chromium/third_party/skia/bench/TimerData.h @@ -0,0 +1,86 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef TimerData_DEFINED +#define TimerData_DEFINED + +#include "SkString.h" +#include "SkTemplates.h" + +#ifdef SK_BUILD_FOR_WIN + #pragma warning(push) + #pragma warning(disable : 4530) +#endif + +#include "SkJSONCPP.h" + +#ifdef SK_BUILD_FOR_WIN + #pragma warning(pop) +#endif + +class BenchTimer; + +class TimerData { +public: + /** + * Constructs a TimerData to hold at most maxNumTimings sets of elapsed timer values. + **/ + explicit TimerData(int maxNumTimings); + + /** + * Collect times from the BenchTimer for an iteration. It will fail if called more often than + * indicated in the constructor. + * + * @param BenchTimer Must not be null. + */ + bool appendTimes(BenchTimer*); + + enum Result { + kMin_Result, + kAvg_Result, + kPerIter_Result + }; + + enum TimerFlags { + kWall_Flag = 0x1, + kTruncatedWall_Flag = 0x2, + kCpu_Flag = 0x4, + kTruncatedCpu_Flag = 0x8, + kGpu_Flag = 0x10 + }; + + /** + * Gets the timer data results as a string. + * @param doubleFormat printf-style format for doubles (e.g. "%02d") + * @param result the type of result desired + * @param the name of the config being timed (prepended to results string) + * @param timerFlags bitfield of TimerFlags values indicating which timers should be reported. + * @param itersPerTiming the number of test/bench iterations that correspond to each + * appendTimes() call, 1 when appendTimes is called for each iteration. + */ + SkString getResult(const char* doubleFormat, + Result result, + const char* configName, + uint32_t timerFlags, + int itersPerTiming = 1); + Json::Value getJSON(uint32_t timerFlags, + Result result, + int itersPerTiming = 1); + +private: + int fMaxNumTimings; + int fCurrTiming; + + SkAutoTArray<double> fWallTimes; + SkAutoTArray<double> fTruncatedWallTimes; + SkAutoTArray<double> fCpuTimes; + SkAutoTArray<double> fTruncatedCpuTimes; + SkAutoTArray<double> fGpuTimes; +}; + +#endif // TimerData_DEFINED diff --git a/chromium/third_party/skia/bench/VertBench.cpp b/chromium/third_party/skia/bench/VertBench.cpp new file mode 100644 index 00000000000..e426ad8a5ef --- /dev/null +++ b/chromium/third_party/skia/bench/VertBench.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkShader.h" +#include "SkString.h" + +enum VertFlags { + kColors_VertFlag, + kTexture_VertFlag, +}; + +class VertBench : public Benchmark { + SkString fName; + enum { + W = 640, + H = 480, + ROW = 20, + COL = 20, + PTS = (ROW + 1) * (COL + 1), + IDX = ROW * COL * 6, + }; + + SkPoint fPts[PTS]; + SkColor fColors[PTS]; + uint16_t fIdx[IDX]; + + static void load_2_tris(uint16_t idx[], int x, int y, int rb) { + int n = y * rb + x; + idx[0] = n; idx[1] = n + 1; idx[2] = rb + n + 1; + idx[3] = n; idx[4] = rb + n + 1; idx[5] = n + rb; + } + +public: + VertBench() { + const SkScalar dx = SkIntToScalar(W) / COL; + const SkScalar dy = SkIntToScalar(H) / COL; + + SkPoint* pts = fPts; + uint16_t* idx = fIdx; + + SkScalar yy = 0; + for (int y = 0; y <= ROW; y++) { + SkScalar xx = 0; + for (int x = 0; x <= COL; ++x) { + pts->set(xx, yy); + pts += 1; + xx += dx; + + if (x < COL && y < ROW) { + load_2_tris(idx, x, y, COL + 1); + for (int i = 0; i < 6; i++) { + SkASSERT(idx[i] < PTS); + } + idx += 6; + } + } + yy += dy; + } + SkASSERT(PTS == pts - fPts); + SkASSERT(IDX == idx - fIdx); + + SkRandom rand; + for (int i = 0; i < PTS; ++i) { + fColors[i] = rand.nextU() | (0xFF << 24); + } + + fName.set("verts"); + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + virtual void onDraw(const int loops, SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + + for (int i = 0; i < loops; i++) { + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, PTS, + fPts, NULL, fColors, NULL, fIdx, IDX, paint); + } + } +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return SkNEW_ARGS(VertBench, ()); ) diff --git a/chromium/third_party/skia/bench/WritePixelsBench.cpp b/chromium/third_party/skia/bench/WritePixelsBench.cpp new file mode 100644 index 00000000000..5138375ffba --- /dev/null +++ b/chromium/third_party/skia/bench/WritePixelsBench.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkString.h" + +class WritePixelsBench : public Benchmark { +public: + WritePixelsBench(SkColorType ct, SkAlphaType at) + : fColorType(ct) + , fAlphaType(at) + , fName("writepix") + { + switch (ct) { + case kRGBA_8888_SkColorType: + fName.append("_RGBA"); + break; + case kBGRA_8888_SkColorType: + fName.append("_BGRA"); + break; + default: + SkASSERT(0); + break; + } + switch (at) { + case kPremul_SkAlphaType: + fName.append("_PM"); + break; + case kUnpremul_SkAlphaType: + fName.append("_UPM"); + break; + default: + SkASSERT(0); + break; + } + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkISize size = canvas->getDeviceSize(); + + canvas->clear(0xFFFF0000); + + SkBitmap bmp; + bmp.allocN32Pixels(size.width(), size.height()); + canvas->readPixels(&bmp, 0, 0); + + SkImageInfo info = bmp.info(); + info.fColorType = fColorType; + info.fAlphaType = fAlphaType; + + for (int loop = 0; loop < loops; ++loop) { + canvas->writePixels(info, bmp.getPixels(), bmp.rowBytes(), 0, 0); + } + } + +private: + SkColorType fColorType; + SkAlphaType fAlphaType; + SkString fName; + + typedef Benchmark INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (kRGBA_8888_SkColorType, kPremul_SkAlphaType)); ) +DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (kRGBA_8888_SkColorType, kUnpremul_SkAlphaType)); ) diff --git a/chromium/third_party/skia/bench/WriterBench.cpp b/chromium/third_party/skia/bench/WriterBench.cpp new file mode 100644 index 00000000000..906a9d2ee84 --- /dev/null +++ b/chromium/third_party/skia/bench/WriterBench.cpp @@ -0,0 +1,41 @@ + +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkWriter32.h" + +class WriterBench : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "writer"; + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + static const char gStr[] = "abcdefghimjklmnopqrstuvwxyz"; + static const size_t gLen = strlen(gStr); + SkWriter32 writer; + for (int i = 0; i < loops; i++) { + for (size_t j = 0; j <= gLen; j++) { + writer.writeString(gStr, j); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +DEF_BENCH( return new WriterBench(); ) diff --git a/chromium/third_party/skia/bench/XfermodeBench.cpp b/chromium/third_party/skia/bench/XfermodeBench.cpp new file mode 100644 index 00000000000..f73943bcf7e --- /dev/null +++ b/chromium/third_party/skia/bench/XfermodeBench.cpp @@ -0,0 +1,127 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Benchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" +#include "SkXfermode.h" + +// Benchmark that draws non-AA rects with an SkXfermode::Mode +class XfermodeBench : public Benchmark { +public: + XfermodeBench(SkXfermode::Mode mode) { + fXfermode.reset(SkXfermode::Create(mode)); + SkASSERT(NULL != fXfermode.get() || SkXfermode::kSrcOver_Mode == mode); + fName.printf("Xfermode_%s", SkXfermode::ModeName(mode)); + } + + XfermodeBench(SkXfermode* xferMode, const char* name) { + SkASSERT(NULL != xferMode); + fXfermode.reset(xferMode); + fName.printf("Xfermode_%s", name); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { return fName.c_str(); } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkISize size = canvas->getDeviceSize(); + SkRandom random; + for (int i = 0; i < loops; ++i) { + SkPaint paint; + paint.setXfermode(fXfermode.get()); + paint.setColor(random.nextU()); + SkScalar w = random.nextRangeScalar(SkIntToScalar(kMinSize), SkIntToScalar(kMaxSize)); + SkScalar h = random.nextRangeScalar(SkIntToScalar(kMinSize), SkIntToScalar(kMaxSize)); + SkRect rect = SkRect::MakeXYWH( + random.nextUScalar1() * (size.fWidth - w), + random.nextUScalar1() * (size.fHeight - h), + w, + h + ); + canvas->drawRect(rect, paint); + } + } + +private: + enum { + kMinSize = 50, + kMaxSize = 100, + }; + SkAutoTUnref<SkXfermode> fXfermode; + SkString fName; + + typedef Benchmark INHERITED; +}; + +class XferCreateBench : public Benchmark { +public: + virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + return backend == kNonRendering_Backend; + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { return "xfermode_create"; } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + for (int outer = 0; outer < loops * 10; ++outer) { + for (int i = 0; i <= SkXfermode::kLastMode; ++i) { + SkXfermode* xfer = SkXfermode::Create(SkXfermode::Mode(i)); + SkSafeUnref(xfer); + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +#define CONCAT_I(x, y) x ## y +#define CONCAT(x, y) CONCAT_I(x, y) // allow for macro expansion +#define BENCH(...) \ + DEF_BENCH( return new XfermodeBench(__VA_ARGS__); );\ + + +BENCH(SkXfermode::kClear_Mode) +BENCH(SkXfermode::kSrc_Mode) +BENCH(SkXfermode::kDst_Mode) +BENCH(SkXfermode::kSrcOver_Mode) +BENCH(SkXfermode::kDstOver_Mode) +BENCH(SkXfermode::kSrcIn_Mode) +BENCH(SkXfermode::kDstIn_Mode) +BENCH(SkXfermode::kSrcOut_Mode) +BENCH(SkXfermode::kDstOut_Mode) +BENCH(SkXfermode::kSrcATop_Mode) +BENCH(SkXfermode::kDstATop_Mode) +BENCH(SkXfermode::kXor_Mode) + +BENCH(SkXfermode::kPlus_Mode) +BENCH(SkXfermode::kModulate_Mode) +BENCH(SkXfermode::kScreen_Mode) + +BENCH(SkXfermode::kOverlay_Mode) +BENCH(SkXfermode::kDarken_Mode) +BENCH(SkXfermode::kLighten_Mode) +BENCH(SkXfermode::kColorDodge_Mode) +BENCH(SkXfermode::kColorBurn_Mode) +BENCH(SkXfermode::kHardLight_Mode) +BENCH(SkXfermode::kSoftLight_Mode) +BENCH(SkXfermode::kDifference_Mode) +BENCH(SkXfermode::kExclusion_Mode) +BENCH(SkXfermode::kMultiply_Mode) + +BENCH(SkXfermode::kHue_Mode) +BENCH(SkXfermode::kSaturation_Mode) +BENCH(SkXfermode::kColor_Mode) +BENCH(SkXfermode::kLuminosity_Mode) + +DEF_BENCH(return new XferCreateBench;) diff --git a/chromium/third_party/skia/bench/bench_compare.py b/chromium/third_party/skia/bench/bench_compare.py new file mode 100755 index 00000000000..f4f773442e7 --- /dev/null +++ b/chromium/third_party/skia/bench/bench_compare.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python +''' +Created on May 16, 2011 + +@author: bungeman +''' +import sys +import getopt +import bench_util + +def usage(): + """Prints simple usage information.""" + + print '-o <file> the old bench output file.' + print '-n <file> the new bench output file.' + print '-h causes headers to be output.' + print '-s <stat> the type of statistical analysis used' + print ' Not specifying is the same as -s "avg".' + print ' avg: average of all data points' + print ' min: minimum of all data points' + print ' med: median of all data points' + print ' 25th: twenty-fifth percentile for all data points' + print '-f <fieldSpec> which fields to output and in what order.' + print ' Not specifying is the same as -f "bctondp".' + print ' b: bench' + print ' c: config' + print ' t: time type' + print ' o: old time' + print ' n: new time' + print ' d: diff' + print ' p: percent diff' + print '-t use tab delimited format for output.' + print '--match <bench> only matches benches which begin with <bench>.' + +class BenchDiff: + """A compare between data points produced by bench. + + (BenchDataPoint, BenchDataPoint)""" + def __init__(self, old, new): + self.old = old + self.new = new + self.diff = old.time - new.time + diffp = 0 + if old.time != 0: + diffp = self.diff / old.time + self.diffp = diffp + + def __repr__(self): + return "BenchDiff(%s, %s)" % ( + str(self.new), + str(self.old), + ) + +def main(): + """Parses command line and writes output.""" + + try: + opts, _ = getopt.getopt(sys.argv[1:], "f:o:n:s:ht", ['match=']) + except getopt.GetoptError, err: + print str(err) + usage() + sys.exit(2) + + old = None + new = None + column_format = "" + header_format = "" + columns = 'bctondp' + header = False + stat_type = "avg" + use_tabs = False + match_bench = None; + + for option, value in opts: + if option == "-o": + old = value + elif option == "-n": + new = value + elif option == "-h": + header = True + elif option == "-f": + columns = value + elif option == "-s": + stat_type = value + elif option == "-t": + use_tabs = True + elif option == "--match": + match_bench = value + else: + usage() + assert False, "unhandled option" + + if old is None or new is None: + usage() + sys.exit(2) + + old_benches = bench_util.parse({}, open(old, 'r'), stat_type) + new_benches = bench_util.parse({}, open(new, 'r'), stat_type) + + bench_diffs = [] + for old_bench in old_benches: + #filter benches by the match criteria + if match_bench and not old_bench.bench.startswith(match_bench): + continue + + #filter new_benches for benches that match old_bench + new_bench_match = [bench for bench in new_benches + if old_bench.bench == bench.bench and + old_bench.config == bench.config and + old_bench.time_type == bench.time_type + ] + if (len(new_bench_match) < 1): + continue + bench_diffs.append(BenchDiff(old_bench, new_bench_match[0])) + + if use_tabs: + column_formats = { + 'b' : '{bench}\t', + 'c' : '{config}\t', + 't' : '{time_type}\t', + 'o' : '{old_time: 0.2f}\t', + 'n' : '{new_time: 0.2f}\t', + 'd' : '{diff: 0.2f}\t', + 'p' : '{diffp: 0.1%}\t', + } + header_formats = { + 'b' : '{bench}\t', + 'c' : '{config}\t', + 't' : '{time_type}\t', + 'o' : '{old_time}\t', + 'n' : '{new_time}\t', + 'd' : '{diff}\t', + 'p' : '{diffp}\t', + } + else: + bench_max_len = max(map(lambda b: len(b.old.bench), bench_diffs)) + config_max_len = max(map(lambda b: len(b.old.config), bench_diffs)) + column_formats = { + 'b' : '{bench: >%d} ' % (bench_max_len), + 'c' : '{config: <%d} ' % (config_max_len), + 't' : '{time_type: <4} ', + 'o' : '{old_time: >10.2f} ', + 'n' : '{new_time: >10.2f} ', + 'd' : '{diff: >+10.2f} ', + 'p' : '{diffp: >+8.1%} ', + } + header_formats = { + 'b' : '{bench: >%d} ' % (bench_max_len), + 'c' : '{config: <%d} ' % (config_max_len), + 't' : '{time_type: <4} ', + 'o' : '{old_time: >10} ', + 'n' : '{new_time: >10} ', + 'd' : '{diff: >10} ', + 'p' : '{diffp: >8} ', + } + + for column_char in columns: + if column_formats[column_char]: + column_format += column_formats[column_char] + header_format += header_formats[column_char] + else: + usage() + sys.exit(2) + + if header: + print header_format.format( + bench='bench' + , config='conf' + , time_type='time' + , old_time='old' + , new_time='new' + , diff='diff' + , diffp='diffP' + ) + + bench_diffs.sort(key=lambda d : [d.diffp, + d.old.bench, + d.old.config, + d.old.time_type, + ]) + for bench_diff in bench_diffs: + print column_format.format( + bench=bench_diff.old.bench.strip() + , config=bench_diff.old.config.strip() + , time_type=bench_diff.old.time_type + , old_time=bench_diff.old.time + , new_time=bench_diff.new.time + , diff=bench_diff.diff + , diffp=bench_diff.diffp + ) + +if __name__ == "__main__": + main() diff --git a/chromium/third_party/skia/bench/bench_util.py b/chromium/third_party/skia/bench/bench_util.py new file mode 100644 index 00000000000..b6fecb7ca80 --- /dev/null +++ b/chromium/third_party/skia/bench/bench_util.py @@ -0,0 +1,356 @@ +''' +Created on May 19, 2011 + +@author: bungeman +''' + +import os +import re +import math + +# bench representation algorithm constant names +ALGORITHM_AVERAGE = 'avg' +ALGORITHM_MEDIAN = 'med' +ALGORITHM_MINIMUM = 'min' +ALGORITHM_25TH_PERCENTILE = '25th' + +# Regular expressions used throughout. +PER_SETTING_RE = '([^\s=]+)(?:=(\S+))?' +SETTINGS_RE = 'skia bench:((?:\s+' + PER_SETTING_RE + ')*)' +BENCH_RE = 'running bench (?:\[\d+ \d+\] )?\s*(\S+)' +TIME_RE = '(?:(\w*)msecs = )?\s*((?:\d+\.\d+)(?:,\s*\d+\.\d+)*)' +# non-per-tile benches have configs that don't end with ']' or '>' +CONFIG_RE = '(\S+[^\]>]):\s+((?:' + TIME_RE + '\s+)+)' +# per-tile bench lines are in the following format. Note that there are +# non-averaged bench numbers in separate lines, which we ignore now due to +# their inaccuracy. +TILE_RE = (' tile_(\S+): tile \[\d+,\d+\] out of \[\d+,\d+\] <averaged>:' + ' ((?:' + TIME_RE + '\s+)+)') +# for extracting tile layout +TILE_LAYOUT_RE = ' out of \[(\d+),(\d+)\] <averaged>: ' + +PER_SETTING_RE_COMPILED = re.compile(PER_SETTING_RE) +SETTINGS_RE_COMPILED = re.compile(SETTINGS_RE) +BENCH_RE_COMPILED = re.compile(BENCH_RE) +TIME_RE_COMPILED = re.compile(TIME_RE) +CONFIG_RE_COMPILED = re.compile(CONFIG_RE) +TILE_RE_COMPILED = re.compile(TILE_RE) +TILE_LAYOUT_RE_COMPILED = re.compile(TILE_LAYOUT_RE) + +class BenchDataPoint: + """A single data point produced by bench. + """ + def __init__(self, bench, config, time_type, time, settings, + tile_layout='', per_tile_values=[], per_iter_time=[]): + # string name of the benchmark to measure + self.bench = bench + # string name of the configurations to run + self.config = config + # type of the timer in string: '' (walltime), 'c' (cpu) or 'g' (gpu) + self.time_type = time_type + # float number of the bench time value + self.time = time + # dictionary of the run settings + self.settings = settings + # how tiles cover the whole picture: '5x3' means 5 columns and 3 rows + self.tile_layout = tile_layout + # list of float for per_tile bench values, if applicable + self.per_tile_values = per_tile_values + # list of float for per-iteration bench time, if applicable + self.per_iter_time = per_iter_time + + def __repr__(self): + return "BenchDataPoint(%s, %s, %s, %s, %s)" % ( + str(self.bench), + str(self.config), + str(self.time_type), + str(self.time), + str(self.settings), + ) + +class _ExtremeType(object): + """Instances of this class compare greater or less than other objects.""" + def __init__(self, cmpr, rep): + object.__init__(self) + self._cmpr = cmpr + self._rep = rep + + def __cmp__(self, other): + if isinstance(other, self.__class__) and other._cmpr == self._cmpr: + return 0 + return self._cmpr + + def __repr__(self): + return self._rep + +Max = _ExtremeType(1, "Max") +Min = _ExtremeType(-1, "Min") + +class _ListAlgorithm(object): + """Algorithm for selecting the representation value from a given list. + representation is one of the ALGORITHM_XXX representation types.""" + def __init__(self, data, representation=None): + if not representation: + representation = ALGORITHM_AVERAGE # default algorithm + self._data = data + self._len = len(data) + if representation == ALGORITHM_AVERAGE: + self._rep = sum(self._data) / self._len + else: + self._data.sort() + if representation == ALGORITHM_MINIMUM: + self._rep = self._data[0] + else: + # for percentiles, we use the value below which x% of values are + # found, which allows for better detection of quantum behaviors. + if representation == ALGORITHM_MEDIAN: + x = int(round(0.5 * self._len + 0.5)) + elif representation == ALGORITHM_25TH_PERCENTILE: + x = int(round(0.25 * self._len + 0.5)) + else: + raise Exception("invalid representation algorithm %s!" % + representation) + self._rep = self._data[x - 1] + + def compute(self): + return self._rep + +def _ParseAndStoreTimes(config_re_compiled, is_per_tile, line, bench, + value_dic, layout_dic): + """Parses given bench time line with regex and adds data to value_dic. + + config_re_compiled: precompiled regular expression for parsing the config + line. + is_per_tile: boolean indicating whether this is a per-tile bench. + If so, we add tile layout into layout_dic as well. + line: input string line to parse. + bench: name of bench for the time values. + value_dic: dictionary to store bench values. See bench_dic in parse() below. + layout_dic: dictionary to store tile layouts. See parse() for descriptions. + """ + + for config in config_re_compiled.finditer(line): + current_config = config.group(1) + tile_layout = '' + if is_per_tile: # per-tile bench, add name prefix + current_config = 'tile_' + current_config + layouts = TILE_LAYOUT_RE_COMPILED.search(line) + if layouts and len(layouts.groups()) == 2: + tile_layout = '%sx%s' % layouts.groups() + times = config.group(2) + for new_time in TIME_RE_COMPILED.finditer(times): + current_time_type = new_time.group(1) + iters = [float(i) for i in + new_time.group(2).strip().split(',')] + value_dic.setdefault(bench, {}).setdefault( + current_config, {}).setdefault(current_time_type, []).append( + iters) + layout_dic.setdefault(bench, {}).setdefault( + current_config, {}).setdefault(current_time_type, tile_layout) + +def parse_skp_bench_data(directory, revision, rep, default_settings=None): + """Parses all the skp bench data in the given directory. + + Args: + directory: string of path to input data directory. + revision: git hash revision that matches the data to process. + rep: bench representation algorithm, see bench_util.py. + default_settings: dictionary of other run settings. See writer.option() in + bench/benchmain.cpp. + + Returns: + A list of BenchDataPoint objects. + """ + revision_data_points = [] + file_list = os.listdir(directory) + file_list.sort() + for bench_file in file_list: + scalar_type = None + # Scalar type, if any, is in the bench filename after 'scalar_'. + if (bench_file.startswith('bench_' + revision + '_data_')): + if bench_file.find('scalar_') > 0: + components = bench_file.split('_') + scalar_type = components[components.index('scalar') + 1] + else: # Skips non skp bench files. + continue + + with open('/'.join([directory, bench_file]), 'r') as file_handle: + settings = dict(default_settings or {}) + settings['scalar'] = scalar_type + revision_data_points.extend(parse(settings, file_handle, rep)) + + return revision_data_points + +# TODO(bensong): switch to reading JSON output when available. This way we don't +# need the RE complexities. +def parse(settings, lines, representation=None): + """Parses bench output into a useful data structure. + + ({str:str}, __iter__ -> str) -> [BenchDataPoint] + representation is one of the ALGORITHM_XXX types.""" + + benches = [] + current_bench = None + # [bench][config][time_type] -> [[per-iter values]] where per-tile config + # has per-iter value list for each tile [[<tile1_iter1>,<tile1_iter2>,...], + # [<tile2_iter1>,<tile2_iter2>,...],...], while non-per-tile config only + # contains one list of iterations [[iter1, iter2, ...]]. + bench_dic = {} + # [bench][config][time_type] -> tile_layout + layout_dic = {} + + for line in lines: + + # see if this line is a settings line + settingsMatch = SETTINGS_RE_COMPILED.search(line) + if (settingsMatch): + settings = dict(settings) + for settingMatch in PER_SETTING_RE_COMPILED.finditer(settingsMatch.group(1)): + if (settingMatch.group(2)): + settings[settingMatch.group(1)] = settingMatch.group(2) + else: + settings[settingMatch.group(1)] = True + + # see if this line starts a new bench + new_bench = BENCH_RE_COMPILED.search(line) + if new_bench: + current_bench = new_bench.group(1) + + # add configs on this line to the bench_dic + if current_bench: + if line.startswith(' tile_') : + _ParseAndStoreTimes(TILE_RE_COMPILED, True, line, current_bench, + bench_dic, layout_dic) + else: + _ParseAndStoreTimes(CONFIG_RE_COMPILED, False, line, + current_bench, bench_dic, layout_dic) + + # append benches to list + for bench in bench_dic: + for config in bench_dic[bench]: + for time_type in bench_dic[bench][config]: + tile_layout = '' + per_tile_values = [] # empty for non-per-tile configs + per_iter_time = [] # empty for per-tile configs + bench_summary = None # a single final bench value + if len(bench_dic[bench][config][time_type]) > 1: + # per-tile config; compute representation for each tile + per_tile_values = [ + _ListAlgorithm(iters, representation).compute() + for iters in bench_dic[bench][config][time_type]] + # use sum of each tile representation for total bench value + bench_summary = sum(per_tile_values) + # extract tile layout + tile_layout = layout_dic[bench][config][time_type] + else: + # get the list of per-iteration values + per_iter_time = bench_dic[bench][config][time_type][0] + bench_summary = _ListAlgorithm( + per_iter_time, representation).compute() + benches.append(BenchDataPoint( + bench, + config, + time_type, + bench_summary, + settings, + tile_layout, + per_tile_values, + per_iter_time)) + + return benches + +class LinearRegression: + """Linear regression data based on a set of data points. + + ([(Number,Number)]) + There must be at least two points for this to make sense.""" + def __init__(self, points): + n = len(points) + max_x = Min + min_x = Max + + Sx = 0.0 + Sy = 0.0 + Sxx = 0.0 + Sxy = 0.0 + Syy = 0.0 + for point in points: + x = point[0] + y = point[1] + max_x = max(max_x, x) + min_x = min(min_x, x) + + Sx += x + Sy += y + Sxx += x*x + Sxy += x*y + Syy += y*y + + denom = n*Sxx - Sx*Sx + if (denom != 0.0): + B = (n*Sxy - Sx*Sy) / denom + else: + B = 0.0 + a = (1.0/n)*(Sy - B*Sx) + + se2 = 0 + sB2 = 0 + sa2 = 0 + if (n >= 3 and denom != 0.0): + se2 = (1.0/(n*(n-2)) * (n*Syy - Sy*Sy - B*B*denom)) + sB2 = (n*se2) / denom + sa2 = sB2 * (1.0/n) * Sxx + + + self.slope = B + self.intercept = a + self.serror = math.sqrt(max(0, se2)) + self.serror_slope = math.sqrt(max(0, sB2)) + self.serror_intercept = math.sqrt(max(0, sa2)) + self.max_x = max_x + self.min_x = min_x + + def __repr__(self): + return "LinearRegression(%s, %s, %s, %s, %s)" % ( + str(self.slope), + str(self.intercept), + str(self.serror), + str(self.serror_slope), + str(self.serror_intercept), + ) + + def find_min_slope(self): + """Finds the minimal slope given one standard deviation.""" + slope = self.slope + intercept = self.intercept + error = self.serror + regr_start = self.min_x + regr_end = self.max_x + regr_width = regr_end - regr_start + + if slope < 0: + lower_left_y = slope*regr_start + intercept - error + upper_right_y = slope*regr_end + intercept + error + return min(0, (upper_right_y - lower_left_y) / regr_width) + + elif slope > 0: + upper_left_y = slope*regr_start + intercept + error + lower_right_y = slope*regr_end + intercept - error + return max(0, (lower_right_y - upper_left_y) / regr_width) + + return 0 + +def CreateRevisionLink(revision_number): + """Returns HTML displaying the given revision number and linking to + that revision's change page at code.google.com, e.g. + http://code.google.com/p/skia/source/detail?r=2056 + """ + return '<a href="http://code.google.com/p/skia/source/detail?r=%s">%s</a>'%( + revision_number, revision_number) + +def main(): + foo = [[0.0, 0.0], [0.0, 1.0], [0.0, 2.0], [0.0, 3.0]] + LinearRegression(foo) + +if __name__ == "__main__": + main() diff --git a/chromium/third_party/skia/bench/benchmain.cpp b/chromium/third_party/skia/bench/benchmain.cpp new file mode 100644 index 00000000000..6b3f5872f2c --- /dev/null +++ b/chromium/third_party/skia/bench/benchmain.cpp @@ -0,0 +1,686 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "BenchLogger.h" +#include "BenchTimer.h" +#include "Benchmark.h" +#include "CrashHandler.h" +#include "GMBench.h" +#include "ResultsWriter.h" +#include "SkBitmapDevice.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkCommandLineFlags.h" +#include "SkData.h" +#include "SkDeferredCanvas.h" +#include "SkGraphics.h" +#include "SkImageEncoder.h" +#include "SkOSFile.h" +#include "SkPicture.h" +#include "SkPictureRecorder.h" +#include "SkString.h" +#include "SkSurface.h" + +#if SK_SUPPORT_GPU +#include "GrContext.h" +#include "GrContextFactory.h" +#include "GrRenderTarget.h" +#include "SkGpuDevice.h" +#include "gl/GrGLDefines.h" +#else +class GrContext; +#endif // SK_SUPPORT_GPU + +#include <limits> + +enum BenchMode { + kNormal_BenchMode, + kDeferred_BenchMode, + kDeferredSilent_BenchMode, + kRecord_BenchMode, + kPictureRecord_BenchMode +}; +const char* BenchMode_Name[] = { + "normal", "deferred", "deferredSilent", "record", "picturerecord" +}; + +static const char kDefaultsConfigStr[] = "defaults"; + +/////////////////////////////////////////////////////////////////////////////// + +class Iter { +public: + Iter() : fBenches(BenchRegistry::Head()), fGMs(skiagm::GMRegistry::Head()) {} + + Benchmark* next() { + if (fBenches) { + BenchRegistry::Factory f = fBenches->factory(); + fBenches = fBenches->next(); + return (*f)(NULL); + } + + while (fGMs) { + SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL)); + fGMs = fGMs->next(); + if (gm->getFlags() & skiagm::GM::kAsBench_Flag) { + return SkNEW_ARGS(GMBench, (gm.detach())); + } + } + + return NULL; + } + +private: + const BenchRegistry* fBenches; + const skiagm::GMRegistry* fGMs; +}; + +static void make_filename(const char name[], SkString* path) { + path->set(name); + for (int i = 0; name[i]; i++) { + switch (name[i]) { + case '/': + case '\\': + case ' ': + case ':': + path->writable_str()[i] = '-'; + break; + default: + break; + } + } +} + +static void saveFile(const char name[], const char config[], const char dir[], + const SkImage* image) { + SkAutoTUnref<SkData> data(image->encode(SkImageEncoder::kPNG_Type, 100)); + if (NULL == data.get()) { + return; + } + + SkString filename; + make_filename(name, &filename); + filename.appendf("_%s.png", config); + SkString path = SkOSPath::SkPathJoin(dir, filename.c_str()); + ::remove(path.c_str()); + + SkFILEWStream stream(path.c_str()); + stream.write(data->data(), data->size()); +} + +static void perform_clip(SkCanvas* canvas, int w, int h) { + SkRect r; + + r.set(SkIntToScalar(10), SkIntToScalar(10), + SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); + canvas->clipRect(r, SkRegion::kIntersect_Op); + + r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), + SkIntToScalar(w-10), SkIntToScalar(h-10)); + canvas->clipRect(r, SkRegion::kXOR_Op); +} + +static void perform_rotate(SkCanvas* canvas, int w, int h) { + const SkScalar x = SkIntToScalar(w) / 2; + const SkScalar y = SkIntToScalar(h) / 2; + + canvas->translate(x, y); + canvas->rotate(SkIntToScalar(35)); + canvas->translate(-x, -y); +} + +static void perform_scale(SkCanvas* canvas, int w, int h) { + const SkScalar x = SkIntToScalar(w) / 2; + const SkScalar y = SkIntToScalar(h) / 2; + + canvas->translate(x, y); + // just enough so we can't take the sprite case + canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); + canvas->translate(-x, -y); +} + +static SkSurface* make_surface(SkColorType colorType, const SkIPoint& size, + Benchmark::Backend backend, int sampleCount, + GrContext* context) { + SkSurface* surface = NULL; + SkImageInfo info = SkImageInfo::Make(size.fX, size.fY, colorType, + kPremul_SkAlphaType); + + switch (backend) { + case Benchmark::kRaster_Backend: + surface = SkSurface::NewRaster(info); + surface->getCanvas()->clear(SK_ColorWHITE); + break; +#if SK_SUPPORT_GPU + case Benchmark::kGPU_Backend: { + surface = SkSurface::NewRenderTarget(context, info, sampleCount); + break; + } +#endif + case Benchmark::kPDF_Backend: + default: + SkDEBUGFAIL("unsupported"); + } + return surface; +} + +#if SK_SUPPORT_GPU +GrContextFactory gContextFactory; +typedef GrContextFactory::GLContextType GLContextType; +static const GLContextType kNative = GrContextFactory::kNative_GLContextType; +static const GLContextType kNVPR = GrContextFactory::kNVPR_GLContextType; +#if SK_ANGLE +static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType; +#endif +static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType; +static const GLContextType kNull = GrContextFactory::kNull_GLContextType; +#else +typedef int GLContextType; +static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0; +#endif + +#ifdef SK_DEBUG +static const bool kIsDebug = true; +#else +static const bool kIsDebug = false; +#endif + +static const struct Config { + SkColorType fColorType; + const char* name; + int sampleCount; + Benchmark::Backend backend; + GLContextType contextType; + bool runByDefault; +} gConfigs[] = { + { kN32_SkColorType, "NONRENDERING", 0, Benchmark::kNonRendering_Backend, kNative, true}, + { kN32_SkColorType, "8888", 0, Benchmark::kRaster_Backend, kNative, true}, + { kRGB_565_SkColorType, "565", 0, Benchmark::kRaster_Backend, kNative, true}, +#if SK_SUPPORT_GPU + { kN32_SkColorType, "GPU", 0, Benchmark::kGPU_Backend, kNative, true}, + { kN32_SkColorType, "MSAA4", 4, Benchmark::kGPU_Backend, kNative, false}, + { kN32_SkColorType, "MSAA16", 16, Benchmark::kGPU_Backend, kNative, false}, + { kN32_SkColorType, "NVPRMSAA4", 4, Benchmark::kGPU_Backend, kNVPR, true}, + { kN32_SkColorType, "NVPRMSAA16", 16, Benchmark::kGPU_Backend, kNVPR, false}, +#if SK_ANGLE + { kN32_SkColorType, "ANGLE", 0, Benchmark::kGPU_Backend, kANGLE, true}, +#endif // SK_ANGLE + { kN32_SkColorType, "Debug", 0, Benchmark::kGPU_Backend, kDebug, kIsDebug}, + { kN32_SkColorType, "NULLGPU", 0, Benchmark::kGPU_Backend, kNull, true}, +#endif // SK_SUPPORT_GPU +}; + +DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir."); +DEFINE_string(timers, "cg", "Timers to display. " + "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)"); + +DEFINE_bool(rotate, false, "Rotate canvas before bench run?"); +DEFINE_bool(scale, false, "Scale canvas before bench run?"); +DEFINE_bool(clip, false, "Clip canvas before bench run?"); + +DEFINE_bool(forceAA, true, "Force anti-aliasing?"); +DEFINE_bool(forceFilter, false, "Force bitmap filtering?"); +DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?"); +DEFINE_bool(forceBlend, false, "Force alpha blending?"); + +DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable cache."); +DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to disable cache."); + +DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects."); +DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n" + "Multiple matches may be separated by spaces.\n" + "~ causes a matching test to always be skipped\n" + "^ requires the start of the test to match\n" + "$ requires the end of the test to match\n" + "^ and $ requires an exact match\n" + "If a test does not match any list entry,\n" + "it is skipped unless some list entry starts with ~\n"); +DEFINE_string(mode, "normal", + "normal: draw to a normal canvas;\n" + "deferred: draw to a deferred canvas;\n" + "deferredSilent: deferred with silent playback;\n" + "record: draw to an SkPicture;\n" + "picturerecord: draw from an SkPicture to an SkPicture.\n"); +DEFINE_string(config, kDefaultsConfigStr, + "Run configs given. By default, runs the configs marked \"runByDefault\" in gConfigs."); +DEFINE_string(logFile, "", "Also write stdout here."); +DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run."); +DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run."); +DEFINE_bool(runOnce, kIsDebug, "Run each bench exactly once and don't report timings."); +DEFINE_double(error, 0.01, + "Ratio of subsequent bench measurements must drop within 1±error to converge."); +DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops."); +DEFINE_bool2(verbose, v, false, "Print more."); +DEFINE_string(outResultsFile, "", "If given, the results will be written to the file in JSON format."); +DEFINE_bool(dryRun, false, "Don't actually run the tests, just print what would have been done."); + +// Has this bench converged? First arguments are milliseconds / loop iteration, +// last is overall runtime in milliseconds. +static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw) { + if (currRaw < FLAGS_minMs) { + return false; + } + const double low = 1 - FLAGS_error, high = 1 + FLAGS_error; + const double ratio = currPerLoop / prevPerLoop; + return low < ratio && ratio < high; +} + +int tool_main(int argc, char** argv); +int tool_main(int argc, char** argv) { + SetupCrashHandler(); + SkCommandLineFlags::Parse(argc, argv); +#if SK_ENABLE_INST_COUNT + if (FLAGS_leaks) { + gPrintInstCount = true; + } +#endif + SkAutoGraphics ag; + + // First, parse some flags. + BenchLogger logger; + if (FLAGS_logFile.count()) { + logger.SetLogFile(FLAGS_logFile[0]); + } + + LoggerResultsWriter logWriter(logger, FLAGS_timeFormat[0]); + MultiResultsWriter writer; + writer.add(&logWriter); + + SkAutoTDelete<JSONResultsWriter> jsonWriter; + if (FLAGS_outResultsFile.count()) { + jsonWriter.reset(SkNEW(JSONResultsWriter(FLAGS_outResultsFile[0]))); + writer.add(jsonWriter.get()); + } + + // Instantiate after all the writers have been added to writer so that we + // call close() before their destructors are called on the way out. + CallEnd<MultiResultsWriter> ender(writer); + + const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF; + SkTriState::State dither = SkTriState::kDefault; + for (size_t i = 0; i < 3; i++) { + if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) { + dither = static_cast<SkTriState::State>(i); + } + } + + BenchMode benchMode = kNormal_BenchMode; + for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) { + if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) { + benchMode = static_cast<BenchMode>(i); + } + } + + SkTDArray<int> configs; + bool runDefaultConfigs = false; + // Try user-given configs first. + for (int i = 0; i < FLAGS_config.count(); i++) { + for (int j = 0; j < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++j) { + if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) { + *configs.append() = j; + } else if (0 == strcmp(FLAGS_config[i], kDefaultsConfigStr)) { + runDefaultConfigs = true; + } + } + } + // If there weren't any, fill in with defaults. + if (runDefaultConfigs) { + for (int i = 0; i < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++i) { + if (gConfigs[i].runByDefault) { + *configs.append() = i; + } + } + } + // Filter out things we can't run. + if (kNormal_BenchMode != benchMode) { + // Non-rendering configs only run in normal mode + for (int i = 0; i < configs.count(); ++i) { + const Config& config = gConfigs[configs[i]]; + if (Benchmark::kNonRendering_Backend == config.backend) { + configs.remove(i, 1); + --i; + } + } + } + +#if SK_SUPPORT_GPU + for (int i = 0; i < configs.count(); ++i) { + const Config& config = gConfigs[configs[i]]; + + if (Benchmark::kGPU_Backend == config.backend) { + GrContext* context = gContextFactory.get(config.contextType); + if (NULL == context) { + SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n", + config.name); + configs.remove(i); + --i; + continue; + } + if (config.sampleCount > context->getMaxSampleCount()){ + SkDebugf( + "Sample count (%d) for config %s is not supported. Config will be skipped.\n", + config.sampleCount, config.name); + configs.remove(i); + --i; + continue; + } + } + } +#endif + + // All flags should be parsed now. Report our settings. + if (FLAGS_runOnce) { + logger.logError("bench was run with --runOnce, so we're going to hide the times." + " It's for your own good!\n"); + } + writer.option("mode", FLAGS_mode[0]); + writer.option("alpha", SkStringPrintf("0x%02X", alpha).c_str()); + writer.option("antialias", SkStringPrintf("%d", FLAGS_forceAA).c_str()); + writer.option("filter", SkStringPrintf("%d", FLAGS_forceFilter).c_str()); + writer.option("dither", SkTriState::Name[dither]); + + writer.option("rotate", SkStringPrintf("%d", FLAGS_rotate).c_str()); + writer.option("scale", SkStringPrintf("%d", FLAGS_scale).c_str()); + writer.option("clip", SkStringPrintf("%d", FLAGS_clip).c_str()); + +#if defined(SK_BUILD_FOR_WIN32) + writer.option("system", "WIN32"); +#elif defined(SK_BUILD_FOR_MAC) + writer.option("system", "MAC"); +#elif defined(SK_BUILD_FOR_ANDROID) + writer.option("system", "ANDROID"); +#elif defined(SK_BUILD_FOR_UNIX) + writer.option("system", "UNIX"); +#else + writer.option("system", "other"); +#endif + +#if defined(SK_DEBUG) + writer.option("build", "DEBUG"); +#else + writer.option("build", "RELEASE"); +#endif + + // Set texture cache limits if non-default. + for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { +#if SK_SUPPORT_GPU + const Config& config = gConfigs[i]; + if (Benchmark::kGPU_Backend != config.backend) { + continue; + } + GrContext* context = gContextFactory.get(config.contextType); + if (NULL == context) { + continue; + } + + size_t bytes; + int count; + context->getResourceCacheLimits(&count, &bytes); + if (-1 != FLAGS_gpuCacheBytes) { + bytes = static_cast<size_t>(FLAGS_gpuCacheBytes); + } + if (-1 != FLAGS_gpuCacheCount) { + count = FLAGS_gpuCacheCount; + } + context->setResourceCacheLimits(count, bytes); +#endif + } + + // Run each bench in each configuration it supports and we asked for. + Iter iter; + Benchmark* bench; + while ((bench = iter.next()) != NULL) { + SkAutoTUnref<Benchmark> benchUnref(bench); + if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { + continue; + } + + bench->setForceAlpha(alpha); + bench->setForceAA(FLAGS_forceAA); + bench->setForceFilter(FLAGS_forceFilter); + bench->setDither(dither); + bench->preDraw(); + + bool loggedBenchName = false; + for (int i = 0; i < configs.count(); ++i) { + const int configIndex = configs[i]; + const Config& config = gConfigs[configIndex]; + + if (!bench->isSuitableFor(config.backend)) { + continue; + } + + GrContext* context = NULL; +#if SK_SUPPORT_GPU + SkGLContextHelper* glContext = NULL; + if (Benchmark::kGPU_Backend == config.backend) { + context = gContextFactory.get(config.contextType); + if (NULL == context) { + continue; + } + glContext = gContextFactory.getGLContext(config.contextType); + } +#endif + + SkAutoTUnref<SkCanvas> canvas; + SkAutoTUnref<SkPicture> recordFrom; + SkPictureRecorder recorderTo; + const SkIPoint dim = bench->getSize(); + + SkAutoTUnref<SkSurface> surface; + if (Benchmark::kNonRendering_Backend != config.backend) { + surface.reset(make_surface(config.fColorType, + dim, + config.backend, + config.sampleCount, + context)); + if (!surface.get()) { + logger.logError(SkStringPrintf( + "Device creation failure for config %s. Will skip.\n", config.name)); + continue; + } + + switch(benchMode) { + case kDeferredSilent_BenchMode: + case kDeferred_BenchMode: + canvas.reset(SkDeferredCanvas::Create(surface.get())); + break; + case kRecord_BenchMode: + canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY))); + break; + case kPictureRecord_BenchMode: { + SkPictureRecorder recorderFrom; + bench->draw(1, recorderFrom.beginRecording(dim.fX, dim.fY)); + recordFrom.reset(recorderFrom.endRecording()); + canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY))); + break; + } + case kNormal_BenchMode: + canvas.reset(SkRef(surface->getCanvas())); + break; + default: + SkASSERT(false); + } + } + + if (NULL != canvas) { + canvas->clear(SK_ColorWHITE); + if (FLAGS_clip) { + perform_clip(canvas, dim.fX, dim.fY); + } + if (FLAGS_scale) { + perform_scale(canvas, dim.fX, dim.fY); + } + if (FLAGS_rotate) { + perform_rotate(canvas, dim.fX, dim.fY); + } + } + + if (!loggedBenchName) { + loggedBenchName = true; + writer.bench(bench->getName(), dim.fX, dim.fY); + } + +#if SK_SUPPORT_GPU + SkGLContextHelper* contextHelper = NULL; + if (Benchmark::kGPU_Backend == config.backend) { + contextHelper = gContextFactory.getGLContext(config.contextType); + } + BenchTimer timer(contextHelper); +#else + BenchTimer timer; +#endif + + double previous = std::numeric_limits<double>::infinity(); + bool converged = false; + + // variables used to compute loopsPerFrame + double frameIntervalTime = 0.0f; + int frameIntervalTotalLoops = 0; + + bool frameIntervalComputed = false; + int loopsPerFrame = 0; + int loopsPerIter = 0; + if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.name); } + if (!FLAGS_dryRun) { + do { + // Ramp up 1 -> 2 -> 4 -> 8 -> 16 -> ... -> ~1 billion. + loopsPerIter = (loopsPerIter == 0) ? 1 : loopsPerIter * 2; + if (loopsPerIter >= (1<<30) || timer.fWall > FLAGS_maxMs) { + // If you find it takes more than a billion loops to get up to 20ms of runtime, + // you've got a computer clocked at several THz or have a broken benchmark. ;) + // "1B ought to be enough for anybody." + logger.logError(SkStringPrintf( + "\nCan't get %s %s to converge in %dms (%d loops)", + bench->getName(), config.name, FLAGS_maxMs, loopsPerIter)); + break; + } + + if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) { + // Clear the recorded commands so that they do not accumulate. + canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY))); + } + + timer.start(); + // Inner loop that allows us to break the run into smaller + // chunks (e.g. frames). This is especially useful for the GPU + // as we can flush and/or swap buffers to keep the GPU from + // queuing up too much work. + for (int loopCount = loopsPerIter; loopCount > 0; ) { + // Save and restore around each call to draw() to guarantee a pristine canvas. + SkAutoCanvasRestore saveRestore(canvas, true/*also save*/); + + int loops; + if (frameIntervalComputed && loopCount > loopsPerFrame) { + loops = loopsPerFrame; + loopCount -= loopsPerFrame; + } else { + loops = loopCount; + loopCount = 0; + } + + if (benchMode == kPictureRecord_BenchMode) { + recordFrom->draw(canvas); + } else { + bench->draw(loops, canvas); + } + + if (kDeferredSilent_BenchMode == benchMode) { + static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush(); + } else if (NULL != canvas) { + canvas->flush(); + } + + #if SK_SUPPORT_GPU + // swap drawing buffers on each frame to prevent the GPU + // from queuing up too much work + if (NULL != glContext) { + glContext->swapBuffers(); + } + #endif + } + + + + // Stop truncated timers before GL calls complete, and stop the full timers after. + timer.truncatedEnd(); + #if SK_SUPPORT_GPU + if (NULL != glContext) { + context->flush(); + SK_GL(*glContext, Finish()); + } + #endif + timer.end(); + + // setup the frame interval for subsequent iterations + if (!frameIntervalComputed) { + frameIntervalTime += timer.fWall; + frameIntervalTotalLoops += loopsPerIter; + if (frameIntervalTime >= FLAGS_minMs) { + frameIntervalComputed = true; + loopsPerFrame = + (int)(((double)frameIntervalTotalLoops / frameIntervalTime) * FLAGS_minMs); + if (loopsPerFrame < 1) { + loopsPerFrame = 1; + } + // SkDebugf(" %s has %d loops in %f ms (normalized to %d)\n", + // bench->getName(), frameIntervalTotalLoops, + // timer.fWall, loopsPerFrame); + } + } + + const double current = timer.fWall / loopsPerIter; + if (FLAGS_verbose && current > previous) { SkDebugf("↑"); } + if (FLAGS_verbose) { SkDebugf("%.3g ", current); } + converged = HasConverged(previous, current, timer.fWall); + previous = current; + } while (!FLAGS_runOnce && !converged); + } + if (FLAGS_verbose) { SkDebugf("\n"); } + + if (!FLAGS_dryRun && FLAGS_outDir.count() && Benchmark::kNonRendering_Backend != config.backend) { + SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); + if (image.get()) { + saveFile(bench->getName(), config.name, FLAGS_outDir[0], + image); + } + } + + if (FLAGS_runOnce) { + // Let's not mislead ourselves by looking at Debug build or single iteration bench times! + continue; + } + + // Normalize to ms per 1000 iterations. + const double normalize = 1000.0 / loopsPerIter; + const struct { char shortName; const char* longName; double ms; } times[] = { + {'w', "msecs", normalize * timer.fWall}, + {'W', "Wmsecs", normalize * timer.fTruncatedWall}, + {'c', "cmsecs", normalize * timer.fCpu}, + {'C', "Cmsecs", normalize * timer.fTruncatedCpu}, + {'g', "gmsecs", normalize * timer.fGpu}, + }; + + writer.config(config.name); + for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) { + if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms > 0) { + writer.timer(times[i].longName, times[i].ms); + } + } + } + } +#if SK_SUPPORT_GPU + gContextFactory.destroyContexts(); +#endif + return 0; +} + +#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) +int main(int argc, char * const argv[]) { + return tool_main(argc, (char**) argv); +} +#endif diff --git a/chromium/third_party/skia/bench/check_bench_regressions.py b/chromium/third_party/skia/bench/check_bench_regressions.py new file mode 100644 index 00000000000..ea9146421a0 --- /dev/null +++ b/chromium/third_party/skia/bench/check_bench_regressions.py @@ -0,0 +1,244 @@ +''' +Created on May 16, 2011 + +@author: bungeman +''' +import bench_util +import getopt +import httplib +import itertools +import json +import os +import re +import sys +import urllib +import urllib2 +import xml.sax.saxutils + +# Maximum expected number of characters we expect in an svn revision. +MAX_SVN_REV_LENGTH = 5 + +# Indices for getting elements from bench expectation files. +# See bench_expectations_<builder>.txt for details. +EXPECTED_IDX = -3 +LB_IDX = -2 +UB_IDX = -1 + +# Indices of the tuple of dictionaries containing slower and faster alerts. +SLOWER = 0 +FASTER = 1 + +# URL prefix for the bench dashboard page. Showing recent 15 days of data. +DASHBOARD_URL_PREFIX = 'http://go/skpdash/#15' + +def usage(): + """Prints simple usage information.""" + + print '-a <representation_alg> bench representation algorithm to use. ' + print ' Defaults to "25th". See bench_util.py for details.' + print '-b <builder> name of the builder whose bench data we are checking.' + print '-d <dir> a directory containing bench_<revision>_<scalar> files.' + print '-e <file> file containing expected bench builder values/ranges.' + print ' Will raise exception if actual bench values are out of range.' + print ' See bench_expectations_<builder>.txt for data format / examples.' + print '-r <revision> the git commit hash or svn revision for checking ' + print ' bench values.' + + +class Label: + """The information in a label. + + (str, str, str, str, {str:str})""" + def __init__(self, bench, config, time_type, settings): + self.bench = bench + self.config = config + self.time_type = time_type + self.settings = settings + + def __repr__(self): + return "Label(%s, %s, %s, %s)" % ( + str(self.bench), + str(self.config), + str(self.time_type), + str(self.settings), + ) + + def __str__(self): + return "%s_%s_%s_%s" % ( + str(self.bench), + str(self.config), + str(self.time_type), + str(self.settings), + ) + + def __eq__(self, other): + return (self.bench == other.bench and + self.config == other.config and + self.time_type == other.time_type and + self.settings == other.settings) + + def __hash__(self): + return (hash(self.bench) ^ + hash(self.config) ^ + hash(self.time_type) ^ + hash(frozenset(self.settings.iteritems()))) + +def create_bench_dict(revision_data_points): + """Convert current revision data into a dictionary of line data. + + Args: + revision_data_points: a list of bench data points + + Returns: + a dictionary of this form: + keys = Label objects + values = the corresponding bench value + """ + bench_dict = {} + for point in revision_data_points: + point_name = Label(point.bench,point.config,point.time_type, + point.settings) + if point_name not in bench_dict: + bench_dict[point_name] = point.time + else: + raise Exception('Duplicate expectation entry: ' + str(point_name)) + + return bench_dict + +def read_expectations(expectations, filename): + """Reads expectations data from file and put in expectations dict.""" + for expectation in open(filename).readlines(): + elements = expectation.strip().split(',') + if not elements[0] or elements[0].startswith('#'): + continue + if len(elements) != 5: + raise Exception("Invalid expectation line format: %s" % + expectation) + bench_entry = elements[0] + ',' + elements[1] + if bench_entry in expectations: + raise Exception("Dup entries for bench expectation %s" % + bench_entry) + # [<Bench_BmpConfig_TimeType>,<Platform-Alg>] -> (LB, UB, EXPECTED) + expectations[bench_entry] = (float(elements[LB_IDX]), + float(elements[UB_IDX]), + float(elements[EXPECTED_IDX])) + +def check_expectations(lines, expectations, key_suffix): + """Check if any bench results are outside of expected range. + + For each input line in lines, checks the expectations dictionary to see if + the bench is out of the given range. + + Args: + lines: dictionary mapping Label objects to the bench values. + expectations: dictionary returned by read_expectations(). + key_suffix: string of <Platform>-<Alg> containing the bot platform and the + bench representation algorithm. + + Returns: + No return value. + + Raises: + Exception containing bench data that are out of range, if any. + """ + # The platform for this bot, to pass to the dashboard plot. + platform = key_suffix[ : key_suffix.rfind('-')] + # Tuple of dictionaries recording exceptions that are slower and faster, + # respectively. Each dictionary maps off_ratio (ratio of actual to expected) + # to a list of corresponding exception messages. + exceptions = ({}, {}) + for line in lines: + line_str = str(line) + line_str = line_str[ : line_str.find('_{')] + # Extracts bench and config from line_str, which is in the format + # <bench-picture-name>.skp_<config>_ + bench, config = line_str.strip('_').split('.skp_') + bench_platform_key = line_str + ',' + key_suffix + if bench_platform_key not in expectations: + continue + this_bench_value = lines[line] + this_min, this_max, this_expected = expectations[bench_platform_key] + if this_bench_value < this_min or this_bench_value > this_max: + off_ratio = this_bench_value / this_expected + exception = 'Bench %s out of range [%s, %s] (%s vs %s, %s%%).' % ( + bench_platform_key, this_min, this_max, this_bench_value, + this_expected, (off_ratio - 1) * 100) + exception += '\n' + '~'.join([ + DASHBOARD_URL_PREFIX, bench, platform, config]) + if off_ratio > 1: # Bench is slower. + exceptions[SLOWER].setdefault(off_ratio, []).append(exception) + else: + exceptions[FASTER].setdefault(off_ratio, []).append(exception) + outputs = [] + for i in [SLOWER, FASTER]: + if exceptions[i]: + ratios = exceptions[i].keys() + ratios.sort(reverse=True) + li = [] + for ratio in ratios: + li.extend(exceptions[i][ratio]) + header = '%s benches got slower (sorted by %% difference):' % len(li) + if i == FASTER: + header = header.replace('slower', 'faster') + outputs.extend(['', header] + li) + + if outputs: + # Directly raising Exception will have stderr outputs tied to the line + # number of the script, so use sys.stderr.write() instead. + # Add a trailing newline to supress new line checking errors. + sys.stderr.write('\n'.join(['Exception:'] + outputs + ['\n'])) + exit(1) + + +def main(): + """Parses command line and checks bench expectations.""" + try: + opts, _ = getopt.getopt(sys.argv[1:], + "a:b:d:e:r:", + "default-setting=") + except getopt.GetoptError, err: + print str(err) + usage() + sys.exit(2) + + directory = None + bench_expectations = {} + rep = '25th' # bench representation algorithm, default to 25th + rev = None # git commit hash or svn revision number + bot = None + + try: + for option, value in opts: + if option == "-a": + rep = value + elif option == "-b": + bot = value + elif option == "-d": + directory = value + elif option == "-e": + read_expectations(bench_expectations, value) + elif option == "-r": + rev = value + else: + usage() + assert False, "unhandled option" + except ValueError: + usage() + sys.exit(2) + + if directory is None or bot is None or rev is None: + usage() + sys.exit(2) + + platform_and_alg = bot + '-' + rep + + data_points = bench_util.parse_skp_bench_data(directory, rev, rep) + + bench_dict = create_bench_dict(data_points) + + if bench_expectations: + check_expectations(bench_dict, bench_expectations, platform_and_alg) + + +if __name__ == "__main__": + main() diff --git a/chromium/third_party/skia/bench/gUniqueGlyphIDs.h b/chromium/third_party/skia/bench/gUniqueGlyphIDs.h new file mode 100644 index 00000000000..fe1c67a0950 --- /dev/null +++ b/chromium/third_party/skia/bench/gUniqueGlyphIDs.h @@ -0,0 +1,468 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +/* runs of unique glyph IDs, with a 0xFFFF sentinel between different runs + * + * Test data generated by examining web pages and their calls to drawText. + */ +static const uint16_t gUniqueGlyphIDs[] = { +3, 41, 44, 50, 57, 58, 59, 60, 61, 62, 63, 64, 65, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 81, 89, 90, 91, 92, 93, 94, 95, 96, 97, 100, 101, 102, 103, 104, 106, 107, 108, 109, 110, 111, 112, 113, 0xFFFF, +3, 10, 11, 12, 13, 15, 16, 17, 19, 20, 21, 22, 23, 25, 27, 28, 29, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 53, 54, 55, 56, 57, 58, 60, 61, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 175, 0xFFFF, +3, 16, 17, 20, 21, 22, 25, 28, 35, 54, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 0xFFFF, +4, 37, 39, 40, 41, 43, 44, 50, 51, 52, 55, 56, 0xFFFF, +3, 29, 68, 70, 76, 78, 79, 81, 82, 85, 86, 87, 88, 0xFFFF, +3, 17, 29, 38, 39, 40, 41, 45, 47, 48, 50, 51, 54, 55, 58, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 0xFFFF, +3, 15, 16, 18, 19, 28, 36, 40, 56, 68, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 133, 0xFFFF, +3, 16, 19, 20, 50, 68, 71, 72, 73, 74, 76, 79, 80, 81, 82, 85, 86, 87, 88, 89, 0xFFFF, +3, 10, 16, 17, 19, 20, 21, 22, 25, 35, 36, 38, 39, 43, 44, 47, 48, 49, 50, 53, 54, 55, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 95, 107, 0xFFFF, +179, 0xFFFF, +3, 36, 38, 55, 57, 59, 61, 63, 64, 65, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 0xFFFF, +3, 4, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 28, 29, 30, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 200, 201, 202, 203, 205, 206, 0xFFFF, +3, 4, 17, 34, 36, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 0xFFFF, +3, 40, 53, 54, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 0xFFFF, +3, 4, 11, 12, 15, 16, 17, 18, 29, 30, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 200, 201, 203, 205, 206, 0xFFFF, +1707, 3039, 3477, 23264, 29479, 33487, 0xFFFF, +3, 19, 0xFFFF, +3, 7, 10, 15, 16, 17, 19, 20, 23, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 181, 182, 0xFFFF, +3, 40, 42, 43, 53, 55, 57, 0xFFFF, +3, 58, 68, 72, 76, 85, 87, 89, 90, 0xFFFF, +3, 5, 10, 15, 16, 17, 19, 20, 21, 29, 36, 38, 39, 41, 43, 47, 48, 50, 51, 53, 54, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 178, 0xFFFF, +3, 17, 36, 38, 39, 42, 49, 53, 54, 57, 68, 70, 71, 72, 73, 75, 76, 79, 80, 81, 82, 85, 86, 87, 88, 0xFFFF, +3, 40, 44, 47, 49, 50, 57, 58, 0xFFFF, +3, 7, 10, 17, 19, 24, 26, 36, 37, 40, 41, 43, 48, 49, 50, 51, 53, 54, 56, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 0xFFFF, +3, 10, 38, 40, 41, 42, 43, 44, 48, 60, 68, 71, 72, 74, 75, 76, 80, 81, 82, 85, 86, 87, 88, 0xFFFF, +3, 10, 54, 68, 73, 76, 81, 85, 88, 0xFFFF, +3, 4, 6, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 28, 29, 30, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 53, 54, 55, 56, 57, 58, 59, 60, 62, 64, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 171, 177, 178, 179, 180, 181, 182, 397, 0xFFFF, +7, 15, 16, 17, 18, 19, 20, 24, 25, 28, 64, 73, 0xFFFF, +3, 9, 16, 36, 37, 38, 39, 40, 41, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 0xFFFF, +3, 37, 50, 68, 69, 70, 78, 80, 85, 0xFFFF, +3, 9, 36, 37, 39, 40, 43, 44, 46, 47, 48, 49, 50, 53, 54, 55, 56, 57, 58, 0xFFFF, +3, 15, 19, 21, 22, 23, 25, 26, 28, 38, 42, 54, 68, 71, 72, 76, 81, 85, 86, 87, 0xFFFF, +38, 45, 72, 74, 81, 82, 85, 86, 87, 0xFFFF, +68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 0xFFFF, +3, 47, 71, 72, 73, 76, 82, 83, 86, 87, 0xFFFF, +3, 41, 49, 68, 72, 85, 86, 87, 88, 90, 0xFFFF, +19, 20, 21, 23, 25, 26, 0xFFFF, +3, 37, 57, 58, 59, 60, 61, 63, 64, 65, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 0xFFFF, +41, 68, 72, 85, 86, 87, 88, 0xFFFF, +3, 39, 41, 54, 68, 69, 70, 71, 72, 76, 79, 81, 82, 85, 86, 87, 88, 90, 0xFFFF, +3, 5, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 106, 160, 161, 182, 0xFFFF, +3, 16, 19, 28, 36, 38, 39, 40, 41, 42, 43, 44, 47, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 0xFFFF, +3, 9, 36, 41, 43, 47, 48, 50, 51, 53, 54, 55, 58, 68, 69, 70, 71, 72, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 91, 92, 178, 0xFFFF, +3, 11, 12, 14, 15, 16, 17, 19, 20, 21, 24, 25, 27, 28, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 139, 140, 177, 0xFFFF, +17, 51, 58, 70, 71, 72, 80, 82, 85, 86, 0xFFFF, +37, 49, 68, 70, 72, 78, 87, 91, 0xFFFF, +3, 11, 12, 17, 20, 36, 39, 41, 42, 44, 46, 47, 48, 49, 51, 54, 55, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 0xFFFF, +3, 9, 16, 17, 18, 29, 30, 36, 39, 40, 41, 42, 45, 46, 48, 49, 54, 55, 59, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 0xFFFF, +3, 16, 47, 68, 71, 72, 73, 75, 76, 78, 79, 81, 82, 83, 86, 87, 166, 0xFFFF, +3, 9, 15, 17, 36, 45, 51, 55, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 0xFFFF, +3, 9, 17, 19, 20, 21, 23, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 0xFFFF, +3, 7, 10, 15, 16, 19, 20, 21, 36, 37, 38, 41, 42, 43, 46, 47, 48, 49, 51, 53, 54, 55, 56, 58, 60, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 0xFFFF, +17, 51, 58, 70, 71, 72, 80, 82, 85, 86, 0xFFFF, +19, 20, 21, 22, 23, 24, 0xFFFF, +3, 5, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 112, 177, 182, 386, 387, 0xFFFF, +7, 17, 19, 20, 21, 23, 24, 25, 26, 27, 28, 0xFFFF, +3, 37, 38, 39, 40, 41, 42, 44, 45, 47, 49, 51, 53, 54, 55, 58, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 81, 82, 85, 86, 87, 88, 89, 90, 92, 95, 0xFFFF, +3, 4, 16, 19, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 0xFFFF, +3, 4, 5, 6, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 135, 140, 171, 178, 179, 180, 182, 392, 393, 0xFFFF, +3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 97, 111, 112, 124, 133, 139, 140, 171, 177, 178, 179, 180, 181, 182, 194, 0xFFFF, +3, 36, 38, 39, 40, 44, 46, 48, 50, 51, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 91, 92, 0xFFFF, +3, 15, 16, 17, 20, 26, 29, 34, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 203, 0xFFFF, +15, 19, 20, 23, 24, 25, 28, 0xFFFF, +3, 11, 12, 15, 16, 17, 19, 21, 26, 28, 38, 39, 40, 41, 43, 45, 46, 49, 51, 53, 54, 56, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 90, 92, 131, 179, 180, 0xFFFF, +3, 4, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 36, 37, 38, 39, 41, 42, 43, 44, 48, 50, 51, 53, 54, 55, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 139, 0xFFFF, +19, 20, 21, 22, 23, 24, 26, 44, 54, 70, 72, 74, 76, 79, 81, 82, 83, 85, 86, 87, 0xFFFF, +3, 8, 9, 17, 19, 24, 36, 39, 41, 42, 49, 50, 51, 55, 60, 68, 70, 72, 73, 74, 75, 76, 78, 79, 80, 82, 85, 86, 87, 90, 95, 0xFFFF, +41, 131, 0xFFFF, +3, 15, 16, 17, 19, 21, 24, 25, 37, 40, 43, 47, 56, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 194, 0xFFFF, +3, 19, 20, 21, 29, 36, 40, 41, 51, 70, 71, 72, 73, 74, 75, 76, 78, 79, 82, 85, 86, 87, 88, 92, 182, 0xFFFF, +3, 5, 9, 10, 11, 12, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 108, 112, 124, 0xFFFF, +23, 24, 0xFFFF, +3, 11, 12, 15, 19, 22, 23, 28, 36, 38, 48, 57, 58, 68, 72, 75, 76, 81, 82, 85, 87, 88, 90, 0xFFFF, +3, 15, 19, 21, 25, 26, 27, 28, 37, 50, 68, 69, 70, 78, 80, 85, 0xFFFF, +3, 17, 48, 49, 55, 68, 70, 72, 74, 75, 76, 79, 81, 82, 83, 85, 86, 87, 88, 92, 0xFFFF, +3, 25, 28, 29, 30, 32, 33, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 200, 201, 202, 203, 204, 0xFFFF, +3, 5, 15, 16, 19, 20, 21, 22, 27, 29, 34, 36, 37, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 57, 59, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 134, 166, 184, 190, 214, 0xFFFF, +3, 4, 17, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 61, 68, 70, 71, 72, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 170, 0xFFFF, +3, 10, 16, 17, 19, 20, 21, 22, 29, 34, 36, 37, 38, 41, 42, 44, 46, 47, 48, 49, 50, 53, 54, 55, 56, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 0xFFFF, +3, 14, 36, 37, 38, 39, 40, 42, 43, 44, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 0xFFFF, +16, 35, 68, 70, 71, 72, 73, 76, 80, 81, 82, 87, 0xFFFF, +3, 6, 15, 17, 18, 19, 20, 21, 26, 29, 36, 37, 38, 50, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 0xFFFF, +17, 48, 60, 76, 78, 82, 85, 86, 88, 503, 522, 525, 528, 534, 536, 537, 538, 544, 551, 0xFFFF, +3, 11, 12, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 36, 37, 38, 41, 42, 43, 45, 46, 47, 48, 49, 50, 53, 54, 55, 58, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 91, 92, 93, 0xFFFF, +17, 20, 23, 24, 25, 27, 28, 0xFFFF, +3, 8, 11, 12, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 91, 92, 0xFFFF, +3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 20, 25, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 53, 54, 55, 56, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 179, 180, 182, 0xFFFF, +3, 11, 12, 19, 20, 21, 37, 49, 51, 53, 54, 68, 69, 70, 71, 72, 76, 78, 79, 80, 81, 82, 85, 87, 88, 89, 112, 130, 193, 0xFFFF, +3, 37, 42, 49, 57, 68, 70, 71, 72, 76, 78, 82, 87, 88, 91, 0xFFFF, +3, 200, 0xFFFF, +3, 18, 29, 39, 43, 49, 68, 72, 76, 79, 80, 81, 82, 86, 87, 0xFFFF, +3, 5, 15, 16, 19, 22, 25, 26, 29, 36, 40, 41, 43, 46, 48, 49, 51, 54, 55, 59, 60, 66, 68, 71, 72, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 166, 184, 214, 0xFFFF, +4, 5, 11, 16, 20, 21, 22, 23, 24, 27, 28, 29, 30, 37, 38, 39, 40, 41, 42, 44, 45, 50, 52, 54, 55, 56, 57, 59, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 0xFFFF, +3, 40, 53, 54, 68, 69, 70, 71, 72, 75, 76, 79, 80, 81, 82, 85, 86, 87, 88, 89, 92, 0xFFFF, +38, 51, 68, 72, 74, 76, 78, 79, 81, 82, 85, 86, 87, 0xFFFF, +3, 11, 12, 48, 72, 82, 85, 170, 0xFFFF, +3, 29, 36, 38, 39, 49, 53, 54, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 0xFFFF, +3, 6, 15, 20, 36, 53, 54, 55, 56, 68, 70, 71, 72, 73, 76, 79, 80, 81, 82, 85, 86, 87, 88, 89, 92, 0xFFFF, +3, 4, 10, 16, 19, 20, 21, 22, 23, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 47, 49, 53, 54, 55, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 0xFFFF, +3, 4, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 171, 182, 314, 376, 377, 390, 0xFFFF, +3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 98, 105, 106, 107, 110, 111, 112, 114, 116, 117, 121, 122, 123, 124, 126, 127, 170, 171, 179, 180, 182, 190, 213, 255, 259, 264, 458, 533, 1133, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1209, 1215, 1219, 1221, 1223, 1227, 1229, 1231, 1233, 1235, 1237, 1239, 1243, 1245, 1247, 1249, 1251, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1273, 1275, 0xFFFF, +3, 4, 5, 6, 8, 9, 10, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 98, 105, 106, 107, 108, 109, 111, 112, 114, 116, 117, 121, 123, 126, 129, 131, 138, 139, 170, 182, 188, 208, 213, 247, 250, 255, 259, 264, 570, 573, 574, 581, 582, 583, 584, 586, 587, 588, 594, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 627, 629, 630, 633, 1131, 1133, 1189, 1191, 1193, 1195, 1199, 1201, 1211, 1213, 1219, 1221, 1223, 1227, 1231, 1233, 1235, 1237, 1239, 1243, 1245, 1247, 1249, 1255, 1259, 1261, 1265, 1267, 1269, 1275, 0xFFFF, +3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 97, 105, 106, 107, 109, 111, 112, 114, 116, 117, 121, 123, 126, 127, 129, 138, 170, 177, 179, 180, 182, 194, 213, 247, 248, 255, 259, 264, 377, 378, 429, 484, 1131, 1133, 1189, 1190, 1191, 1193, 1195, 1201, 1203, 1211, 1215, 1219, 1221, 1223, 1225, 1227, 1231, 1235, 1237, 1239, 1241, 1245, 1247, 1249, 1251, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1275, 0xFFFF, +3, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 33, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 98, 101, 103, 120, 131, 182, 255, 264, 313, 1133, 1255, 0xFFFF, +53, 54, 56, 0xFFFF, +3, 10, 16, 19, 20, 21, 25, 27, 29, 34, 37, 39, 42, 43, 44, 50, 51, 54, 55, 57, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 93, 0xFFFF, +3, 5, 7, 9, 10, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 30, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 178, 0xFFFF, +3, 16, 54, 71, 72, 75, 82, 84, 87, 88, 90, 91, 378, 0xFFFF, +3, 8, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 36, 37, 38, 39, 41, 44, 47, 48, 51, 54, 55, 56, 58, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 112, 130, 138, 193, 0xFFFF, +23, 41, 131, 0xFFFF, +3, 40, 41, 49, 54, 68, 72, 74, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 0xFFFF, +3, 9, 68, 70, 71, 72, 76, 79, 81, 82, 83, 85, 86, 87, 88, 92, 0xFFFF, +40, 49, 55, 68, 70, 72, 73, 76, 80, 81, 82, 85, 86, 0xFFFF, +3, 0xFFFF, +3, 5, 9, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 135, 0xFFFF, +3, 38, 48, 51, 55, 56, 58, 68, 69, 71, 72, 73, 76, 79, 80, 81, 82, 85, 86, 87, 88, 0xFFFF, +3, 15, 17, 36, 38, 40, 42, 44, 48, 49, 50, 51, 53, 56, 0xFFFF, +3, 11, 12, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 39, 42, 51, 53, 62, 64, 68, 69, 71, 72, 73, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 0xFFFF, +388, 418, 882, 883, 885, 886, 910, 913, 917, 921, 923, 925, 928, 929, 934, 936, 938, 939, 940, 944, 952, 954, 955, 964, 966, 969, 974, 984, 1011, 1022, 1032, 1037, 1042, 1046, 1050, 1056, 1060, 1066, 1073, 1082, 1083, 1095, 1096, 1098, 1101, 1102, 1103, 1105, 1106, 1107, 1109, 1111, 1114, 1115, 1117, 1121, 1125, 1128, 1130, 1132, 1135, 1144, 1146, 1150, 1154, 1165, 1166, 1167, 1172, 1175, 1177, 1179, 1180, 1185, 1198, 1199, 1203, 1206, 1207, 1220, 1233, 1235, 1236, 1264, 1270, 1272, 1274, 1281, 1291, 1293, 1297, 1298, 1300, 1307, 1313, 1314, 1318, 1320, 1321, 1322, 1333, 1334, 1347, 1350, 1354, 1362, 1376, 1378, 1390, 1406, 1407, 1409, 1410, 1414, 1418, 1427, 1429, 1430, 1438, 1440, 1442, 1443, 1447, 1453, 1456, 1458, 1461, 1464, 1466, 1478, 1483, 1484, 1491, 1502, 1508, 1509, 1511, 1516, 1528, 1533, 1541, 1554, 1555, 1556, 1568, 1573, 1574, 1579, 1580, 1592, 1599, 1600, 1607, 1614, 1615, 1616, 1625, 1627, 1629, 1652, 1653, 1657, 1659, 1660, 1663, 1667, 1668, 1670, 1673, 1677, 1679, 1691, 1692, 1693, 1694, 1696, 1700, 1706, 1709, 1713, 1719, 1724, 1730, 1733, 1734, 1740, 1744, 1747, 1750, 1752, 1755, 1758, 1762, 1765, 1771, 1775, 1777, 1781, 1788, 1789, 1790, 1791, 1792, 1796, 1800, 1803, 1805, 1808, 1822, 1826, 1831, 1844, 1849, 1853, 1858, 1860, 1863, 1864, 1879, 1880, 1882, 1885, 1897, 1898, 1914, 1919, 1929, 1932, 1953, 1955, 1956, 1958, 1960, 1963, 1965, 1966, 1969, 1972, 1977, 1994, 1999, 2003, 2004, 2005, 2006, 2007, 2010, 2011, 2018, 2030, 2033, 2036, 2057, 2059, 2061, 2063, 2079, 2081, 2085, 2090, 2092, 2096, 2098, 2101, 2104, 2108, 2109, 2110, 2113, 2125, 2127, 2128, 2130, 2138, 2149, 2153, 2154, 2159, 2165, 2174, 2175, 2182, 2188, 2196, 2199, 2201, 2202, 2209, 2211, 2230, 2235, 2237, 2256, 2257, 2264, 2270, 2271, 2274, 2275, 2294, 2296, 2302, 2303, 2304, 2308, 2309, 2310, 2312, 2314, 2318, 2320, 2321, 2327, 2329, 2331, 2332, 2333, 2334, 2339, 2343, 2349, 2357, 2358, 2369, 2378, 2387, 2389, 2390, 2392, 2396, 2397, 2398, 2400, 2407, 2408, 2409, 2410, 2413, 2416, 2430, 2437, 2441, 2446, 2448, 2450, 2456, 2477, 2480, 2482, 2484, 2487, 2493, 2497, 2518, 2522, 2524, 2538, 2539, 2542, 2545, 2555, 2563, 2564, 2565, 2575, 2576, 2579, 2584, 2588, 2589, 2593, 2597, 2598, 2602, 2610, 2623, 2630, 2635, 2640, 2641, 2642, 2643, 2645, 2661, 2665, 2668, 2670, 2693, 2699, 2707, 2708, 2709, 2712, 2715, 2735, 2736, 2742, 2748, 2753, 2759, 2761, 2768, 2771, 2781, 2784, 2786, 2794, 2795, 2797, 2803, 2823, 2826, 2835, 2836, 2837, 2838, 2840, 2841, 2842, 2847, 2848, 2863, 2874, 2876, 2877, 2889, 2890, 2899, 2901, 2904, 2905, 2910, 2914, 2916, 2922, 2927, 2928, 2929, 2938, 2942, 2946, 2947, 2949, 2959, 2963, 2964, 2966, 2968, 2969, 2979, 2982, 3011, 3017, 3025, 3027, 3028, 3030, 3031, 3036, 3039, 3041, 3042, 3045, 3055, 3056, 3069, 3070, 3073, 3076, 3082, 3084, 3088, 3092, 3096, 3100, 3102, 3103, 3108, 3112, 3120, 3123, 3131, 3164, 3166, 3176, 3198, 3200, 3205, 3208, 3210, 3214, 3216, 3217, 3219, 3222, 3229, 3248, 3249, 3257, 3258, 3259, 3263, 3264, 3265, 3271, 3276, 3281, 3282, 3283, 3284, 3286, 3288, 3294, 3296, 3299, 3301, 3313, 3316, 3320, 3323, 3324, 3325, 3333, 3335, 3343, 3347, 3348, 3353, 3354, 3362, 3367, 3371, 3373, 3375, 3384, 3388, 3391, 3399, 3406, 3413, 3415, 3416, 3418, 3429, 3445, 3447, 3450, 3453, 3455, 3458, 3461, 3466, 3469, 3477, 3487, 3501, 3503, 3510, 3528, 3529, 3530, 3531, 3532, 3541, 3543, 3545, 3551, 3555, 3558, 3565, 3567, 3569, 3571, 3582, 3591, 3594, 3598, 3603, 3610, 3612, 3618, 3620, 3628, 3630, 3639, 3651, 3654, 3658, 3660, 3665, 3680, 3681, 3683, 3686, 3691, 3693, 3698, 3705, 3706, 3707, 3712, 3713, 3719, 3722, 3724, 3726, 3733, 3736, 3743, 3750, 3754, 3763, 3764, 3786, 3795, 3802, 3805, 3814, 3816, 3819, 3827, 3828, 3830, 3854, 3856, 3860, 3863, 3875, 3896, 3925, 3926, 3930, 3941, 3946, 3949, 3951, 3965, 3970, 3999, 4047, 4063, 4086, 4104, 4125, 4133, 4146, 4185, 4204, 4222, 4226, 4273, 4285, 4317, 4354, 4366, 4370, 4374, 4378, 4391, 4396, 4397, 4398, 4406, 4412, 4480, 4495, 4504, 4531, 4606, 4666, 4673, 4678, 4695, 4710, 4712, 4721, 4729, 4769, 4770, 4788, 4794, 4804, 4808, 4810, 4816, 4819, 4827, 4830, 4834, 4861, 4895, 4919, 4926, 4985, 5010, 5014, 5033, 5034, 5047, 5065, 5097, 5103, 5136, 5149, 5180, 5224, 5245, 5281, 5306, 5313, 5355, 5398, 5452, 5475, 5478, 5540, 5558, 5563, 5654, 5655, 5681, 5687, 5691, 5695, 5700, 5705, 5757, 5762, 5777, 5838, 5851, 5867, 5902, 5998, 6016, 6054, 6055, 6058, 6076, 6104, 6108, 6129, 6163, 6220, 6221, 6226, 6335, 6403, 6405, 6445, 6472, 6482, 6496, 6522, 6550, 6640, 6678, 6679, 6683, 6684, 6712, 6721, 6753, 6760, 6794, 6809, 6837, 6838, 6853, 6862, 6878, 6881, 6897, 6915, 6989, 7014, 7029, 7141, 7192, 7355, 7362, 7588, 7617, 7760, 8047, 8065, 8078, 8084, 8090, 8097, 8113, 8116, 8118, 8122, 8136, 8178, 8181, 8222, 8327, 8623, 8723, 8852, 8878, 8945, 9364, 9505, 9786, 10296, 12427, 12429, 12430, 12432, 12434, 12435, 12449, 12450, 12459, 12460, 12461, 12462, 13236, 13857, 15066, 16495, 17497, 20320, 22577, 0xFFFF, +3, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 178, 179, 180, 181, 182, 0xFFFF, +1, 13, 21, 25, 32, 42, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 0xFFFF, +1, 8, 13, 14, 25, 27, 34, 36, 45, 48, 49, 51, 52, 53, 55, 56, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 90, 0xFFFF, +3, 10, 55, 68, 74, 75, 76, 78, 81, 83, 84, 86, 87, 88, 92, 106, 121, 1201, 1203, 1219, 1237, 1247, 0xFFFF, +20, 21, 26, 0xFFFF, +3, 19, 20, 21, 22, 38, 41, 42, 44, 55, 58, 68, 69, 70, 72, 75, 76, 79, 81, 82, 85, 86, 87, 0xFFFF, +4, 16, 23, 29, 30, 37, 38, 39, 41, 43, 44, 45, 46, 48, 50, 51, 54, 55, 56, 59, 69, 71, 72, 73, 75, 76, 77, 79, 80, 82, 83, 84, 86, 88, 89, 91, 93, 0xFFFF, +3, 15, 17, 40, 50, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 0xFFFF, +68, 72, 73, 76, 79, 82, 83, 85, 87, 89, 90, 92, 0xFFFF, +40, 49, 55, 68, 70, 72, 73, 76, 80, 81, 82, 85, 86, 0xFFFF, +16, 68, 69, 71, 72, 74, 76, 78, 81, 85, 87, 90, 0xFFFF, +3, 16, 17, 18, 27, 28, 35, 42, 45, 51, 58, 68, 70, 71, 72, 73, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 89, 171, 0xFFFF, +3, 51, 53, 71, 72, 78, 80, 81, 82, 112, 0xFFFF, +3, 4, 16, 19, 20, 21, 38, 51, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 80, 81, 82, 83, 85, 86, 87, 90, 92, 139, 0xFFFF, +3, 36, 38, 39, 40, 41, 43, 44, 47, 49, 51, 53, 54, 55, 57, 58, 68, 69, 70, 71, 72, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 0xFFFF, +3, 37, 38, 39, 43, 44, 51, 68, 71, 72, 74, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 92, 0xFFFF, +3, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 74, 76, 89, 0xFFFF, +3, 39, 41, 43, 48, 54, 55, 68, 70, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 92, 93, 0xFFFF, +3, 11, 12, 16, 17, 38, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 85, 86, 87, 88, 89, 93, 0xFFFF, +3, 17, 18, 29, 40, 41, 51, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 111, 114, 120, 129, 170, 0xFFFF, +3, 29, 48, 51, 58, 68, 70, 71, 73, 76, 79, 81, 82, 85, 86, 87, 0xFFFF, +40, 48, 49, 51, 54, 92, 0xFFFF, +14, 20, 21, 22, 0xFFFF, +226, 250, 258, 262, 267, 268, 275, 281, 286, 289, 383, 384, 387, 913, 939, 952, 1046, 1065, 1094, 1107, 1109, 1147, 1344, 1724, 1803, 1806, 1858, 1914, 2081, 2125, 2134, 2264, 2303, 2308, 2310, 2312, 2334, 2357, 2397, 2407, 2551, 2580, 2641, 2642, 2711, 2735, 2784, 2826, 2863, 2910, 2974, 3039, 3076, 3229, 3249, 3271, 3354, 3466, 3503, 3528, 3677, 3707, 3723, 3802, 4285, 4496, 4606, 4729, 5033, 6405, 6901, 8623, 10275, 10606, 12465, 12466, 13615, 14453, 14460, 17761, 17813, 17830, 17834, 18124, 20381, 21531, 0xFFFF, +3, 6, 7, 8, 9, 10, 11, 12, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 38, 39, 40, 44, 45, 46, 50, 56, 57, 67, 89, 101, 0xFFFF, +3, 4, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 25, 27, 29, 34, 36, 37, 38, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 97, 163, 179, 180, 182, 213, 247, 397, 0xFFFF, +1, 2, 8, 15, 27, 34, 37, 38, 42, 49, 52, 53, 55, 66, 67, 68, 69, 70, 71, 72, 73, 74, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 90, 0xFFFF, +3, 16, 18, 19, 20, 21, 22, 23, 28, 55, 68, 70, 72, 73, 76, 80, 81, 82, 85, 86, 0xFFFF, +3, 19, 20, 21, 27, 29, 36, 38, 42, 44, 46, 51, 54, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 182, 0xFFFF, +3, 4, 6, 17, 20, 22, 23, 24, 29, 38, 40, 42, 43, 44, 48, 49, 51, 54, 55, 57, 60, 68, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 85, 86, 87, 88, 89, 90, 177, 179, 180, 182, 0xFFFF, +3, 10, 38, 39, 40, 43, 44, 46, 50, 51, 53, 54, 55, 0xFFFF, +3, 82, 85, 0xFFFF, +3, 38, 42, 45, 46, 55, 60, 66, 101, 0xFFFF, +4, 10, 15, 17, 20, 21, 22, 23, 26, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 69, 70, 72, 73, 74, 75, 77, 79, 80, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 0xFFFF, +54, 68, 70, 72, 75, 85, 0xFFFF, +20, 21, 22, 23, 24, 25, 26, 27, 0xFFFF, +3, 5, 11, 12, 13, 15, 16, 17, 21, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 112, 0xFFFF, +3, 15, 17, 20, 21, 22, 24, 25, 26, 27, 28, 40, 42, 57, 58, 70, 71, 72, 73, 74, 79, 81, 82, 85, 87, 88, 91, 92, 0xFFFF, +3, 17, 40, 51, 68, 69, 70, 78, 79, 82, 85, 92, 0xFFFF, +388, 1073, 1083, 1316, 1329, 1458, 1531, 1609, 1612, 1707, 1795, 1806, 1858, 2007, 2079, 2092, 2201, 2224, 2497, 2565, 2643, 2735, 2781, 2833, 2834, 2920, 3039, 3056, 3229, 3347, 3477, 9068, 9093, 9095, 9097, 9100, 9101, 9104, 9106, 9108, 9111, 9112, 9114, 9116, 9120, 9128, 9129, 9132, 9135, 9139, 9160, 9164, 9165, 9166, 9168, 9171, 9172, 9182, 9183, 9184, 9186, 9190, 9193, 9195, 9196, 9197, 9198, 9199, 9201, 9203, 9205, 9206, 9207, 9208, 9211, 9212, 9215, 9220, 9221, 9228, 9229, 9231, 9233, 9235, 9237, 9241, 9244, 9245, 9246, 9247, 9248, 9249, 9251, 9253, 9255, 9256, 9257, 9263, 12435, 12461, 12462, 12468, 12490, 12494, 12495, 12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 0xFFFF, +19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 62, 64, 0xFFFF, +36, 37, 38, 39, 40, 41, 43, 44, 50, 51, 53, 54, 55, 56, 57, 58, 0xFFFF, +3, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 33, 68, 72, 74, 80, 86, 0xFFFF, +3, 19, 20, 21, 24, 38, 54, 68, 71, 74, 75, 76, 80, 81, 82, 85, 88, 169, 170, 183, 0xFFFF, +3, 15, 19, 21, 22, 23, 27, 37, 39, 54, 61, 68, 69, 72, 74, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 93, 183, 314, 0xFFFF, +3, 8, 10, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 105, 106, 107, 109, 111, 114, 116, 117, 121, 122, 123, 124, 126, 127, 129, 139, 181, 213, 247, 248, 250, 255, 259, 264, 458, 1133, 1191, 1193, 1195, 1201, 1211, 1219, 1221, 1225, 1227, 1229, 1231, 1233, 1235, 1237, 1245, 1247, 1249, 1259, 1261, 1263, 1273, 1275, 0xFFFF, +4, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 69, 70, 71, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 180, 0xFFFF, +3, 0xFFFF, +21, 23, 0xFFFF, +1, 7, 52, 66, 68, 69, 70, 73, 74, 77, 80, 81, 83, 84, 85, 86, 0xFFFF, +3, 54, 70, 72, 80, 81, 82, 85, 87, 0xFFFF, +3, 38, 40, 42, 50, 53, 54, 57, 0xFFFF, +17, 19, 20, 26, 27, 28, 0xFFFF, +3, 5, 16, 29, 34, 488, 489, 491, 492, 496, 498, 500, 501, 505, 506, 507, 509, 512, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 547, 548, 549, 550, 551, 0xFFFF, +3, 37, 40, 48, 68, 72, 75, 76, 79, 81, 82, 83, 85, 86, 87, 91, 0xFFFF, +3, 10, 36, 39, 40, 41, 43, 44, 50, 53, 54, 55, 57, 0xFFFF, +3, 43, 68, 72, 76, 78, 79, 80, 81, 82, 85, 86, 87, 88, 89, 92, 166, 242, 0xFFFF, +3, 11, 12, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 54, 68, 72, 81, 82, 86, 177, 0xFFFF, +3, 4, 17, 22, 34, 38, 44, 45, 48, 51, 54, 55, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 93, 0xFFFF, +3, 10, 11, 12, 16, 17, 19, 20, 23, 24, 25, 26, 27, 28, 29, 36, 37, 38, 40, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 60, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 93, 138, 314, 0xFFFF, +3, 40, 59, 68, 69, 70, 71, 72, 78, 79, 81, 82, 83, 85, 86, 87, 89, 91, 92, 0xFFFF, +1, 13, 56, 66, 69, 70, 73, 79, 80, 83, 84, 85, 0xFFFF, +1, 14, 23, 25, 27, 32, 36, 37, 38, 45, 47, 49, 51, 52, 53, 56, 57, 66, 67, 68, 69, 70, 71, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 90, 91, 0xFFFF, +3, 48, 72, 82, 85, 170, 0xFFFF, +1, 8, 13, 27, 34, 38, 39, 41, 42, 45, 47, 48, 49, 52, 53, 56, 57, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 90, 0xFFFF, +3, 4, 5, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 100, 109, 111, 112, 116, 121, 123, 171, 177, 179, 180, 182, 225, 229, 252, 268, 286, 0xFFFF, +3, 15, 16, 17, 19, 20, 21, 22, 23, 27, 28, 29, 36, 37, 40, 44, 46, 47, 48, 49, 54, 56, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 111, 213, 0xFFFF, +3, 15, 20, 21, 39, 41, 55, 68, 70, 71, 72, 76, 85, 86, 87, 90, 92, 0xFFFF, +3, 16, 28, 37, 38, 42, 46, 51, 53, 54, 55, 57, 59, 68, 70, 71, 72, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 105, 106, 107, 109, 116, 117, 121, 122, 123, 208, 234, 255, 259, 1133, 1189, 1190, 1191, 1193, 1201, 1211, 1219, 1221, 1223, 1233, 1235, 1237, 1241, 1245, 1247, 1249, 1261, 1269, 1273, 0xFFFF, +3, 20, 29, 39, 41, 42, 50, 55, 68, 72, 73, 74, 75, 76, 78, 79, 80, 81, 85, 86, 87, 1193, 0xFFFF, +1, 42, 52, 66, 67, 68, 69, 70, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 87, 90, 0xFFFF, +3, 4, 11, 12, 14, 15, 16, 17, 19, 20, 23, 26, 28, 37, 38, 39, 40, 48, 49, 54, 56, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 85, 86, 87, 88, 89, 90, 92, 135, 0xFFFF, +1, 8, 27, 34, 38, 52, 53, 66, 67, 68, 69, 70, 72, 73, 74, 75, 78, 79, 80, 83, 84, 85, 86, 87, 88, 90, 0xFFFF, +3, 40, 55, 68, 71, 72, 75, 76, 79, 80, 85, 86, 87, 0xFFFF, +7, 15, 17, 19, 20, 21, 22, 23, 24, 28, 0xFFFF, +3, 10, 19, 25, 38, 41, 54, 68, 70, 71, 72, 76, 81, 82, 85, 86, 87, 131, 0xFFFF, +3, 55, 60, 69, 71, 72, 81, 82, 85, 86, 88, 0xFFFF, +19, 20, 21, 22, 25, 26, 27, 0xFFFF, +3, 36, 39, 40, 41, 42, 44, 47, 48, 49, 50, 53, 54, 55, 56, 57, 58, 0xFFFF, +3, 9, 10, 11, 12, 16, 17, 18, 20, 21, 23, 26, 29, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 91, 92, 93, 0xFFFF, +3, 170, 0xFFFF, +3, 14, 24, 36, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 0xFFFF, +3, 47, 51, 73, 76, 78, 80, 81, 82, 86, 87, 112, 0xFFFF, +1, 7, 12, 17, 18, 19, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 49, 51, 52, 53, 54, 55, 56, 58, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 90, 0xFFFF, +3, 16, 20, 24, 27, 28, 34, 35, 0xFFFF, +3, 17, 34, 37, 41, 53, 58, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 92, 0xFFFF, +3, 42, 44, 50, 68, 70, 71, 72, 74, 75, 76, 80, 81, 82, 83, 85, 86, 87, 88, 92, 179, 180, 182, 0xFFFF, +3, 40, 43, 55, 0xFFFF, +4, 30, 41, 52, 56, 69, 71, 72, 73, 74, 75, 76, 80, 82, 83, 84, 86, 88, 92, 0xFFFF, +1, 2, 8, 13, 14, 17, 18, 19, 20, 27, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 58, 59, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 0xFFFF, +1, 14, 18, 25, 37, 53, 66, 69, 70, 72, 73, 74, 77, 78, 79, 80, 83, 84, 85, 86, 88, 0xFFFF, +3, 17, 29, 37, 42, 47, 48, 50, 51, 54, 57, 58, 68, 70, 71, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 92, 112, 0xFFFF, +3, 39, 44, 47, 51, 54, 70, 72, 76, 79, 87, 0xFFFF, +1, 2, 8, 9, 10, 13, 14, 15, 17, 18, 19, 20, 25, 26, 27, 34, 37, 38, 42, 45, 46, 48, 49, 51, 52, 53, 55, 56, 57, 66, 67, 68, 69, 70, 71, 72, 73, 74, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 0xFFFF, +3, 41, 44, 48, 50, 51, 53, 54, 55, 56, 0xFFFF, +3, 5, 15, 17, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 0xFFFF, +3, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 36, 38, 39, 40, 44, 47, 49, 50, 53, 54, 55, 58, 60, 0xFFFF, +3, 41, 54, 68, 79, 81, 82, 90, 0xFFFF, +3, 38, 48, 50, 68, 72, 73, 75, 76, 80, 81, 82, 83, 85, 86, 87, 88, 92, 0xFFFF, +3, 5, 17, 36, 37, 38, 39, 40, 41, 42, 43, 44, 47, 49, 50, 51, 53, 54, 55, 56, 58, 60, 0xFFFF, +1, 2, 8, 13, 14, 15, 17, 18, 19, 23, 25, 26, 27, 34, 36, 37, 38, 39, 40, 41, 42, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 58, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 90, 0xFFFF, +3, 48, 50, 51, 54, 68, 69, 70, 72, 75, 76, 79, 81, 82, 83, 85, 86, 87, 88, 93, 0xFFFF, +3, 37, 40, 42, 43, 44, 49, 50, 53, 54, 55, 57, 60, 0xFFFF, +3, 10, 15, 16, 17, 19, 20, 34, 36, 37, 38, 39, 41, 42, 48, 49, 51, 53, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 182, 0xFFFF, +3, 15, 16, 17, 40, 41, 44, 47, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 0xFFFF, +3, 51, 65, 70, 72, 76, 78, 80, 81, 82, 83, 86, 112, 0xFFFF, +3, 38, 40, 44, 48, 49, 50, 53, 54, 55, 57, 58, 0xFFFF, +3, 17, 38, 39, 40, 41, 48, 49, 53, 55, 57, 68, 71, 72, 76, 79, 81, 82, 85, 86, 88, 89, 90, 0xFFFF, +54, 76, 78, 79, 82, 86, 88, 0xFFFF, +3, 95, 0xFFFF, +3, 4, 5, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 97, 98, 111, 139, 171, 173, 177, 178, 179, 180, 182, 0xFFFF, +3, 16, 41, 55, 59, 72, 75, 76, 79, 86, 0xFFFF, +3, 4, 16, 19, 20, 21, 29, 498, 517, 520, 521, 522, 524, 525, 530, 533, 534, 535, 536, 537, 538, 539, 542, 0xFFFF, +3, 15, 19, 20, 21, 23, 24, 25, 26, 28, 29, 602, 607, 608, 611, 616, 617, 618, 620, 622, 0xFFFF, +3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 133, 138, 139, 140, 170, 177, 178, 179, 180, 182, 188, 314, 378, 581, 585, 602, 605, 610, 612, 613, 615, 616, 618, 619, 630, 0xFFFF, +3, 14, 15, 17, 19, 20, 21, 24, 40, 41, 42, 44, 47, 48, 51, 55, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 81, 82, 85, 86, 87, 90, 0xFFFF, +3, 26, 36, 41, 42, 44, 47, 49, 50, 51, 54, 55, 56, 58, 68, 69, 71, 72, 73, 76, 78, 79, 81, 82, 83, 85, 86, 87, 88, 93, 0xFFFF, +3, 0xFFFF, +44, 69, 71, 72, 81, 91, 0xFFFF, +135, 0xFFFF, +46, 51, 72, 76, 81, 83, 86, 87, 88, 0xFFFF, +3, 49, 58, 68, 72, 75, 86, 87, 90, 178, 182, 0xFFFF, +3, 7, 10, 15, 16, 17, 19, 20, 21, 22, 25, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 170, 178, 0xFFFF, +3, 36, 38, 55, 68, 70, 72, 75, 78, 79, 81, 85, 87, 88, 89, 0xFFFF, +3, 170, 0xFFFF, +3, 10, 11, 12, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 114, 194, 196, 0xFFFF, +3, 7, 19, 20, 22, 23, 24, 28, 29, 47, 49, 54, 55, 68, 70, 71, 72, 74, 76, 79, 80, 81, 82, 83, 85, 86, 87, 90, 0xFFFF, +3, 15, 16, 36, 37, 38, 39, 41, 42, 43, 44, 48, 51, 53, 54, 55, 56, 58, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 93, 0xFFFF, +17, 48, 49, 74, 76, 81, 82, 86, 0xFFFF, +3, 16, 38, 41, 59, 68, 70, 72, 74, 76, 79, 81, 82, 83, 85, 86, 87, 90, 92, 0xFFFF, +3, 10, 15, 16, 17, 34, 36, 37, 38, 39, 40, 42, 44, 48, 49, 50, 51, 52, 53, 54, 55, 57, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93, 170, 171, 172, 176, 189, 202, 0xFFFF, +3, 4, 11, 12, 15, 16, 17, 18, 19, 24, 29, 34, 37, 38, 39, 40, 41, 44, 47, 48, 49, 50, 51, 53, 54, 56, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93, 109, 125, 130, 137, 162, 169, 170, 171, 172, 182, 187, 200, 202, 0xFFFF, +3, 4, 15, 16, 17, 36, 40, 47, 57, 58, 68, 69, 70, 71, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 91, 93, 162, 171, 172, 202, 0xFFFF, +3, 4, 16, 34, 37, 38, 39, 43, 44, 48, 54, 58, 68, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 92, 0xFFFF, +3, 41, 42, 44, 46, 47, 49, 50, 53, 0xFFFF, +37, 68, 72, 85, 86, 0xFFFF, +49, 51, 0xFFFF, +20, 36, 41, 0xFFFF, +3, 11, 12, 36, 37, 38, 40, 41, 44, 48, 50, 51, 52, 53, 55, 56, 59, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 85, 86, 87, 88, 91, 93, 0xFFFF, +3, 16, 29, 37, 41, 44, 55, 58, 59, 68, 72, 75, 76, 79, 81, 82, 86, 87, 89, 0xFFFF, +1, 34, 35, 37, 38, 39, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 143, 0xFFFF, +51, 56, 68, 70, 74, 76, 79, 80, 81, 82, 83, 85, 88, 0xFFFF, +36, 40, 41, 44, 50, 53, 54, 55, 57, 0xFFFF, +3, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 27, 28, 35, 36, 38, 42, 48, 51, 52, 54, 68, 69, 70, 72, 73, 76, 79, 80, 81, 82, 84, 85, 87, 88, 170, 171, 0xFFFF, +2797, 0xFFFF, +3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 27, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 179, 180, 182, 213, 247, 0xFFFF, +3, 4, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 131, 170, 171, 178, 182, 0xFFFF, +3, 38, 49, 60, 72, 76, 78, 82, 85, 87, 90, 92, 0xFFFF, +3, 15, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 39, 41, 48, 54, 55, 58, 68, 69, 70, 71, 72, 75, 76, 80, 81, 82, 85, 86, 87, 88, 92, 0xFFFF, +3, 17, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 53, 55, 56, 57, 58, 59, 61, 0xFFFF, +3, 17, 55, 68, 69, 70, 71, 72, 75, 76, 79, 81, 82, 85, 86, 87, 88, 89, 92, 0xFFFF, +17, 35, 70, 73, 76, 79, 80, 81, 82, 88, 0xFFFF, +3, 17, 28, 42, 46, 50, 52, 53, 54, 55, 56, 59, 62, 66, 74, 0xFFFF, +3, 16, 17, 20, 24, 27, 28, 31, 33, 34, 35, 37, 38, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 74, 75, 76, 82, 89, 113, 0xFFFF, +1, 14, 0xFFFF, +3, 53, 68, 72, 74, 75, 76, 83, 86, 87, 0xFFFF, +40, 44, 47, 57, 0xFFFF, +3, 6, 9, 10, 11, 13, 28, 31, 76, 0xFFFF, +3, 36, 37, 38, 40, 43, 44, 47, 53, 54, 56, 58, 0xFFFF, +3, 15, 16, 17, 37, 47, 48, 51, 53, 60, 68, 71, 72, 74, 76, 78, 81, 82, 85, 86, 88, 89, 92, 489, 490, 491, 495, 496, 498, 500, 501, 502, 503, 504, 505, 508, 517, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 541, 542, 543, 544, 545, 547, 548, 551, 0xFFFF, +3, 10, 11, 12, 17, 34, 40, 43, 45, 48, 49, 50, 51, 54, 56, 58, 65, 68, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 91, 112, 651, 0xFFFF, +226, 232, 246, 250, 251, 255, 259, 260, 262, 274, 275, 277, 281, 282, 295, 874, 913, 1107, 1144, 1167, 1177, 1362, 1419, 1619, 1879, 2003, 2059, 2103, 2175, 2264, 2312, 2387, 2390, 2518, 2610, 2617, 2641, 2642, 2735, 2738, 2863, 2993, 3039, 3088, 3174, 3178, 3241, 3347, 3348, 3354, 3373, 3461, 3492, 3503, 3565, 3618, 3733, 3941, 4226, 4374, 4770, 5034, 5048, 5363, 6629, 12428, 12429, 12432, 12435, 12449, 12450, 12461, 12462, 17497, 0xFFFF, +3, 17, 29, 36, 37, 38, 41, 45, 47, 49, 51, 54, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 0xFFFF, +3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 226, 227, 229, 231, 232, 233, 234, 235, 236, 238, 241, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 262, 264, 265, 266, 267, 268, 270, 271, 273, 274, 275, 277, 278, 279, 280, 281, 282, 286, 287, 288, 289, 290, 293, 294, 295, 299, 383, 384, 386, 387, 531, 588, 650, 658, 917, 923, 927, 929, 939, 952, 954, 955, 967, 969, 1011, 1022, 1046, 1060, 1065, 1094, 1101, 1102, 1105, 1107, 1109, 1125, 1137, 1138, 1144, 1147, 1150, 1154, 1167, 1172, 1203, 1233, 1264, 1271, 1294, 1317, 1344, 1350, 1376, 1406, 1408, 1476, 1484, 1509, 1524, 1568, 1579, 1615, 1619, 1652, 1715, 1724, 1734, 1750, 1758, 1763, 1790, 1803, 1806, 1858, 1880, 1885, 1897, 1905, 1932, 1956, 1959, 1963, 1969, 1972, 1981, 1983, 1999, 2003, 2007, 2010, 2025, 2035, 2040, 2046, 2069, 2078, 2081, 2090, 2101, 2103, 2104, 2105, 2121, 2125, 2127, 2151, 2182, 2201, 2230, 2235, 2264, 2270, 2312, 2331, 2334, 2339, 2357, 2378, 2387, 2397, 2398, 2407, 2410, 2413, 2446, 2483, 2493, 2497, 2551, 2579, 2584, 2602, 2617, 2641, 2642, 2643, 2645, 2668, 2702, 2711, 2712, 2735, 2779, 2781, 2797, 2833, 2836, 2842, 2850, 2863, 2876, 2885, 2890, 2903, 2905, 2910, 2915, 2927, 2929, 2943, 2946, 2963, 2974, 2982, 2994, 3007, 3025, 3030, 3031, 3039, 3045, 3056, 3057, 3076, 3078, 3081, 3097, 3171, 3174, 3178, 3216, 3218, 3229, 3248, 3249, 3277, 3281, 3289, 3313, 3321, 3325, 3335, 3347, 3348, 3350, 3362, 3381, 3384, 3400, 3406, 3416, 3418, 3461, 3477, 3478, 3528, 3541, 3565, 3594, 3612, 3628, 3630, 3654, 3677, 3681, 3682, 3683, 3691, 3696, 3698, 3705, 3706, 3713, 3724, 3726, 3746, 3748, 3763, 3793, 3802, 3806, 3825, 3828, 3848, 3861, 3863, 3883, 3922, 3926, 3999, 4002, 4063, 4126, 4133, 4163, 4222, 4226, 4269, 4362, 4387, 4569, 4698, 4729, 4741, 5034, 5136, 5277, 5306, 5475, 5687, 5838, 5851, 5918, 6054, 6055, 6211, 6220, 6221, 6355, 6513, 6634, 6651, 6712, 6838, 6864, 7029, 7180, 8047, 8048, 8101, 8152, 8596, 8630, 8850, 9744, 10275, 10908, 12427, 12428, 12429, 12432, 12434, 12449, 12450, 13453, 13615, 14446, 14478, 14507, 14843, 17761, 17779, 17792, 17804, 17809, 17812, 17820, 17827, 18124, 18186, 18829, 18872, 20270, 20381, 20387, 21063, 21531, 23123, 24663, 28777, 29479, 29739, 0xFFFF, +0, 226, 227, 229, 232, 233, 244, 245, 246, 247, 248, 250, 251, 253, 254, 258, 259, 260, 262, 264, 267, 268, 270, 273, 274, 275, 277, 278, 279, 280, 281, 282, 286, 287, 289, 290, 292, 293, 294, 299, 383, 384, 387, 939, 952, 955, 1011, 1046, 1094, 1095, 1107, 1125, 1143, 1167, 1210, 1294, 1363, 1364, 1411, 1462, 1476, 1508, 1604, 1663, 1665, 1677, 1724, 1750, 1781, 1803, 1805, 1906, 1932, 1965, 1999, 2008, 2010, 2047, 2081, 2089, 2174, 2182, 2188, 2270, 2298, 2312, 2317, 2334, 2357, 2387, 2390, 2397, 2398, 2407, 2413, 2431, 2433, 2445, 2448, 2450, 2493, 2551, 2583, 2602, 2637, 2641, 2642, 2645, 2686, 2692, 2711, 2712, 2735, 2784, 2795, 2796, 2797, 2826, 2828, 2863, 2890, 2910, 2959, 2974, 3041, 3055, 3056, 3073, 3082, 3110, 3117, 3120, 3133, 3229, 3249, 3271, 3313, 3316, 3333, 3347, 3354, 3373, 3406, 3464, 3528, 3538, 3565, 3582, 3610, 3612, 3628, 3649, 3674, 3698, 3705, 3706, 3707, 3736, 3798, 3803, 3828, 3856, 4040, 4071, 4204, 4222, 4269, 4374, 4397, 4606, 4666, 4695, 4741, 4830, 5306, 5912, 5918, 5977, 6037, 6163, 6210, 6355, 6482, 6712, 6901, 7588, 8226, 9095, 9118, 9129, 10275, 12427, 12429, 12432, 12461, 12462, 17269, 17497, 17761, 17840, 18147, 20394, 21028, 21056, 0xFFFF, +3, 9, 11, 12, 15, 16, 17, 22, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 122, 195, 196, 0xFFFF, +190, 0xFFFF, +3, 37, 38, 40, 49, 51, 55, 68, 71, 72, 76, 80, 81, 82, 85, 86, 0xFFFF, +4, 18, 37, 41, 44, 51, 54, 57, 58, 59, 61, 0xFFFF, +3, 10, 11, 12, 15, 16, 17, 19, 20, 21, 22, 23, 25, 27, 29, 36, 37, 38, 39, 40, 41, 42, 44, 45, 47, 48, 49, 51, 53, 54, 55, 56, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 120, 139, 0xFFFF, +3, 17, 36, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 0xFFFF, +3, 0xFFFF, +3, 16, 19, 20, 22, 25, 26, 29, 36, 37, 39, 43, 45, 48, 49, 50, 51, 53, 54, 55, 57, 68, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 166, 184, 214, 0xFFFF, +3, 36, 37, 38, 42, 43, 47, 48, 50, 55, 58, 72, 82, 85, 170, 0xFFFF, +3, 41, 47, 68, 71, 72, 76, 79, 81, 82, 87, 88, 90, 91, 0xFFFF, +3, 7, 19, 20, 21, 23, 26, 28, 40, 42, 54, 56, 68, 70, 71, 72, 74, 75, 76, 81, 82, 83, 85, 86, 87, 88, 0xFFFF, +42, 68, 76, 79, 80, 0xFFFF, +3, 7, 9, 15, 16, 17, 19, 20, 21, 23, 24, 25, 26, 27, 28, 36, 37, 38, 39, 40, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 0xFFFF, +3, 4, 5, 10, 11, 12, 15, 17, 19, 20, 21, 23, 24, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 182, 190, 0xFFFF, +3, 4, 5, 6, 7, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 62, 64, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 171, 177, 178, 179, 180, 182, 0xFFFF, +3, 4, 36, 38, 40, 43, 44, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 60, 68, 70, 72, 75, 76, 81, 82, 85, 86, 87, 88, 89, 92, 0xFFFF, +3, 10, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 170, 0xFFFF, +3, 16, 36, 40, 41, 46, 71, 76, 79, 80, 82, 85, 86, 87, 88, 92, 0xFFFF, +3, 7, 10, 17, 21, 23, 24, 26, 28, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 53, 54, 55, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 131, 238, 0xFFFF, +3, 36, 46, 47, 48, 51, 57, 68, 72, 75, 76, 77, 78, 79, 80, 81, 82, 85, 86, 87, 88, 89, 92, 166, 184, 242, 0xFFFF, +3, 16, 36, 46, 48, 55, 57, 60, 68, 71, 72, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 166, 184, 214, 0xFFFF, +3, 36, 44, 46, 48, 50, 51, 54, 55, 56, 60, 103, 0xFFFF, +3, 5, 29, 36, 43, 68, 72, 75, 76, 78, 79, 81, 82, 83, 85, 86, 87, 88, 89, 108, 0xFFFF, +3, 19, 20, 22, 26, 27, 28, 46, 51, 54, 68, 69, 70, 72, 75, 76, 79, 82, 85, 86, 87, 88, 92, 0xFFFF, +3, 10, 14, 15, 17, 19, 20, 21, 22, 24, 26, 29, 32, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 50, 51, 54, 55, 56, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 179, 180, 182, 0xFFFF, +34, 0xFFFF, +20, 23, 131, 0xFFFF, +8, 19, 20, 0xFFFF, +37, 71, 72, 76, 81, 85, 86, 88, 0xFFFF, +3, 10, 29, 36, 48, 50, 54, 58, 68, 69, 70, 71, 72, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 0xFFFF, +38, 39, 40, 42, 44, 49, 50, 53, 54, 55, 0xFFFF, +3, 17, 36, 54, 68, 72, 75, 76, 78, 81, 82, 83, 84, 85, 86, 87, 88, 90, 92, 0xFFFF, +3, 4, 15, 29, 34, 36, 40, 43, 45, 46, 47, 51, 54, 55, 61, 68, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 166, 184, 190, 214, 0xFFFF, +3, 15, 18, 19, 20, 21, 22, 23, 24, 26, 29, 57, 69, 72, 74, 75, 76, 79, 81, 82, 86, 87, 90, 0xFFFF, +46, 68, 69, 72, 81, 86, 87, 88, 0xFFFF, +3, 54, 72, 76, 87, 0xFFFF, +3, 37, 41, 42, 44, 50, 51, 54, 56, 68, 69, 72, 76, 79, 80, 81, 82, 83, 85, 87, 88, 0xFFFF, +17, 68, 70, 72, 76, 85, 87, 89, 0xFFFF, +3, 4, 9, 10, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 120, 139, 0xFFFF, +3, 38, 68, 69, 72, 76, 81, 82, 85, 86, 87, 88, 90, 92, 0xFFFF, +3, 15, 16, 17, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 36, 37, 38, 40, 41, 42, 44, 46, 47, 48, 49, 50, 51, 54, 55, 56, 58, 62, 64, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 81, 82, 83, 85, 86, 87, 88, 90, 0xFFFF, +3, 15, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 37, 39, 42, 43, 45, 46, 47, 48, 50, 51, 54, 56, 66, 68, 72, 76, 81, 82, 83, 86, 88, 105, 1189, 0xFFFF, +3, 17, 21, 29, 36, 37, 38, 39, 42, 43, 47, 49, 51, 53, 54, 55, 68, 69, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 85, 86, 87, 88, 89, 92, 93, 95, 106, 111, 124, 213, 248, 250, 1245, 0xFFFF, +20, 21, 26, 0xFFFF, +1, 34, 35, 36, 37, 38, 39, 42, 44, 48, 49, 51, 52, 53, 56, 143, 0xFFFF, +4, 11, 12, 13, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 0xFFFF, +3, 42, 44, 45, 47, 49, 50, 0xFFFF, +3, 11, 12, 29, 49, 69, 74, 81, 88, 92, 875, 0xFFFF, +3, 68, 70, 71, 72, 76, 79, 80, 81, 82, 83, 87, 92, 0xFFFF, +3, 11, 12, 15, 38, 39, 51, 54, 58, 61, 68, 70, 71, 72, 75, 76, 79, 81, 82, 83, 85, 86, 87, 92, 0xFFFF, +3, 4, 5, 8, 10, 11, 12, 15, 16, 17, 19, 20, 21, 22, 24, 27, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 312, 0xFFFF, +3, 10, 11, 12, 15, 16, 17, 19, 20, 21, 23, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 53, 54, 55, 57, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 116, 178, 179, 180, 182, 0xFFFF, +3, 15, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 36, 39, 48, 49, 50, 51, 55, 58, 68, 69, 70, 71, 72, 80, 81, 82, 85, 86, 87, 88, 89, 92, 0xFFFF, +3, 17, 47, 50, 54, 68, 72, 74, 75, 76, 79, 81, 82, 85, 87, 90, 92, 171, 0xFFFF, +3, 16, 18, 20, 21, 22, 23, 26, 27, 37, 39, 43, 49, 57, 68, 71, 72, 74, 75, 76, 79, 80, 81, 82, 85, 86, 87, 88, 90, 92, 0xFFFF, +3, 36, 38, 41, 51, 68, 70, 71, 72, 76, 79, 80, 81, 82, 85, 86, 87, 88, 0xFFFF, +3, 53, 68, 71, 72, 80, 82, 85, 0xFFFF, +4, 5, 11, 16, 18, 35, 37, 45, 49, 55, 56, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 93, 0xFFFF, +3, 20, 26, 39, 41, 44, 51, 72, 76, 82, 85, 86, 87, 88, 0xFFFF, +51, 56, 68, 70, 72, 76, 78, 79, 80, 81, 82, 86, 87, 88, 0xFFFF, +4, 16, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 37, 38, 40, 46, 48, 49, 54, 55, 56, 59, 69, 70, 71, 72, 73, 75, 76, 77, 80, 81, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 0xFFFF, +3, 9, 17, 22, 36, 38, 39, 43, 45, 46, 47, 48, 51, 53, 54, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 0xFFFF, +3, 15, 17, 70, 71, 72, 73, 74, 75, 76, 79, 81, 82, 83, 85, 86, 87, 92, 0xFFFF, +3, 40, 48, 49, 53, 68, 70, 72, 73, 74, 76, 78, 79, 81, 82, 85, 86, 87, 91, 0xFFFF, +4, 36, 39, 40, 41, 45, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 69, 70, 71, 72, 73, 74, 75, 77, 79, 80, 82, 83, 86, 87, 88, 89, 90, 91, 0xFFFF, +4, 17, 37, 39, 41, 43, 48, 52, 54, 55, 56, 57, 69, 70, 71, 72, 73, 75, 76, 77, 80, 81, 82, 83, 84, 86, 87, 88, 89, 0xFFFF, +4, 8, 12, 13, 15, 16, 20, 21, 22, 23, 24, 27, 28, 29, 37, 38, 39, 40, 41, 42, 44, 45, 48, 49, 51, 52, 54, 55, 56, 58, 59, 69, 71, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 102, 0xFFFF, +4, 10, 18, 21, 27, 37, 38, 39, 40, 41, 43, 44, 45, 47, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59, 61, 0xFFFF, +226, 227, 229, 231, 232, 233, 235, 236, 238, 241, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 262, 264, 265, 266, 267, 268, 269, 270, 271, 273, 274, 275, 277, 278, 279, 280, 281, 282, 286, 287, 288, 289, 290, 292, 293, 294, 295, 299, 383, 384, 385, 386, 387, 388, 910, 913, 925, 932, 955, 1046, 1091, 1095, 1107, 1111, 1132, 1172, 1344, 1399, 1453, 1465, 1487, 1496, 1533, 1584, 1601, 1660, 1750, 1791, 1820, 1831, 1906, 1912, 1948, 1963, 1969, 2018, 2025, 2029, 2081, 2090, 2186, 2210, 2264, 2265, 2329, 2357, 2368, 2377, 2397, 2536, 2551, 2602, 2610, 2640, 2641, 2681, 2712, 2719, 2735, 2742, 2745, 2797, 2827, 2863, 2901, 2910, 2947, 2966, 3013, 3041, 3078, 3159, 3166, 3214, 3249, 3258, 3281, 3284, 3310, 3314, 3354, 3362, 3406, 3415, 3631, 3643, 3654, 3658, 3708, 3731, 3750, 3764, 3848, 3976, 4329, 4503, 4708, 4741, 5149, 5453, 5705, 5918, 5977, 6108, 6404, 7252, 8101, 8329, 8344, 10275, 10606, 12429, 12432, 12460, 12461, 12462, 13924, 14421, 14422, 14466, 17264, 17773, 18189, 21028, 21303, 23264, 29479, 33487, 0xFFFF, +3, 18, 41, 48, 54, 58, 68, 69, 70, 71, 72, 73, 76, 78, 81, 82, 83, 85, 86, 171, 0xFFFF, +3, 4, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 98, 108, 0xFFFF, +3, 15, 16, 20, 21, 22, 27, 29, 36, 39, 41, 42, 43, 45, 46, 48, 49, 51, 53, 54, 55, 57, 59, 60, 68, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 166, 171, 184, 214, 0xFFFF, +3, 29, 37, 68, 72, 79, 85, 86, 87, 88, 0xFFFF, +55, 72, 75, 80, 86, 0xFFFF, +3, 10, 15, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 0xFFFF, +3, 36, 39, 41, 46, 47, 56, 68, 69, 70, 71, 72, 74, 75, 79, 80, 81, 82, 85, 86, 87, 88, 90, 92, 177, 0xFFFF, +3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 103, 108, 116, 120, 124, 138, 140, 158, 170, 171, 177, 178, 179, 180, 181, 182, 194, 383, 572, 577, 580, 582, 583, 584, 586, 590, 602, 603, 604, 605, 606, 607, 610, 612, 613, 614, 615, 616, 618, 619, 620, 621, 622, 624, 627, 629, 630, 633, 0xFFFF, +3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 98, 103, 108, 110, 112, 124, 129, 138, 139, 170, 171, 177, 178, 179, 180, 181, 182, 190, 194, 1317, 0xFFFF, +3, 4, 10, 15, 16, 17, 19, 20, 21, 22, 23, 24, 27, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 0xFFFF, +3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 98, 105, 106, 107, 108, 109, 111, 112, 114, 116, 117, 121, 122, 123, 127, 138, 139, 170, 177, 178, 182, 190, 194, 213, 234, 248, 250, 255, 259, 264, 303, 312, 314, 404, 550, 1131, 1133, 1189, 1190, 1191, 1193, 1195, 1196, 1197, 1201, 1203, 1211, 1213, 1215, 1217, 1219, 1221, 1223, 1227, 1231, 1233, 1235, 1237, 1239, 1241, 1245, 1247, 1249, 1251, 1255, 1257, 1259, 1263, 1265, 1267, 1269, 1273, 0xFFFF, +3, 5, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 102, 111, 114, 129, 135, 139, 170, 177, 602, 604, 606, 607, 609, 610, 613, 616, 618, 619, 620, 622, 623, 629, 909, 913, 916, 942, 972, 991, 1012, 0xFFFF, +3, 4, 6, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 60, 61, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 135, 194, 572, 583, 602, 606, 607, 608, 610, 611, 612, 613, 614, 615, 616, 617, 620, 621, 625, 626, 629, 0xFFFF, +40, 55, 57, 0xFFFF, +131, 0xFFFF, +3, 16, 20, 21, 23, 39, 68, 72, 76, 81, 82, 86, 87, 89, 0xFFFF, +3, 9, 10, 15, 16, 17, 19, 20, 21, 22, 23, 36, 38, 39, 41, 42, 44, 45, 47, 50, 54, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 0xFFFF, +8, 22, 23, 24, 28, 131, 0xFFFF, +3, 34, 43, 46, 47, 54, 55, 58, 68, 71, 72, 75, 76, 79, 81, 82, 83, 85, 86, 87, 88, 89, 90, 0xFFFF, +3, 15, 16, 29, 36, 38, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 92, 0xFFFF, +43, 71, 72, 76, 81, 0xFFFF, +3, 0xFFFF, +4, 16, 18, 20, 21, 22, 29, 38, 39, 40, 41, 49, 54, 61, 73, 77, 79, 80, 82, 83, 88, 89, 90, 91, 93, 0xFFFF, +3, 10, 29, 37, 38, 50, 51, 55, 68, 71, 72, 73, 74, 75, 76, 79, 81, 82, 83, 85, 86, 87, 88, 0xFFFF, +35, 68, 69, 70, 72, 74, 75, 77, 78, 79, 81, 85, 87, 0xFFFF, +3, 17, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 37, 47, 54, 55, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 0xFFFF, +3, 34, 36, 37, 46, 48, 68, 71, 72, 74, 76, 78, 79, 80, 81, 85, 86, 87, 88, 89, 92, 0xFFFF, +3, 4, 15, 16, 17, 29, 34, 36, 37, 38, 39, 41, 43, 44, 47, 48, 49, 51, 54, 55, 56, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 91, 92, 179, 180, 0xFFFF, +3, 15, 19, 20, 21, 24, 25, 26, 27, 37, 38, 39, 46, 48, 50, 53, 58, 68, 70, 71, 72, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 92, 0xFFFF, +3, 10, 54, 70, 71, 72, 76, 78, 82, 83, 85, 86, 87, 88, 0xFFFF, +21, 23, 24, 78, 0xFFFF, +22, 24, 0xFFFF, +3, 4, 7, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 27, 28, 36, 37, 38, 39, 42, 43, 44, 48, 51, 53, 54, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 91, 92, 0xFFFF, +3, 17, 38, 40, 49, 55, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 92, 0xFFFF, +3, 16, 29, 36, 39, 46, 47, 48, 50, 51, 53, 68, 69, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 166, 0xFFFF, +3, 4, 10, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 108, 121, 124, 177, 180, 0xFFFF, +3, 11, 12, 16, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 37, 41, 44, 48, 50, 54, 55, 58, 59, 68, 69, 70, 72, 73, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 92, 0xFFFF, +3, 4, 9, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 53, 54, 55, 56, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 112, 179, 180, 0xFFFF, +3, 4, 5, 16, 19, 21, 23, 29, 48, 49, 54, 56, 68, 70, 71, 72, 73, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 91, 93, 176, 197, 293, 0xFFFF, +3, 41, 54, 68, 72, 74, 76, 80, 85, 86, 87, 194, 0xFFFF, +11, 16, 0xFFFF, +3, 37, 49, 50, 54, 55, 58, 68, 69, 70, 71, 72, 76, 78, 79, 80, 81, 82, 85, 86, 87, 89, 90, 0xFFFF, +226, 229, 250, 258, 262, 267, 286, 383, 387, 1707, 2008, 3039, 3477, 23264, 29479, 33487, 0xFFFF, +3, 9, 36, 37, 38, 60, 71, 72, 74, 75, 76, 79, 81, 82, 85, 86, 87, 88, 0xFFFF, +3, 30, 41, 42, 43, 44, 45, 46, 47, 49, 57, 58, 59, 60, 61, 62, 65, 66, 70, 71, 72, 74, 75, 76, 77, 78, 0xFFFF, +3, 7, 9, 10, 15, 16, 17, 19, 20, 21, 22, 23, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 108, 178, 0xFFFF, +3, 15, 16, 17, 36, 38, 39, 40, 41, 43, 44, 45, 46, 51, 53, 54, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 0xFFFF, +3, 4, 34, 36, 37, 38, 39, 40, 41, 43, 44, 49, 50, 54, 58, 60, 68, 70, 71, 72, 75, 76, 79, 81, 82, 83, 85, 86, 87, 88, 90, 0xFFFF, +3, 11, 12, 15, 16, 17, 29, 30, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 0xFFFF, +4, 19, 0xFFFF, +3, 7, 10, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 125, 0xFFFF, +3, 17, 18, 36, 37, 38, 40, 41, 43, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 58, 0xFFFF, +3, 57, 58, 59, 61, 62, 63, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 79, 81, 82, 89, 91, 93, 97, 99, 102, 103, 106, 107, 108, 111, 113, 0xFFFF, +3, 5, 15, 16, 19, 20, 21, 29, 34, 178, 488, 489, 490, 491, 492, 493, 495, 496, 498, 499, 500, 501, 502, 504, 505, 506, 507, 508, 509, 511, 512, 517, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 547, 548, 550, 551, 0xFFFF, +3, 4, 5, 15, 16, 17, 20, 21, 22, 23, 28, 29, 36, 37, 38, 39, 40, 41, 42, 44, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 125, 164, 176, 197, 288, 289, 293, 0xFFFF, +3, 68, 70, 76, 78, 79, 81, 82, 85, 86, 87, 88, 0xFFFF, +3, 17, 0xFFFF, +2797, 0xFFFF, +3, 9, 16, 43, 51, 53, 60, 68, 70, 71, 72, 73, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 0xFFFF, +39, 57, 58, 61, 68, 72, 79, 86, 0xFFFF, +3, 57, 59, 60, 61, 63, 64, 65, 68, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 0xFFFF, +3, 9, 10, 15, 16, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 34, 35, 36, 37, 39, 41, 42, 44, 47, 48, 51, 54, 55, 56, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 139, 177, 0xFFFF, +3, 18, 37, 41, 47, 49, 50, 54, 55, 56, 68, 69, 70, 71, 72, 74, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 93, 112, 0xFFFF, +3, 0xFFFF, +1, 27, 38, 51, 53, 55, 66, 69, 70, 73, 79, 81, 83, 85, 86, 0xFFFF, +3, 36, 40, 42, 49, 51, 55, 59, 0xFFFF, +36, 39, 70, 72, 76, 78, 81, 82, 85, 86, 89, 90, 0xFFFF, +3, 4, 8, 10, 16, 17, 19, 20, 21, 25, 26, 29, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 182, 572, 610, 611, 616, 620, 0xFFFF, +3, 39, 40, 41, 42, 43, 44, 47, 57, 58, 59, 61, 64, 65, 66, 68, 70, 71, 74, 75, 76, 77, 78, 0xFFFF, +3, 39, 40, 41, 42, 44, 48, 51, 53, 54, 57, 68, 69, 70, 72, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 121, 0xFFFF, +3, 5, 7, 8, 10, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 49, 50, 51, 52, 53, 54, 55, 57, 58, 59, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 178, 179, 180, 182, 0xFFFF, +3, 4, 10, 11, 12, 15, 16, 17, 19, 21, 27, 29, 30, 31, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 53, 54, 55, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 182, 0xFFFF, +3, 4, 5, 7, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 65, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 97, 105, 108, 109, 111, 112, 114, 116, 120, 121, 124, 126, 129, 139, 170, 181, 182, 210, 257, 0xFFFF, +3, 4, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 95, 135, 139, 170, 178, 182, 0xFFFF, +3, 9, 10, 16, 17, 19, 20, 23, 28, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 170, 0xFFFF, +3, 7, 8, 10, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 27, 29, 32, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 101, 112, 170, 181, 182, 0xFFFF, +68, 69, 70, 72, 75, 78, 85, 86, 0xFFFF, +3, 17, 36, 37, 38, 39, 40, 42, 43, 44, 46, 47, 49, 50, 51, 53, 54, 55, 56, 58, 60, 0xFFFF, +29, 36, 51, 70, 71, 72, 76, 78, 80, 81, 82, 83, 86, 91, 112, 0xFFFF, +3, 38, 47, 57, 68, 70, 72, 74, 75, 76, 82, 86, 0xFFFF, +3, 4, 19, 20, 22, 26, 27, 29, 36, 41, 43, 48, 50, 51, 60, 76, 85, 0xFFFF, +3, 4, 9, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 29, 36, 37, 39, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 72, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 170, 0xFFFF, +3, 4, 6, 9, 10, 11, 12, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 63, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 105, 107, 109, 111, 112, 116, 125, 126, 139, 170, 200, 0xFFFF, +3, 4, 5, 15, 16, 19, 20, 21, 29, 36, 37, 38, 41, 42, 44, 45, 46, 47, 49, 53, 54, 55, 57, 58, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 108, 124, 0xFFFF, +3, 40, 41, 42, 43, 46, 57, 58, 59, 60, 61, 63, 64, 65, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 80, 81, 89, 91, 92, 93, 96, 97, 100, 102, 104, 106, 107, 108, 109, 111, 0xFFFF, +3, 36, 37, 38, 39, 44, 47, 51, 54, 58, 68, 70, 71, 72, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 93, 0xFFFF, +3, 4, 9, 10, 13, 15, 16, 17, 19, 20, 21, 25, 26, 27, 28, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 139, 0xFFFF, +3, 4, 29, 36, 38, 44, 47, 53, 54, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 89, 92, 0xFFFF, +3, 5, 7, 10, 15, 16, 17, 19, 20, 21, 23, 24, 25, 26, 27, 28, 30, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 197, 199, 200, 201, 0xFFFF, +3, 17, 29, 37, 48, 51, 54, 58, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 85, 86, 87, 90, 0xFFFF, +41, 66, 76, 78, 82, 87, 0xFFFF, +3, 29, 36, 42, 48, 54, 68, 70, 72, 76, 78, 82, 85, 86, 87, 0xFFFF, +3, 4, 5, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 57, 58, 60, 65, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 106, 110, 111, 112, 114, 120, 129, 178, 227, 253, 254, 586, 587, 602, 610, 611, 612, 613, 619, 620, 621, 623, 629, 1219, 1227, 0xFFFF, +3, 15, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 60, 68, 69, 70, 71, 72, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 90, 0xFFFF, +36, 39, 40, 44, 48, 49, 53, 54, 55, 57, 0xFFFF, +1, 0xFFFF, +3, 4, 5, 6, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 53, 54, 55, 58, 60, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 0xFFFF, +71, 75, 79, 82, 86, 88, 0xFFFF, +3, 37, 42, 51, 54, 68, 70, 71, 72, 74, 76, 81, 83, 85, 86, 87, 88, 0xFFFF, +1329, 2149, 2201, 2275, 2901, 3253, 3406, 3824, 9106, 9125, 9137, 9172, 12431, 0xFFFF, +3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 97, 98, 105, 106, 107, 108, 109, 112, 113, 114, 116, 117, 120, 121, 122, 123, 124, 125, 126, 127, 131, 138, 139, 140, 169, 170, 171, 177, 178, 179, 180, 182, 188, 194, 198, 200, 208, 234, 240, 255, 259, 264, 429, 458, 484, 570, 571, 572, 573, 574, 575, 576, 577, 578, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 593, 594, 595, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 629, 630, 631, 632, 633, 1131, 1133, 1189, 1190, 1191, 1192, 1193, 1195, 1197, 1199, 1201, 1203, 1209, 1211, 1213, 1215, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1231, 1233, 1235, 1237, 1239, 1241, 1243, 1245, 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1273, 1275, 0xFFFF, +0xFFFF }; diff --git a/chromium/third_party/skia/bench/gen_bench_expectations.py b/chromium/third_party/skia/bench/gen_bench_expectations.py new file mode 100644 index 00000000000..4edc38c09d2 --- /dev/null +++ b/chromium/third_party/skia/bench/gen_bench_expectations.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" Generate bench_expectations file from a given set of bench data files. """ + +import argparse +import bench_util +import json +import os +import re +import sys +import urllib2 + +# Parameters for calculating bench ranges. +RANGE_RATIO_UPPER = 1.5 # Ratio of range for upper bounds. +RANGE_RATIO_LOWER = 2.0 # Ratio of range for lower bounds. +ERR_RATIO = 0.08 # Further widens the range by the ratio of average value. +ERR_UB = 1.0 # Adds an absolute upper error to cope with small benches. +ERR_LB = 1.5 + +# List of bench configs to monitor. Ignore all other configs. +CONFIGS_TO_INCLUDE = ['simple_viewport_1000x1000', + 'simple_viewport_1000x1000_angle', + 'simple_viewport_1000x1000_gpu', + 'simple_viewport_1000x1000_scalar_1.100000', + 'simple_viewport_1000x1000_scalar_1.100000_gpu', + ] + +# List of flaky entries that should be excluded. Each entry is defined by a list +# of 3 strings, corresponding to the substrings of [bench, config, builder] to +# search for. A bench expectations line is excluded when each of the 3 strings +# in the list is a substring of the corresponding element of the given line. For +# instance, ['desk_yahooanswers', 'gpu', 'Ubuntu'] will skip expectation entries +# of SKP benchs whose name contains 'desk_yahooanswers' on all gpu-related +# configs of all Ubuntu builders. +ENTRIES_TO_EXCLUDE = [ + ] + +_GS_CLOUD_FORMAT = 'http://storage.googleapis.com/chromium-skia-gm/perfdata/%s/%s' + +def compute_ranges(benches, more_benches=None): + """Given a list of bench numbers, calculate the alert range. + + Args: + benches: a list of float bench values. + more_benches: a tuple of lists of additional bench values. + The first value of each tuple is the number of commits before the current + one that set of values is at, and the second value is a list of + bench results. + + Returns: + a list of float [lower_bound, upper_bound]. + """ + avg = sum(benches)/len(benches) + minimum = min(benches) + maximum = max(benches) + diff = maximum - minimum + + return [minimum - diff*RANGE_RATIO_LOWER - avg*ERR_RATIO - ERR_LB, + maximum + diff*RANGE_RATIO_UPPER + avg*ERR_RATIO + ERR_UB] + + +def create_expectations_dict(revision_data_points, builder, extra_data=None): + """Convert list of bench data points into a dictionary of expectations data. + + Args: + revision_data_points: a list of BenchDataPoint objects. + builder: string of the corresponding buildbot builder name. + + Returns: + a dictionary of this form: + keys = tuple of (config, bench) strings. + values = list of float [expected, lower_bound, upper_bound] for the key. + """ + bench_dict = {} + for point in revision_data_points: + if (point.time_type or # Not walltime which has time_type '' + not point.config in CONFIGS_TO_INCLUDE): + continue + to_skip = False + for bench_substr, config_substr, builder_substr in ENTRIES_TO_EXCLUDE: + if (bench_substr in point.bench and config_substr in point.config and + builder_substr in builder): + to_skip = True + break + if to_skip: + continue + key = (point.config, point.bench) + + extras = [] + for idx, dataset in extra_data: + for data in dataset: + if (data.bench == point.bench and data.config == point.config and + data.time_type == point.time_type and data.per_iter_time): + extras.append((idx, data.per_iter_time)) + + if key in bench_dict: + raise Exception('Duplicate bench entry: ' + str(key)) + bench_dict[key] = [point.time] + compute_ranges(point.per_iter_time, extras) + + return bench_dict + + +def get_parent_commits(start_hash, num_back): + """Returns a list of commits that are the parent of the commit passed in.""" + list_commits = urllib2.urlopen( + 'https://skia.googlesource.com/skia/+log/%s?format=json&n=%d' % + (start_hash, num_back)) + # NOTE: Very brittle. Removes the four extraneous characters + # so json can be read successfully + trunc_list = list_commits.read()[4:] + json_data = json.loads(trunc_list) + return [revision['commit'] for revision in json_data['log']] + + +def get_file_suffixes(commit_hash, directory): + """Gets all the suffixes available in the directory""" + possible_files = os.listdir(directory) + prefix = 'bench_' + commit_hash + '_data_' + return [name[len(prefix):] for name in possible_files + if name.startswith(prefix)] + + +def download_bench_data(builder, commit_hash, suffixes, directory): + """Downloads data, returns the number successfully downloaded""" + cur_files = os.listdir(directory) + count = 0 + for suffix in suffixes: + file_name = 'bench_'+commit_hash+'_data_'+suffix + if file_name in cur_files: + continue + try: + src = urllib2.urlopen(_GS_CLOUD_FORMAT % (builder, file_name)) + with open(os.path.join(directory, file_name), 'w') as dest: + dest.writelines(src) + count += 1 + except urllib2.HTTPError: + pass + return count + + +def main(): + """Reads bench data points, then calculate and export expectations. + """ + parser = argparse.ArgumentParser() + parser.add_argument( + '-a', '--representation_alg', default='25th', + help='bench representation algorithm to use, see bench_util.py.') + parser.add_argument( + '-b', '--builder', required=True, + help='name of the builder whose bench ranges we are computing.') + parser.add_argument( + '-d', '--input_dir', required=True, + help='a directory containing bench data files.') + parser.add_argument( + '-o', '--output_file', required=True, + help='file path and name for storing the output bench expectations.') + parser.add_argument( + '-r', '--git_revision', required=True, + help='the git hash to indicate the revision of input data to use.') + parser.add_argument( + '-t', '--back_track', required=False, default=10, + help='the number of commit hashes backwards to look to include' + + 'in the calculations.') + parser.add_argument( + '-m', '--max_commits', required=False, default=1, + help='the number of commit hashes to include in the calculations.') + args = parser.parse_args() + + builder = args.builder + + data_points = bench_util.parse_skp_bench_data( + args.input_dir, args.git_revision, args.representation_alg) + + parent_commits = get_parent_commits(args.git_revision, args.back_track) + print "Using commits: {}".format(parent_commits) + suffixes = get_file_suffixes(args.git_revision, args.input_dir) + print "Using suffixes: {}".format(suffixes) + + # TODO(kelvinly): Find a better approach to than directly copying from + # the GS server? + downloaded_commits = [] + for idx, commit in enumerate(parent_commits): + num_downloaded = download_bench_data( + builder, commit, suffixes, args.input_dir) + if num_downloaded > 0: + downloaded_commits.append((num_downloaded, idx, commit)) + + if len(downloaded_commits) < args.max_commits: + print ('Less than desired number of commits found. Please increase' + '--back_track in later runs') + trunc_commits = sorted(downloaded_commits, reverse=True)[:args.max_commits] + extra_data = [] + for _, idx, commit in trunc_commits: + extra_data.append((idx, bench_util.parse_skp_bench_data( + args.input_dir, commit, args.representation_alg))) + + expectations_dict = create_expectations_dict(data_points, builder, + extra_data) + + out_lines = [] + keys = expectations_dict.keys() + keys.sort() + for (config, bench) in keys: + (expected, lower_bound, upper_bound) = expectations_dict[(config, bench)] + out_lines.append('%(bench)s_%(config)s_,%(builder)s-%(representation)s,' + '%(expected)s,%(lower_bound)s,%(upper_bound)s' % { + 'bench': bench, + 'config': config, + 'builder': builder, + 'representation': args.representation_alg, + 'expected': expected, + 'lower_bound': lower_bound, + 'upper_bound': upper_bound}) + + with open(args.output_file, 'w') as file_handle: + file_handle.write('\n'.join(out_lines)) + + +if __name__ == "__main__": + main() diff --git a/chromium/third_party/skia/bench/tile_analyze.py b/chromium/third_party/skia/bench/tile_analyze.py new file mode 100755 index 00000000000..03fe08673dd --- /dev/null +++ b/chromium/third_party/skia/bench/tile_analyze.py @@ -0,0 +1,279 @@ +#!/usr/bin/env python +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be found +# in the LICENSE file. + +""" Analyze per-tile and viewport bench data, and output visualized results. +""" + +__author__ = 'bensong@google.com (Ben Chen)' + +import bench_util +import boto +import math +import optparse +import os +import re +import shutil + +from oauth2_plugin import oauth2_plugin + +# The default platform to analyze. Used when OPTION_PLATFORM flag is not set. +DEFAULT_PLATFORM = 'Nexus10_4-1_Float_Bench_32' + +# Template for gsutil uri. +GOOGLE_STORAGE_URI_SCHEME = 'gs' +URI_BUCKET = 'chromium-skia-gm' + +# Maximum number of rows of tiles to track for viewport covering. +MAX_TILE_ROWS = 8 + +# Constants for optparse. +USAGE_STRING = 'USAGE: %s [options]' +HOWTO_STRING = """ +Note: to read bench data stored in Google Storage, you will need to set up the +corresponding Python library. +See http://developers.google.com/storage/docs/gspythonlibrary for details. +""" +HELP_STRING = """ +For the given platform and revision number, find corresponding viewport and +tile benchmarks for each available picture bench, and output visualization and +analysis in HTML. By default it reads from Skia's Google Storage location where +bot data are stored, but if --dir is given, will read from local directory +instead. +""" + HOWTO_STRING + +OPTION_DIR = '--dir' +OPTION_DIR_SHORT = '-d' +OPTION_REVISION = '--rev' +OPTION_REVISION_SHORT = '-r' +OPTION_PLATFORM = '--platform' +OPTION_PLATFORM_SHORT = '-p' +# Bench representation algorithm flag. +OPTION_REPRESENTATION_ALG = '--algorithm' +OPTION_REPRESENTATION_ALG_SHORT = '-a' + +# Bench representation algorithm. See trunk/bench/bench_util.py. +REPRESENTATION_ALG = bench_util.ALGORITHM_25TH_PERCENTILE + +# Constants for bench file matching. +GOOGLE_STORAGE_OBJECT_NAME_PREFIX = 'perfdata/Skia_' +BENCH_FILE_PREFIX_TEMPLATE = 'bench_r%s_' +TILING_FILE_NAME_INDICATOR = '_tile_' +VIEWPORT_FILE_NAME_INDICATOR = '_viewport_' + +# Regular expression for matching format '<integer>x<integer>'. +DIMENSIONS_RE = '(\d+)x(\d+)' + +# HTML and JS output templates. +HTML_PREFIX = """ +<html><head><script type="text/javascript" src="https://www.google.com/jsapi"> +</script><script type="text/javascript">google.load("visualization", "1.1", +{packages:["table"]});google.load("prototype", "1.6");</script> +<script type="text/javascript" src="https://systemsbiology-visualizations.googlecode.com/svn/trunk/src/main/js/load.js"></script><script +type="text/javascript"> systemsbiology.load("visualization", "1.0", +{packages:["bioheatmap"]});</script><script type="text/javascript"> +google.setOnLoadCallback(drawVisualization); function drawVisualization() { +""" +HTML_SUFFIX = '</body></html>' +BAR_CHART_TEMPLATE = ('<img src="https://chart.googleapis.com/chart?chxr=0,0,' + '300&chxt=x&chbh=15,0&chs=600x150&cht=bhg&chco=80C65A,224499,FF0000,0A8C8A,' + 'EBB671,DE091A,000000,00ffff&chds=a&chdl=%s&chd=t:%s" /><br>\n') +DRAW_OPTIONS = ('{passThroughBlack:false,useRowLabels:false,cellWidth:30,' + 'cellHeight:30}') +TABLE_OPTIONS = '{showRowNumber:true,firstRowNumber:" ",sort:"disable"}' + +def GetFiles(rev, bench_dir, platform): + """Reads in bench files of interest into a dictionary. + + If bench_dir is not empty, tries to read in local bench files; otherwise check + Google Storage. Filters files by revision (rev) and platform, and ignores + non-tile, non-viewport bench files. + Outputs dictionary [filename] -> [file content]. + """ + file_dic = {} + if not bench_dir: + uri = boto.storage_uri(URI_BUCKET, GOOGLE_STORAGE_URI_SCHEME) + # The boto API does not allow prefix/wildcard matching of Google Storage + # objects. And Google Storage has a flat structure instead of being + # organized in directories. Therefore, we have to scan all objects in the + # Google Storage bucket to find the files we need, which is slow. + # The option of implementing prefix matching as in gsutil seems to be + # overkill, but gsutil does not provide an API ready for use. If speed is a + # big concern, we suggest copying bot bench data from Google Storage using + # gsutil and use --log_dir for fast local data reading. + for obj in uri.get_bucket(): + # Filters out files of no interest. + if (not obj.name.startswith(GOOGLE_STORAGE_OBJECT_NAME_PREFIX) or + (obj.name.find(TILING_FILE_NAME_INDICATOR) < 0 and + obj.name.find(VIEWPORT_FILE_NAME_INDICATOR) < 0) or + obj.name.find(platform) < 0 or + obj.name.find(BENCH_FILE_PREFIX_TEMPLATE % rev) < 0): + continue + file_dic[ + obj.name[obj.name.rfind('/') + 1 : ]] = obj.get_contents_as_string() + else: + for f in os.listdir(bench_dir): + if (not os.path.isfile(os.path.join(bench_dir, f)) or + (f.find(TILING_FILE_NAME_INDICATOR) < 0 and + f.find(VIEWPORT_FILE_NAME_INDICATOR) < 0) or + not f.startswith(BENCH_FILE_PREFIX_TEMPLATE % rev)): + continue + file_dic[f] = open(os.path.join(bench_dir, f)).read() + + if not file_dic: + raise Exception('No bench file found in "%s" or Google Storage.' % + bench_dir) + + return file_dic + +def GetTileMatrix(layout, tile_size, values, viewport): + """For the given tile layout and per-tile bench values, returns a matrix of + bench values with tiles outside the given viewport set to 0. + + layout, tile_size and viewport are given in string of format <w>x<h>, where + <w> is viewport width or number of tile columns, and <h> is viewport height or + number of tile rows. We truncate tile rows to MAX_TILE_ROWS to adjust for very + long skp's. + + values: per-tile benches ordered row-by-row, starting from the top-left tile. + + Returns [sum, matrix] where sum is the total bench tile time that covers the + viewport, and matrix is used for visualizing the tiles. + """ + [tile_cols, tile_rows] = [int(i) for i in layout.split('x')] + [tile_x, tile_y] = [int(i) for i in tile_size.split('x')] + [viewport_x, viewport_y] = [int(i) for i in viewport.split('x')] + viewport_cols = int(math.ceil(viewport_x * 1.0 / tile_x)) + viewport_rows = int(math.ceil(viewport_y * 1.0 / tile_y)) + truncated_tile_rows = min(tile_rows, MAX_TILE_ROWS) + + viewport_tile_sum = 0 + matrix = [[0 for y in range(tile_cols)] for x in range(truncated_tile_rows)] + for y in range(min(viewport_cols, tile_cols)): + for x in range(min(truncated_tile_rows, viewport_rows)): + matrix[x][y] = values[x * tile_cols + y] + viewport_tile_sum += values[x * tile_cols + y] + + return [viewport_tile_sum, matrix] + +def GetTileVisCodes(suffix, matrix): + """Generates and returns strings of [js_codes, row1, row2] which are codes for + visualizing the benches from the given tile config and matrix data. + row1 is used for the first row of heatmaps; row2 is for corresponding tables. + suffix is only used to avoid name conflicts in the whole html output. + """ + this_js = 'var data_%s=new google.visualization.DataTable();' % suffix + for i in range(len(matrix[0])): + this_js += 'data_%s.addColumn("number","%s");' % (suffix, i) + this_js += 'data_%s.addRows(%s);' % (suffix, str(matrix)) + # Adds heatmap chart. + this_js += ('var heat_%s=new org.systemsbiology.visualization' % suffix + + '.BioHeatMap(document.getElementById("%s"));' % suffix + + 'heat_%s.draw(data_%s,%s);' % (suffix, suffix, DRAW_OPTIONS)) + # Adds data table chart. + this_js += ('var table_%s=new google.visualization.Table(document.' % suffix + + 'getElementById("t%s"));table_%s.draw(data_%s,%s);\n' % ( + suffix, suffix, suffix, TABLE_OPTIONS)) + table_row1 = '<td>%s<div id="%s"></div></td>' % (suffix, suffix) + table_row2 = '<td><div id="t%s"></div></td>' % suffix + + return [this_js, table_row1, table_row2] + +def OutputTileAnalysis(rev, representation_alg, bench_dir, platform): + """Reads skp bench data and outputs tile vs. viewport analysis for the given + platform. + + Ignores data with revisions other than rev. If bench_dir is not empty, read + from the local directory instead of Google Storage. + Uses the provided representation_alg for calculating bench representations. + + Returns (js_codes, body_codes): strings of js/html codes for stats and + visualization. + """ + js_codes = '' + body_codes = ('}</script></head><body>' + '<h3>PLATFORM: %s REVISION: %s</h3><br>' % (platform, rev)) + bench_dic = {} # [bench][config] -> [layout, [values]] + file_dic = GetFiles(rev, bench_dir, platform) + for f in file_dic: + for point in bench_util.parse('', file_dic[f].split('\n'), + representation_alg): + if point.time_type: # Ignores non-walltime time_type. + continue + bench = point.bench.replace('.skp', '') + config = point.config.replace('simple_', '') + components = config.split('_') + if components[0] == 'viewport': + bench_dic.setdefault(bench, {})[config] = [components[1], [point.time]] + else: # Stores per-tile benches. + bench_dic.setdefault(bench, {})[config] = [ + point.tile_layout, point.per_tile_values] + benches = bench_dic.keys() + benches.sort() + for bench in benches: + body_codes += '<h4>%s</h4><br><table><tr>' % bench + heat_plots = '' # For table row of heatmap plots. + table_plots = '' # For table row of data table plots. + # For bar plot legends and values in URL string. + legends = '' + values = '' + keys = bench_dic[bench].keys() + keys.sort() + if not keys[-1].startswith('viewport'): # No viewport to analyze; skip. + continue + else: + # Extracts viewport size, which for all viewport configs is the same. + viewport = bench_dic[bench][keys[-1]][0] + for config in keys: + [layout, value_li] = bench_dic[bench][config] + if config.startswith('tile_'): # For per-tile data, visualize tiles. + tile_size = config.split('_')[1] + if (not re.search(DIMENSIONS_RE, layout) or + not re.search(DIMENSIONS_RE, tile_size) or + not re.search(DIMENSIONS_RE, viewport)): + continue # Skip unrecognized formats. + [viewport_tile_sum, matrix] = GetTileMatrix( + layout, tile_size, value_li, viewport) + values += '%s|' % viewport_tile_sum + [this_js, row1, row2] = GetTileVisCodes(config + '_' + bench, matrix) + heat_plots += row1 + table_plots += row2 + js_codes += this_js + else: # For viewport data, there is only one element in value_li. + values += '%s|' % sum(value_li) + legends += '%s:%s|' % (config, sum(value_li)) + body_codes += (heat_plots + '</tr><tr>' + table_plots + '</tr></table>' + + '<br>' + BAR_CHART_TEMPLATE % (legends[:-1], values[:-1])) + + return (js_codes, body_codes) + +def main(): + """Parses flags and outputs expected Skia picture bench results.""" + parser = optparse.OptionParser(USAGE_STRING % '%prog' + HELP_STRING) + parser.add_option(OPTION_PLATFORM_SHORT, OPTION_PLATFORM, + dest='plat', default=DEFAULT_PLATFORM, + help='Platform to analyze. Set to DEFAULT_PLATFORM if not given.') + parser.add_option(OPTION_REVISION_SHORT, OPTION_REVISION, + dest='rev', + help='(Mandatory) revision number to analyze.') + parser.add_option(OPTION_DIR_SHORT, OPTION_DIR, + dest='log_dir', default='', + help=('(Optional) local directory where bench log files reside. If left ' + 'empty (by default), will try to read from Google Storage.')) + parser.add_option(OPTION_REPRESENTATION_ALG_SHORT, OPTION_REPRESENTATION_ALG, + dest='alg', default=REPRESENTATION_ALG, + help=('Bench representation algorithm. ' + 'Default to "%s".' % REPRESENTATION_ALG)) + (options, args) = parser.parse_args() + if not (options.rev and options.rev.isdigit()): + parser.error('Please provide correct mandatory flag %s' % OPTION_REVISION) + return + rev = int(options.rev) + (js_codes, body_codes) = OutputTileAnalysis( + rev, options.alg, options.log_dir, options.plat) + print HTML_PREFIX + js_codes + body_codes + HTML_SUFFIX + + +if '__main__' == __name__: + main() |