#include #include #include #include #include #include #include #include #include #include #include /************************************************************************************************************/ /* _ ********************************************************************************************************/ /************************************************************************************************************/ static void _draw (void); static void _init_cairo (void); static void _init_xcb (void); static void _reset (void); static void _run (void); /************************************************************************************************************/ /************************************************************************************************************/ /************************************************************************************************************/ static uint32_t _opt_frame_divider = 1; static int _opt_async = 0; static xcb_connection_t *_x_con = NULL; static xcb_screen_t *_x_scr = NULL; static xcb_visualtype_t *_x_vis = NULL; static xcb_special_event_t *_x_sev = NULL; static xcb_window_t _x_win = 0; static xcb_pixmap_t _x_pix = 0; static cairo_surface_t *_c_srf = NULL; static cairo_t *_c_ctx = NULL; static int _speed1 = 60; static int _speed2 = 5; static double _pos1 = 0; static double _inc1 = 1; static double _pos2 = 0; static double _inc2 = 1; static long _t_full = 0; static long _t_paint = 0; static long _t_xsync = 0; static double _fps = 0; static long _total = 0; static uint32_t stamp = 0; /************************************************************************************************************/ /************************************************************************************************************/ /************************************************************************************************************/ int main(int argc, char **argv) { /* options */ int opt; while ((opt = getopt(argc, argv, "al:")) != -1) { switch (opt) { case 'a': _opt_async = 1; break; case 'l': _opt_frame_divider = (unsigned int)atoi(optarg); break; } } /* program */ _init_xcb(); _init_cairo(); _run(); _reset(); return 0; } /************************************************************************************************************/ /* _ ********************************************************************************************************/ /************************************************************************************************************/ static void _draw(void) { /* background */ cairo_set_source_rgb(_c_ctx, 0.1, 0.1, 0.1); cairo_rectangle(_c_ctx, 0, 0, 700, 700); cairo_fill(_c_ctx); /* big square */ double adv1 = (double)(_speed1 * _t_full) / 1000000.0; _pos1 += adv1 * _inc1; while (_pos1 > 600.0 || _pos1 < 0.0) { if (_pos1 > 600.0) { _inc1 = -1; adv1 = _pos1 - 600; _pos1 = 600; } else { _inc1 = 1; adv1 = -_pos1; _pos1 = 0; } _pos1 += adv1 * _inc1; } cairo_set_source_rgb(_c_ctx, 0.8, 0.8, 0.8); cairo_rectangle(_c_ctx, _pos1, _pos1, 100, 100); cairo_fill(_c_ctx); /* small square */ double adv2 = (double)(_speed2 * _t_full) / 1000000.0; _pos2 += adv2 * _inc2; while (_pos2 > 80.0 || _pos2 < 0.0) { if (_pos2 > 80.0) { _inc2 = -1; adv2 = _pos2 - 80; _pos2 = 80; } else { _inc2 = 1; adv2 = -_pos2; _pos2 = 0; } _pos2 += adv2 * _inc2; } cairo_set_source_rgb(_c_ctx, 0.3, 0.3, 0.3); cairo_rectangle(_c_ctx, _pos1 + 80 - _pos2, _pos1 + _pos2, 20, 20); cairo_fill(_c_ctx); /* counters */ char str[128]; cairo_set_source_rgb(_c_ctx, 1.0, 1.0, 1.0); sprintf(str, "fps : %f", _fps); cairo_move_to(_c_ctx, 25, 555); cairo_show_text(_c_ctx, str); sprintf(str, "frame time (µs) : %li", _t_full); cairo_move_to(_c_ctx, 25, 585); cairo_show_text(_c_ctx, str); sprintf(str, "paint time (µs) : %li", _t_paint); cairo_move_to(_c_ctx, 25, 615); cairo_show_text(_c_ctx, str); sprintf(str, "x sync time (µs) : %li", _t_xsync); cairo_move_to(_c_ctx, 25, 645); cairo_show_text(_c_ctx, str); sprintf(str, "total frames : %li", _total); cairo_move_to(_c_ctx, 25, 675); cairo_show_text(_c_ctx, str); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ static void _init_cairo(void) { _c_srf = cairo_xcb_surface_create(_x_con, _x_pix, _x_vis, 700, 700); _c_ctx = cairo_create(_c_srf); cairo_set_font_size(_c_ctx, 20); cairo_select_font_face(_c_ctx, "Terminus", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_surface_flush(_c_srf); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ static void _init_xcb(void) { /* connection */ _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; } } } /* window */ uint32_t mask_vals[2]; mask_vals[0] = _x_scr->black_pixel; mask_vals[1] = XCB_EVENT_MASK_EXPOSURE; _x_win = xcb_generate_id(_x_con); xcb_create_window( _x_con, XCB_COPY_FROM_PARENT, _x_win, _x_scr->root, 0, 0, 700, 700, 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); xcb_flush(_x_con); /* pixmap */ _x_pix = xcb_generate_id(_x_con); xcb_create_pixmap(_x_con, _x_scr->root_depth, _x_pix, _x_win, 700, 700); /* present extension */ uint32_t id = xcb_generate_id(_x_con); xcb_present_select_input( _x_con, id, _x_win, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); /* optional setup a special event queue for the present extension */ /* if not done present completion events can still be recoved from the regular */ /* xcb_wait_for_event() queue */ _x_sev = xcb_register_for_special_xge(_x_con, &xcb_present_id, id, &stamp); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ static void _reset(void) { cairo_destroy(_c_ctx); cairo_surface_destroy(_c_srf); xcb_free_pixmap(_x_con, _x_pix); xcb_destroy_window(_x_con, _x_win); xcb_disconnect(_x_con); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ static void _run(void) { xcb_generic_event_t *ev = NULL; int n = 0; long t1 = 0; long t2 = 0; long t3 = 0; struct timespec ts = {0}; while (1) { _total++; clock_gettime(CLOCK_MONOTONIC, &ts); t1 = ts.tv_nsec / 1000 + ts.tv_sec * 1000000; _draw(); clock_gettime(CLOCK_MONOTONIC, &ts); t2 = ts.tv_nsec / 1000 + ts.tv_sec * 1000000; xcb_present_pixmap( _x_con, _x_win, _x_pix, 123456, XCB_XFIXES_REGION_NONE, XCB_XFIXES_REGION_NONE, 0, 0, 0, 0, 0, _opt_async ? XCB_PRESENT_OPTION_ASYNC : XCB_PRESENT_OPTION_NONE, 0, _opt_frame_divider, 0, 0, NULL); xcb_flush(_x_con); clock_gettime(CLOCK_MONOTONIC, &ts); t3 = ts.tv_nsec / 1000 + ts.tv_sec * 1000000; _t_paint = t2 - t1; _t_xsync = t3 - t2; ev = xcb_wait_for_special_event(_x_con, _x_sev); if (!ev) { printf("exiting\n"); return; } free(ev); clock_gettime(CLOCK_MONOTONIC, &ts); _t_full = ts.tv_nsec / 1000 + ts.tv_sec * 1000000 - t1; _fps = 1000000.0 / (double)_t_full; } }