Little test that I made to figure out how use the Present extension of X11 with XCB.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

347 lines
8.9KB

  1. #include <pthread.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <cairo/cairo.h>
  5. #include <cairo/cairo-xcb.h>
  6. #include <xcb/xcb.h>
  7. #include <xcb/present.h>
  8. /************************************************************************************************************/
  9. /************************************************************************************************************/
  10. /************************************************************************************************************/
  11. #define WIN_W 600
  12. #define WIN_H 400
  13. #define RECT_W 100
  14. #define RECT_SPEED 5 /* 300 px/s at 60 Hz */
  15. /************************************************************************************************************/
  16. /************************************************************************************************************/
  17. /************************************************************************************************************/
  18. static void _draw (void);
  19. static void _init_graphics (void);
  20. static void _init_threads (void);
  21. static void _reset (void);
  22. static void * _thread_event (void *p);
  23. static void * _thread_render (void *p);
  24. /************************************************************************************************************/
  25. /************************************************************************************************************/
  26. /************************************************************************************************************/
  27. static xcb_connection_t *_x_con = NULL;
  28. static xcb_screen_t *_x_scr = NULL;
  29. static xcb_visualtype_t *_x_vis = NULL;
  30. static xcb_window_t _x_win = 0;
  31. static xcb_pixmap_t _x_pix = 0;
  32. static xcb_gcontext_t _x_ctx = 0;
  33. static uint8_t _x_opcode = 0;
  34. static cairo_surface_t *_c_srf = NULL;
  35. static cairo_t *_c_ctx = NULL;
  36. static pthread_t _t_id_ev;
  37. static pthread_t _t_id_rd;
  38. static pthread_cond_t _t_cond_rd_1;
  39. static pthread_cond_t _t_cond_rd_2;
  40. static pthread_mutex_t _t_mutex_rd_1;
  41. static pthread_mutex_t _t_mutex_rd_2;
  42. static int _rect_pos = WIN_W;
  43. static int _update = 1;
  44. static int _serial = 0;
  45. /************************************************************************************************************/
  46. /************************************************************************************************************/
  47. /************************************************************************************************************/
  48. int
  49. main(int argc, char **argv)
  50. {
  51. /* initialisation */
  52. _init_graphics();
  53. _init_threads();
  54. /* initial render for first expose event */
  55. _draw();
  56. /* start the threads */
  57. /* the event thread leads the tempo */
  58. pthread_create(&_t_id_ev, NULL, _thread_event, NULL);
  59. pthread_create(&_t_id_rd, NULL, _thread_render, NULL);
  60. pthread_join(_t_id_ev, NULL);
  61. pthread_cancel(_t_id_rd);
  62. pthread_join(_t_id_rd, NULL);
  63. /* end */
  64. _reset();
  65. }
  66. /************************************************************************************************************/
  67. /************************************************************************************************************/
  68. /************************************************************************************************************/
  69. static void
  70. _draw(void)
  71. {
  72. /* update position */
  73. _rect_pos += RECT_SPEED;
  74. if (_rect_pos >= WIN_W) {
  75. _rect_pos = -RECT_W;
  76. }
  77. /* update pixmap */
  78. cairo_set_source_rgb(_c_ctx, 0.3, 0.3, 0.3);
  79. cairo_paint(_c_ctx);
  80. cairo_set_source_rgb(_c_ctx, 0.7, 0.7, 0.7);
  81. cairo_rectangle(_c_ctx, _rect_pos, 0, RECT_W, WIN_H);
  82. cairo_fill(_c_ctx);
  83. cairo_surface_flush(_c_srf);
  84. }
  85. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  86. static void
  87. _init_graphics(void)
  88. {
  89. /* setup xcb */
  90. _x_con = xcb_connect(NULL, NULL);
  91. _x_scr = xcb_setup_roots_iterator(xcb_get_setup(_x_con)).data;
  92. xcb_visualtype_iterator_t x_vi;
  93. xcb_depth_iterator_t x_di;
  94. x_di = xcb_screen_allowed_depths_iterator(_x_scr);
  95. for (; x_di.rem; xcb_depth_next(&x_di)) {
  96. x_vi = xcb_depth_visuals_iterator(x_di.data);
  97. for (; x_vi.rem; xcb_visualtype_next(&x_vi)) {
  98. if (_x_scr->root_visual == x_vi.data->visual_id) {
  99. _x_vis = x_vi.data;
  100. break;
  101. }
  102. }
  103. }
  104. /* setup generic xcb graphical context for copying the pixmap */
  105. _x_ctx = xcb_generate_id(_x_con);
  106. xcb_create_gc(
  107. _x_con,
  108. _x_ctx,
  109. _x_scr->root,
  110. XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES,
  111. &(uint32_t[2]){_x_scr->black_pixel, 0});
  112. /* setup xcb window */
  113. uint32_t mask_vals[2];
  114. mask_vals[0] = _x_scr->black_pixel;
  115. mask_vals[1] = XCB_EVENT_MASK_EXPOSURE |
  116. XCB_EVENT_MASK_STRUCTURE_NOTIFY |
  117. XCB_EVENT_MASK_KEY_PRESS |
  118. XCB_EVENT_MASK_BUTTON_PRESS;
  119. _x_win = xcb_generate_id(_x_con);
  120. xcb_create_window(
  121. _x_con,
  122. XCB_COPY_FROM_PARENT,
  123. _x_win,
  124. _x_scr->root,
  125. 0, 0,
  126. WIN_W, WIN_H,
  127. 0,
  128. XCB_WINDOW_CLASS_INPUT_OUTPUT,
  129. _x_scr->root_visual,
  130. XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
  131. mask_vals);
  132. xcb_map_window(_x_con, _x_win);
  133. /* setup xcb pixmap */
  134. _x_pix = xcb_generate_id(_x_con);
  135. xcb_create_pixmap(_x_con, _x_scr->root_depth, _x_pix, _x_win, WIN_W, WIN_H);
  136. /* setup xcb present extension */
  137. xcb_present_select_input(
  138. _x_con,
  139. xcb_generate_id(_x_con),
  140. _x_win,
  141. XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
  142. /* dynamicaly get the present extention opcode for event identification */
  143. xcb_query_extension_reply_t *r =
  144. xcb_query_extension_reply(_x_con, xcb_query_extension(_x_con, 7, "Present"), NULL);
  145. _x_opcode = r->major_opcode;
  146. free(r);
  147. /* setup cairo drawable */
  148. _c_srf = cairo_xcb_surface_create(_x_con, _x_pix, _x_vis, WIN_W, WIN_H);
  149. _c_ctx = cairo_create(_c_srf);
  150. /* end */
  151. cairo_surface_flush(_c_srf);
  152. xcb_flush(_x_con);
  153. }
  154. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  155. static void
  156. _init_threads(void)
  157. {
  158. pthread_mutex_init(&_t_mutex_rd_1, NULL);
  159. pthread_mutex_init(&_t_mutex_rd_2, NULL);
  160. pthread_cond_init(&_t_cond_rd_1, NULL);
  161. pthread_cond_init(&_t_cond_rd_2, NULL);
  162. }
  163. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  164. void
  165. _reset(void)
  166. {
  167. pthread_mutex_destroy(&_t_mutex_rd_1);
  168. pthread_mutex_destroy(&_t_mutex_rd_2);
  169. pthread_cond_destroy(&_t_cond_rd_1);
  170. pthread_cond_destroy(&_t_cond_rd_2);
  171. cairo_destroy(_c_ctx);
  172. cairo_surface_destroy(_c_srf);
  173. xcb_free_gc(_x_con, _x_ctx);
  174. xcb_free_pixmap(_x_con, _x_pix);
  175. xcb_destroy_window(_x_con, _x_win);
  176. xcb_disconnect(_x_con);
  177. }
  178. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  179. static void *
  180. _thread_event(void *p)
  181. {
  182. int run = 1;
  183. int x_pev_serial;
  184. xcb_generic_event_t *x_ev;
  185. xcb_ge_generic_event_t *x_gev;
  186. xcb_present_complete_notify_event_t *x_pev;
  187. while (run && (x_ev = xcb_wait_for_event(_x_con))) {
  188. switch (x_ev->response_type & ~0x80) {
  189. case XCB_EXPOSE:
  190. /* immediate update without syncing to the refresh rate */
  191. /* without it there are visual glitches when resizing the window */
  192. xcb_copy_area(_x_con, _x_pix, _x_win, _x_ctx, 0, 0, 0, 0, WIN_W, WIN_H);
  193. break;
  194. case XCB_BUTTON_PRESS:
  195. pthread_mutex_lock(&_t_mutex_rd_2);
  196. _update = !_update;
  197. pthread_mutex_unlock(&_t_mutex_rd_2);
  198. pthread_cond_signal(&_t_cond_rd_2);
  199. break;
  200. case XCB_KEY_PRESS:
  201. run = 0;
  202. break;
  203. case XCB_GE_GENERIC:
  204. /* most of this is just checking that we got the right event */
  205. /* unecessary in simple cases */
  206. x_gev = (xcb_ge_generic_event_t*)x_ev;
  207. if (x_gev->extension == _x_opcode && x_gev->event_type == XCB_PRESENT_EVENT_COMPLETE_NOTIFY) {
  208. x_pev = (xcb_present_complete_notify_event_t*)x_ev;
  209. pthread_mutex_lock(&_t_mutex_rd_2);
  210. x_pev_serial = _serial;
  211. pthread_mutex_unlock(&_t_mutex_rd_2);
  212. if (x_pev->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP && x_pev->serial == x_pev_serial) {
  213. pthread_cond_signal(&_t_cond_rd_1);
  214. }
  215. }
  216. break;
  217. }
  218. xcb_flush(_x_con);
  219. free(x_ev);
  220. }
  221. pthread_exit(NULL);
  222. }
  223. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  224. static void *
  225. _thread_render(void *p)
  226. {
  227. pthread_mutex_lock(&_t_mutex_rd_1);
  228. while (1) {
  229. /* check if an update is needed, if not, wait */
  230. pthread_mutex_lock(&_t_mutex_rd_2);
  231. if (!_update) {
  232. pthread_cond_wait(&_t_cond_rd_2, &_t_mutex_rd_2);
  233. }
  234. pthread_mutex_unlock(&_t_mutex_rd_2);
  235. /* update pixmap */
  236. _draw();
  237. /* update window with pixmap */
  238. _serial++;
  239. xcb_present_pixmap(
  240. _x_con,
  241. _x_win,
  242. _x_pix,
  243. _serial,
  244. XCB_XFIXES_REGION_NONE,
  245. XCB_XFIXES_REGION_NONE,
  246. 0, 0,
  247. 0,
  248. 0,
  249. 0,
  250. XCB_PRESENT_OPTION_NONE,
  251. 0, 0, 0,
  252. 0,
  253. NULL);
  254. /* important af, don't forget it */
  255. xcb_flush(_x_con);
  256. /* wait for present event notification in the event thread */
  257. pthread_cond_wait(&_t_cond_rd_1, &_t_mutex_rd_1);
  258. }
  259. pthread_mutex_unlock(&_t_mutex_rd_1);
  260. pthread_exit(NULL);
  261. }