Higher resolution timers for bench.
http://codereview.appspot.com/4548090/


git-svn-id: http://skia.googlecode.com/svn/trunk@1534 2bbb7eff-a529-9590-31e7-b0007b416f81
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;
+}