2 * Copyright © 2007 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * Jesse Barnes <jesse.barnes@intel.com>
29 * The program is simple: it paints a window alternating colors (red &
30 * white) either as fast as possible or synchronized to vblank events
32 * If run normally, the program should display a window that exhibits
33 * significant tearing between red and white colors (e.g. you might get
34 * a "waterfall" effect of red and white horizontal bars).
36 * If run with the '-s b' option, the program should synchronize the
37 * window color changes with the vertical blank period, resulting in a
38 * window that looks orangish with a high frequency flicker (which may
39 * be invisible). If the window is moved to another screen, this
40 * property should be preserved. If the window spans two screens, it
41 * shouldn't tear on whichever screen most of the window is on; the
42 * portion on the other screen may show some tearing (like the
43 * waterfall effect above).
45 * Other options include '-w <width>' and '-h <height' to set the
55 #include <GL/glxext.h>
58 #include <X11/Xutil.h>
60 void (*video_sync_get
)();
63 static int GLXExtensionSupported(Display
*dpy
, const char *extension
)
65 const char *extensionsString
, *client_extensions
, *pos
;
67 extensionsString
= glXQueryExtensionsString(dpy
, DefaultScreen(dpy
));
68 client_extensions
= glXGetClientString(dpy
, GLX_EXTENSIONS
);
70 pos
= strstr(extensionsString
, extension
);
72 if (pos
!= NULL
&& (pos
== extensionsString
|| pos
[-1] == ' ') &&
73 (pos
[strlen(extension
)] == ' ' || pos
[strlen(extension
)] == '\0'))
76 pos
= strstr(client_extensions
, extension
);
78 if (pos
!= NULL
&& (pos
== extensionsString
|| pos
[-1] == ' ') &&
79 (pos
[strlen(extension
)] == ' ' || pos
[strlen(extension
)] == '\0'))
86 extern int optind
, opterr
, optopt
;
87 static char optstr
[] = "w:h:s:v";
95 static void usage(char *name
)
97 printf("usage: %s [-w <width>] [-h <height>] [-s<sync method>] "
99 printf("\t-s<sync method>:\n");
100 printf("\t\tn: none\n");
101 printf("\t\ts: SGI video sync extension\n");
102 printf("\t\tb: buffer swap\n");
103 printf("\t-v: verbose (print count)\n");
107 int main(int argc
, char *argv
[])
111 XSetWindowAttributes swa
;
113 GLint last_val
= -1, count
= 0;
117 enum sync_type waitforsync
= none
;
118 int width
= 500, height
= 500, verbose
= 0,
123 while ((c
= getopt(argc
, argv
, optstr
)) != -1) {
126 width
= atoi(optarg
);
129 height
= atoi(optarg
);
137 waitforsync
= sgi_video_sync
;
140 waitforsync
= buffer_swap
;
156 disp
= XOpenDisplay(NULL
);
158 fprintf(stderr
, "failed to open display\n");
162 if (!glXQueryExtension(disp
, &dummy
, &dummy
)) {
163 fprintf(stderr
, "glXQueryExtension failed\n");
167 if (!GLXExtensionSupported(disp
, "GLX_SGI_video_sync")) {
168 fprintf(stderr
, "GLX_SGI_video_sync not supported, exiting\n");
172 attrib
[0] = GLX_RGBA
;
174 attrib
[2] = GLX_RED_SIZE
;
176 attrib
[4] = GLX_GREEN_SIZE
;
178 attrib
[6] = GLX_BLUE_SIZE
;
180 if (waitforsync
!= buffer_swap
)
183 attrib
[8] = GLX_DOUBLEBUFFER
;
189 pvi
= glXChooseVisual(disp
, DefaultScreen(disp
), attrib
);
191 fprintf(stderr
, "failed to choose visual, exiting\n");
195 context
= glXCreateContext(disp
, pvi
, None
, GL_TRUE
);
197 fprintf(stderr
, "failed to create glx context\n");
201 pvi
->screen
= DefaultScreen(disp
);
203 swa
.colormap
= XCreateColormap(disp
, RootWindow(disp
, pvi
->screen
),
204 pvi
->visual
, AllocNone
);
205 swa
.border_pixel
= 0;
206 swa
.event_mask
= ExposureMask
| KeyPressMask
| ButtonPressMask
|
208 winGL
= XCreateWindow(disp
, RootWindow(disp
, pvi
->screen
),
211 0, pvi
->depth
, InputOutput
, pvi
->visual
,
212 CWBorderPixel
| CWColormap
| CWEventMask
, &swa
);
214 fprintf(stderr
, "window creation failed\n");
217 wmDelete
= XInternAtom(disp
, "WM_DELETE_WINDOW", True
);
218 XSetWMProtocols(disp
, winGL
, &wmDelete
, 1);
220 XSetStandardProperties(disp
, winGL
, "glsync test", "glsync text",
221 None
, NULL
, 0, NULL
);
223 XMapRaised(disp
, winGL
);
225 glXMakeCurrent(disp
, winGL
, context
);
227 video_sync_get
= glXGetProcAddress((unsigned char *)"glXGetVideoSyncSGI");
228 video_sync
= glXGetProcAddress((unsigned char *)"glXWaitVideoSyncSGI");
230 if (!video_sync_get
|| !video_sync
) {
231 fprintf(stderr
, "failed to get sync functions\n");
235 video_sync_get(&count
);
239 if (waitforsync
== sgi_video_sync
) {
241 fprintf(stderr
, "waiting on count %d\n", count
);
242 video_sync(2, (count
+ 1) % 2, &count
);
243 if (count
< last_val
)
244 fprintf(stderr
, "error: vblank count went backwards: %d -> %d\n", last_val
, count
);
245 if (count
== last_val
)
246 fprintf(stderr
, "error: count didn't change: %d\n", count
);
248 } else if (waitforsync
== buffer_swap
) {
249 glXSwapBuffers(disp
, winGL
);
253 video_sync(2, 1, &count
);
254 fprintf(stderr
, "current count: %d\n", count
);
259 /* Alternate colors to make tearing obvious */
261 glClearColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
263 glClearColor(1.0f
, 0.0f
, 0.0f
, 0.0f
);
264 glClear(GL_COLOR_BUFFER_BIT
);
268 XDestroyWindow(disp
, winGL
);
269 glXDestroyContext(disp
, context
);