diff options
author | Keith Packard <keithp@keithp.com> | 2014-01-30 12:11:00 -0800 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2014-01-30 12:11:00 -0800 |
commit | 739c624630154b422d7f5e4ae92f93df42fa35b9 (patch) | |
tree | 19bab22b07540ef45da62a0128c847e2b583be79 | |
parent | e8828fa0513e666fa7246cd213001c51d7957e0e (diff) |
present demo: support multiple pixmaps
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r-- | present.c | 146 |
1 files changed, 119 insertions, 27 deletions
@@ -18,11 +18,15 @@ #include <stdio.h> #include <stddef.h> #include <stdlib.h> +#include <unistd.h> +#include <stdbool.h> #include <time.h> #include <sys/mman.h> #include <xcb/xcb.h> #include <xcb/xcb_aux.h> #include <xcb/present.h> +#include <xcb/xfixes.h> +#include <xcb/sync.h> #define INIT_WIDTH 500 #define INIT_HEIGHT 500 @@ -34,9 +38,14 @@ xcb_screen_t *screen; xcb_gc_t gc; xcb_present_event_t present_event; xcb_window_t window; -xcb_pixmap_t pixmap; +xcb_xfixes_region_t update; +#define NPIXMAP 3 +xcb_pixmap_t pixmap[NPIXMAP]; +bool busy[NPIXMAP]; xcb_generic_event_t *event; xcb_generic_error_t *error; +xcb_sync_fence_t wait_fence; +int using_fence; const xcb_query_extension_reply_t *present_extension; uint32_t window_mask; uint32_t window_values[5]; @@ -49,29 +58,54 @@ int x; int x_inc = 30; uint64_t msc; uint64_t target_msc; +int interval = 0; +uint32_t serial; +uint32_t options = 0; // XCB_PRESENT_OPTION_ASYNC; -static void make_pixmap(void) +static void make_pixmap(int i) { xcb_create_pixmap(c, 24, - (pixmap = xcb_generate_id(c)), + (pixmap[i] = xcb_generate_id(c)), window, width, height); } +static void make_update(void) +{ + return; + xcb_rectangle_t rect = { .x = 0, .y = 0, .width = width, .height = height }; + + xcb_xfixes_create_region(c, + (update = xcb_generate_id(c)), + 1, + &rect); +} + static void discard_pixmap(void) { - if (pixmap) { - xcb_free_pixmap (c, pixmap); - pixmap = 0; + int i; + for (i = 0; i < NPIXMAP; i++) { + if (pixmap[i]) { + xcb_free_pixmap (c, pixmap[i]); + pixmap[i] = 0; + } + } + + if (update) { + xcb_xfixes_destroy_region(c, update); + update = 0; } } -static void draw(void) +static void draw(int i) { - if (!pixmap) - make_pixmap(); + if (!pixmap[i]) + make_pixmap(i); + + if (!update) + make_update(); gc_mask = XCB_GC_FOREGROUND; gc_values[0] = 0xffffffff; @@ -80,7 +114,7 @@ static void draw(void) rectangle.y = 0; rectangle.width = width; rectangle.height = height; - xcb_poly_fill_rectangle(c, pixmap, gc, 1, &rectangle); + xcb_poly_fill_rectangle(c, pixmap[i], gc, 1, &rectangle); gc_mask = XCB_GC_FOREGROUND; gc_values[0] = 0x0; @@ -90,7 +124,7 @@ static void draw(void) rectangle.y = 0; rectangle.width = 60; rectangle.height = height; - xcb_poly_fill_rectangle(c, pixmap, gc, 1, &rectangle); + xcb_poly_fill_rectangle(c, pixmap[i], gc, 1, &rectangle); x += x_inc; if (x_inc > 0) { @@ -104,20 +138,20 @@ static void draw(void) #define None 0 -static void show(void) +static void show(int i) { xcb_present_pixmap (c, window, - pixmap, - 0, - None, + pixmap[i], + i, None, + update, 0, 0, None, + using_fence ? wait_fence : None, None, - None, - 0, + options, target_msc, 0, 0, @@ -126,6 +160,9 @@ static void show(void) } int frame_count; +int skip_count; +int copy_count; +int flip_count; uint32_t start_time; uint32_t end_time; @@ -139,10 +176,16 @@ millis(void) static void frame(void) { - draw(); - target_msc = msc + 1; - show(); - ++frame_count; + int p; + + for (p = 0; p < NPIXMAP; p++) { + if (!busy[p]) { + busy[p] = true; + draw(p); + target_msc += interval; + show(p); + } + } } int @@ -155,9 +198,11 @@ main (int argc, char **argv) } screen = xcb_aux_get_screen(c, screen_num); + (void) xcb_xfixes_query_version(c, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); + window_mask = XCB_CW_BACK_PIXEL|XCB_CW_EVENT_MASK; window_values[0] = 0xffffff; - window_values[1] = XCB_EVENT_MASK_EXPOSURE; + window_values[1] = XCB_EVENT_MASK_EXPOSURE|XCB_EVENT_MASK_KEY_PRESS; width = INIT_WIDTH; height = INIT_HEIGHT; @@ -181,6 +226,11 @@ main (int argc, char **argv) 0, /* mask */ NULL); /* values */ + xcb_sync_create_fence(c, + window, + (wait_fence = xcb_generate_id(c)), + 0); + xcb_present_select_input(c, (present_event = xcb_generate_id(c)), window, @@ -191,10 +241,10 @@ main (int argc, char **argv) present_extension = xcb_get_extension_data(c, &xcb_present_id); start_time = millis(); - draw(); + draw(0); xcb_map_window(c, window); - show(); + show(0); xcb_present_notify_msc(c, window, 0, 0, 5 * 60, 0); printf ("mapped\n"); @@ -207,6 +257,21 @@ main (int argc, char **argv) switch (event->response_type) { case XCB_EXPOSE: break; + case XCB_KEY_PRESS: + switch (++using_fence) { + case 1: + printf ("wait fence\n"); + break; + case 2: + printf ("trigger fence\n"); + xcb_sync_trigger_fence(c, wait_fence); + break; + case 3: + printf ("no fence\n"); + xcb_sync_reset_fence(c, wait_fence); + using_fence = 0; + } + break; case 0: error = (xcb_generic_error_t *) event; printf ("error %d major %d minor %d\n", @@ -229,25 +294,52 @@ main (int argc, char **argv) } case XCB_PRESENT_COMPLETE_NOTIFY: { xcb_present_complete_notify_event_t *ce = (void *) event; +// printf ("kind %d mode %d\n", ce->kind, ce->mode); if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) { int64_t diff = ce->msc - target_msc; if (diff< 0) diff = -diff; - if (diff) + if (diff && interval) printf ("target %lld actual %lld\n", target_msc, ce->msc); + ++frame_count; + switch (ce->mode) { + case XCB_PRESENT_COMPLETE_MODE_COPY: + ++copy_count; + break; + case XCB_PRESENT_COMPLETE_MODE_SKIP: + ++skip_count; + break; + case XCB_PRESENT_COMPLETE_MODE_FLIP: + ++flip_count; + break; + } msc = ce->msc; - frame(); + target_msc = msc + interval; + if (interval) + frame(); } else { xcb_present_notify_msc(c, window, 0, 0, 5 * 60, 0); end_time = millis(); double seconds = (end_time - start_time) / 1000.0; - printf ("%5d frames in %8.3f seconds. frame rate: %f\n", frame_count, seconds, (double) frame_count / ((double) (end_time - start_time) / 1000.0)); + printf ("%5d frames in %8.3f seconds. frame rate: %f copy %d skip %d flip %d\n", + frame_count, seconds, (double) frame_count / ((double) (end_time - start_time) / 1000.0), + copy_count, skip_count, flip_count); frame_count = 0; + copy_count = 0; + skip_count = 0; + flip_count = 0; start_time = millis(); } break; } + case XCB_PRESENT_IDLE_NOTIFY: { + xcb_present_idle_notify_event_t *ie = (void *) event; + busy[ie->serial] = false; + if (!interval) + frame(); + break; + } } } break; |