[Piglit] New piglit test case for swap event

Jian Zhao jian.j.zhao at intel.com
Wed Oct 13 02:17:17 PDT 2010


/*
 *  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");
        exit(1);
    } 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");
            exit(1);
        } 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");
                    exit(1);
                }
            } else{
                (*pglXSwapIntervalMESA)(0);
                interval=(*pglXGetSwapIntervalMESA)();
                if ( !  interval == 0 ) {
                    printf("Failed to set swap interval to 0.\n");
                    exit(1);
                }
            }
        }
        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 (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)
{
    int attribs[] = { GLX_RGBA,
                      GLX_RED_SIZE, 1,
                      GLX_GREEN_SIZE, 1,
                      GLX_BLUE_SIZE, 1,
                      GLX_DOUBLEBUFFER,
                      GLX_DEPTH_SIZE, 1,
                      None };
    int scrnum;
    XSetWindowAttributes attr;
    unsigned long mask;
    Window root;
    Window win;
    GLXContext ctx;
    XVisualInfo *visinfo;
    
    scrnum = DefaultScreen( dpy );
    root = RootWindow( dpy, scrnum );
    
    if (fullscreen) {
        x = 0; y = 0;
        width = DisplayWidth( dpy, scrnum );
        height = DisplayHeight( dpy, scrnum );
    }
    
    visinfo = glXChooseVisual( dpy, scrnum, attribs );
    if (!visinfo) {
        printf("Error: couldn't get an RGB, Double-buffered visual\n");
        exit(1);
    }
    
    /* 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 );
    
    if (fullscreen)
        no_border(dpy, win);
    
    /* set hints and properties */
    {
        XSizeHints sizehints;
        sizehints.x = x;
        sizehints.y = y;
        sizehints.width  = width;
        sizehints.height = height;
        sizehints.flags = USSize | USPosition;
        XSetNormalHints(dpy, win, &sizehints);
        XSetStandardProperties(dpy, win, name, name,
                                None, (char **)NULL, 0, &sizehints);
    }
    
    ctx = glXCreateContext( dpy, visinfo, NULL, True );
    if (!ctx) {
        printf("Error: glXCreateContext failed\n");
        exit(1);
    }
    
    XFree(visinfo);
    
    *winRet = win;
    *ctxRet = ctx;
}



/**
 * 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, Window 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 in \
asynchronous\n");
}
 

int
main(int argc, char *argv[])
{
    unsigned int winWidth = 30, winHeight = 30;
    int x = 0, y = 0;
    Display *dpy;
    Window win;
    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();
            return -1;
        }
    }
    
    dpy = XOpenDisplay(dpyName);
    if (!dpy) {
        printf("Error: couldn't open display %s\n",
            dpyName ? dpyName : getenv("DISPLAY"));
        return -1;
    }
    
    make_window(dpy, "Swap event test", x, y, winWidth, winHeight, &win, &ctx);
    
    XMapWindow(dpy, win);
    glXMakeCurrent(dpy, win, ctx);
    query_swap_event(dpy);
    
    glXQueryExtension(dpy, &error_base, &event_base);
    
    if (interval_diff) {
        (*pglXSwapIntervalMESA)(1);
        interval=(*pglXGetSwapIntervalMESA)();
    }
    event_loop(dpy, win);
    
    glXDestroyContext(dpy, ctx);
    XDestroyWindow(dpy, win);
    XCloseDisplay(dpy);
    
    return 0;
}


More information about the Piglit mailing list