diff options
author | Derek Sollenberger <djsollen@google.com> | 2011-06-24 11:30:32 -0700 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2011-06-24 11:30:32 -0700 |
commit | a4f65ce780e319268a9f300a9edbc07657adff0a (patch) | |
tree | 91583d9787e2efdf5f98026a127b688da07823f1 | |
parent | 3c1b974a7eae43f061c5e773f8cef0d545a087b2 (diff) | |
parent | 0199fa7423f89a129da2b22a488f2c18e2e4727f (diff) | |
download | external_skia-a4f65ce780e319268a9f300a9edbc07657adff0a.zip external_skia-a4f65ce780e319268a9f300a9edbc07657adff0a.tar.gz external_skia-a4f65ce780e319268a9f300a9edbc07657adff0a.tar.bz2 |
Merge "Skia Merge (revision 1562)"
62 files changed, 1353 insertions, 151 deletions
diff --git a/bench/Android.mk b/bench/Android.mk index 71523af..a0fe86c 100644 --- a/bench/Android.mk +++ b/bench/Android.mk @@ -3,17 +3,20 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - BitmapBench.cpp \ + BenchGpuTimer_none.cpp \ + BenchSysTimer_posix.cpp \ + BenchTimer.cpp \ + BitmapBench.cpp \ DecodeBench.cpp \ FPSBench.cpp \ GradientBench.cpp \ MatrixBench.cpp \ PathBench.cpp \ - RectBench.cpp \ - RepeatTileBench.cpp \ - TextBench.cpp \ - SkBenchmark.cpp \ - benchmain.cpp + RectBench.cpp \ + RepeatTileBench.cpp \ + TextBench.cpp \ + SkBenchmark.cpp \ + benchmain.cpp # additional optional class for this tool LOCAL_SRC_FILES += \ diff --git a/bench/BenchGpuTimer_gl.cpp b/bench/BenchGpuTimer_gl.cpp new file mode 100644 index 0000000..ec2145d --- /dev/null +++ b/bench/BenchGpuTimer_gl.cpp @@ -0,0 +1,181 @@ +#include "BenchGpuTimer_gl.h" +#include <string.h> + +//GL +#define BENCH_GL_FUNCTION_TYPE +#if defined(SK_MESA) + #include <GL/osmesa.h> + #define SK_BENCH_CONTEXT_CHECK (NULL != OSMesaGetCurrentContext()) + + #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \ + OSMesaGetProcAddress("gl" #F); + #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\ + OSMesaGetProcAddress("gl" #F #S); + +#elif defined(SK_BUILD_FOR_WIN32) + #define WIN32_LEAN_AND_MEAN 1 + #include <Windows.h> + #include <GL/GL.h> + #define SK_BENCH_CONTEXT_CHECK (NULL != wglGetCurrentContext()) + + #undef BENCH_GL_FUNCTION_TYPE + #define BENCH_GL_FUNCTION_TYPE __stdcall + + #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \ + wglGetProcAddress("gl" #F); + #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\ + wglGetProcAddress("gl" #F #S); + +#elif defined(SK_BUILD_FOR_MAC) + #include <OpenGL/gl.h> + #include <OpenGL/CGLCurrent.h> + #define SK_BENCH_CONTEXT_CHECK (NULL != CGLGetCurrentContext()) + +#elif defined(SK_BUILD_FOR_UNIX) + #include <GL/gl.h> + #include <GL/glx.h> + #define SK_BENCH_CONTEXT_CHECK (NULL != glXGetCurrentContext()) + + #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \ + glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F)); + #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\ + glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F #S)); +#else + #error unsupported platform +#endif + +#define BenchGL_TIME_ELAPSED 0x88BF +#define BenchGL_QUERY_RESULT 0x8866 +#define BenchGL_QUERY_RESULT_AVAILABLE 0x8867 + +#if defined(SK_BUILD_FOR_WIN32) +typedef UINT64 BenchGLuint64; +#else +#include <stdint.h> +typedef uint64_t BenchGLuint64; +#endif + +typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGenQueriesProc) (GLsizei n, GLuint *ids); +typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLBeginQueryProc) (GLenum target, GLuint id); +typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLEndQueryProc) (GLenum target); +typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLDeleteQueriesProc) (GLsizei n, const GLuint *ids); +typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectivProc) (GLuint id, GLenum pname, GLint *params); +typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectui64vProc) (GLuint id, GLenum pname, BenchGLuint64 *params); + +struct BenchGLInterface { + bool fHasTimer; + BenchGLGenQueriesProc fGenQueries; + BenchGLBeginQueryProc fBeginQuery; + BenchGLEndQueryProc fEndQuery; + BenchGLDeleteQueriesProc fDeleteQueries; + BenchGLGetQueryObjectivProc fGetQueryObjectiv; + BenchGLGetQueryObjectui64vProc fGetQueryObjectui64v; +}; + +static bool BenchGLCheckExtension(const char* ext, + const char* extensionString) { + int extLength = strlen(ext); + + while (true) { + int n = strcspn(extensionString, " "); + if (n == extLength && 0 == strncmp(ext, extensionString, n)) { + return true; + } + if (0 == extensionString[n]) { + return false; + } + extensionString += n+1; + } + + return false; +} + +static BenchGLInterface gBenchGL; +static bool gBenchGLInterfaceInit = false; + +static void BenchGLSetDefaultGLInterface() { + gBenchGL.fHasTimer = false; + if (gBenchGLInterfaceInit || !SK_BENCH_CONTEXT_CHECK) return; + + const char* glExts = + reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); + const GLboolean ext = + BenchGLCheckExtension("GL_EXT_timer_query", glExts); + const GLboolean arb = + BenchGLCheckExtension("GL_ARB_timer_query", glExts); + if (ext || arb) { +#if defined(SK_BUILD_FOR_MAC) + #if GL_EXT_timer_query || GL_ARB_timer_query + gBenchGL.fHasTimer = true; + gBenchGL.fGenQueries = glGenQueries; + gBenchGL.fBeginQuery = glBeginQuery; + gBenchGL.fEndQuery = glEndQuery; + gBenchGL.fDeleteQueries = glDeleteQueries; + gBenchGL.fGetQueryObjectiv = glGetQueryObjectiv; + #endif + #if GL_ARB_timer_query + gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64v; + #elif GL_EXT_timer_query + gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64vEXT; + #endif +#else + gBenchGL.fHasTimer = true; + SK_GL_GET_PROC(GenQueries) + SK_GL_GET_PROC(BeginQuery) + SK_GL_GET_PROC(EndQuery) + SK_GL_GET_PROC(DeleteQueries) + + SK_GL_GET_PROC(GetQueryObjectiv) + if (arb) { + SK_GL_GET_PROC(GetQueryObjectui64v) + } else { + SK_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT) + } +#endif + } + gBenchGLInterfaceInit = true; +} + +BenchGpuTimer::BenchGpuTimer() { + BenchGLSetDefaultGLInterface(); + if (gBenchGL.fHasTimer) { + gBenchGL.fGenQueries(1, &this->fQuery); + } +} + +BenchGpuTimer::~BenchGpuTimer() { + if (gBenchGL.fHasTimer) { + gBenchGL.fDeleteQueries(1, &this->fQuery); + } +} + +void BenchGpuTimer::startGpu() { + if (!gBenchGL.fHasTimer) return; + + this->fStarted = true; + gBenchGL.fBeginQuery(BenchGL_TIME_ELAPSED, this->fQuery); +} + +/** + * It is important to stop the cpu clocks first, + * as this will cpu wait for the gpu to finish. + */ +double BenchGpuTimer::endGpu() { + if (!gBenchGL.fHasTimer) return 0; + + this->fStarted = false; + gBenchGL.fEndQuery(BenchGL_TIME_ELAPSED); + + GLint available = 0; + while (!available) { + gBenchGL.fGetQueryObjectiv(this->fQuery + , BenchGL_QUERY_RESULT_AVAILABLE + , &available); + } + BenchGLuint64 totalGPUTimeElapsed = 0; + gBenchGL.fGetQueryObjectui64v(this->fQuery + , BenchGL_QUERY_RESULT + , &totalGPUTimeElapsed); + + return totalGPUTimeElapsed / 1000000.0; +} diff --git a/bench/BenchGpuTimer_gl.h b/bench/BenchGpuTimer_gl.h new file mode 100644 index 0000000..ac23482 --- /dev/null +++ b/bench/BenchGpuTimer_gl.h @@ -0,0 +1,33 @@ +#ifndef SkBenchGpuTimer_DEFINED +#define SkBenchGpuTimer_DEFINED + +#if defined(SK_MESA) + #include <GL/osmesa.h> + +#elif defined(SK_BUILD_FOR_WIN32) + #define WIN32_LEAN_AND_MEAN 1 + #include <Windows.h> + #include <GL/GL.h> + +#elif defined(SK_BUILD_FOR_MAC) + #include <OpenGL/gl.h> + +#elif defined(SK_BUILD_FOR_UNIX) + #include <GL/gl.h> + +#else + #error unsupported platform +#endif + +class BenchGpuTimer { +public: + BenchGpuTimer(); + ~BenchGpuTimer(); + void startGpu(); + double endGpu(); +private: + GLuint fQuery; + int fStarted; +}; + +#endif diff --git a/bench/BenchGpuTimer_none.cpp b/bench/BenchGpuTimer_none.cpp new file mode 100644 index 0000000..0dba6d7 --- /dev/null +++ b/bench/BenchGpuTimer_none.cpp @@ -0,0 +1,14 @@ +#include "BenchGpuTimer_none.h" + +BenchGpuTimer::BenchGpuTimer() { +} + +BenchGpuTimer::~BenchGpuTimer() { +} + +void BenchGpuTimer::startGpu() { +} + +double BenchGpuTimer::endGpu() { + return -1.0; +} diff --git a/bench/BenchGpuTimer_none.h b/bench/BenchGpuTimer_none.h new file mode 100644 index 0000000..7069ca4 --- /dev/null +++ b/bench/BenchGpuTimer_none.h @@ -0,0 +1,12 @@ +#ifndef SkBenchGpuTimer_DEFINED +#define SkBenchGpuTimer_DEFINED + +class BenchGpuTimer { +public: + BenchGpuTimer(); + ~BenchGpuTimer(); + void startGpu(); + double endGpu(); +}; + +#endif diff --git a/bench/BenchSysTimer_c.cpp b/bench/BenchSysTimer_c.cpp new file mode 100644 index 0000000..fc0850b --- /dev/null +++ b/bench/BenchSysTimer_c.cpp @@ -0,0 +1,20 @@ +#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/bench/BenchSysTimer_c.h b/bench/BenchSysTimer_c.h new file mode 100644 index 0000000..c598f30 --- /dev/null +++ b/bench/BenchSysTimer_c.h @@ -0,0 +1,19 @@ +#ifndef SkBenchSysTimer_DEFINED +#define SkBenchSysTimer_DEFINED + +//Time +#include <time.h> +#warning standard clocks + +class BenchSysTimer { +public: + void startWall(); + void startCpu(); + double endCpu(); + double endWall(); +private: + clock_t start_cpu; + time_t fStartWall; +}; + +#endif diff --git a/bench/BenchSysTimer_mach.cpp b/bench/BenchSysTimer_mach.cpp new file mode 100644 index 0000000..b23897c --- /dev/null +++ b/bench/BenchSysTimer_mach.cpp @@ -0,0 +1,69 @@ +#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; + } +} diff --git a/bench/BenchSysTimer_mach.h b/bench/BenchSysTimer_mach.h new file mode 100644 index 0000000..da4fff0 --- /dev/null +++ b/bench/BenchSysTimer_mach.h @@ -0,0 +1,19 @@ +#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/bench/BenchSysTimer_posix.cpp b/bench/BenchSysTimer_posix.cpp new file mode 100644 index 0000000..5d28f40 --- /dev/null +++ b/bench/BenchSysTimer_posix.cpp @@ -0,0 +1,50 @@ +#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/bench/BenchSysTimer_posix.h b/bench/BenchSysTimer_posix.h new file mode 100644 index 0000000..09dfb0e --- /dev/null +++ b/bench/BenchSysTimer_posix.h @@ -0,0 +1,19 @@ +#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/bench/BenchSysTimer_windows.cpp b/bench/BenchSysTimer_windows.cpp new file mode 100644 index 0000000..923754c --- /dev/null +++ b/bench/BenchSysTimer_windows.cpp @@ -0,0 +1,55 @@ +#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 (end_cpu - this->fStartCpu) / 10000; +} +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; + } else { + return (double)ticks_elapsed.QuadPart / frequency.QuadPart * 1000; + } +} diff --git a/bench/BenchSysTimer_windows.h b/bench/BenchSysTimer_windows.h new file mode 100644 index 0000000..72a3fb2 --- /dev/null +++ b/bench/BenchSysTimer_windows.h @@ -0,0 +1,19 @@ +#ifndef SkBenchSysTimer_DEFINED +#define SkBenchSysTimer_DEFINED + +//Time +#define WIN32_LEAN_AND_MEAN 1 +#include <Windows.h> + +struct BenchSysTimer { +public: + void startWall(); + void startCpu(); + double endCpu(); + double endWall(); +private: + ULONGLONG fStartCpu; + LARGE_INTEGER fStartWall; +}; + +#endif diff --git a/bench/BenchTimer.cpp b/bench/BenchTimer.cpp new file mode 100644 index 0000000..e7b0068 --- /dev/null +++ b/bench/BenchTimer.cpp @@ -0,0 +1,48 @@ +#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) + #include "BenchSysTimer_posix.h" +#else + #include "BenchSysTimer_c.h" +#endif + +#if defined(SK_MESA) || \ + defined(SK_BUILD_FOR_WIN32) || \ + defined(SK_BUILD_FOR_MAC) || \ + defined(SK_BUILD_FOR_UNIX) + #include "BenchGpuTimer_gl.h" + +#else + #include "BenchGpuTimer_none.h" +#endif + +BenchTimer::BenchTimer() + : fCpu(-1.0) + , fWall(-1.0) + , fGpu(-1.0) +{ + this->fSysTimer = new BenchSysTimer(); + this->fGpuTimer = new BenchGpuTimer(); +} + +BenchTimer::~BenchTimer() { + delete this->fSysTimer; + delete this->fGpuTimer; +} + +void BenchTimer::start() { + this->fSysTimer->startWall(); + this->fGpuTimer->startGpu(); + this->fSysTimer->startCpu(); +} + +void BenchTimer::end() { + this->fCpu = this->fSysTimer->endCpu(); + //It is important to stop the cpu clocks first, + //as the following will cpu wait for the gpu to finish. + this->fGpu = this->fGpuTimer->endGpu(); + this->fWall = this->fSysTimer->endWall(); +} diff --git a/bench/BenchTimer.h b/bench/BenchTimer.h new file mode 100644 index 0000000..eae82d5 --- /dev/null +++ b/bench/BenchTimer.h @@ -0,0 +1,27 @@ +#ifndef SkBenchTimer_DEFINED +#define SkBenchTimer_DEFINED + +class BenchSysTimer; +class BenchGpuTimer; + +/** + * SysTimers and GpuTimers are implemented orthogonally. + * This class combines a SysTimer and a GpuTimer into one single, + * platform specific, Timer with a simple interface. + */ +class BenchTimer { +public: + BenchTimer(); + ~BenchTimer(); + void start(); + void end(); + double fCpu; + double fWall; + double fGpu; + +private: + BenchSysTimer *fSysTimer; + BenchGpuTimer *fGpuTimer; +}; + +#endif diff --git a/bench/MatrixBench.cpp b/bench/MatrixBench.cpp index d963bc7..dce0358 100644 --- a/bench/MatrixBench.cpp +++ b/bench/MatrixBench.cpp @@ -67,11 +67,10 @@ private: class ScaleMatrixBench : public MatrixBench { public: ScaleMatrixBench(void* param) : INHERITED(param, "scale") { - + fSX = fSY = SkFloatToScalar(1.5f); fM0.reset(); fM1.setScale(fSX, fSY); fM2.setTranslate(fSX, fSY); - fSX = fSY = SkFloatToScalar(1.5f); } protected: virtual void performTest() { @@ -215,6 +214,89 @@ private: typedef MatrixBench INHERITED; }; +#ifdef SK_SCALAR_IS_FLOAT +class ScaleTransMixedMatrixBench : public MatrixBench { + public: + ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) { + fMatrix.setAll(fRandom.nextS(), fRandom.nextS(), fRandom.nextS(), + fRandom.nextS(), fRandom.nextS(), fRandom.nextS(), + fRandom.nextS(), fRandom.nextS(), fRandom.nextS()); + int i; + for (i = 0; i < fCount; i++) { + fSrc[i].fX = fRandom.nextS(); + fSrc[i].fY = fRandom.nextS(); + fDst[i].fX = fRandom.nextS(); + fDst[i].fY = fRandom.nextS(); + } + } + protected: + virtual void performTest() { + SkPoint* dst = fDst; + const SkPoint* src = fSrc; + int count = fCount; + 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: + SkMatrix fMatrix; + SkPoint fSrc [16]; + SkPoint fDst [16]; + int fCount; + SkRandom fRandom; + typedef MatrixBench INHERITED; +}; + + +class ScaleTransDoubleMatrixBench : public MatrixBench { + public: + ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) { + init9(fMatrix); + int i; + for (i = 0; i < fCount; i++) { + fSrc[i].fX = fRandom.nextS(); + fSrc[i].fY = fRandom.nextS(); + fDst[i].fX = fRandom.nextS(); + fDst[i].fY = fRandom.nextS(); + } + } + protected: + virtual void performTest() { + SkPoint* dst = fDst; + const SkPoint* src = fSrc; + int count = fCount; + // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode + float mx = fMatrix[SkMatrix::kMScaleX]; + float my = fMatrix[SkMatrix::kMScaleY]; + float tx = fMatrix[SkMatrix::kMTransX]; + float ty = fMatrix[SkMatrix::kMTransY]; + do { + dst->fY = src->fY * my + ty; + dst->fX = src->fX * mx + tx; + src += 1; + dst += 1; + } while (--count); + } + private: + double fMatrix [9]; + SkPoint fSrc [16]; + SkPoint fDst [16]; + int fCount; + SkRandom fRandom; + typedef MatrixBench INHERITED; +}; +#endif + + + + static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); } static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); } @@ -227,3 +309,10 @@ static BenchRegistry gReg1(M1); static BenchRegistry gReg2(M2); static BenchRegistry gReg3(M3); static BenchRegistry gReg4(M4); + +#ifdef SK_SCALAR_IS_FLOAT +static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); } +static SkBenchmark* FlM1(void* p) { return new ScaleTransDoubleMatrixBench(p); } +static BenchRegistry gFlReg5(FlM0); +static BenchRegistry gFlReg6(FlM1); +#endif diff --git a/bench/ScalarBench.cpp b/bench/ScalarBench.cpp new file mode 100644 index 0000000..29fe5c4 --- /dev/null +++ b/bench/ScalarBench.cpp @@ -0,0 +1,97 @@ +#include "SkBenchmark.h" +#include "SkFloatBits.h" +#include "SkRandom.h" +#include "SkString.h" + +class ScalarBench : public SkBenchmark { + SkString fName; + enum { N = 100000 }; +public: + ScalarBench(void* param, const char name[]) : INHERITED(param) { + fName.printf("scalar_%s", name); + } + + virtual void performTest() = 0; + +protected: + virtual int mulLoopCount() const { return 1; } + + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(SkCanvas* canvas) { + int n = N * this->mulLoopCount(); + for (int i = 0; i < n; i++) { + this->performTest(); + } + } + +private: + typedef SkBenchmark INHERITED; +}; + +// we want to stop the compiler from eliminating code that it thinks is a no-op +// so we have a non-static global we increment, hoping that will convince the +// compiler to execute everything +int gScalarBench_NonStaticGlobal; + +#define always_do(pred) \ + do { \ + if (pred) { \ + ++gScalarBench_NonStaticGlobal; \ + } \ + } while (0) + +// 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(void* param) : INHERITED(param, "compare_float") { + init9(fArray); + } +protected: + virtual int mulLoopCount() const { return 4; } + virtual void performTest() { + always_do(fArray[6] != 0.0f || fArray[7] != 0.0f || fArray[8] != 1.0f); + always_do(fArray[2] != 0.0f || fArray[5] != 0.0f); + } +private: + float fArray[9]; + typedef ScalarBench INHERITED; +}; + +class ForcedIntComparisonBench : public ScalarBench { +public: + ForcedIntComparisonBench(void* param) + : INHERITED(param, "compare_forced_int") { + init9(fArray); + } +protected: + virtual int mulLoopCount() const { return 4; } + virtual void performTest() { + always_do(SkScalarAs2sCompliment(fArray[6]) | + SkScalarAs2sCompliment(fArray[7]) | + (SkScalarAs2sCompliment(fArray[8]) - kPersp1Int)); + always_do(SkScalarAs2sCompliment(fArray[2]) | + SkScalarAs2sCompliment(fArray[5])); + } +private: + static const int32_t kPersp1Int = 0x3f800000; + SkScalar fArray[9]; + typedef ScalarBench INHERITED; +}; + +static SkBenchmark* S0(void* p) { return new FloatComparisonBench(p); } +static SkBenchmark* S1(void* p) { return new ForcedIntComparisonBench(p); } + +static BenchRegistry gReg0(S0); +static BenchRegistry gReg1(S1); diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index 066573a..34f8a1a 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -5,12 +5,12 @@ #include "SkNWayCanvas.h" #include "SkPicture.h" #include "SkString.h" -#include "SkTime.h" #include "GrContext.h" #include "SkGpuDevice.h" #include "SkEGLContext.h" #include "SkBenchmark.h" +#include "BenchTimer.h" #ifdef ANDROID static void log_error(const char msg[]) { SkDebugf("%s", msg); } @@ -212,6 +212,9 @@ int main (int argc, char * const argv[]) { bool forceAA = true; bool forceFilter = false; SkTriState::State forceDither = SkTriState::kDefault; + bool timerWall = false; + bool timerCpu = true; + bool timerGpu = true; bool doScale = false; bool doRotate = false; bool doClip = false; @@ -246,6 +249,23 @@ int main (int argc, char * const argv[]) { log_error("missing arg for -repeat\n"); return -1; } + } else if (strcmp(*argv, "-timers") == 0) { + argv++; + if (argv < stop) { + timerWall = false; + timerCpu = false; + timerGpu = false; + for (char* t = *argv; *t; ++t) { + switch (*t) { + case 'w': timerWall = true; break; + case 'c': timerCpu = true; break; + case 'g': timerGpu = true; break; + } + } + } else { + log_error("missing arg for -timers\n"); + return -1; + } } else if (!strcmp(*argv, "-rotate")) { doRotate = true; } else if (!strcmp(*argv, "-scale")) { @@ -346,6 +366,8 @@ int main (int argc, char * const argv[]) { context = GrContext::CreateGLShaderContext(); } + BenchTimer timer = BenchTimer(); + Iter iter(&defineDict); SkBenchmark* bench; while ((bench = iter.next()) != NULL) { @@ -399,30 +421,36 @@ int main (int argc, char * const argv[]) { performRotate(&canvas, dim.fX, dim.fY); } + bool gpu = kGPU_Backend == backend && context; //warm up caches if needed if (repeatDraw > 1) { SkAutoCanvasRestore acr(&canvas, true); bench->draw(&canvas); - if (kGPU_Backend == backend && context) { + if (gpu) { context->flush(); glFinish(); } } - SkMSec now = SkTime::GetMSecs(); + timer.start(); for (int i = 0; i < repeatDraw; i++) { SkAutoCanvasRestore acr(&canvas, true); bench->draw(&canvas); } - if (kGPU_Backend == backend && context) { - context->flush(); - glFinish(); - } + timer.end(); if (repeatDraw > 1) { - double duration = SkTime::GetMSecs() - now; SkString str; - str.printf(" %4s: msecs = %5.2f", configName, duration / repeatDraw); + str.printf(" %4s:", configName); + if (timerWall) { + str.appendf(" msecs = %6.2f", timer.fWall / repeatDraw); + } + if (timerCpu) { + str.appendf(" cmsecs = %6.2f", timer.fCpu / repeatDraw); + } + if (timerGpu && gpu && timer.fGpu > 0) { + str.appendf(" gmsecs = %6.2f", timer.fGpu / repeatDraw); + } log_progress(str); } if (outDir.size() > 0) { diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index ea205e3..37c3ee3 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -120,7 +120,7 @@ static void compute_diff(const SkBitmap& target, const SkBitmap& base, } static bool compare(const SkBitmap& target, const SkBitmap& base, - const SkString& name, const char* modeDescriptor, + const SkString& name, const char* renderModeDescriptor, SkBitmap* diff) { SkBitmap copy; const SkBitmap* bm = ⌖ @@ -134,8 +134,9 @@ static bool compare(const SkBitmap& target, const SkBitmap& base, const int w = bm->width(); const int h = bm->height(); if (w != base.width() || h != base.height()) { - SkDebugf("---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n", - modeDescriptor, name.c_str(), + SkDebugf( +"---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n", + renderModeDescriptor, name.c_str(), base.width(), base.height(), w, h); return false; } @@ -148,8 +149,9 @@ static bool compare(const SkBitmap& target, const SkBitmap& base, SkPMColor c0 = *base.getAddr32(x, y); SkPMColor c1 = *bm->getAddr32(x, y); if (c0 != c1) { - SkDebugf("----- %s pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n", - modeDescriptor, name.c_str(), x, y, c0, c1); + SkDebugf( +"----- %s pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n", + renderModeDescriptor, name.c_str(), x, y, c0, c1); if (diff) { diff->setConfig(SkBitmap::kARGB_8888_Config, w, h); @@ -250,17 +252,17 @@ static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) { static bool write_reference_image(const ConfigData& gRec, const char writePath [], - const char writePathSuffix [], + const char renderModeDescriptor [], const SkString& name, SkBitmap& bitmap, SkDynamicMemoryWStream* pdf) { SkString path; bool success = false; if (gRec.fBackend != kPDF_Backend) { - path = make_filename(writePath, writePathSuffix, name, "png"); + path = make_filename(writePath, renderModeDescriptor, name, "png"); success = write_bitmap(path, bitmap); } else if (pdf) { - path = make_filename(writePath, writePathSuffix, name, "pdf"); + path = make_filename(writePath, renderModeDescriptor, name, "pdf"); success = write_pdf(path, *pdf); } if (!success) { @@ -273,7 +275,7 @@ static bool compare_to_reference_image(const char readPath [], const SkString& name, SkBitmap &bitmap, const char diffPath [], - const char modeDescriptor []) { + const char renderModeDescriptor []) { SkString path = make_filename(readPath, "", name, "png"); SkBitmap orig; bool success = SkImageDecoder::DecodeFile(path.c_str(), &orig, @@ -281,7 +283,7 @@ static bool compare_to_reference_image(const char readPath [], SkImageDecoder::kDecodePixels_Mode, NULL); if (success) { SkBitmap diffBitmap; - success = compare(bitmap, orig, name, modeDescriptor, + success = compare(bitmap, orig, name, renderModeDescriptor, diffPath ? &diffBitmap : NULL); if (!success && diffPath) { SkString diffName = make_filename(diffPath, "", name, ".diff.png"); @@ -299,18 +301,18 @@ static bool handle_test_results(GM* gm, const char writePath [], const char readPath [], const char diffPath [], - const char writePathSuffix [], + const char renderModeDescriptor [], SkBitmap& bitmap, SkDynamicMemoryWStream* pdf) { SkString name = make_name(gm->shortName(), gRec.fName); if (writePath) { - write_reference_image(gRec, writePath, writePathSuffix, + write_reference_image(gRec, writePath, renderModeDescriptor, name, bitmap, pdf); // TODO: Figure out a way to compare PDFs. } else if (readPath && gRec.fBackend != kPDF_Backend) { return compare_to_reference_image(readPath, name, bitmap, - diffPath, writePathSuffix); + diffPath, renderModeDescriptor); } return true; } @@ -377,7 +379,6 @@ static bool test_drawing(GM* gm, static bool test_picture_playback(GM* gm, const ConfigData& gRec, - const char writePath [], const char readPath [], const char diffPath []) { SkPicture* pict = generate_new_picture(gm); @@ -386,7 +387,7 @@ static bool test_picture_playback(GM* gm, if (kRaster_Backend == gRec.fBackend) { SkBitmap bitmap; generate_image_from_picture(gm, gRec, pict, &bitmap); - return handle_test_results(gm, gRec, writePath, readPath, diffPath, + return handle_test_results(gm, gRec, NULL, readPath, diffPath, "-replay", bitmap, NULL); } return true; @@ -394,7 +395,6 @@ static bool test_picture_playback(GM* gm, static bool test_picture_serialization(GM* gm, const ConfigData& gRec, - const char writePath [], const char readPath [], const char diffPath []) { SkPicture* pict = generate_new_picture(gm); @@ -405,7 +405,7 @@ static bool test_picture_serialization(GM* gm, if (kRaster_Backend == gRec.fBackend) { SkBitmap bitmap; generate_image_from_picture(gm, gRec, repict, &bitmap); - return handle_test_results(gm, gRec, writePath, readPath, diffPath, + return handle_test_results(gm, gRec, NULL, readPath, diffPath, "-serialize", bitmap, NULL); } return true; @@ -493,29 +493,31 @@ int main(int argc, char * const argv[]) { // Accumulate success of all tests so we can flag error in any // one with the return value. - bool testSuccess = true; + bool overallSuccess = true; while ((gm = iter.next()) != NULL) { SkISize size = gm->getISize(); SkDebugf("drawing... %s [%d %d]\n", gm->shortName(), size.width(), size.height()); for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) { - testSuccess &= test_drawing(gm, gRec[i], + bool testSuccess = test_drawing(gm, gRec[i], writePath, readPath, diffPath, context); + overallSuccess &= testSuccess; - if (doReplay) { - testSuccess &= test_picture_playback(gm, gRec[i], - writePath, readPath, diffPath); + if (doReplay && testSuccess) { + testSuccess = test_picture_playback(gm, gRec[i], + readPath, diffPath); + overallSuccess &= testSuccess; } - if (doSerialize) { - testSuccess &= test_picture_serialization(gm, gRec[i], - writePath, readPath, diffPath); + if (doSerialize && testSuccess) { + overallSuccess &= test_picture_serialization(gm, gRec[i], + readPath, diffPath); } } SkDELETE(gm); } - if (false == testSuccess) { + if (false == overallSuccess) { return -1; } return 0; diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h index 58c53ba..8809271 100644 --- a/gpu/include/GrContext.h +++ b/gpu/include/GrContext.h @@ -66,6 +66,13 @@ public: void contextLost(); /** + * Similar to contextLost, but makes no attempt to reset state. + * Use this method when GrContext destruction is pending, but + * the graphics context is destroyed first. + */ + void contextDestroyed(); + + /** * Frees gpu created by the context. Can be called to reduce GPU memory * pressure. */ diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h index 574a430..5cb885a 100644 --- a/gpu/include/GrGpu.h +++ b/gpu/include/GrGpu.h @@ -325,7 +325,7 @@ public: * Called to tell Gpu object that all GrResources have been lost and should * be abandoned. */ - void abandonResources(); + virtual void abandonResources(); /** * Called to tell Gpu object to release all GrResources. diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index dae1cd1..4ebf225 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -57,7 +57,7 @@ GrContext* GrContext::Create(GrEngine engine, } GrContext* GrContext::CreateGLShaderContext() { - return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL); + return GrContext::Create(kOpenGL_Shaders_GrEngine, 0); } GrContext::~GrContext() { @@ -74,6 +74,11 @@ GrContext::~GrContext() { } void GrContext::contextLost() { + contextDestroyed(); + this->setupDrawBuffer(); +} + +void GrContext::contextDestroyed() { // abandon first to so destructors // don't try to free the resources in the API. fGpu->abandonResources(); @@ -93,8 +98,6 @@ void GrContext::contextLost() { fTextureCache->removeAll(); fFontCache->freeAll(); fGpu->markContextDirty(); - - this->setupDrawBuffer(); } void GrContext::resetContext() { @@ -1192,6 +1195,9 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path, GrRect pathBounds = path.getBounds(); GrIRect pathIBounds; if (!pathBounds.isEmpty()) { + if (NULL != translate) { + pathBounds.offset(*translate); + } target->getViewMatrix().mapRect(&pathBounds, pathBounds); pathBounds.roundOut(&pathIBounds); if (!bound.intersect(pathIBounds)) { @@ -1242,8 +1248,10 @@ void GrContext::flushText() { void GrContext::flushDrawBuffer() { #if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING - fDrawBuffer->playback(fGpu); - fDrawBuffer->reset(); + if (fDrawBuffer) { + fDrawBuffer->playback(fGpu); + fDrawBuffer->reset(); + } #endif } @@ -1302,6 +1310,7 @@ void GrContext::writePixels(int left, int top, int width, int height, matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top)); fGpu->setViewMatrix(matrix); + fGpu->setColorFilter(0, SkXfermode::kDst_Mode); fGpu->disableState(GrDrawTarget::kClip_StateBit); fGpu->setAlpha(0xFF); fGpu->setBlendFunc(kOne_BlendCoeff, diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp index 4fe7ccc..4f260c7 100644 --- a/gpu/src/GrGpu.cpp +++ b/gpu/src/GrGpu.cpp @@ -527,7 +527,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { } } else { SET_RANDOM_COLOR - this->drawSimpleRect(bounds, 0, NULL); + this->drawSimpleRect(bounds, NULL, 0); } } } diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp index 50be67f..0a933b5 100644 --- a/gpu/src/GrGpuGLShaders.cpp +++ b/gpu/src/GrGpuGLShaders.cpp @@ -130,6 +130,11 @@ public: } }; +void GrGpuGLShaders::abandonResources(){ + INHERITED::abandonResources(); + fProgramCache->abandon(); +} + void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) { GR_GL(DeleteShader(programData->fVShaderID)); GR_GL(DeleteShader(programData->fFShaderID)); diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h index 9392d1c..557a4e3 100644 --- a/gpu/src/GrGpuGLShaders.h +++ b/gpu/src/GrGpuGLShaders.h @@ -31,6 +31,8 @@ public: virtual void resetContext(); + virtual void abandonResources(); + protected: // overrides from GrGpu virtual bool flushGraphicsState(GrPrimitiveType type); diff --git a/gpu/src/android/GrGLDefaultInterface_android.cpp b/gpu/src/android/GrGLDefaultInterface_android.cpp new file mode 100644 index 0000000..e52277e --- /dev/null +++ b/gpu/src/android/GrGLDefaultInterface_android.cpp @@ -0,0 +1,138 @@ +// Modified from chromium/src/webkit/glue/gl_bindings_skia_cmd_buffer.cc + +// Copyright (c) 2011 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. + +#include "GrGLInterface.h" + +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES +#endif + +#include "gl2.h" +#include "gl2ext.h" +/* +#include "gpu/GLES2/gl2.h" +#include "gpu/GLES2/gl2ext.h" +*/ +void GrGLSetDefaultGLInterface() { + static GrGLInterface cmd_buffer_interface = { + kES2_GrGLBinding, + + glActiveTexture, + glAttachShader, + glBindAttribLocation, + glBindBuffer, + glBindTexture, + glBlendColor, + glBlendFunc, + glBufferData, + glBufferSubData, + glClear, + glClearColor, + glClearStencil, + NULL, // glClientActiveTexture + NULL, // glColor4ub + glColorMask, + NULL, // glColorPointer + glCompileShader, + glCompressedTexImage2D, + glCreateProgram, + glCreateShader, + glCullFace, + glDeleteBuffers, + glDeleteProgram, + glDeleteShader, + glDeleteTextures, + glDepthMask, + glDisable, + NULL, // glDisableClientState + glDisableVertexAttribArray, + glDrawArrays, + glDrawElements, + glEnable, + NULL, // glEnableClientState + glEnableVertexAttribArray, + glFrontFace, + glGenBuffers, + glGenTextures, + glGetBufferParameteriv, + glGetError, + glGetIntegerv, + glGetProgramInfoLog, + glGetProgramiv, + glGetShaderInfoLog, + glGetShaderiv, + glGetString, + glGetUniformLocation, + glLineWidth, + glLinkProgram, + NULL, // glLoadMatrixf + NULL, // glMatrixMode + glPixelStorei, + NULL, // glPointSize + glReadPixels, + glScissor, + NULL, // glShadeModel + glShaderSource, + glStencilFunc, + glStencilFuncSeparate, + glStencilMask, + glStencilMaskSeparate, + glStencilOp, + glStencilOpSeparate, + NULL, // glTexCoordPointer + NULL, // glTexEnvi + glTexImage2D, + glTexParameteri, + glTexSubImage2D, + glUniform1f, + glUniform1i, + glUniform1fv, + glUniform1iv, + glUniform2f, + glUniform2i, + glUniform2fv, + glUniform2iv, + glUniform3f, + glUniform3i, + glUniform3fv, + glUniform3iv, + glUniform4f, + glUniform4i, + glUniform4fv, + glUniform4iv, + glUniformMatrix2fv, + glUniformMatrix3fv, + glUniformMatrix4fv, + glUseProgram, + glVertexAttrib4fv, + glVertexAttribPointer, + NULL, // glVertexPointer + glViewport, + glBindFramebuffer, + glBindRenderbuffer, + glCheckFramebufferStatus, + glDeleteFramebuffers, + glDeleteRenderbuffers, + glFramebufferRenderbuffer, + glFramebufferTexture2D, + glGenFramebuffers, + glGenRenderbuffers, + glRenderbufferStorage, + NULL, // glRenderbufferStorageMultisampleEXT, + NULL, // glBlitFramebufferEXT, + NULL, // glResolveMultisampleFramebuffer + glMapBufferOES, + glUnmapBufferOES, + NULL, + GrGLInterface::kStaticInitEndGuard + }; + static bool host_StubGL_initialized = false; + if (!host_StubGL_initialized) { + GrGLSetGLInterface(&cmd_buffer_interface); + host_StubGL_initialized = true; + } +} + diff --git a/gpu/src/app-android.cpp b/gpu/src/app-android.cpp index eea9a4d..e07aa1d 100644 --- a/gpu/src/app-android.cpp +++ b/gpu/src/app-android.cpp @@ -14,8 +14,8 @@ static GrContext* make_context() { SkDebugf("---- before create\n"); - GrContext* ctx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL); -// GrContext* ctx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL); + GrContext* ctx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, 0); +// GrContext* ctx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, 0); SkDebugf("---- after create %p\n", ctx); return ctx; } diff --git a/gpu/src/skia/SkUIView.mm b/gpu/src/skia/SkUIView.mm index 667a474..8cd6c77 100644 --- a/gpu/src/skia/SkUIView.mm +++ b/gpu/src/skia/SkUIView.mm @@ -362,9 +362,9 @@ static GrContext* get_global_grctx() { // should be pthread-local at least if (NULL == gCtx) { #ifdef USE_GL_1 - gCtx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL); + gCtx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, 0); #else - gCtx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL); + gCtx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, 0); #endif } return gCtx; diff --git a/include/core/SkDrawFilter.h b/include/core/SkDrawFilter.h index 1434391..c8af187 100644 --- a/include/core/SkDrawFilter.h +++ b/include/core/SkDrawFilter.h @@ -44,7 +44,7 @@ public: * Called with the paint that will be used to draw the specified type. * The implementation may modify the paint as they wish. */ - virtual void filter(SkPaint*, Type) {} + virtual void filter(SkPaint*, Type) = 0; }; #endif diff --git a/include/core/SkFixed.h b/include/core/SkFixed.h index c58c6de..8b56c50 100644 --- a/include/core/SkFixed.h +++ b/include/core/SkFixed.h @@ -111,6 +111,9 @@ inline SkFixed SkFixedFraction(SkFixed x) #define SkFixedAbs(x) SkAbs32(x) #define SkFixedAve(a, b) (((a) + (b)) >> 1) +// The same as SkIntToFixed(SkFixedFloor(x)) +#define SkFixedFloorToFixed(x) ((x) & ~0xFFFF) + SkFixed SkFixedMul_portable(SkFixed, SkFixed); SkFract SkFractMul_portable(SkFract, SkFract); inline SkFixed SkFixedSquare_portable(SkFixed value) diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h index d0f7c65..e20ea05 100644 --- a/include/core/SkFontHost.h +++ b/include/core/SkFontHost.h @@ -150,14 +150,22 @@ public: */ static SkScalerContext* CreateScalerContext(const SkDescriptor* desc); - /** Given a "current" fontID, return the next logical fontID to use - when searching fonts for a given unicode value. Typically the caller - will query a given font, and if a unicode value is not supported, they - will call this, and if 0 is not returned, will search that font, and so - on. This process must be finite, and when the fonthost sees a - font with no logical successor, it must return 0. - */ - static uint32_t NextLogicalFont(SkFontID fontID); + /** + * Given a "current" fontID, return the next logical fontID to use + * when searching fonts for a given unicode value. Typically the caller + * will query a given font, and if a unicode value is not supported, they + * will call this, and if 0 is not returned, will search that font, and so + * on. This process must be finite, and when the fonthost sees a + * font with no logical successor, it must return 0. + * + * The original fontID is also provided. This is the initial font that was + * stored in the typeface of the caller. It is provided as an aid to choose + * the best next logical font. e.g. If the original font was bold or serif, + * but the 2nd in the logical chain was plain, then a subsequent call to + * get the 3rd can still inspect the original, and try to match its + * stylistic attributes. + */ + static SkFontID NextLogicalFont(SkFontID currFontID, SkFontID origFontID); /////////////////////////////////////////////////////////////////////////// diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h index 5dbf684..ba113f4 100644 --- a/include/core/SkScalar.h +++ b/include/core/SkScalar.h @@ -18,6 +18,7 @@ #define SkScalar_DEFINED #include "SkFixed.h" +#include "SkFloatingPoint.h" /** \file SkScalar.h @@ -29,7 +30,6 @@ */ #ifdef SK_SCALAR_IS_FLOAT - #include "SkFloatingPoint.h" /** SkScalar is our type for fractional values and coordinates. Depending on compile configurations, it is either represented as an IEEE float, or diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h index 3f818a3..cbbbdf0 100644 --- a/include/core/SkScalerContext.h +++ b/include/core/SkScalerContext.h @@ -189,6 +189,7 @@ private: }; public: struct Rec { + uint32_t fOrigFontID; uint32_t fFontID; SkScalar fTextSize, fPreScaleX, fPreSkewX; SkScalar fPost2x2[2][2]; diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h index acc4f9b..8627ae4 100644 --- a/include/effects/SkLayerDrawLooper.h +++ b/include/effects/SkLayerDrawLooper.h @@ -74,12 +74,12 @@ public: /** * This layer will draw with the original paint, ad the specified offset */ - SkPaint* addLayer(SkScalar dx, SkScalar dy); + void addLayer(SkScalar dx, SkScalar dy); /** * This layer will with the original paint and no offset. */ - SkPaint* addLayer() { return this->addLayer(0, 0); } + void addLayer() { this->addLayer(0, 0); } // overrides from SkDrawLooper virtual void init(SkCanvas*); diff --git a/include/views/SkOSWindow_Unix.h b/include/views/SkOSWindow_Unix.h index 803ca13..45b53d5 100644 --- a/include/views/SkOSWindow_Unix.h +++ b/include/views/SkOSWindow_Unix.h @@ -63,13 +63,11 @@ protected: private: SkUnixWindow fUnixWindow; bool fGLAttached; - bool fRestart; // Needed for GL XVisualInfo* fVi; void doPaint(); - void restartLoop(); void mapWindowAndWait(); typedef SkWindow INHERITED; diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index 3efffe6..f05fe6e 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -848,7 +848,7 @@ void SampleWindow::afterChildren(SkCanvas* orig) { break; #ifdef SK_SUPPORT_GL case kGPU_CanvasType: - if (fShowZoomer) { + if (fShowZoomer && fGpuCanvas) { this->showZoomer(fGpuCanvas); } delete fGpuCanvas; diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp index dbd1bfa..dec355a 100644 --- a/src/core/SkBlitter_ARGB32.cpp +++ b/src/core/SkBlitter_ARGB32.cpp @@ -295,14 +295,10 @@ void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask, int height = clip.height(); #if defined(SK_SUPPORT_LCDTEXT) - const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format; - const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format; -#endif + const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format; + const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format; // In LCD mode the masks have either an extra couple of rows or columns on the edges. - SkPMColor srcColor = fPMColor; - -#if defined(SK_SUPPORT_LCDTEXT) if (lcdMode || verticalLCDMode) { int widthAdjustment, heightAdjustment; const uint32_t* alpha32; @@ -313,6 +309,7 @@ void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask, unsigned devRB = fDevice.rowBytes() - (width << 2); unsigned alphaExtraRowWords = mask.rowWordsLCD() - width; + SkPMColor srcColor = fPMColor; do { unsigned w = width; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index e2d70ee..7d29f74 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1064,7 +1064,7 @@ bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { return true; } - if (fMCRec->fMatrix->getType() & SkMatrix::kPerspective_Mask) { + if (fMCRec->fMatrix->hasPerspective()) { SkRect dst; fMCRec->fMatrix->mapRect(&dst, rect); SkIRect idst; @@ -1666,4 +1666,3 @@ const SkPaint& SkCanvas::LayerIter::paint() const { const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } int SkCanvas::LayerIter::x() const { return fImpl->getX(); } int SkCanvas::LayerIter::y() const { return fImpl->getY(); } - diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 14e5a80..74a30e9 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -864,7 +864,7 @@ static SkScalar fast_len(const SkVector& vec) { // for that we'll transform (0,1) and (1,0), and check that the resulting dot-prod // is nearly one static bool map_radius(const SkMatrix& matrix, SkScalar* value) { - if (matrix.getType() & SkMatrix::kPerspective_Mask) { + if (matrix.hasPerspective()) { return false; } SkVector src[2], dst[2]; @@ -1562,7 +1562,7 @@ void SkDraw::drawText(const char text[], size_t byteLength, } if (/*paint.isLinearText() ||*/ - (fMatrix->getType() & SkMatrix::kPerspective_Mask)) { + (fMatrix->hasPerspective())) { this->drawText_asPaths(text, byteLength, x, y, paint); handle_aftertext(this, paint, underlineWidth, underlineStart); return; @@ -1760,7 +1760,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, } if (/*paint.isLinearText() ||*/ - (fMatrix->getType() & SkMatrix::kPerspective_Mask)) { + (fMatrix->hasPerspective())) { // TODO !!!! // this->drawText_asPaths(text, byteLength, x, y, paint); return; diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index 06bca1e..da66a68 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -46,10 +46,6 @@ void SkMatrix::reset() { this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask); } -static inline int has_perspective(const SkMatrix& matrix) { - return matrix.getType() & SkMatrix::kPerspective_Mask; -} - // this guy aligns with the masks, so we can compute a mask from a varaible 0/1 enum { kTranslate_Shift, @@ -71,22 +67,36 @@ enum { uint8_t SkMatrix::computeTypeMask() const { unsigned mask = 0; +#ifdef SK_SCALAR_SLOW_COMPARES if (SkScalarAs2sCompliment(fMat[kMPersp0]) | SkScalarAs2sCompliment(fMat[kMPersp1]) | (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) { mask |= kPerspective_Mask; } - + if (SkScalarAs2sCompliment(fMat[kMTransX]) | SkScalarAs2sCompliment(fMat[kMTransY])) { mask |= kTranslate_Mask; } +#else + // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment + // is a win, but replacing those below is not. We don't yet understand + // that result. + if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || + fMat[kMPersp2] != kMatrix22Elem) { + mask |= kPerspective_Mask; + } + + if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) { + mask |= kTranslate_Mask; + } +#endif int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]); int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]); int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]); int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]); - + if (m01 | m10) { mask |= kAffine_Mask; } @@ -94,21 +104,21 @@ uint8_t SkMatrix::computeTypeMask() const { if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) { mask |= kScale_Mask; } - + if ((mask & kPerspective_Mask) == 0) { // map non-zero to 1 m00 = m00 != 0; m01 = m01 != 0; m10 = m10 != 0; m11 = m11 != 0; - + // record if the (p)rimary and (s)econdary diagonals are all 0 or // all non-zero (answer is 0 or 1) int dp0 = (m00 | m11) ^ 1; // true if both are 0 int dp1 = m00 & m11; // true if both are 1 int ds0 = (m01 | m10) ^ 1; // true if both are 0 int ds1 = m01 & m10; // true if both are 1 - + // return 1 if primary is 1 and secondary is 0 or // primary is 0 and secondary is 1 mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; @@ -151,7 +161,7 @@ void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) { } bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) { - if (has_perspective(*this)) { + if (this->hasPerspective()) { SkMatrix m; m.setTranslate(dx, dy); return this->preConcat(m); @@ -169,7 +179,7 @@ bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) { } bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) { - if (has_perspective(*this)) { + if (this->hasPerspective()) { SkMatrix m; m.setTranslate(dx, dy); return this->postConcat(m); @@ -754,7 +764,7 @@ bool SkMatrix::pdfTransform(SkScalar transform[6]) const { SkMatrix identity; const SkMatrix* use = this; bool ret = true; - if (has_perspective(*this)) { + if (this->hasPerspective()) { identity.reset(); use = &identity; ret = false; @@ -769,7 +779,7 @@ bool SkMatrix::pdfTransform(SkScalar transform[6]) const { } bool SkMatrix::invert(SkMatrix* inv) const { - int isPersp = has_perspective(*this); + int isPersp = this->hasPerspective(); int shift; SkDetScalar scale = sk_inv_determinant(fMat, isPersp, &shift); @@ -951,7 +961,7 @@ void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[], void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) { - SkASSERT((m.getType() & kPerspective_Mask) == 0); + SkASSERT(!m.hasPerspective()); if (count > 0) { SkScalar mx = m.fMat[kMScaleX]; @@ -973,7 +983,7 @@ void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[], void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) { - SkASSERT(m.getType() & kPerspective_Mask); + SkASSERT(m.hasPerspective()); #ifdef SK_SCALAR_IS_FIXED SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]); @@ -1030,7 +1040,7 @@ void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const { /////////////////////////////////////////////////////////////////////////////// void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const { - if (this->getType() & kPerspective_Mask) { + if (this->hasPerspective()) { SkPoint origin; MapXYProc proc = this->getMapXYProc(); @@ -1085,7 +1095,7 @@ SkScalar SkMatrix::mapRadius(SkScalar radius) const { void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, SkPoint* pt) { - SkASSERT(m.getType() & kPerspective_Mask); + SkASSERT(m.hasPerspective()); SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) + SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; @@ -1747,4 +1757,3 @@ void SkMatrix::toDumpString(SkString* str) const { fMat[6], fMat[7], fMat[8]); #endif } - diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index a607424..c29c4f0 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1242,10 +1242,10 @@ static SkScalar sk_relax(SkScalar x) { void SkScalerContext::MakeRec(const SkPaint& paint, const SkMatrix* deviceMatrix, Rec* rec) { - SkASSERT(deviceMatrix == NULL || - (deviceMatrix->getType() & SkMatrix::kPerspective_Mask) == 0); + SkASSERT(deviceMatrix == NULL || !deviceMatrix->hasPerspective()); - rec->fFontID = SkTypeface::UniqueID(paint.getTypeface()); + rec->fOrigFontID = SkTypeface::UniqueID(paint.getTypeface()); + rec->fFontID = rec->fOrigFontID; rec->fTextSize = paint.getTextSize(); rec->fPreScaleX = paint.getTextScaleX(); rec->fPreSkewX = paint.getTextSkewX(); diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index ca57237..b88b20f 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -949,7 +949,7 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { dst = (SkPath*)this; } - if (matrix.getType() & SkMatrix::kPerspective_Mask) { + if (matrix.hasPerspective()) { SkPath tmp; tmp.fFillType = fFillType; @@ -1532,4 +1532,3 @@ SkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) { } return state.getConvexity(); } - diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index 6b5f663..05439f1 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -180,7 +180,7 @@ static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) { // fonthost will determine the next possible font to search, based // on the current font in fRec. It will return NULL if ctx is our // last font that can be searched (i.e. ultimate fallback font) - uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID); + uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID); if (0 == newFontID) { return NULL; } diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index 398f786..4dc2cd3 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -26,8 +26,20 @@ #define SCALE (1 << SHIFT) #define MASK (SCALE - 1) +/* + We have two techniques for capturing the output of the supersampler: + - SUPERMASK, which records a large mask-bitmap + this is often faster for small, complex objects + - RLE, which records a rle-encoded scanline + this is often faster for large objects with big spans + + NEW_AA is a set of code-changes to try to make both paths produce identical + results. Its not quite there yet, though the remaining differences may be + in the subsequent blits, and not in the different masks/runs... + */ //#define FORCE_SUPERMASK //#define FORCE_RLE +//#define SK_SUPPORT_NEW_AA /////////////////////////////////////////////////////////////////////////////// @@ -281,9 +293,17 @@ static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount, edge of the current span round to the same super-sampled x value, I might overflow to 256 with this add, hence the funny subtract. */ +#ifdef SK_SUPPORT_NEW_AA + if (startAlpha) { + unsigned tmp = *alpha + startAlpha; + SkASSERT(tmp <= 256); + *alpha++ = SkToU8(tmp - (tmp >> 8)); + } +#else unsigned tmp = *alpha + startAlpha; SkASSERT(tmp <= 256); *alpha++ = SkToU8(tmp - (tmp >> 8)); +#endif if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) { // loop until we're quad-byte aligned @@ -365,7 +385,15 @@ void MaskSuperBlitter::blitH(int x, int y, int width) { SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1); add_aa_span(row, coverage_to_alpha(fe - fb)); } else { +#ifdef SK_SUPPORT_NEW_AA + if (0 == fb) { + n += 1; + } else { + fb = (1 << SHIFT) - fb; + } +#else fb = (1 << SHIFT) - fb; +#endif SkASSERT(row >= fMask.fImage); SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1); add_aa_span(row, coverage_to_alpha(fb), n, coverage_to_alpha(fe), diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index 7b46953..b51705e 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -185,7 +185,7 @@ void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) { MatrixClass mc = kLinear_MatrixClass; - if (mat.getType() & SkMatrix::kPerspective_Mask) { + if (mat.hasPerspective()) { if (mat.fixedStepInX(0, NULL, NULL)) { mc = kFixedStepInX_MatrixClass; } else { diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp index 34c3238..5d0fdcf 100644 --- a/src/effects/SkLayerDrawLooper.cpp +++ b/src/effects/SkLayerDrawLooper.cpp @@ -37,11 +37,11 @@ SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) { return &rec->fPaint; } -SkPaint* SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) { +void SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) { LayerInfo info; info.fOffset.set(dx, dy); - return this->addLayer(info); + (void)this->addLayer(info); } void SkLayerDrawLooper::init(SkCanvas* canvas) { diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 7166a07..ae8ab6c 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1211,16 +1211,23 @@ static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state, } /* - * Skia calls us with fx,fy already biased by 1/2. It does this to speed - * up rounding these, so that all of its procs (like us) can just call - * SkFixedFloor and get the "rounded" value. + * What should we do with fy? (assuming horizontal/latin text) * - * We take advantage of that for fx, where we pass a rounded value, but - * we want the fractional fy, so we have to unbias it first. + * The raster code calls SkFixedFloorToFixed on it, as it does with fx. + * It calls that rather than round, because our caller has already added + * SK_FixedHalf, so that calling floor gives us the rounded integer. + * + * Test code between raster and gpu (they should draw the same) + * + * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint); + * + * Perhaps we should only perform this integralization if there is no + * fExtMatrix... */ + fy = SkFixedFloorToFixed(fy); + procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0), - SkIntToFixed(SkFixedFloor(fx)), - fy - SK_FixedHalf, + SkFixedFloorToFixed(fx), fy, procs->fFontScaler); } diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index d01577d..e9b3986 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -632,7 +632,7 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, } } -uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { load_system_fonts(); /* First see if fontID is already one of our fallbacks. If so, return @@ -642,7 +642,7 @@ uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { */ const uint32_t* list = gFallbackFonts; for (int i = 0; list[i] != 0; i++) { - if (list[i] == fontID) { + if (list[i] == currFontID) { return list[i+1]; } } diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp index 21fc773..332c911 100644 --- a/src/ports/SkFontHost_fontconfig.cpp +++ b/src/ports/SkFontHost_fontconfig.cpp @@ -364,8 +364,7 @@ SkTypeface* SkFontHost::Deserialize(SkStream* stream) { return NULL; } -// static -uint32_t SkFontHost::NextLogicalFont(SkFontID fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { // We don't handle font fallback, WebKit does. return 0; } diff --git a/src/ports/SkFontHost_linux.cpp b/src/ports/SkFontHost_linux.cpp index 37c2c35..9ede78c 100644 --- a/src/ports/SkFontHost_linux.cpp +++ b/src/ports/SkFontHost_linux.cpp @@ -578,7 +578,7 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, return 0; } -uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { return 0; } diff --git a/src/ports/SkFontHost_mac_atsui.cpp b/src/ports/SkFontHost_mac_atsui.cpp index 5bc438a..fb61c60 100644 --- a/src/ports/SkFontHost_mac_atsui.cpp +++ b/src/ports/SkFontHost_mac_atsui.cpp @@ -491,9 +491,9 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return new SkScalerContext_Mac(desc); } -uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { uint32_t newFontID = find_default_fontID(); - if (newFontID == fontID) { + if (newFontID == currFontID) { newFontID = 0; } return newFontID; diff --git a/src/ports/SkFontHost_mac_coretext.cpp b/src/ports/SkFontHost_mac_coretext.cpp index ad57e16..f9eba95 100644 --- a/src/ports/SkFontHost_mac_coretext.cpp +++ b/src/ports/SkFontHost_mac_coretext.cpp @@ -887,10 +887,10 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return new SkScalerContext_Mac(desc); } -SkFontID SkFontHost::NextLogicalFont(SkFontID fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { SkFontID nextFontID = 0; SkTypeface* face = GetDefaultFace(); - if (face->uniqueID() != fontID) { + if (face->uniqueID() != currFontID) { nextFontID = face->uniqueID(); } return nextFontID; diff --git a/src/ports/SkFontHost_none.cpp b/src/ports/SkFontHost_none.cpp index 91546f8..0593dd5 100644 --- a/src/ports/SkFontHost_none.cpp +++ b/src/ports/SkFontHost_none.cpp @@ -80,7 +80,7 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return NULL; } -uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { return 0; } diff --git a/src/ports/SkFontHost_simple.cpp b/src/ports/SkFontHost_simple.cpp index 54d326e..d63aec2 100644 --- a/src/ports/SkFontHost_simple.cpp +++ b/src/ports/SkFontHost_simple.cpp @@ -620,7 +620,7 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, } } -uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { load_system_fonts(); /* First see if fontID is already one of our fallbacks. If so, return @@ -630,7 +630,7 @@ uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { */ const uint32_t* list = gFallbackFonts; for (int i = 0; list[i] != 0; i++) { - if (list[i] == fontID) { + if (list[i] == currFontID) { return list[i+1]; } } diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index f5d126e..62b0a0c 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -179,7 +179,7 @@ SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { return face; } -uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { // Zero means that we don't have any fallback fonts for this fontID. // This function is implemented on Android, but doesn't have much // meaning here. diff --git a/src/utils/unix/SkOSWindow_Unix.cpp b/src/utils/unix/SkOSWindow_Unix.cpp index ae881d5..652a1ae 100644 --- a/src/utils/unix/SkOSWindow_Unix.cpp +++ b/src/utils/unix/SkOSWindow_Unix.cpp @@ -18,8 +18,8 @@ extern "C" { #include "keysym2ucs.h" } -const int WIDTH = 1000; -const int HEIGHT = 1000; +const int WIDTH = 500; +const int HEIGHT = 500; // Determine which events to listen for. const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask @@ -33,13 +33,16 @@ SkOSWindow::SkOSWindow(void* unused) : fGLAttached(false), fVi(0) // Attempt to create a window that supports GL GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 8, None }; - fVi = glXChooseVisual(dsp, 0, att); + fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att); if (fVi) { + Colormap colorMap = XCreateColormap(dsp, RootWindow(dsp, fVi->screen), + fVi->visual, AllocNone); XSetWindowAttributes swa; + swa.colormap = colorMap; swa.event_mask = EVENT_MASK; - fUnixWindow.fWin = XCreateWindow(dsp, DefaultRootWindow(dsp), + fUnixWindow.fWin = XCreateWindow(dsp, RootWindow(dsp, fVi->screen), 0, 0, WIDTH, HEIGHT, 0, fVi->depth, - InputOutput, fVi->visual, CWEventMask, &swa); + InputOutput, fVi->visual, CWEventMask | CWColormap, &swa); } else { // Create a simple window instead. We will not be able to @@ -51,7 +54,6 @@ SkOSWindow::SkOSWindow(void* unused) : fGLAttached(false), fVi(0) fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL); } this->resize(WIDTH, HEIGHT); - fRestart = false; fUnixWindow.fGLCreated = false; } @@ -84,14 +86,6 @@ void SkOSWindow::post_linuxevent() (XEvent*) &event); } -void SkOSWindow::restartLoop() -{ - // We have a new window, so we need to set the title again and restart the - // loop. - this->onSetTitle(this->getTitle()); - fRestart = true; -} - void SkOSWindow::loop() { Display* dsp = fUnixWindow.fDisplay; @@ -100,11 +94,6 @@ void SkOSWindow::loop() bool loop = true; XEvent evt; while (loop) { - if (fRestart) { - fRestart = false; - this->loop(); - return; - } XNextEvent(dsp, &evt); switch (evt.type) { case Expose: @@ -194,8 +183,6 @@ bool SkOSWindow::attachGL() glXMakeCurrent(dsp, fUnixWindow.fWin, fUnixWindow.fGLContext); fGLAttached = true; - - this->restartLoop(); return true; } @@ -205,7 +192,6 @@ void SkOSWindow::detachGL() fGLAttached = false; // Returns back to normal drawing. glXMakeCurrent(fUnixWindow.fDisplay, None, NULL); - this->restartLoop(); // Ensure that we redraw when switching back to raster. this->inval(NULL); } diff --git a/tests/Android.mk b/tests/Android.mk index 5823b0e..4db6c75 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \ PackBitsTest.cpp \ PaintTest.cpp \ ParsePathTest.cpp \ + PathCoverageTest.cpp \ PathMeasureTest.cpp \ PathTest.cpp \ Reader32Test.cpp \ diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp index 7a9364f..efdad3a 100644 --- a/tests/MathTest.cpp +++ b/tests/MathTest.cpp @@ -188,7 +188,7 @@ static float make_zero() { static void unittest_isfinite(skiatest::Reporter* reporter) { #ifdef SK_SCALAR_IS_FLOAT - float nan = ::asin(2); + float nan = sk_float_asin(2); float inf = 1.0 / make_zero(); float big = 3.40282e+038; diff --git a/tests/Matrix44Test.cpp b/tests/Matrix44Test.cpp new file mode 100644 index 0000000..8755bd3 --- /dev/null +++ b/tests/Matrix44Test.cpp @@ -0,0 +1,70 @@ +#include "Test.h" +#include "SkMatrix44.h" + +static bool nearly_equal_scalar(SkScalar a, SkScalar b) { + // Note that we get more compounded error for multiple operations when + // SK_SCALAR_IS_FIXED. +#ifdef SK_SCALAR_IS_FLOAT + const SkScalar tolerance = SK_Scalar1 / 200000; +#else + const SkScalar tolerance = SK_Scalar1 / 1024; +#endif + + return SkScalarAbs(a - b) <= tolerance; +} + +static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) { + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + if (!nearly_equal_scalar(a.get(i, j), b.get(i, j))) { + printf("not equal %g %g\n", (float)a.get(i, j), (float)b.get(i, j)); + return false; + } + } + } + return true; +} + +static bool is_identity(const SkMatrix44& m) { + SkMatrix44 identity; + identity.reset(); + return nearly_equal(m, identity); +} + + +void TestMatrix44(skiatest::Reporter* reporter) { + SkMatrix44 mat, inverse, iden1, iden2, rot; + + mat.reset(); + mat.setTranslate(SK_Scalar1, SK_Scalar1, SK_Scalar1); + mat.invert(&inverse); + iden1.setConcat(mat, inverse); + REPORTER_ASSERT(reporter, is_identity(iden1)); + + mat.setScale(SkIntToScalar(2), SkIntToScalar(2), SkIntToScalar(2)); + mat.invert(&inverse); + iden1.setConcat(mat, inverse); + REPORTER_ASSERT(reporter, is_identity(iden1)); + + mat.setScale(SK_Scalar1/2, SK_Scalar1/2, SK_Scalar1/2); + mat.invert(&inverse); + iden1.setConcat(mat, inverse); + REPORTER_ASSERT(reporter, is_identity(iden1)); + + mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20)); + rot.setRotateDegreesAbout( + SkIntToScalar(0), + SkIntToScalar(0), + SkIntToScalar(-1), + SkIntToScalar(90)); + mat.postConcat(rot); + REPORTER_ASSERT(reporter, mat.invert(NULL)); + mat.invert(&inverse); + iden1.setConcat(mat, inverse); + REPORTER_ASSERT(reporter, is_identity(iden1)); + iden2.setConcat(inverse, mat); + REPORTER_ASSERT(reporter, is_identity(iden2)); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44) diff --git a/tests/PathCoverageTest.cpp b/tests/PathCoverageTest.cpp new file mode 100644 index 0000000..8676029 --- /dev/null +++ b/tests/PathCoverageTest.cpp @@ -0,0 +1,129 @@ +#include "SkPoint.h" +#include "SkScalar.h" +#include "Test.h" + +/* + Duplicates lots of code from gpu/src/GrPathUtils.cpp + It'd be nice not to do so, but that code's set up currently to only have a single implementation. +*/ + +#define MAX_COEFF_SHIFT 6 +static const uint32_t MAX_POINTS_PER_CURVE = 1 << MAX_COEFF_SHIFT; + +static inline int cheap_distance(SkScalar dx, SkScalar dy) { + int idx = SkAbs32(SkScalarRound(dx)); + int idy = SkAbs32(SkScalarRound(dy)); + if (idx > idy) { + idx += idy >> 1; + } else { + idx = idy + (idx >> 1); + } + return idx; +} + +static inline int diff_to_shift(SkScalar dx, SkScalar dy) { + int dist = cheap_distance(dx, dy); + return (32 - SkCLZ(dist)); +} + +uint32_t estimatedQuadraticPointCount(const SkPoint points[], SkScalar tol) { + int shift = diff_to_shift(points[1].fX * 2 - points[2].fX - points[0].fX, + points[1].fY * 2 - points[2].fY - points[0].fY); + SkASSERT(shift >= 0); + //SkDebugf("Quad shift %d;", shift); + // bias to more closely approximate exact value, then clamp to zero + shift -= 2; + shift &= ~(shift>>31); + + if (shift > MAX_COEFF_SHIFT) { + shift = MAX_COEFF_SHIFT; + } + uint32_t count = 1 << shift; + //SkDebugf(" biased shift %d, scale %u\n", shift, count); + return count; +} + +uint32_t computedQuadraticPointCount(const SkPoint points[], SkScalar tol) { + SkScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]); + if (d < tol) { + return 1; + } else { + int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol))); + uint32_t count = SkMinScalar(SkNextPow2(temp), MAX_POINTS_PER_CURVE); + return count; + } +} + +// Curve from samplecode/SampleSlides.cpp +static const int gXY[] = { + 4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4 +}; + +static const int gSawtooth[] = { + 0, 0, 10, 10, 20, 20, 30, 10, 40, 0, 50, -10, 60, -20, 70, -10, 80, 0 +}; + +static const int gOvalish[] = { + 0, 0, 5, 15, 20, 20, 35, 15, 40, 0 +}; + +static const int gSharpSawtooth[] = { + 0, 0, 1, 10, 2, 0, 3, -10, 4, 0 +}; + +// Curve crosses back over itself around 0,10 +static const int gRibbon[] = { + -4, 0, 4, 20, 0, 25, -4, 20, 4, 0 +}; + +static bool one_d_pe(const int* array, const unsigned int count, + skiatest::Reporter* reporter) { + SkPoint path [3]; + path[1] = SkPoint::Make(SkIntToScalar(array[0]), SkIntToScalar(array[1])); + path[2] = SkPoint::Make(SkIntToScalar(array[2]), SkIntToScalar(array[3])); + int numErrors = 0; + for (unsigned i = 4; i < (count); i += 2) { + path[0] = path[1]; + path[1] = path[2]; + path[2] = SkPoint::Make(SkIntToScalar(array[i]), + SkIntToScalar(array[i+1])); + uint32_t computedCount = + computedQuadraticPointCount(path, SkIntToScalar(1)); + uint32_t estimatedCount = + estimatedQuadraticPointCount(path, SkIntToScalar(1)); + // Allow estimated to be off by a factor of two, but no more. + if ((estimatedCount > 2 * computedCount) || + (computedCount > estimatedCount * 2)) { + SkString errorDescription; + errorDescription.printf( + "Curve from %.2f %.2f through %.2f %.2f to %.2f %.2f " + "computes %d, estimates %d\n", + path[0].fX, path[0].fY, path[1].fX, path[1].fY, + path[2].fX, path[2].fY, computedCount, estimatedCount); + numErrors++; + reporter->reportFailed(errorDescription); + } + } + + if (numErrors > 0) + printf("%d curve segments differ\n", numErrors); + return (numErrors == 0); +} + + + +static void TestQuadPointCount(skiatest::Reporter* reporter) { + one_d_pe(gXY, SK_ARRAY_COUNT(gXY), reporter); + one_d_pe(gSawtooth, SK_ARRAY_COUNT(gSawtooth), reporter); + one_d_pe(gOvalish, SK_ARRAY_COUNT(gOvalish), reporter); + one_d_pe(gSharpSawtooth, SK_ARRAY_COUNT(gSharpSawtooth), reporter); + one_d_pe(gRibbon, SK_ARRAY_COUNT(gRibbon), reporter); +} + +static void TestPathCoverage(skiatest::Reporter* reporter) { + TestQuadPointCount(reporter); + +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("PathCoverage", PathCoverageTestClass, TestPathCoverage) diff --git a/tests/Reader32Test.cpp b/tests/Reader32Test.cpp index c752b0f..cad2d33 100644 --- a/tests/Reader32Test.cpp +++ b/tests/Reader32Test.cpp @@ -52,7 +52,9 @@ static void Tests(skiatest::Reporter* reporter) { const int32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; const SkScalar data2[] = { 0, SK_Scalar1, -SK_Scalar1, SK_Scalar1/2 }; - char buffer[SkMax32(sizeof(data), sizeof(data2))]; + const size_t bufsize = sizeof(data) > sizeof(data2) ? + sizeof(data) : sizeof(data2); + char buffer[bufsize]; reader.setMemory(data, sizeof(data)); for (i = 0; i < SK_ARRAY_COUNT(data); ++i) { diff --git a/tests/tests_files.mk b/tests/tests_files.mk index 9b90179..667c9b5 100644 --- a/tests/tests_files.mk +++ b/tests/tests_files.mk @@ -20,6 +20,7 @@ SOURCE := \ PackBitsTest.cpp \ PaintTest.cpp \ ParsePathTest.cpp \ + PathCoverageTest.cpp \ PathMeasureTest.cpp \ PathTest.cpp \ Reader32Test.cpp \ |