Browse Source

Upload files to ''

master
bricks 1 year ago
parent
commit
9315767d09
2 changed files with 348 additions and 0 deletions
  1. +2
    -0
      makefile
  2. +346
    -0
      test.c

+ 2
- 0
makefile View File

@@ -0,0 +1,2 @@
test: test.c
gcc -o test test.c -lxcb -lxcb-util -lxcb-present -lcairo -pthread

+ 346
- 0
test.c View File

@@ -0,0 +1,346 @@
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

#include <cairo/cairo.h>
#include <cairo/cairo-xcb.h>
#include <xcb/xcb.h>
#include <xcb/present.h>

/************************************************************************************************************/
/************************************************************************************************************/
/************************************************************************************************************/

#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);
}

Loading…
Cancel
Save