]> git.cworth.org Git - fips/blob - glwrap.c
Wrap all OpenGL drawing calls, measure GPU time of each, and account to shader.
[fips] / glwrap.c
1 /* Copyright © 2013, Intel Corporation
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21
22 #include "fips.h"
23
24 #include "glwrap.h"
25
26 #define GL_GLEXT_PROTOTYPES
27 #include <GL/gl.h>
28
29 #include <sys/time.h>
30
31 #include "dlwrap.h"
32
33 typedef struct counter
34 {
35         unsigned id;
36         unsigned program;
37         struct counter *next;
38 } counter_t;
39
40 typedef struct program_metrics
41 {
42         unsigned id;
43         double ticks;
44 } program_metrics_t;
45
46 typedef struct context
47 {
48         unsigned int program;
49
50         counter_t *counter_head;
51         counter_t *counter_tail;
52
53         unsigned num_program_metrics;
54         program_metrics_t *program_metrics;
55 } context_t;
56
57 /* FIXME: Need a map from integers to context objects and track the
58  * current context with glXMakeContextCurrent, eglMakeCurrent, etc. */
59
60 context_t current_context;
61
62 static unsigned
63 add_counter (void)
64 {
65         counter_t *counter;
66
67         counter = malloc (sizeof(counter_t));
68         if (counter == NULL) {
69                 fprintf (stderr, "Out of memory\n");
70                 exit (1);
71         }
72
73         glGenQueries (1, &counter->id);
74
75         counter->program = current_context.program;
76         counter->next = NULL;
77
78         if (current_context.counter_tail) {
79                 current_context.counter_tail->next = counter;
80                 current_context.counter_tail = counter;
81         } else {
82                 current_context.counter_tail = counter;
83                 current_context.counter_head = counter;
84         }
85
86         return counter->id;
87 }
88
89 static void *
90 lookup (const char *name)
91 {
92         const char *libgl_filename = "libGL.so.1";
93         static void *libgl_handle = NULL;
94
95         if (! libgl_handle) {
96                 libgl_handle = dlwrap_real_dlopen (libgl_filename, RTLD_NOW | RTLD_DEEPBIND);
97                 if (! libgl_handle) {
98                         fprintf (stderr, "Error: Failed to dlopen %s\n",
99                                  libgl_filename);
100                         exit (1);
101                 }
102         }
103
104         return dlwrap_real_dlsym (libgl_handle, name);
105 }
106
107 /* Defer to the underlying, ''real'' function to do the real work. */
108 #define DEFER(function,...) do {                                \
109         static typeof(&function) real_ ## function;             \
110         if (! real_ ## function)                                \
111                 real_ ## function = lookup (#function);         \
112         real_ ## function(__VA_ARGS__);                         \
113 } while (0);
114
115 /* Execute a glBegineQuery/glEndQuery pair around an OpenGL call. */
116 #define TIMED_DEFER(function,...) do {                  \
117         unsigned counter;                               \
118         counter = add_counter ();                       \
119         glBeginQuery (GL_TIME_ELAPSED, counter);        \
120         DEFER(function, __VA_ARGS__);                   \
121         glEndQuery (GL_TIME_ELAPSED);                   \
122 } while (0);
123
124 /* Thanks to apitrace source code for the list of OpenGL draw calls. */
125 void
126 glDrawArrays (GLenum mode, GLint first, GLsizei count)
127 {
128         TIMED_DEFER (glDrawArrays, mode, first, count);
129 }
130
131 void
132 glDrawArraysEXT (GLenum mode, GLint first, GLsizei count)
133 {
134         TIMED_DEFER (glDrawArraysEXT, mode, first, count);
135 }
136
137 void
138 glDrawArraysIndirect (GLenum mode, const GLvoid *indirect)
139 {
140         TIMED_DEFER (glDrawArraysIndirect, mode, indirect);
141 }
142
143 void
144 glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count,
145                        GLsizei primcount)
146 {
147         TIMED_DEFER (glDrawArraysInstanced, mode, first, count, primcount);
148 }
149
150 void
151 glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count,
152                           GLsizei primcount)
153 {
154         TIMED_DEFER (glDrawArraysInstancedARB, mode, first, count, primcount);
155 }
156
157 void
158 glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count,
159                           GLsizei primcount)
160 {
161         TIMED_DEFER (glDrawArraysInstancedEXT, mode, start, count, primcount);
162 }
163
164 void
165 glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count,
166                                    GLsizei primcount, GLuint baseinstance)
167 {
168         TIMED_DEFER (glDrawArraysInstancedBaseInstance, mode,
169                      first, count, primcount, baseinstance);
170 }
171
172 void
173 glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width)
174 {
175         TIMED_DEFER (glDrawMeshArraysSUN, mode, first, count, width);
176 }
177
178 void
179 glMultiDrawArrays (GLenum mode, const GLint *first,
180                    const GLsizei *count, GLsizei primcount)
181 {
182         TIMED_DEFER (glMultiDrawArrays, mode, first, count, primcount);
183 }
184
185 void
186 glMultiDrawArraysEXT (GLenum mode, const GLint *first,
187                       const GLsizei *count, GLsizei primcount)
188 {
189         TIMED_DEFER (glMultiDrawArraysEXT, mode, first, count, primcount);
190 }
191
192 void
193 glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first,
194                           const GLsizei *count, GLsizei primcount,
195                           GLint modestride)
196 {
197         TIMED_DEFER (glMultiModeDrawArraysIBM, mode,
198                      first, count, primcount, modestride);
199 }
200
201 /* FIXME?
202 void
203 glMultiDrawArraysIndirect (...)
204 {
205         TIMED_DEFER (glMultiDrawArraysIndirect, ...);
206 }
207 */
208
209 void
210 glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect,
211                               GLsizei primcount, GLsizei stride)
212 {
213         TIMED_DEFER (glMultiDrawArraysIndirectAMD, mode,
214                      indirect, primcount, stride);
215 }
216
217 void
218 glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
219 {
220         TIMED_DEFER (glDrawElements, mode, count, type, indices);
221 }
222
223 void
224 glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type,
225                           const GLvoid *indices, GLint basevertex)
226 {
227         TIMED_DEFER (glDrawElementsBaseVertex, mode, count,
228                      type, indices, basevertex);
229 }
230
231 void
232 glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect)
233 {
234         TIMED_DEFER (glDrawElementsIndirect, mode, type, indirect);
235 }
236
237 void
238 glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type,
239                          const GLvoid *indices, GLsizei primcount)
240 {
241         TIMED_DEFER (glDrawElementsInstanced, mode, count,
242                      type, indices, primcount);
243 }
244
245 void
246 glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type,
247                             const GLvoid *indices, GLsizei primcount)
248 {
249         TIMED_DEFER (glDrawElementsInstancedARB, mode, count,
250                      type, indices, primcount);
251 }
252
253 void
254 glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type,
255                             const GLvoid *indices, GLsizei primcount)
256 {
257         TIMED_DEFER (glDrawElementsInstancedEXT, mode, count,
258                      type, indices, primcount);
259 }
260
261 void
262 glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type,
263                                    const GLvoid *indices, GLsizei primcount,
264                                    GLint basevertex)
265 {
266         TIMED_DEFER (glDrawElementsInstancedBaseVertex, mode, count,
267                      type, indices, primcount, basevertex);
268 }
269
270 void
271 glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type,
272                                      const void *indices, GLsizei primcount,
273                                      GLuint baseinstance)
274 {
275         TIMED_DEFER (glDrawElementsInstancedBaseInstance, mode, count, type,
276                      indices, primcount, baseinstance);
277 }
278
279 void
280 glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count,
281                       GLenum type, const void *indices, GLsizei primcount,
282                       GLint basevertex, GLuint baseinstance)
283 {
284         TIMED_DEFER (glDrawElementsInstancedBaseVertexBaseInstance, mode,
285                      count, type, indices, primcount, basevertex, baseinstance);
286 }
287
288 void
289 glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count,
290                      GLenum type, const GLvoid *indices)
291 {
292         TIMED_DEFER (glDrawRangeElements, mode, start, end,
293                      count, type, indices);
294 }
295
296 void
297 glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count,
298                         GLenum type, const GLvoid *indices)
299 {
300         TIMED_DEFER (glDrawRangeElementsEXT, mode, start, end,
301                      count, type, indices);
302 }
303
304 void
305 glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end,
306                                GLsizei count, GLenum type,
307                                const GLvoid *indices, GLint basevertex)
308 {
309         TIMED_DEFER (glDrawRangeElementsBaseVertex, mode, start, end,
310                      count, type, indices, basevertex);
311 }
312
313 void
314 glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type,
315                      const GLvoid* *indices, GLsizei primcount)
316 {
317         TIMED_DEFER (glMultiDrawElements, mode, count, type,
318                      indices, primcount);
319 }
320
321 void
322 glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count,
323                                GLenum type, const GLvoid* *indices,
324                                GLsizei primcount, const GLint *basevertex)
325 {
326         TIMED_DEFER (glMultiDrawElementsBaseVertex, mode, count,
327                      type, indices, primcount, basevertex);
328 }
329
330 void
331 glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type,
332                         const GLvoid* *indices, GLsizei primcount)
333 {
334         TIMED_DEFER (glMultiDrawElementsEXT, mode, count,
335                      type, indices, primcount);
336 }
337
338 void
339 glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count,
340                             GLenum type, const GLvoid* const *indices,
341                             GLsizei primcount, GLint modestride)
342 {
343         TIMED_DEFER (glMultiModeDrawElementsIBM, mode, count,
344                      type, indices, primcount, modestride);
345 }
346
347 /* FIXME?
348 void
349 glMultiDrawElementsIndirect (...)
350 {
351         TIMED_DEFER (glMultiDrawElementsIndirect, ...);
352 }
353 */
354
355 void
356 glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type,
357                                 const GLvoid *indirect,
358                                 GLsizei primcount, GLsizei stride)
359 {
360         TIMED_DEFER (glMultiDrawElementsIndirectAMD, mode, type,
361                      indirect, primcount, stride);
362 }
363
364 void
365 glCallList (GLuint list)
366 {
367         TIMED_DEFER (glCallList, list);
368 }
369
370 void
371 glCallLists (GLsizei n, GLenum type, const GLvoid *lists)
372 {
373         TIMED_DEFER (glCallLists, n, type, lists);
374 }
375
376 void
377 glClear (GLbitfield mask)
378 {
379         TIMED_DEFER (glClear, mask);
380 }
381
382 void
383 glEnd (void)
384 {
385         TIMED_DEFER (glEnd,);
386 }
387
388 void
389 glDrawPixels (GLsizei width, GLsizei height, GLenum format,
390               GLenum type, const GLvoid *pixels)
391 {
392         TIMED_DEFER (glDrawPixels, width, height, format, type, pixels);
393 }
394
395 void
396 glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
397                    GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
398                    GLbitfield mask, GLenum filter)
399 {
400         TIMED_DEFER (glBlitFramebuffer,
401                      srcX0, srcY0, srcX1, srcY1,
402                      dstX0, dstY0, dstX1, dstY1,
403                      mask, filter);
404 }
405
406 void
407 glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
408                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
409                       GLbitfield mask, GLenum filter)
410 {
411         TIMED_DEFER (glBlitFramebufferEXT,
412                      srcX0, srcY0, srcX1, srcY1,
413                      dstX0, dstY0, dstX1, dstY1,
414                      mask, filter);
415 }
416
417 void
418 glUseProgram (GLuint program)
419 {
420         current_context.program = program;
421
422         DEFER(glUseProgram, program);
423 }
424
425 void
426 glUseProgramObjectARB (GLhandleARB programObj)
427 {
428         current_context.program = programObj;
429
430         DEFER(glUseProgramObjectARB, programObj);
431 }
432
433 static void
434 accumulate_program_ticks (unsigned program_id, unsigned ticks)
435 {
436         context_t *ctx = &current_context;
437         unsigned i;
438
439         if (program_id >= ctx->num_program_metrics) {
440                 ctx->program_metrics = realloc (ctx->program_metrics,
441                                                 (program_id + 1) * sizeof (program_metrics_t));
442                 for (i = ctx->num_program_metrics; i < program_id + 1; i++) {
443                         ctx->program_metrics[i].id = i;
444                         ctx->program_metrics[i].ticks = 0.0;
445                 }
446
447                 ctx->num_program_metrics = program_id + 1;
448         }
449
450         ctx->program_metrics[program_id].ticks += ticks;
451 }
452
453 /* FIXME: Should sort the metrics, print out percentages, etc. */
454 static void
455 print_program_metrics (void)
456 {
457         context_t *ctx = &current_context;
458         unsigned i;
459
460         for (i = 0; i < ctx->num_program_metrics; i++) {
461                 if (ctx->program_metrics[i].ticks == 0.0)
462                         continue;
463                 printf ("Program %d:\t%7.2f mega-ticks\n",
464                         i, ctx->program_metrics[i].ticks / 1e6);
465         }
466 }
467
468 void
469 glwrap_end_frame (void)
470 {
471         static int initialized = 0;
472         static int frames;
473         static struct timeval tv_start, tv_now;
474
475         if (! initialized) {
476                 frames = 0;
477                 gettimeofday (&tv_start, NULL);
478                 initialized = 1;
479         }
480
481
482         frames++;
483
484         if (frames % 60 == 0) {
485                 double fps;
486                 gettimeofday (&tv_now, NULL);
487
488                 fps = (double) frames / (tv_now.tv_sec - tv_start.tv_sec +
489                                          (tv_now.tv_usec - tv_start.tv_usec) / 1.0e6);
490
491                 printf("FPS: %.3f\n", fps);
492
493                 print_program_metrics ();
494         }
495
496         /* Consume all counters that are ready. */
497         counter_t *counter = current_context.counter_head;
498
499         while (counter) {
500                 GLint available;
501                 GLuint elapsed;
502
503                 glGetQueryObjectiv (counter->id, GL_QUERY_RESULT_AVAILABLE,
504                                     &available);
505                 if (! available)
506                         break;
507
508                 glGetQueryObjectuiv (counter->id, GL_QUERY_RESULT, &elapsed);
509
510                 accumulate_program_ticks (counter->program, elapsed);
511
512                 current_context.counter_head = counter->next;
513                 if (current_context.counter_head == NULL)
514                         current_context.counter_tail = NULL;
515
516                 glDeleteQueries (1, &counter->id);
517
518                 free (counter);
519                 counter = current_context.counter_head;
520         }
521 }