Little test that I made to figure out how use the Present extension of X11 with XCB.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

341 rinda
8.1KB

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