Hi,
Recently I have made a piglit case that can test the behaviors of buffer swap,
they are 1) test whether we can get swap events. 2) verify whether the swap is
asynchronous 3) verify the swap frequency of swap interval being 0 is larger
than interval being 1. Jesse has helped me have brief look on it and give me
some advice. I have modified it. Can you help to add it into piglit tests?
Thanks for help and comments!
Best regards,
Zhao Jian
/*
* * This is a simple test case on the intel_swap_event.
* * Port by Jian Zhao 08 Sep 2010
* * jian.j.z...@intel.com
* *
* * See usage() below for command line options.
*/
#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 single 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;
static int Intel_swap_event=0;
int swap_count=0, event_count=0, 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(0);
}else{
printf("The GLX_INTEL_swap_event is supported in current
version.\n");
}
if (is_glx_extension_supported(dpy, "GLX_MESA_swap_control")) {
pglXGetSwapIntervalMESA = (PFNGLXGETSWAPINTERVALMESAPROC)
glXGetProcAddressARB((const GLubyte *) "glXGetSwapIntervalMESA");
pglXSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
glXGetProcAddressARB((const GLubyte *) "glXSwapIntervalMESA");
}else{
printf("GLX_MESA_swap_control was not supported by the
driver.\n");
}
}
/** 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 (message_count & 0x1){
(*pglXSwapIntervalMESA)(1);
interval=(*pglXGetSwapIntervalMESA)();
if ( ! interval == 1 ){
printf("Failed to set swap interval to 1 by
glXSwapIntervalMESA.\n");
exit(0);
}
}else{
(*pglXSwapIntervalMESA)(0);
interval=(*pglXGetSwapIntervalMESA)();
if ( ! interval == 0 ){
printf("Failed to set swap interval to 0 by
glXSwapIntervalMESA.\n");
exit(0);
}
}
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
events received, and the swap type is %s.\n", swap_event_type);
}
piglit_report_result(PIGLIT_SUCCESS);
exit(0);
}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);
exit(1);
}
}
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);
exit(0);
}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);
exit(1);
}
}
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);
exit(0);
}else{
piglit_report_result(PIGLIT_FAILURE);
exit(1);
}
}
}
}
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);
(*pglXSwapIntervalMESA)(1);
interval=(*pglXGetSwapIntervalMESA)();
event_loop(dpy, win);
glXDestroyContext(dpy, ctx);
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
return 0;
}
------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1, ECMAScript5, and DOM L2 & L3.
Spend less time writing and rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel