|
|
@@ -0,0 +1,340 @@ |
|
|
|
#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 _delay = 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); |
|
|
|
|
|
|
|
/* get frame delay */ |
|
|
|
|
|
|
|
xcb_randr_get_screen_info_cookie_t k = xcb_randr_get_screen_info(_x_con, _x_scr->root); |
|
|
|
xcb_randr_get_screen_info_reply_t *r = xcb_randr_get_screen_info_reply(_x_con, k, NULL); |
|
|
|
|
|
|
|
_delay = 1000000.0 / (double)r->rate; |
|
|
|
|
|
|
|
free(r); |
|
|
|
} |
|
|
|
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
} |