aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDerek Sollenberger <djsollen@google.com>2011-06-24 11:30:32 -0700
committerAndroid Code Review <code-review@android.com>2011-06-24 11:30:32 -0700
commita4f65ce780e319268a9f300a9edbc07657adff0a (patch)
tree91583d9787e2efdf5f98026a127b688da07823f1
parent3c1b974a7eae43f061c5e773f8cef0d545a087b2 (diff)
parent0199fa7423f89a129da2b22a488f2c18e2e4727f (diff)
downloadexternal_skia-a4f65ce780e319268a9f300a9edbc07657adff0a.zip
external_skia-a4f65ce780e319268a9f300a9edbc07657adff0a.tar.gz
external_skia-a4f65ce780e319268a9f300a9edbc07657adff0a.tar.bz2
Merge "Skia Merge (revision 1562)"
-rw-r--r--bench/Android.mk15
-rw-r--r--bench/BenchGpuTimer_gl.cpp181
-rw-r--r--bench/BenchGpuTimer_gl.h33
-rw-r--r--bench/BenchGpuTimer_none.cpp14
-rw-r--r--bench/BenchGpuTimer_none.h12
-rw-r--r--bench/BenchSysTimer_c.cpp20
-rw-r--r--bench/BenchSysTimer_c.h19
-rw-r--r--bench/BenchSysTimer_mach.cpp69
-rw-r--r--bench/BenchSysTimer_mach.h19
-rw-r--r--bench/BenchSysTimer_posix.cpp50
-rw-r--r--bench/BenchSysTimer_posix.h19
-rw-r--r--bench/BenchSysTimer_windows.cpp55
-rw-r--r--bench/BenchSysTimer_windows.h19
-rw-r--r--bench/BenchTimer.cpp48
-rw-r--r--bench/BenchTimer.h27
-rw-r--r--bench/MatrixBench.cpp93
-rw-r--r--bench/ScalarBench.cpp97
-rw-r--r--bench/benchmain.cpp46
-rw-r--r--gm/gmmain.cpp54
-rw-r--r--gpu/include/GrContext.h7
-rw-r--r--gpu/include/GrGpu.h2
-rw-r--r--gpu/src/GrContext.cpp19
-rw-r--r--gpu/src/GrGpu.cpp2
-rw-r--r--gpu/src/GrGpuGLShaders.cpp5
-rw-r--r--gpu/src/GrGpuGLShaders.h2
-rw-r--r--gpu/src/android/GrGLDefaultInterface_android.cpp138
-rw-r--r--gpu/src/app-android.cpp4
-rw-r--r--gpu/src/skia/SkUIView.mm4
-rw-r--r--include/core/SkDrawFilter.h2
-rw-r--r--include/core/SkFixed.h3
-rw-r--r--include/core/SkFontHost.h24
-rw-r--r--include/core/SkScalar.h2
-rw-r--r--include/core/SkScalerContext.h1
-rw-r--r--include/effects/SkLayerDrawLooper.h4
-rw-r--r--include/views/SkOSWindow_Unix.h2
-rw-r--r--samplecode/SampleApp.cpp2
-rw-r--r--src/core/SkBlitter_ARGB32.cpp9
-rw-r--r--src/core/SkCanvas.cpp3
-rw-r--r--src/core/SkDraw.cpp6
-rw-r--r--src/core/SkMatrix.cpp45
-rw-r--r--src/core/SkPaint.cpp6
-rw-r--r--src/core/SkPath.cpp3
-rw-r--r--src/core/SkScalerContext.cpp2
-rw-r--r--src/core/SkScan_AntiPath.cpp28
-rw-r--r--src/core/SkShader.cpp2
-rw-r--r--src/effects/SkLayerDrawLooper.cpp4
-rw-r--r--src/gpu/SkGpuDevice.cpp21
-rw-r--r--src/ports/SkFontHost_android.cpp4
-rw-r--r--src/ports/SkFontHost_fontconfig.cpp3
-rw-r--r--src/ports/SkFontHost_linux.cpp2
-rw-r--r--src/ports/SkFontHost_mac_atsui.cpp4
-rw-r--r--src/ports/SkFontHost_mac_coretext.cpp4
-rw-r--r--src/ports/SkFontHost_none.cpp2
-rw-r--r--src/ports/SkFontHost_simple.cpp4
-rwxr-xr-xsrc/ports/SkFontHost_win.cpp2
-rw-r--r--src/utils/unix/SkOSWindow_Unix.cpp30
-rw-r--r--tests/Android.mk1
-rw-r--r--tests/MathTest.cpp2
-rw-r--r--tests/Matrix44Test.cpp70
-rw-r--r--tests/PathCoverageTest.cpp129
-rw-r--r--tests/Reader32Test.cpp4
-rw-r--r--tests/tests_files.mk1
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 = &target;
@@ -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 \