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)
52 typedef UINT64 BenchGLuint64;
53 #else
54 #include <stdint.h>
55 typedef uint64_t BenchGLuint64;
56 #endif
57
58 typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGenQueriesProc) (GLsizei n, GLuint *ids);
59 typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLBeginQueryProc) (GLenum target, GLuint id);
60 typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLEndQueryProc) (GLenum target);
61 typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLDeleteQueriesProc) (GLsizei n, const GLuint *ids);
62 typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectivProc) (GLuint id, GLenum pname, GLint *params);
63 typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectui64vProc) (GLuint id, GLenum pname, BenchGLuint64 *params);
64
65 struct BenchGLInterface {
66 bool fHasTimer;
67 BenchGLGenQueriesProc fGenQueries;
68 BenchGLBeginQueryProc fBeginQuery;
69 BenchGLEndQueryProc fEndQuery;
70 BenchGLDeleteQueriesProc fDeleteQueries;
71 BenchGLGetQueryObjectivProc fGetQueryObjectiv;
72 BenchGLGetQueryObjectui64vProc fGetQueryObjectui64v;
73 };
74
BenchGLCheckExtension(const char * ext,const char * extensionString)75 static 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
93 static BenchGLInterface gBenchGL;
94 static bool gBenchGLInterfaceInit = false;
95
BenchGLSetDefaultGLInterface()96 static 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
BenchGpuTimer()139 BenchGpuTimer::BenchGpuTimer() {
140 BenchGLSetDefaultGLInterface();
141 if (gBenchGL.fHasTimer) {
142 gBenchGL.fGenQueries(1, &this->fQuery);
143 }
144 }
145
~BenchGpuTimer()146 BenchGpuTimer::~BenchGpuTimer() {
147 if (gBenchGL.fHasTimer) {
148 gBenchGL.fDeleteQueries(1, &this->fQuery);
149 }
150 }
151
startGpu()152 void 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 */
endGpu()163 double 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