|
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <unistd.h>
-
- #include <cairo/cairo.h>
- #include <cairo/cairo-xcb.h>
- #include <xcb/xcb.h>
- #include <xcb/present.h>
- #include <xcb/xfixes.h>
- #include <xcb/randr.h>
-
- /************************************************************************************************************/
- /* _ ********************************************************************************************************/
- /************************************************************************************************************/
-
- 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;
- }
- }
|