From 9315767d091640fb3af3bd63f0bfe84618710c25 Mon Sep 17 00:00:00 2001 From: bricks Date: Sun, 19 Feb 2023 11:02:29 -0500 Subject: [PATCH] Upload files to '' --- makefile | 2 + test.c | 346 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 makefile create mode 100644 test.c diff --git a/makefile b/makefile new file mode 100644 index 0000000..14d3595 --- /dev/null +++ b/makefile @@ -0,0 +1,2 @@ +test: test.c + gcc -o test test.c -lxcb -lxcb-util -lxcb-present -lcairo -pthread diff --git a/test.c b/test.c new file mode 100644 index 0000000..d901d3a --- /dev/null +++ b/test.c @@ -0,0 +1,346 @@ +#include +#include +#include + +#include +#include +#include +#include + +/************************************************************************************************************/ +/************************************************************************************************************/ +/************************************************************************************************************/ + +#define WIN_W 600 +#define WIN_H 400 + +#define RECT_W 100 +#define RECT_SPEED 5 /* 300 px/s at 60 Hz */ + +/************************************************************************************************************/ +/************************************************************************************************************/ +/************************************************************************************************************/ + +static void _draw (void); +static void _init_graphics (void); +static void _init_threads (void); +static void _reset (void); + +static void * _thread_event (void *p); +static void * _thread_render (void *p); + +/************************************************************************************************************/ +/************************************************************************************************************/ +/************************************************************************************************************/ + +static xcb_connection_t *_x_con = NULL; +static xcb_screen_t *_x_scr = NULL; +static xcb_visualtype_t *_x_vis = NULL; +static xcb_window_t _x_win = 0; +static xcb_pixmap_t _x_pix = 0; +static xcb_gcontext_t _x_ctx = 0; + +static uint8_t _x_opcode = 0; + +static cairo_surface_t *_c_srf = NULL; +static cairo_t *_c_ctx = NULL; + +static pthread_t _t_id_ev; +static pthread_t _t_id_rd; +static pthread_cond_t _t_cond_rd_1; +static pthread_cond_t _t_cond_rd_2; +static pthread_mutex_t _t_mutex_rd_1; +static pthread_mutex_t _t_mutex_rd_2; + +static int _rect_pos = WIN_W; +static int _update = 1; +static int _serial = 0; + +/************************************************************************************************************/ +/************************************************************************************************************/ +/************************************************************************************************************/ + +int +main(int argc, char **argv) +{ + /* initialisation */ + + _init_graphics(); + _init_threads(); + + /* initial render for first expose event */ + + _draw(); + + /* start the threads */ + /* the event thread leads the tempo */ + + pthread_create(&_t_id_ev, NULL, _thread_event, NULL); + pthread_create(&_t_id_rd, NULL, _thread_render, NULL); + + pthread_join(_t_id_ev, NULL); + + pthread_cancel(_t_id_rd); + pthread_join(_t_id_rd, NULL); + + /* end */ + + _reset(); +} + +/************************************************************************************************************/ +/************************************************************************************************************/ +/************************************************************************************************************/ + +static void +_draw(void) +{ + /* update position */ + + _rect_pos += RECT_SPEED; + if (_rect_pos >= WIN_W) { + _rect_pos = -RECT_W; + } + + /* update pixmap */ + + cairo_set_source_rgb(_c_ctx, 0.3, 0.3, 0.3); + cairo_paint(_c_ctx); + + cairo_set_source_rgb(_c_ctx, 0.7, 0.7, 0.7); + cairo_rectangle(_c_ctx, _rect_pos, 0, RECT_W, WIN_H); + cairo_fill(_c_ctx); + + cairo_surface_flush(_c_srf); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +static void +_init_graphics(void) +{ + /* setup xcb */ + + _x_con = xcb_connect(NULL, NULL); + _x_scr = xcb_setup_roots_iterator(xcb_get_setup(_x_con)).data; + + xcb_visualtype_iterator_t x_vi; + xcb_depth_iterator_t x_di; + + x_di = xcb_screen_allowed_depths_iterator(_x_scr); + for (; x_di.rem; xcb_depth_next(&x_di)) { + x_vi = xcb_depth_visuals_iterator(x_di.data); + for (; x_vi.rem; xcb_visualtype_next(&x_vi)) { + if (_x_scr->root_visual == x_vi.data->visual_id) { + _x_vis = x_vi.data; + break; + } + } + } + + /* setup generic xcb graphical context for copying the pixmap */ + + _x_ctx = xcb_generate_id(_x_con); + xcb_create_gc( + _x_con, + _x_ctx, + _x_scr->root, + XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES, + &(uint32_t[2]){_x_scr->black_pixel, 0}); + + /* setup xcb window */ + + uint32_t mask_vals[2]; + mask_vals[0] = _x_scr->black_pixel; + mask_vals[1] = XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_KEY_PRESS | + XCB_EVENT_MASK_BUTTON_PRESS; + + _x_win = xcb_generate_id(_x_con); + xcb_create_window( + _x_con, + XCB_COPY_FROM_PARENT, + _x_win, + _x_scr->root, + 0, 0, + WIN_W, WIN_H, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + _x_scr->root_visual, + XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, + mask_vals); + + xcb_map_window(_x_con, _x_win); + + /* setup xcb pixmap */ + + _x_pix = xcb_generate_id(_x_con); + xcb_create_pixmap(_x_con, _x_scr->root_depth, _x_pix, _x_win, WIN_W, WIN_H); + + /* setup xcb present extension */ + + xcb_present_select_input( + _x_con, + xcb_generate_id(_x_con), + _x_win, + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); + + /* dynamicaly get the present extention opcode for event identification */ + + xcb_query_extension_reply_t *r = + xcb_query_extension_reply(_x_con, xcb_query_extension(_x_con, 7, "Present"), NULL); + + _x_opcode = r->major_opcode; + free(r); + + /* setup cairo drawable */ + + _c_srf = cairo_xcb_surface_create(_x_con, _x_pix, _x_vis, WIN_W, WIN_H); + _c_ctx = cairo_create(_c_srf); + + /* end */ + + cairo_surface_flush(_c_srf); + xcb_flush(_x_con); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +static void +_init_threads(void) +{ + pthread_mutex_init(&_t_mutex_rd_1, NULL); + pthread_mutex_init(&_t_mutex_rd_2, NULL); + + pthread_cond_init(&_t_cond_rd_1, NULL); + pthread_cond_init(&_t_cond_rd_2, NULL); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +void +_reset(void) +{ + pthread_mutex_destroy(&_t_mutex_rd_1); + pthread_mutex_destroy(&_t_mutex_rd_2); + + pthread_cond_destroy(&_t_cond_rd_1); + pthread_cond_destroy(&_t_cond_rd_2); + + cairo_destroy(_c_ctx); + cairo_surface_destroy(_c_srf); + + xcb_free_gc(_x_con, _x_ctx); + xcb_free_pixmap(_x_con, _x_pix); + xcb_destroy_window(_x_con, _x_win); + xcb_disconnect(_x_con); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +static void * +_thread_event(void *p) +{ + int run = 1; + int x_pev_serial; + + xcb_generic_event_t *x_ev; + xcb_ge_generic_event_t *x_gev; + xcb_present_complete_notify_event_t *x_pev; + + while (run && (x_ev = xcb_wait_for_event(_x_con))) { + switch (x_ev->response_type & ~0x80) { + + case XCB_EXPOSE: + /* immediate update without syncing to the refresh rate */ + /* without it there are visual glitches when resizing the window */ + xcb_copy_area(_x_con, _x_pix, _x_win, _x_ctx, 0, 0, 0, 0, WIN_W, WIN_H); + break; + + case XCB_BUTTON_PRESS: + pthread_mutex_lock(&_t_mutex_rd_2); + _update = !_update; + pthread_mutex_unlock(&_t_mutex_rd_2); + pthread_cond_signal(&_t_cond_rd_2); + break; + + case XCB_KEY_PRESS: + run = 0; + break; + + case XCB_GE_GENERIC: + /* most of this is just checking that we got the right event */ + /* unecessary in simple cases */ + x_gev = (xcb_ge_generic_event_t*)x_ev; + if (x_gev->extension == _x_opcode && x_gev->event_type == XCB_PRESENT_EVENT_COMPLETE_NOTIFY) { + x_pev = (xcb_present_complete_notify_event_t*)x_ev; + pthread_mutex_lock(&_t_mutex_rd_2); + x_pev_serial = _serial; + pthread_mutex_unlock(&_t_mutex_rd_2); + if (x_pev->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP && x_pev->serial == x_pev_serial) { + pthread_cond_signal(&_t_cond_rd_1); + } + } + break; + } + xcb_flush(_x_con); + free(x_ev); + } + + pthread_exit(NULL); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +static void * +_thread_render(void *p) +{ + pthread_mutex_lock(&_t_mutex_rd_1); + + while (1) { + + /* check if an update is needed, if not, wait */ + + pthread_mutex_lock(&_t_mutex_rd_2); + if (!_update) { + pthread_cond_wait(&_t_cond_rd_2, &_t_mutex_rd_2); + } + pthread_mutex_unlock(&_t_mutex_rd_2); + + /* update pixmap */ + + _draw(); + + /* update window with pixmap */ + + _serial++; + + xcb_present_pixmap( + _x_con, + _x_win, + _x_pix, + _serial, + XCB_XFIXES_REGION_NONE, + XCB_XFIXES_REGION_NONE, + 0, 0, + 0, + 0, + 0, + XCB_PRESENT_OPTION_NONE, + 0, 0, 0, + 0, + NULL); + + /* important af, don't forget it */ + + xcb_flush(_x_con); + + /* wait for present event notification in the event thread */ + + pthread_cond_wait(&_t_cond_rd_1, &_t_mutex_rd_1); + } + + pthread_mutex_unlock(&_t_mutex_rd_1); + pthread_exit(NULL); +}