Little test that I made to figure out how use the Present extension of X11 with XCB.
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.

331 line
7.8KB

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <unistd.h>
  6. #include <cairo/cairo.h>
  7. #include <cairo/cairo-xcb.h>
  8. #include <xcb/xcb.h>
  9. #include <xcb/present.h>
  10. #include <xcb/xfixes.h>
  11. #include <xcb/randr.h>
  12. /************************************************************************************************************/
  13. /* _ ********************************************************************************************************/
  14. /************************************************************************************************************/
  15. static void _draw (void);
  16. static void _init_cairo (void);
  17. static void _init_xcb (void);
  18. static void _reset (void);
  19. static void _run (void);
  20. /************************************************************************************************************/
  21. /************************************************************************************************************/
  22. /************************************************************************************************************/
  23. static uint32_t _opt_frame_divider = 1;
  24. static int _opt_async = 0;
  25. static xcb_connection_t *_x_con = NULL;
  26. static xcb_screen_t *_x_scr = NULL;
  27. static xcb_visualtype_t *_x_vis = NULL;
  28. static xcb_special_event_t *_x_sev = NULL;
  29. static xcb_window_t _x_win = 0;
  30. static xcb_pixmap_t _x_pix = 0;
  31. static cairo_surface_t *_c_srf = NULL;
  32. static cairo_t *_c_ctx = NULL;
  33. static int _speed1 = 60;
  34. static int _speed2 = 5;
  35. static double _pos1 = 0;
  36. static double _inc1 = 1;
  37. static double _pos2 = 0;
  38. static double _inc2 = 1;
  39. static long _t_full = 0;
  40. static long _t_paint = 0;
  41. static long _t_xsync = 0;
  42. static double _fps = 0;
  43. static long _total = 0;
  44. static uint32_t stamp = 0;
  45. /************************************************************************************************************/
  46. /************************************************************************************************************/
  47. /************************************************************************************************************/
  48. int
  49. main(int argc, char **argv)
  50. {
  51. /* options */
  52. int opt;
  53. while ((opt = getopt(argc, argv, "al:")) != -1) {
  54. switch (opt) {
  55. case 'a':
  56. _opt_async = 1;
  57. break;
  58. case 'l':
  59. _opt_frame_divider = (unsigned int)atoi(optarg);
  60. break;
  61. }
  62. }
  63. /* program */
  64. _init_xcb();
  65. _init_cairo();
  66. _run();
  67. _reset();
  68. return 0;
  69. }
  70. /************************************************************************************************************/
  71. /* _ ********************************************************************************************************/
  72. /************************************************************************************************************/
  73. static void
  74. _draw(void)
  75. {
  76. /* background */
  77. cairo_set_source_rgb(_c_ctx, 0.1, 0.1, 0.1);
  78. cairo_rectangle(_c_ctx, 0, 0, 700, 700);
  79. cairo_fill(_c_ctx);
  80. /* big square */
  81. double adv1 = (double)(_speed1 * _t_full) / 1000000.0;
  82. _pos1 += adv1 * _inc1;
  83. while (_pos1 > 600.0 || _pos1 < 0.0) {
  84. if (_pos1 > 600.0) {
  85. _inc1 = -1;
  86. adv1 = _pos1 - 600;
  87. _pos1 = 600;
  88. } else {
  89. _inc1 = 1;
  90. adv1 = -_pos1;
  91. _pos1 = 0;
  92. }
  93. _pos1 += adv1 * _inc1;
  94. }
  95. cairo_set_source_rgb(_c_ctx, 0.8, 0.8, 0.8);
  96. cairo_rectangle(_c_ctx, _pos1, _pos1, 100, 100);
  97. cairo_fill(_c_ctx);
  98. /* small square */
  99. double adv2 = (double)(_speed2 * _t_full) / 1000000.0;
  100. _pos2 += adv2 * _inc2;
  101. while (_pos2 > 80.0 || _pos2 < 0.0) {
  102. if (_pos2 > 80.0) {
  103. _inc2 = -1;
  104. adv2 = _pos2 - 80;
  105. _pos2 = 80;
  106. } else {
  107. _inc2 = 1;
  108. adv2 = -_pos2;
  109. _pos2 = 0;
  110. }
  111. _pos2 += adv2 * _inc2;
  112. }
  113. cairo_set_source_rgb(_c_ctx, 0.3, 0.3, 0.3);
  114. cairo_rectangle(_c_ctx, _pos1 + 80 - _pos2, _pos1 + _pos2, 20, 20);
  115. cairo_fill(_c_ctx);
  116. /* counters */
  117. char str[128];
  118. cairo_set_source_rgb(_c_ctx, 1.0, 1.0, 1.0);
  119. sprintf(str, "fps : %f", _fps);
  120. cairo_move_to(_c_ctx, 25, 555);
  121. cairo_show_text(_c_ctx, str);
  122. sprintf(str, "frame time (µs) : %li", _t_full);
  123. cairo_move_to(_c_ctx, 25, 585);
  124. cairo_show_text(_c_ctx, str);
  125. sprintf(str, "paint time (µs) : %li", _t_paint);
  126. cairo_move_to(_c_ctx, 25, 615);
  127. cairo_show_text(_c_ctx, str);
  128. sprintf(str, "x sync time (µs) : %li", _t_xsync);
  129. cairo_move_to(_c_ctx, 25, 645);
  130. cairo_show_text(_c_ctx, str);
  131. sprintf(str, "total frames : %li", _total);
  132. cairo_move_to(_c_ctx, 25, 675);
  133. cairo_show_text(_c_ctx, str);
  134. }
  135. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  136. static void
  137. _init_cairo(void)
  138. {
  139. _c_srf = cairo_xcb_surface_create(_x_con, _x_pix, _x_vis, 700, 700);
  140. _c_ctx = cairo_create(_c_srf);
  141. cairo_set_font_size(_c_ctx, 20);
  142. cairo_select_font_face(_c_ctx, "Terminus", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
  143. cairo_surface_flush(_c_srf);
  144. }
  145. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  146. static void
  147. _init_xcb(void)
  148. {
  149. /* connection */
  150. _x_con = xcb_connect(NULL, NULL);
  151. _x_scr = xcb_setup_roots_iterator(xcb_get_setup(_x_con)).data;
  152. xcb_visualtype_iterator_t x_vi;
  153. xcb_depth_iterator_t x_di;
  154. x_di = xcb_screen_allowed_depths_iterator(_x_scr);
  155. for (; x_di.rem; xcb_depth_next(&x_di)) {
  156. x_vi = xcb_depth_visuals_iterator(x_di.data);
  157. for (; x_vi.rem; xcb_visualtype_next(&x_vi)) {
  158. if (_x_scr->root_visual == x_vi.data->visual_id) {
  159. _x_vis = x_vi.data;
  160. break;
  161. }
  162. }
  163. }
  164. /* window */
  165. uint32_t mask_vals[2];
  166. mask_vals[0] = _x_scr->black_pixel;
  167. mask_vals[1] = XCB_EVENT_MASK_EXPOSURE;
  168. _x_win = xcb_generate_id(_x_con);
  169. xcb_create_window(
  170. _x_con,
  171. XCB_COPY_FROM_PARENT,
  172. _x_win,
  173. _x_scr->root,
  174. 0, 0,
  175. 700, 700,
  176. 0,
  177. XCB_WINDOW_CLASS_INPUT_OUTPUT,
  178. _x_scr->root_visual,
  179. XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
  180. mask_vals);
  181. xcb_map_window(_x_con, _x_win);
  182. xcb_flush(_x_con);
  183. /* pixmap */
  184. _x_pix = xcb_generate_id(_x_con);
  185. xcb_create_pixmap(_x_con, _x_scr->root_depth, _x_pix, _x_win, 700, 700);
  186. /* present extension */
  187. uint32_t id = xcb_generate_id(_x_con);
  188. xcb_present_select_input(
  189. _x_con,
  190. id,
  191. _x_win,
  192. XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
  193. /* optional setup a special event queue for the present extension */
  194. /* if not done present completion events can still be recoved from the regular */
  195. /* xcb_wait_for_event() queue */
  196. _x_sev = xcb_register_for_special_xge(_x_con, &xcb_present_id, id, &stamp);
  197. }
  198. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  199. static void
  200. _reset(void)
  201. {
  202. cairo_destroy(_c_ctx);
  203. cairo_surface_destroy(_c_srf);
  204. xcb_free_pixmap(_x_con, _x_pix);
  205. xcb_destroy_window(_x_con, _x_win);
  206. xcb_disconnect(_x_con);
  207. }
  208. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  209. static void
  210. _run(void)
  211. {
  212. xcb_generic_event_t *ev = NULL;
  213. int n = 0;
  214. long t1 = 0;
  215. long t2 = 0;
  216. long t3 = 0;
  217. struct timespec ts = {0};
  218. while (1) {
  219. _total++;
  220. clock_gettime(CLOCK_MONOTONIC, &ts);
  221. t1 = ts.tv_nsec / 1000 + ts.tv_sec * 1000000;
  222. _draw();
  223. clock_gettime(CLOCK_MONOTONIC, &ts);
  224. t2 = ts.tv_nsec / 1000 + ts.tv_sec * 1000000;
  225. xcb_present_pixmap(
  226. _x_con,
  227. _x_win,
  228. _x_pix,
  229. 123456,
  230. XCB_XFIXES_REGION_NONE,
  231. XCB_XFIXES_REGION_NONE,
  232. 0, 0,
  233. 0,
  234. 0,
  235. 0,
  236. _opt_async ? XCB_PRESENT_OPTION_ASYNC : XCB_PRESENT_OPTION_NONE,
  237. 0, _opt_frame_divider, 0,
  238. 0,
  239. NULL);
  240. xcb_flush(_x_con);
  241. clock_gettime(CLOCK_MONOTONIC, &ts);
  242. t3 = ts.tv_nsec / 1000 + ts.tv_sec * 1000000;
  243. _t_paint = t2 - t1;
  244. _t_xsync = t3 - t2;
  245. ev = xcb_wait_for_special_event(_x_con, _x_sev);
  246. if (!ev) {
  247. printf("exiting\n");
  248. return;
  249. }
  250. free(ev);
  251. clock_gettime(CLOCK_MONOTONIC, &ts);
  252. _t_full = ts.tv_nsec / 1000 + ts.tv_sec * 1000000 - t1;
  253. _fps = 1000000.0 / (double)_t_full;
  254. }
  255. }