BenchGpuTimer_gl.cpp revision 0199fa7423f89a129da2b22a488f2c18e2e4727f
1#include "BenchGpuTimer_gl.h"
2#include <string.h>
3
4//GL
5#define BENCH_GL_FUNCTION_TYPE
6#if defined(SK_MESA)
7    #include <GL/osmesa.h>
8    #define SK_BENCH_CONTEXT_CHECK (NULL != OSMesaGetCurrentContext())
9
10    #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
11            OSMesaGetProcAddress("gl" #F);
12    #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
13            OSMesaGetProcAddress("gl" #F #S);
14
15#elif defined(SK_BUILD_FOR_WIN32)
16    #define WIN32_LEAN_AND_MEAN 1
17    #include <Windows.h>
18    #include <GL/GL.h>
19    #define SK_BENCH_CONTEXT_CHECK (NULL != wglGetCurrentContext())
20
21    #undef BENCH_GL_FUNCTION_TYPE
22    #define BENCH_GL_FUNCTION_TYPE __stdcall
23
24    #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
25            wglGetProcAddress("gl" #F);
26    #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
27            wglGetProcAddress("gl" #F #S);
28
29#elif defined(SK_BUILD_FOR_MAC)
30    #include <OpenGL/gl.h>
31    #include <OpenGL/CGLCurrent.h>
32    #define SK_BENCH_CONTEXT_CHECK (NULL != CGLGetCurrentContext())
33
34#elif defined(SK_BUILD_FOR_UNIX)
35    #include <GL/gl.h>
36    #include <GL/glx.h>
37    #define SK_BENCH_CONTEXT_CHECK (NULL != glXGetCurrentContext())
38
39    #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
40            glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F));
41    #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
42            glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F #S));
43#else
44    #error unsupported platform
45#endif
46
47#define BenchGL_TIME_ELAPSED 0x88BF
48#define BenchGL_QUERY_RESULT 0x8866
49#define BenchGL_QUERY_RESULT_AVAILABLE 0x8867
50
51#if defined(SK_BUILD_FOR_WIN32)
52typedef UINT64 BenchGLuint64;
53#else
54#include <stdint.h>
55typedef uint64_t BenchGLuint64;
56#endif
57
58typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGenQueriesProc) (GLsizei n, GLuint *ids);
59typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLBeginQueryProc) (GLenum target, GLuint id);
60typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLEndQueryProc) (GLenum target);
61typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLDeleteQueriesProc) (GLsizei n, const GLuint *ids);
62typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectivProc) (GLuint id, GLenum pname, GLint *params);
63typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectui64vProc) (GLuint id, GLenum pname, BenchGLuint64 *params);
64
65struct BenchGLInterface {
66    bool fHasTimer;
67    BenchGLGenQueriesProc fGenQueries;
68    BenchGLBeginQueryProc fBeginQuery;
69    BenchGLEndQueryProc fEndQuery;
70    BenchGLDeleteQueriesProc fDeleteQueries;
71    BenchGLGetQueryObjectivProc fGetQueryObjectiv;
72    BenchGLGetQueryObjectui64vProc fGetQueryObjectui64v;
73};
74
75static bool BenchGLCheckExtension(const char* ext,
76                                  const char* extensionString) {
77    int extLength = strlen(ext);
78
79    while (true) {
80        int n = strcspn(extensionString, " ");
81        if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
82            return true;
83        }
84        if (0 == extensionString[n]) {
85            return false;
86        }
87        extensionString += n+1;
88    }
89
90    return false;
91}
92
93static BenchGLInterface gBenchGL;
94static bool gBenchGLInterfaceInit = false;
95
96static void BenchGLSetDefaultGLInterface() {
97    gBenchGL.fHasTimer = false;
98    if (gBenchGLInterfaceInit || !SK_BENCH_CONTEXT_CHECK) return;
99
100    const char* glExts =
101        reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
102    const GLboolean ext =
103        BenchGLCheckExtension("GL_EXT_timer_query", glExts);
104    const GLboolean arb =
105        BenchGLCheckExtension("GL_ARB_timer_query", glExts);
106    if (ext || arb) {
107#if defined(SK_BUILD_FOR_MAC)
108        #if GL_EXT_timer_query || GL_ARB_timer_query
109        gBenchGL.fHasTimer = true;
110        gBenchGL.fGenQueries = glGenQueries;
111        gBenchGL.fBeginQuery = glBeginQuery;
112        gBenchGL.fEndQuery = glEndQuery;
113        gBenchGL.fDeleteQueries = glDeleteQueries;
114        gBenchGL.fGetQueryObjectiv = glGetQueryObjectiv;
115        #endif
116        #if GL_ARB_timer_query
117        gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64v;
118        #elif GL_EXT_timer_query
119        gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
120        #endif
121#else
122        gBenchGL.fHasTimer = true;
123        SK_GL_GET_PROC(GenQueries)
124        SK_GL_GET_PROC(BeginQuery)
125        SK_GL_GET_PROC(EndQuery)
126        SK_GL_GET_PROC(DeleteQueries)
127
128        SK_GL_GET_PROC(GetQueryObjectiv)
129        if (arb) {
130            SK_GL_GET_PROC(GetQueryObjectui64v)
131        } else {
132            SK_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT)
133        }
134#endif
135    }
136    gBenchGLInterfaceInit = true;
137}
138
139BenchGpuTimer::BenchGpuTimer() {
140    BenchGLSetDefaultGLInterface();
141    if (gBenchGL.fHasTimer) {
142        gBenchGL.fGenQueries(1, &this->fQuery);
143    }
144}
145
146BenchGpuTimer::~BenchGpuTimer() {
147    if (gBenchGL.fHasTimer) {
148        gBenchGL.fDeleteQueries(1, &this->fQuery);
149    }
150}
151
152void BenchGpuTimer::startGpu() {
153    if (!gBenchGL.fHasTimer) return;
154
155    this->fStarted = true;
156    gBenchGL.fBeginQuery(BenchGL_TIME_ELAPSED, this->fQuery);
157}
158
159/**
160 * It is important to stop the cpu clocks first,
161 * as this will cpu wait for the gpu to finish.
162 */
163double BenchGpuTimer::endGpu() {
164    if (!gBenchGL.fHasTimer) return 0;
165
166    this->fStarted = false;
167    gBenchGL.fEndQuery(BenchGL_TIME_ELAPSED);
168
169    GLint available = 0;
170    while (!available) {
171        gBenchGL.fGetQueryObjectiv(this->fQuery
172                                 , BenchGL_QUERY_RESULT_AVAILABLE
173                                 , &available);
174    }
175    BenchGLuint64 totalGPUTimeElapsed = 0;
176    gBenchGL.fGetQueryObjectui64v(this->fQuery
177                                , BenchGL_QUERY_RESULT
178                                , &totalGPUTimeElapsed);
179
180    return totalGPUTimeElapsed / 1000000.0;
181}
182