--- /dev/null
+/* Copyright © 2013, Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "fips.h"
+
+#include "glwrap.h"
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+
+#include <sys/time.h>
+
+#include "dlwrap.h"
+
+typedef struct counter
+{
+ unsigned id;
+ unsigned program;
+ struct counter *next;
+} counter_t;
+
+typedef struct program_metrics
+{
+ unsigned id;
+ double ticks;
+} program_metrics_t;
+
+typedef struct context
+{
+ unsigned int program;
+
+ counter_t *counter_head;
+ counter_t *counter_tail;
+
+ unsigned num_program_metrics;
+ program_metrics_t *program_metrics;
+} context_t;
+
+/* FIXME: Need a map from integers to context objects and track the
+ * current context with glXMakeContextCurrent, eglMakeCurrent, etc. */
+
+context_t current_context;
+
+static unsigned
+add_counter (void)
+{
+ counter_t *counter;
+
+ counter = malloc (sizeof(counter_t));
+ if (counter == NULL) {
+ fprintf (stderr, "Out of memory\n");
+ exit (1);
+ }
+
+ glGenQueries (1, &counter->id);
+
+ counter->program = current_context.program;
+ counter->next = NULL;
+
+ if (current_context.counter_tail) {
+ current_context.counter_tail->next = counter;
+ current_context.counter_tail = counter;
+ } else {
+ current_context.counter_tail = counter;
+ current_context.counter_head = counter;
+ }
+
+ return counter->id;
+}
+
+static void *
+lookup (const char *name)
+{
+ const char *libgl_filename = "libGL.so.1";
+ static void *libgl_handle = NULL;
+
+ if (! libgl_handle) {
+ libgl_handle = dlwrap_real_dlopen (libgl_filename, RTLD_NOW | RTLD_DEEPBIND);
+ if (! libgl_handle) {
+ fprintf (stderr, "Error: Failed to dlopen %s\n",
+ libgl_filename);
+ exit (1);
+ }
+ }
+
+ return dlwrap_real_dlsym (libgl_handle, name);
+}
+
+/* Defer to the underlying, ''real'' function to do the real work. */
+#define DEFER(function,...) do { \
+ static typeof(&function) real_ ## function; \
+ if (! real_ ## function) \
+ real_ ## function = lookup (#function); \
+ real_ ## function(__VA_ARGS__); \
+} while (0);
+
+/* Execute a glBegineQuery/glEndQuery pair around an OpenGL call. */
+#define TIMED_DEFER(function,...) do { \
+ unsigned counter; \
+ counter = add_counter (); \
+ glBeginQuery (GL_TIME_ELAPSED, counter); \
+ DEFER(function, __VA_ARGS__); \
+ glEndQuery (GL_TIME_ELAPSED); \
+} while (0);
+
+/* Thanks to apitrace source code for the list of OpenGL draw calls. */
+void
+glDrawArrays (GLenum mode, GLint first, GLsizei count)
+{
+ TIMED_DEFER (glDrawArrays, mode, first, count);
+}
+
+void
+glDrawArraysEXT (GLenum mode, GLint first, GLsizei count)
+{
+ TIMED_DEFER (glDrawArraysEXT, mode, first, count);
+}
+
+void
+glDrawArraysIndirect (GLenum mode, const GLvoid *indirect)
+{
+ TIMED_DEFER (glDrawArraysIndirect, mode, indirect);
+}
+
+void
+glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count,
+ GLsizei primcount)
+{
+ TIMED_DEFER (glDrawArraysInstanced, mode, first, count, primcount);
+}
+
+void
+glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count,
+ GLsizei primcount)
+{
+ TIMED_DEFER (glDrawArraysInstancedARB, mode, first, count, primcount);
+}
+
+void
+glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count,
+ GLsizei primcount)
+{
+ TIMED_DEFER (glDrawArraysInstancedEXT, mode, start, count, primcount);
+}
+
+void
+glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count,
+ GLsizei primcount, GLuint baseinstance)
+{
+ TIMED_DEFER (glDrawArraysInstancedBaseInstance, mode,
+ first, count, primcount, baseinstance);
+}
+
+void
+glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width)
+{
+ TIMED_DEFER (glDrawMeshArraysSUN, mode, first, count, width);
+}
+
+void
+glMultiDrawArrays (GLenum mode, const GLint *first,
+ const GLsizei *count, GLsizei primcount)
+{
+ TIMED_DEFER (glMultiDrawArrays, mode, first, count, primcount);
+}
+
+void
+glMultiDrawArraysEXT (GLenum mode, const GLint *first,
+ const GLsizei *count, GLsizei primcount)
+{
+ TIMED_DEFER (glMultiDrawArraysEXT, mode, first, count, primcount);
+}
+
+void
+glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first,
+ const GLsizei *count, GLsizei primcount,
+ GLint modestride)
+{
+ TIMED_DEFER (glMultiModeDrawArraysIBM, mode,
+ first, count, primcount, modestride);
+}
+
+/* FIXME?
+void
+glMultiDrawArraysIndirect (...)
+{
+ TIMED_DEFER (glMultiDrawArraysIndirect, ...);
+}
+*/
+
+void
+glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect,
+ GLsizei primcount, GLsizei stride)
+{
+ TIMED_DEFER (glMultiDrawArraysIndirectAMD, mode,
+ indirect, primcount, stride);
+}
+
+void
+glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{
+ TIMED_DEFER (glDrawElements, mode, count, type, indices);
+}
+
+void
+glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLint basevertex)
+{
+ TIMED_DEFER (glDrawElementsBaseVertex, mode, count,
+ type, indices, basevertex);
+}
+
+void
+glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect)
+{
+ TIMED_DEFER (glDrawElementsIndirect, mode, type, indirect);
+}
+
+void
+glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei primcount)
+{
+ TIMED_DEFER (glDrawElementsInstanced, mode, count,
+ type, indices, primcount);
+}
+
+void
+glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei primcount)
+{
+ TIMED_DEFER (glDrawElementsInstancedARB, mode, count,
+ type, indices, primcount);
+}
+
+void
+glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei primcount)
+{
+ TIMED_DEFER (glDrawElementsInstancedEXT, mode, count,
+ type, indices, primcount);
+}
+
+void
+glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei primcount,
+ GLint basevertex)
+{
+ TIMED_DEFER (glDrawElementsInstancedBaseVertex, mode, count,
+ type, indices, primcount, basevertex);
+}
+
+void
+glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type,
+ const void *indices, GLsizei primcount,
+ GLuint baseinstance)
+{
+ TIMED_DEFER (glDrawElementsInstancedBaseInstance, mode, count, type,
+ indices, primcount, baseinstance);
+}
+
+void
+glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count,
+ GLenum type, const void *indices, GLsizei primcount,
+ GLint basevertex, GLuint baseinstance)
+{
+ TIMED_DEFER (glDrawElementsInstancedBaseVertexBaseInstance, mode,
+ count, type, indices, primcount, basevertex, baseinstance);
+}
+
+void
+glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count,
+ GLenum type, const GLvoid *indices)
+{
+ TIMED_DEFER (glDrawRangeElements, mode, start, end,
+ count, type, indices);
+}
+
+void
+glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count,
+ GLenum type, const GLvoid *indices)
+{
+ TIMED_DEFER (glDrawRangeElementsEXT, mode, start, end,
+ count, type, indices);
+}
+
+void
+glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices, GLint basevertex)
+{
+ TIMED_DEFER (glDrawRangeElementsBaseVertex, mode, start, end,
+ count, type, indices, basevertex);
+}
+
+void
+glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type,
+ const GLvoid* *indices, GLsizei primcount)
+{
+ TIMED_DEFER (glMultiDrawElements, mode, count, type,
+ indices, primcount);
+}
+
+void
+glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count,
+ GLenum type, const GLvoid* *indices,
+ GLsizei primcount, const GLint *basevertex)
+{
+ TIMED_DEFER (glMultiDrawElementsBaseVertex, mode, count,
+ type, indices, primcount, basevertex);
+}
+
+void
+glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type,
+ const GLvoid* *indices, GLsizei primcount)
+{
+ TIMED_DEFER (glMultiDrawElementsEXT, mode, count,
+ type, indices, primcount);
+}
+
+void
+glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count,
+ GLenum type, const GLvoid* const *indices,
+ GLsizei primcount, GLint modestride)
+{
+ TIMED_DEFER (glMultiModeDrawElementsIBM, mode, count,
+ type, indices, primcount, modestride);
+}
+
+/* FIXME?
+void
+glMultiDrawElementsIndirect (...)
+{
+ TIMED_DEFER (glMultiDrawElementsIndirect, ...);
+}
+*/
+
+void
+glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type,
+ const GLvoid *indirect,
+ GLsizei primcount, GLsizei stride)
+{
+ TIMED_DEFER (glMultiDrawElementsIndirectAMD, mode, type,
+ indirect, primcount, stride);
+}
+
+void
+glCallList (GLuint list)
+{
+ TIMED_DEFER (glCallList, list);
+}
+
+void
+glCallLists (GLsizei n, GLenum type, const GLvoid *lists)
+{
+ TIMED_DEFER (glCallLists, n, type, lists);
+}
+
+void
+glClear (GLbitfield mask)
+{
+ TIMED_DEFER (glClear, mask);
+}
+
+void
+glEnd (void)
+{
+ TIMED_DEFER (glEnd,);
+}
+
+void
+glDrawPixels (GLsizei width, GLsizei height, GLenum format,
+ GLenum type, const GLvoid *pixels)
+{
+ TIMED_DEFER (glDrawPixels, width, height, format, type, pixels);
+}
+
+void
+glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ TIMED_DEFER (glBlitFramebuffer,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+}
+
+void
+glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ TIMED_DEFER (glBlitFramebufferEXT,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+}
+
+void
+glUseProgram (GLuint program)
+{
+ current_context.program = program;
+
+ DEFER(glUseProgram, program);
+}
+
+void
+glUseProgramObjectARB (GLhandleARB programObj)
+{
+ current_context.program = programObj;
+
+ DEFER(glUseProgramObjectARB, programObj);
+}
+
+static void
+accumulate_program_ticks (unsigned program_id, unsigned ticks)
+{
+ context_t *ctx = ¤t_context;
+ unsigned i;
+
+ if (program_id >= ctx->num_program_metrics) {
+ ctx->program_metrics = realloc (ctx->program_metrics,
+ (program_id + 1) * sizeof (program_metrics_t));
+ for (i = ctx->num_program_metrics; i < program_id + 1; i++) {
+ ctx->program_metrics[i].id = i;
+ ctx->program_metrics[i].ticks = 0.0;
+ }
+
+ ctx->num_program_metrics = program_id + 1;
+ }
+
+ ctx->program_metrics[program_id].ticks += ticks;
+}
+
+/* FIXME: Should sort the metrics, print out percentages, etc. */
+static void
+print_program_metrics (void)
+{
+ context_t *ctx = ¤t_context;
+ unsigned i;
+
+ for (i = 0; i < ctx->num_program_metrics; i++) {
+ if (ctx->program_metrics[i].ticks == 0.0)
+ continue;
+ printf ("Program %d:\t%7.2f mega-ticks\n",
+ i, ctx->program_metrics[i].ticks / 1e6);
+ }
+}
+
+void
+glwrap_end_frame (void)
+{
+ static int initialized = 0;
+ static int frames;
+ static struct timeval tv_start, tv_now;
+
+ if (! initialized) {
+ frames = 0;
+ gettimeofday (&tv_start, NULL);
+ initialized = 1;
+ }
+
+
+ frames++;
+
+ if (frames % 60 == 0) {
+ double fps;
+ gettimeofday (&tv_now, NULL);
+
+ fps = (double) frames / (tv_now.tv_sec - tv_start.tv_sec +
+ (tv_now.tv_usec - tv_start.tv_usec) / 1.0e6);
+
+ printf("FPS: %.3f\n", fps);
+
+ print_program_metrics ();
+ }
+
+ /* Consume all counters that are ready. */
+ counter_t *counter = current_context.counter_head;
+
+ while (counter) {
+ GLint available;
+ GLuint elapsed;
+
+ glGetQueryObjectiv (counter->id, GL_QUERY_RESULT_AVAILABLE,
+ &available);
+ if (! available)
+ break;
+
+ glGetQueryObjectuiv (counter->id, GL_QUERY_RESULT, &elapsed);
+
+ accumulate_program_ticks (counter->program, elapsed);
+
+ current_context.counter_head = counter->next;
+ if (current_context.counter_head == NULL)
+ current_context.counter_tail = NULL;
+
+ glDeleteQueries (1, &counter->id);
+
+ free (counter);
+ counter = current_context.counter_head;
+ }
+}