2 * Copyright © 2007-2010 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 Bool (*glXGetSyncValuesOML
)(Display
*dpy
, GLXDrawable drawable
,
61 int64_t *ust
, int64_t *msc
, int64_t *sbc
);
62 Bool (*glXGetMscRateOML
)(Display
*dpy
, GLXDrawable drawable
, int32_t *numerator
,
63 int32_t *denominator
);
64 int64_t (*glXSwapBuffersMscOML
)(Display
*dpy
, GLXDrawable drawable
,
65 int64_t target_msc
, int64_t divisor
,
67 Bool (*glXWaitForMscOML
)(Display
*dpy
, GLXDrawable drawable
, int64_t target_msc
,
68 int64_t divisor
, int64_t remainder
, int64_t *ust
,
69 int64_t *msc
, int64_t *sbc
);
70 Bool (*glXWaitForSbcOML
)(Display
*dpy
, GLXDrawable drawable
, int64_t target_sbc
,
71 int64_t *ust
, int64_t *msc
, int64_t *sbc
);
72 int (*glXSwapInterval
)(int interval
);
74 static int GLXExtensionSupported(Display
*dpy
, const char *extension
)
76 const char *extensionsString
, *client_extensions
, *pos
;
78 extensionsString
= glXQueryExtensionsString(dpy
, DefaultScreen(dpy
));
79 client_extensions
= glXGetClientString(dpy
, GLX_EXTENSIONS
);
81 pos
= strstr(extensionsString
, extension
);
83 if (pos
!= NULL
&& (pos
== extensionsString
|| pos
[-1] == ' ') &&
84 (pos
[strlen(extension
)] == ' ' || pos
[strlen(extension
)] == '\0'))
87 pos
= strstr(client_extensions
, extension
);
89 if (pos
!= NULL
&& (pos
== extensionsString
|| pos
[-1] == ' ') &&
90 (pos
[strlen(extension
)] == ' ' || pos
[strlen(extension
)] == '\0'))
97 extern int optind
, opterr
, optopt
;
98 static char optstr
[] = "w:h:vd:r:n:i:";
100 static void usage(char *name
)
102 printf("usage: %s [-w <width>] [-h <height>] ...\n", name
);
103 printf("\t-d<divisor> - divisor for OML swap\n");
104 printf("\t-r<remainder> - remainder for OML swap\n");
105 printf("\t-n<interval> - wait interval for OML WaitMSC\n");
106 printf("\t-i<swap interval> - swap at most once every n frames\n");
107 printf("\t-v: verbose (print count)\n");
111 int main(int argc
, char *argv
[])
115 XSetWindowAttributes swa
;
120 int64_t ust
, msc
, sbc
;
121 int width
= 500, height
= 500, verbose
= 0, divisor
= 0, remainder
= 0,
122 wait_interval
= 0, swap_interval
= 1;
125 int db_attribs
[] = { GLX_RGBA
,
132 XSizeHints sizehints
;
135 while ((c
= getopt(argc
, argv
, optstr
)) != -1) {
138 width
= atoi(optarg
);
141 height
= atoi(optarg
);
147 divisor
= atoi(optarg
);
150 remainder
= atoi(optarg
);
153 wait_interval
= atoi(optarg
);
156 swap_interval
= atoi(optarg
);
164 disp
= XOpenDisplay(NULL
);
166 fprintf(stderr
, "failed to open display\n");
170 if (!glXQueryExtension(disp
, &dummy
, &dummy
)) {
171 fprintf(stderr
, "glXQueryExtension failed\n");
175 if (!GLXExtensionSupported(disp
, "GLX_OML_sync_control")) {
176 fprintf(stderr
, "GLX_OML_sync_control not supported\n");
180 if (!GLXExtensionSupported(disp
, "GLX_MESA_swap_control")) {
181 fprintf(stderr
, "GLX_MESA_swap_control not supported\n");
185 pvi
= glXChooseVisual(disp
, DefaultScreen(disp
), db_attribs
);
188 fprintf(stderr
, "failed to choose visual, exiting\n");
192 pvi
->screen
= DefaultScreen(disp
);
194 swa
.colormap
= XCreateColormap(disp
, RootWindow(disp
, pvi
->screen
),
195 pvi
->visual
, AllocNone
);
196 swa
.border_pixel
= 0;
197 swa
.event_mask
= ExposureMask
| KeyPressMask
| ButtonPressMask
|
199 winGL
= XCreateWindow(disp
, RootWindow(disp
, pvi
->screen
),
202 0, pvi
->depth
, InputOutput
, pvi
->visual
,
203 CWBorderPixel
| CWColormap
| CWEventMask
, &swa
);
205 fprintf(stderr
, "window creation failed\n");
208 wmDelete
= XInternAtom(disp
, "WM_DELETE_WINDOW", True
);
209 XSetWMProtocols(disp
, winGL
, &wmDelete
, 1);
213 sizehints
.width
= width
;
214 sizehints
.height
= height
;
215 sizehints
.flags
= USSize
| USPosition
;
217 XSetNormalHints(disp
, winGL
, &sizehints
);
218 XSetStandardProperties(disp
, winGL
, "glsync test", "glsync text",
219 None
, NULL
, 0, &sizehints
);
221 context
= glXCreateContext(disp
, pvi
, NULL
, GL_TRUE
);
223 fprintf(stderr
, "failed to create glx context\n");
227 XMapWindow(disp
, winGL
);
228 ret
= glXMakeCurrent(disp
, winGL
, context
);
230 fprintf(stderr
, "failed to make context current: %d\n", ret
);
233 glXGetSyncValuesOML
= (void *)glXGetProcAddress((unsigned char *)"glXGetSyncValuesOML");
234 glXGetMscRateOML
= (void *)glXGetProcAddress((unsigned char *)"glXGetMscRateOML");
235 glXSwapBuffersMscOML
= (void *)glXGetProcAddress((unsigned char *)"glXSwapBuffersMscOML");
236 glXWaitForMscOML
= (void *)glXGetProcAddress((unsigned char *)"glXWaitForMscOML");
237 glXWaitForSbcOML
= (void *)glXGetProcAddress((unsigned char *)"glXWaitForSbcOML");
238 glXSwapInterval
= (void *)glXGetProcAddress((unsigned char *)"glXSwapIntervalMESA");
240 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
242 glXSwapInterval(swap_interval
);
243 fprintf(stderr
, "set swap interval to %d\n", swap_interval
);
245 glXGetSyncValuesOML(disp
, winGL
, &ust
, &msc
, &sbc
);
247 /* Alternate colors to make tearing obvious */
249 glClearColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
250 glColor3f(1.0f
, 1.0f
, 1.0f
);
252 glClearColor(1.0f
, 0.0f
, 0.0f
, 0.0f
);
253 glColor3f(1.0f
, 0.0f
, 0.0f
);
256 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
257 glRectf(0, 0, width
, height
);
259 glXSwapBuffersMscOML(disp
, winGL
, 0, divisor
, remainder
);
262 glXWaitForMscOML(disp
, winGL
, msc
+ wait_interval
,
263 0, 0, &ust
, &msc
, &sbc
);
267 XDestroyWindow(disp
, winGL
);
268 glXDestroyContext(disp
, context
);