Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

glsync.c 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright © 2007 Intel Corporation
  3. *
  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:
  10. *
  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
  13. * Software.
  14. *
  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
  21. * IN THE SOFTWARE.
  22. *
  23. * Authors:
  24. * Jesse Barnes <jesse.barnes@intel.com>
  25. *
  26. */
  27. /** @file glsync.c
  28. * The program is simple: it paints a window alternating colors (red &
  29. * white) either as fast as possible or synchronized to vblank events
  30. *
  31. * If run normally, the program should display a window that exhibits
  32. * significant tearing between red and white colors (e.g. you might get
  33. * a "waterfall" effect of red and white horizontal bars).
  34. *
  35. * If run with the '-s b' option, the program should synchronize the
  36. * window color changes with the vertical blank period, resulting in a
  37. * window that looks orangish with a high frequency flicker (which may
  38. * be invisible). If the window is moved to another screen, this
  39. * property should be preserved. If the window spans two screens, it
  40. * shouldn't tear on whichever screen most of the window is on; the
  41. * portion on the other screen may show some tearing (like the
  42. * waterfall effect above).
  43. *
  44. * Other options include '-w <width>' and '-h <height' to set the
  45. * window size.
  46. */
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <unistd.h>
  51. #include <GL/gl.h>
  52. #include <GL/glu.h>
  53. #include <GL/glx.h>
  54. #include <GL/glxext.h>
  55. #include <X11/X.h>
  56. #include <X11/Xlib.h>
  57. #include <X11/Xutil.h>
  58. void (*video_sync_get)();
  59. void (*video_sync)();
  60. static int GLXExtensionSupported(Display *dpy, const char *extension)
  61. {
  62. const char *extensionsString, *client_extensions, *pos;
  63. extensionsString = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
  64. client_extensions = glXGetClientString(dpy, GLX_EXTENSIONS);
  65. pos = strstr(extensionsString, extension);
  66. if (pos != NULL && (pos == extensionsString || pos[-1] == ' ') &&
  67. (pos[strlen(extension)] == ' ' || pos[strlen(extension)] == '\0'))
  68. return 1;
  69. pos = strstr(client_extensions, extension);
  70. if (pos != NULL && (pos == extensionsString || pos[-1] == ' ') &&
  71. (pos[strlen(extension)] == ' ' || pos[strlen(extension)] == '\0'))
  72. return 1;
  73. return 0;
  74. }
  75. extern char *optarg;
  76. extern int optind, opterr, optopt;
  77. static char optstr[] = "w:h:s:v";
  78. enum sync_type {
  79. none = 0,
  80. sgi_video_sync,
  81. buffer_swap,
  82. };
  83. static void usage(char *name)
  84. {
  85. printf("usage: %s [-w <width>] [-h <height>] [-s<sync method>] "
  86. "[-vc]\n", name);
  87. printf("\t-s<sync method>:\n");
  88. printf("\t\tn: none\n");
  89. printf("\t\ts: SGI video sync extension\n");
  90. printf("\t\tb: buffer swap\n");
  91. printf("\t-v: verbose (print count)\n");
  92. exit(-1);
  93. }
  94. int main(int argc, char *argv[])
  95. {
  96. Display *disp;
  97. XVisualInfo *pvi;
  98. XSetWindowAttributes swa;
  99. int attrib[14];
  100. GLint last_val = -1, count = 0;
  101. Window winGL;
  102. GLXContext context;
  103. int dummy;
  104. Atom wmDelete;
  105. enum sync_type waitforsync = none;
  106. int width = 500, height = 500, verbose = 0,
  107. countonly = 0;
  108. int c, i = 1;
  109. opterr = 0;
  110. while ((c = getopt(argc, argv, optstr)) != -1) {
  111. switch (c) {
  112. case 'w':
  113. width = atoi(optarg);
  114. break;
  115. case 'h':
  116. height = atoi(optarg);
  117. break;
  118. case 's':
  119. switch (optarg[0]) {
  120. case 'n':
  121. waitforsync = none;
  122. break;
  123. case 's':
  124. waitforsync = sgi_video_sync;
  125. break;
  126. case 'b':
  127. waitforsync = buffer_swap;
  128. break;
  129. default:
  130. usage(argv[0]);
  131. break;
  132. }
  133. break;
  134. case 'v':
  135. verbose = 1;
  136. break;
  137. default:
  138. usage(argv[0]);
  139. break;
  140. }
  141. }
  142. disp = XOpenDisplay(NULL);
  143. if (!disp) {
  144. fprintf(stderr, "failed to open display\n");
  145. return -1;
  146. }
  147. if (!glXQueryExtension(disp, &dummy, &dummy)) {
  148. fprintf(stderr, "glXQueryExtension failed\n");
  149. return -1;
  150. }
  151. if (!GLXExtensionSupported(disp, "GLX_SGI_video_sync")) {
  152. fprintf(stderr, "GLX_SGI_video_sync not supported, exiting\n");
  153. return -1;
  154. }
  155. attrib[0] = GLX_RGBA;
  156. attrib[1] = 1;
  157. attrib[2] = GLX_RED_SIZE;
  158. attrib[3] = 1;
  159. attrib[4] = GLX_GREEN_SIZE;
  160. attrib[5] = 1;
  161. attrib[6] = GLX_BLUE_SIZE;
  162. attrib[7] = 1;
  163. if (waitforsync != buffer_swap)
  164. attrib[8] = None;
  165. else {
  166. attrib[8] = GLX_DOUBLEBUFFER;
  167. attrib[9] = 1;
  168. attrib[10] = None;
  169. }
  170. pvi = glXChooseVisual(disp, DefaultScreen(disp), attrib);
  171. if (!pvi) {
  172. fprintf(stderr, "failed to choose visual, exiting\n");
  173. return -1;
  174. }
  175. context = glXCreateContext(disp, pvi, None, GL_TRUE);
  176. if (!context) {
  177. fprintf(stderr, "failed to create glx context\n");
  178. return -1;
  179. }
  180. pvi->screen = DefaultScreen(disp);
  181. swa.colormap = XCreateColormap(disp, RootWindow(disp, pvi->screen),
  182. pvi->visual, AllocNone);
  183. swa.border_pixel = 0;
  184. swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
  185. StructureNotifyMask;
  186. winGL = XCreateWindow(disp, RootWindow(disp, pvi->screen),
  187. 0, 0,
  188. width, height,
  189. 0, pvi->depth, InputOutput, pvi->visual,
  190. CWBorderPixel | CWColormap | CWEventMask, &swa);
  191. if (!winGL) {
  192. fprintf(stderr, "window creation failed\n");
  193. return -1;
  194. }
  195. wmDelete = XInternAtom(disp, "WM_DELETE_WINDOW", True);
  196. XSetWMProtocols(disp, winGL, &wmDelete, 1);
  197. XSetStandardProperties(disp, winGL, "glsync test", "glsync text",
  198. None, NULL, 0, NULL);
  199. XMapRaised(disp, winGL);
  200. glXMakeCurrent(disp, winGL, context);
  201. video_sync_get = glXGetProcAddress((unsigned char *)"glXGetVideoSyncSGI");
  202. video_sync = glXGetProcAddress((unsigned char *)"glXWaitVideoSyncSGI");
  203. if (!video_sync_get || !video_sync) {
  204. fprintf(stderr, "failed to get sync functions\n");
  205. return -1;
  206. }
  207. video_sync_get(&count);
  208. count++;
  209. while (i++) {
  210. /* Wait for vsync */
  211. if (waitforsync == sgi_video_sync) {
  212. if (verbose)
  213. fprintf(stderr, "waiting on count %d\n", count);
  214. video_sync(2, (count + 1) % 2, &count);
  215. if (count < last_val)
  216. fprintf(stderr, "error: vblank count went backwards: %d -> %d\n", last_val, count);
  217. if (count == last_val)
  218. fprintf(stderr, "error: count didn't change: %d\n", count);
  219. last_val = count;
  220. } else if (waitforsync == buffer_swap) {
  221. glXSwapBuffers(disp, winGL);
  222. }
  223. if (countonly) {
  224. video_sync(2, 1, &count);
  225. fprintf(stderr, "current count: %d\n", count);
  226. sleep(1);
  227. continue;
  228. }
  229. /* Alternate colors to make tearing obvious */
  230. if (i & 1)
  231. glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  232. else
  233. glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
  234. glClear(GL_COLOR_BUFFER_BIT);
  235. glFlush();
  236. }
  237. XDestroyWindow(disp, winGL);
  238. glXDestroyContext(disp, context);
  239. XCloseDisplay(disp);
  240. return 0;
  241. }