[Piglit] [PATCH] Add test for glx swap event's receive and its asynchronization.
Jian Zhao
jian.j.zhao at intel.com
Tue Dec 28 22:51:49 PST 2010
---
tests/all.tests | 3 +
tests/glx/CMakeLists.txt | 1 +
tests/glx/glx-swap-event.c | 515 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 519 insertions(+), 0 deletions(-)
create mode 100644 tests/glx/glx-swap-event.c
diff --git a/tests/all.tests b/tests/all.tests
index 05b27a0..43c64bd 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -789,6 +789,9 @@ add_plain_test(glx, 'glx-destroycontext-2')
add_plain_test(glx, 'glx-multithread')
add_plain_test(glx, 'glx-shader-sharing')
add_plain_test(glx, 'glx-swap-exchange')
+glx['glx-swap-event_event'] = PlainExecTest(['glx-swap-event', '-auto', '--event'])
+glx['glx-swap-event_event'] = PlainExecTest(['glx-swap-event', '-auto', '--async'])
+glx['glx-swap-event_event'] = PlainExecTest(['glx-swap-event', '-auto', '--interval'])
add_plain_test(glx, 'glx-make-current')
add_plain_test(glx, 'glx-make-glxdrawable-current')
diff --git a/tests/glx/CMakeLists.txt b/tests/glx/CMakeLists.txt
index 0592a7a..b943041 100644
--- a/tests/glx/CMakeLists.txt
+++ b/tests/glx/CMakeLists.txt
@@ -26,6 +26,7 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_executable (glx-destroycontext-2 glx-destroycontext-2.c)
add_executable (glx-multithread glx-multithread.c)
add_executable (glx-make-current glx-make-current.c)
+ add_executable (glx-swap-event glx-swap-event.c)
add_executable (glx-make-glxdrawable-current glx-make-glxdrawable-current.c)
target_link_libraries(glx-multithread pthread X11)
add_executable (glx-swap-exchange glx-swap-exchange.c)
diff --git a/tests/glx/glx-swap-event.c b/tests/glx/glx-swap-event.c
new file mode 100644
index 0000000..f0c619f
--- /dev/null
+++ b/tests/glx/glx-swap-event.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright © 2010 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 (including the next
+ * paragraph) 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.
+ *
+ * Authors:
+ * jian.j.zhao at intel.com
+ */
+
+/*
+ * Simple test case on the intel_swap_event.
+ *
+ */
+
+#include "piglit-util.h"
+#include "GL/glx.h"
+#include <sys/time.h>
+
+/* return current time (in seconds) */
+static double
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+PFNGLXSWAPINTERVALMESAPROC pglXSwapIntervalMESA;
+PFNGLXGETSWAPINTERVALMESAPROC pglXGetSwapIntervalMESA;
+
+#define STACK_L 10
+
+static GLboolean fullscreen = GL_FALSE; /* Create a fullscreen window */
+static GLboolean verbose = GL_FALSE; /* Disable verbose. */
+static GLboolean Automatic = GL_FALSE; /* Disable verbose. */
+static GLboolean test_events = GL_FALSE; /* Disable verbose. */
+static GLboolean interval_diff = GL_FALSE; /* Disable verbose. */
+static GLboolean async = GL_FALSE; /* Disable verbose. */
+int event_base, Glx_event, count=0, swap_count=0, event_count=0;
+static int Intel_swap_event=0;
+int event_count_total=0, frames_total=0, message_count=0;
+static double time_call=0.0, time_fin=0.0, time_val=0.0;
+double swap_start[STACK_L],swap_returned[STACK_L];
+int interval=1;
+char * swap_event_type=NULL;
+/**
+ * Determine whether or not a GLX extension is supported.
+ */
+static int
+is_glx_extension_supported(Display *dpy, const char *query)
+{
+ const int scrnum = DefaultScreen(dpy);
+ const char *glx_extensions = NULL;
+ const size_t len = strlen(query);
+ const char *ptr;
+
+ if (glx_extensions == NULL) {
+ glx_extensions = glXQueryExtensionsString(dpy, scrnum);
+ }
+
+ ptr = strstr(glx_extensions, query);
+ return ((ptr != NULL) && ((ptr[len] == ' ') || (ptr[len] == '\0')));
+}
+
+static void
+query_swap_event(Display *dpy)
+{
+
+ if ( ! is_glx_extension_supported(dpy, "GLX_INTEL_swap_event")) {
+ printf("The GLX_INTEL_swap_event is not supported in current version.\n");
+ piglit_report_result(PIGLIT_SKIP);
+ } else {
+ printf("The GLX_INTEL_swap_event is supported in current version.\n");
+ }
+
+ if (interval_diff) {
+ if ( ! is_glx_extension_supported(dpy, "GLX_MESA_swap_control")) {
+ printf("GLX_MESA_swap_control was not supported by the driver.\n");
+ piglit_report_result(PIGLIT_SKIP);
+ } else {
+ pglXGetSwapIntervalMESA = (PFNGLXGETSWAPINTERVALMESAPROC)
+ glXGetProcAddressARB((const GLubyte *) "glXGetSwapIntervalMESA");
+ pglXSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
+ glXGetProcAddressARB((const GLubyte *) "glXSwapIntervalMESA");
+ }
+ }
+}
+
+/** Draw single frame, do SwapBuffers, compute FPS */
+static void
+draw_frame(Display *dpy, Window win)
+{
+ static int frames = 0, async_swap;
+ static double tRot0 = -1.0, tRate0 = -1.0;
+ static double swap_freq[2];
+ double dt, t = current_time();
+ int tem;
+
+ if (tRot0 < 0.0)
+ tRot0 = t;
+ dt = t - tRot0;
+ tRot0 = t;
+
+ if (tRate0 < 0.0)
+ tRate0 = t;
+ if (t - tRate0 >= 3.0) {
+ if (interval_diff) {
+ if (message_count & 0x1) {
+ (*pglXSwapIntervalMESA)(1);
+ interval=(*pglXGetSwapIntervalMESA)();
+ if ( ! interval == 1 ) {
+ printf("Failed to set swap interval to 1.\n");
+ piglit_report_result(PIGLIT_FAILURE);
+ }
+ } else{
+ (*pglXSwapIntervalMESA)(0);
+ interval=(*pglXGetSwapIntervalMESA)();
+ if ( ! interval == 0 ) {
+ printf("Failed to set swap interval to 0.\n");
+ piglit_report_result(PIGLIT_FAILURE);
+ }
+ }
+ }
+ message_count++;
+ GLfloat seconds = t - tRate0;
+ if ( (time_val / frames) < 0.0016 ) {
+ // 0.0016 <=> 60Hz * 10 or 100Hz * 6
+ async_swap=1;
+ } else{
+ async_swap=0;
+ }
+ interval=1-interval;
+ swap_freq[interval] = frames / seconds;
+ if (Automatic) {
+ if (message_count==2) {
+ if (test_events) {
+ if ( ! Intel_swap_event == 0 ) {
+ if (verbose) {
+ printf("glXSwapBuffers is called %d times and there\
+ is %d Intel_swap_event received in past %3.1f seconds.\n", swap_count,
+event_count, seconds);
+ printf("There is swap event received, and the swap \
+type is %s.\n", swap_event_type);
+ }
+ piglit_report_result(PIGLIT_SUCCESS);
+ } else{
+ if (verbose) {
+ printf("glXSwapBuffers is called %d times and there\
+ is %d Intel_swap_event received in past %3.1f seconds.\n", swap_count,
+event_count, seconds);
+ printf("There is no swap event received, and the \
+swap type is %s.\n", swap_event_type);
+ }
+ piglit_report_result(PIGLIT_FAILURE);
+ }
+
+ }
+ if (interval_diff) {
+ tem = 1.5 * swap_freq[1];
+ if ( swap_freq[0] >= tem ) {
+ if (verbose) {
+ printf("The swap frequency of no swap interval is \
+much larger than swap interval being 1.\n");
+ }
+ piglit_report_result(PIGLIT_SUCCESS);
+ } else{
+ if(fullscreen)
+ {
+ if(verbose)
+ printf("In fullscreen mode, the swap frequency of \
+no swap interval is limited under fresh rate.\n");
+ piglit_report_result(PIGLIT_SUCCESS);
+ }
+ if (verbose) {
+ printf("The swap frequency of no swap interval is \
+not much larger than swap interval being 1. They are %lf and %lf.\n",
+swap_freq[0], swap_freq[1]);
+ }
+ piglit_report_result(PIGLIT_FAILURE);
+ }
+ }
+ if (async) {
+ if (verbose) {
+ printf("It takes about %lf seconds returning back from\
+ the glXSwapBuffers call on average.\n", (time_val / frames));
+ }
+ if (async_swap ==1 ) {
+ piglit_report_result(PIGLIT_SUCCESS);
+ } else{
+ piglit_report_result(PIGLIT_FAILURE);
+ }
+ }
+ }
+ }
+ tRate0 = t;
+ frames = 0;
+ time_val = 0;
+ swap_count= 0;
+ event_count= 0;
+ }
+
+ if (frames_total & 1) {
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ glColor3f(1.0f, 1.0f, 1.0f);
+ } else {
+ glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
+ glColor3f(1.0f, 0.0f, 0.0f);
+ }
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ count=frames_total%STACK_L;
+ time_call=current_time();
+ swap_start[count]=time_call;
+ glXSwapBuffers(dpy, win);
+ time_fin=current_time();
+ swap_returned[count]=time_fin;
+ time_val+=(time_fin-time_call);
+
+ frames++;
+ frames_total++;
+ swap_count++;
+}
+
+/**
+ * Remove window border/decorations.
+ */
+static void
+no_border( Display *dpy, Window w)
+{
+ static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
+ static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
+
+ typedef struct
+ {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+ } PropMotifWmHints;
+
+ PropMotifWmHints motif_hints;
+ Atom prop, proptype;
+ unsigned long flags = 0;
+
+ /* setup the property */
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = flags;
+
+ /* get the atom for the property */
+ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
+ if (!prop) {
+ /* something went wrong! */
+ return;
+ }
+
+ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
+ proptype = prop;
+
+ XChangeProperty( dpy, w, /* display, window */
+ prop, proptype, /* property, type */
+ 32, /* format: 32-bit datums */
+ PropModeReplace, /* mode */
+ (unsigned char *) &motif_hints, /* data */
+ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
+ );
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet, GLXWindow *glxWinRet)
+{
+ int attribs[] = {
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DOUBLEBUFFER, True, /* Request a double-buffered color buffer with */
+ GLX_RED_SIZE, 1, /* the maximum number of bits per component */
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ None };
+
+ int scrnum, nelements;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+ GLXFBConfig *fbc;
+ GLXWindow gwin;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ if (fullscreen) {
+ x = 0; y = 0;
+ width = DisplayWidth( dpy, scrnum );
+ height = DisplayHeight( dpy, scrnum );
+ }
+
+ fbc = glXChooseFBConfig(dpy, scrnum, attribs, &nelements);
+ visinfo = glXGetVisualFromFBConfig(dpy, fbc[0]);
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ piglit_report_result(PIGLIT_SKIP);
+ }
+ ctx = glXCreateNewContext(dpy, fbc[0], GLX_RGBA_TYPE, 0, GL_TRUE);
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ /* XXX this is a bad way to get a borderless window! */
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, x, y, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+ XMapWindow(dpy, win);
+ gwin = glXCreateWindow(dpy, fbc[0], win, attribs);
+ glXMakeContextCurrent(dpy, gwin, gwin, ctx);
+ glXSelectEvent(dpy, gwin, GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
+
+ if (fullscreen)
+ no_border(dpy, win);
+
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+ *glxWinRet = gwin;
+}
+
+
+
+/**
+ * Only handle one glx event.
+ */
+void
+handle_event(Display *dpy, Window win, XEvent *event)
+{
+ (void) dpy;
+ (void) win;
+ if ( Glx_event == event->type) {
+ XEvent * event_p=event;
+ GLXBufferSwapComplete * glx_event=(GLXBufferSwapComplete *) event_p;
+ static double t_last=-1.0;
+ time_fin=current_time();
+ if (t_last < 0) {
+ t_last=time_fin;
+ }
+ if ( time_fin - t_last >= 3.0) {
+ if ( verbose ) {
+ count=event_count_total%STACK_L;
+ printf("It receives the recent event at %lf seconds, and that\
+ glXSwapBuffers was called at %lf seconds, its swap returned at %lf seconds, so\
+ the total time of glXSwapBuffers takes is %lf seconds.\n", time_fin,
+swap_start[count], swap_returned[count], (time_fin-swap_start[count]));
+ }
+ t_last=time_fin;
+ }
+ switch (glx_event->event_type) {
+ case GLX_EXCHANGE_COMPLETE_INTEL:
+ Intel_swap_event=GLX_EXCHANGE_COMPLETE_INTEL;
+ swap_event_type="GLX_EXCHANGE_COMPLETE_INTEL";
+ event_count++;
+ event_count_total++;
+ break;
+ case GLX_COPY_COMPLETE_INTEL:
+ Intel_swap_event=GLX_COPY_COMPLETE_INTEL;
+ swap_event_type="GLX_COPY_COMPLETE_INTEL";
+ event_count++;
+ event_count_total++;
+ break;
+ case GLX_FLIP_COMPLETE_INTEL:
+ Intel_swap_event=GLX_FLIP_COMPLETE_INTEL;
+ swap_event_type="GLX_FLIP_COMPLETE_INTEL";
+ event_count++;
+ event_count_total++;
+ break;
+ }
+ }
+}
+
+
+static void
+event_loop(Display *dpy, GLXWindow win)
+{
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ Glx_event=event_base + GLX_BufferSwapComplete;
+ handle_event(dpy, win, &event);
+ }
+
+ draw_frame(dpy, win);
+ }
+}
+
+
+static void
+usage(void)
+{
+ printf("Usage:\n");
+ printf(" -fullscreen run in fullscreen mode\n");
+ printf(" -v verbose mode, have more log\n");
+ printf(" -auto test automatically \n");
+ printf(" --event test whether we can get swap events\n");
+ printf(" --interval we expect that swap interval set to 0 should \
+have higher swap frequency than interval to 1\n");
+ printf(" --async test whether glXSwapBuffers is done asynchronously\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ unsigned int winWidth = 30, winHeight = 30;
+ int x = 0, y = 0;
+ Display *dpy;
+ Window win;
+ GLXWindow glxWin;
+ GLXContext ctx;
+ char *dpyName = NULL;
+ int i, error_base;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-auto") == 0) {
+ Automatic = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-v") == 0) {
+ verbose = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-fullscreen") == 0) {
+ fullscreen = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "--event") == 0) {
+ test_events=GL_TRUE;
+ }
+ else if (strcmp(argv[i], "--async") == 0) {
+ async = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "--interval") == 0) {
+ interval_diff = GL_TRUE;
+ }
+ else {
+ usage();
+ piglit_report_result(PIGLIT_SKIP);
+ }
+ }
+ if (!( interval_diff || async || test_events )) {
+ printf("Which do you want to test, events? asynchronous? or swap interval?\n");
+ usage();
+ piglit_report_result(PIGLIT_SKIP);
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n",
+ dpyName ? dpyName : getenv("DISPLAY"));
+ piglit_report_result(PIGLIT_FAILURE);
+ }
+
+ make_window(dpy, "Swap event test", x, y, winWidth, winHeight, &win, &ctx, &glxWin);
+
+ query_swap_event(dpy);
+
+ glXQueryExtension(dpy, &error_base, &event_base);
+
+ if (interval_diff) {
+ (*pglXSwapIntervalMESA)(1);
+ interval=(*pglXGetSwapIntervalMESA)();
+ if ( ! interval == 1 ) {
+ printf("Failed to set swap interval to 1.\n");
+ piglit_report_result(PIGLIT_FAILURE);
+ }
+ }
+ event_loop(dpy, glxWin);
+
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}
--
1.6.0.6
More information about the Piglit
mailing list