* THE SOFTWARE.
*/
-#include "fips.h"
-
-#include "glwrap.h"
-
-#include "metrics.h"
+#include "dlwrap.h"
/* The prototypes for some OpenGL functions changed at one point from:
*
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
-#include "dlwrap.h"
+#include "fips.h"
+
+#include "glwrap.h"
+
+#include "metrics.h"
+
+static int inside_new_list = 0;
+
+static void *gl_handle;
+
+void
+glwrap_set_gl_handle (void *handle)
+{
+ if (gl_handle == NULL)
+ gl_handle = handle;
+}
void *
glwrap_lookup (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);
+ void *ret;
+
+ /* We don't call dlopen here to find the library in which to
+ * perform a dlsym lookup. That's because the application may
+ * be loading libGL.so or libGLESv2.so for its OpenGL symbols.
+ *
+ * So we instead watch for one of those filenames to go by in
+ * our dlopen wrapper, which will then call
+ * glwrap_set_gl_handle to give us the handle to use here.
+ *
+ * If the application hasn't called dlopen on a "libGL"
+ * library, then presumably the application is linked directly
+ * to an OpenGL implementation. In this case, we can use
+ * RTLD_NEXT to find the symbol.
+ *
+ * But just in case, we also let the user override that by
+ * specifying the FIPS_LIBGL environment variable to the path
+ * of the real libGL.so library that fips should dlopen here.
+ */
+ if (gl_handle == NULL) {
+ const char *path;
+
+ path = getenv ("FIPS_LIBGL");
+ if (path) {
+ gl_handle = dlopen (path, RTLD_LAZY);
+
+ if (gl_handle == NULL) {
+ fprintf (stderr, "Failed to dlopen FIPS_LIBGL: "
+ "%s\n", path);
+ exit (1);
+ }
+ } else {
+ gl_handle = RTLD_NEXT;
}
}
- return dlwrap_real_dlsym (libgl_handle, name);
+ ret = dlwrap_real_dlsym (gl_handle, name);
+
+ if (ret == NULL) {
+ fprintf (stderr, "Error: glwrap_lookup failed to dlsym %s\n",
+ name);
+ exit (1);
+ }
+
+ return ret;
}
-/* Execute a glBegineQuery/glEndQuery pair around an OpenGL call. */
-#define TIMED_DEFER(function,...) do { \
- unsigned counter; \
- counter = metrics_add_counter (); \
- glBeginQuery (GL_TIME_ELAPSED, counter); \
- GLWRAP_DEFER(function, __VA_ARGS__); \
- glEndQuery (GL_TIME_ELAPSED); \
+/* Execute an OpenGL call and time it with a GPU metrics counter. */
+#define TIMED_DEFER(function,...) do { \
+ if (! inside_new_list) { \
+ unsigned counter; \
+ counter = metrics_counter_new (); \
+ metrics_counter_start (counter); \
+ } \
+ GLWRAP_DEFER(function, __VA_ARGS__); \
+ if (! inside_new_list) { \
+ metrics_counter_stop (); \
+ } \
} while (0);
/* Thanks to apitrace source code for the list of OpenGL draw calls. */
first, count, primcount, modestride);
}
-/* FIXME?
void
-glMultiDrawArraysIndirect (...)
+glMultiDrawArraysIndirect (GLenum mode, const void *indirect,
+ GLsizei drawcount, GLsizei stride)
{
- TIMED_DEFER (glMultiDrawArraysIndirect, ...);
+ TIMED_DEFER (glMultiDrawArraysIndirect, mode, indirect, drawcount, stride);
}
-*/
void
glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect,
type, indices, primcount, modestride);
}
-/* FIXME?
void
-glMultiDrawElementsIndirect (...)
+glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect,
+ GLsizei drawcount, GLsizei stride)
{
- TIMED_DEFER (glMultiDrawElementsIndirect, ...);
+ TIMED_DEFER (glMultiDrawElementsIndirect, mode, type,
+ indirect, drawcount, stride);
}
-*/
void
glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type,
TIMED_DEFER (glClear, mask);
}
+/* We can't just use TIMED_DEFER for glBegin/glEnd since the metrics
+ * counter must be started before glBegin and stopped after glEnd,
+ * (that is, everything from glBegin to glEnd is counted as a single
+ * operation). */
+void
+glBegin (GLenum mode)
+{
+ if (! inside_new_list)
+ {
+ unsigned counter;
+ counter = metrics_counter_new ();
+ metrics_counter_start (counter);
+ }
+
+ GLWRAP_DEFER (glBegin, mode);
+}
+
void
glEnd (void)
{
- TIMED_DEFER (glEnd,);
+ GLWRAP_DEFER (glEnd);
+
+ if (! inside_new_list) {
+ metrics_counter_stop ();
+ }
+}
+
+/* And we need to track display lists to avoid inserting queries
+ * inside the list while it's being constructed. */
+void
+glNewList (GLuint list, GLenum mode)
+{
+ inside_new_list = 1;
+ GLWRAP_DEFER (glNewList, list, mode);
+}
+
+void
+glEndList (void)
+{
+ GLWRAP_DEFER (glEndList);
+ inside_new_list = 0;
}
void