Commit b6a0fc0f authored by Jian Zhao's avatar Jian Zhao Committed by root

glx: Add test for glx swap event's receive and its asynchronization.

parent f447d5e2
......@@ -810,6 +810,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')
add_plain_test(glx, 'glx-tfp')
......
......@@ -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)
......
/*
* 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@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;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment