[Piglit] [PATCH] Add test for glx swap event's receive and its asynchronization.

Jian Zhao jian.j.zhao at intel.com
Sun Jan 9 23:49:14 PST 2011


---
 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_async'] = PlainExecTest(['glx-swap-event', '-auto', '--async'])
+glx['glx-swap-event_interval'] = 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