diff options
author | Keith Packard <keithp@keithp.com> | 2013-07-11 17:02:01 -0700 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2013-07-11 17:02:22 -0700 |
commit | 0de6411c1702e81f54ebaed3a6c34e2aeaafa8cd (patch) | |
tree | 6eaf1532c43a107b5549fb5d7d94344a7385f29d | |
parent | cd8a9edcd04033941baedc66003dda4e58a80493 (diff) |
Add lots more examples
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r-- | Makefile | 37 | ||||
-rw-r--r-- | dri3.c | 128 | ||||
-rw-r--r-- | futex.c | 146 | ||||
-rw-r--r-- | present.c | 230 | ||||
-rw-r--r-- | shmfd.c | 4 | ||||
-rw-r--r-- | xfence.c | 45 |
6 files changed, 582 insertions, 8 deletions
@@ -1,10 +1,35 @@ -CFLAGS=-O0 -g $(shell pkg-config --cflags xcb-shm xcb-aux) -LIBS=$(shell pkg-config --libs xcb-shm xcb-aux) +CFLAGS=-Wall -O0 -g $(shell pkg-config --cflags xcb-shm xcb-aux xcb-dri3 xcb-present xshmfence) +LIBS=$(shell pkg-config --libs xcb-shm xcb-aux xcb-dri3 xcb-present xshmfence) -OBJS=shmfd.o +all: shmfd dri3 futex xfence present -shmfd: $(OBJS) - $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) +SHMFD_OBJS=shmfd.o + +shmfd: $(SHMFD_OBJS) + $(CC) $(CFLAGS) -o $@ $(SHMFD_OBJS) $(LIBS) + +DRI3_OBJS=dri3.o + +dri3: $(DRI3_OBJS) + $(CC) $(CFLAGS) -o $@ $(DRI3_OBJS) $(LIBS) + +FUTEX_OBJS=futex.o + +futex: $(FUTEX_OBJS) + $(CC) $(CFLAGS) -o $@ $(FUTEX_OBJS) + +XFENCE_OBJS=xfence.o + +xfence: $(XFENCE_OBJS) + $(CC) $(CFLAGS) -o $@ $(XFENCE_OBJS) $(LIBS) + +PRESENT_OBJS=present.o + +present: $(PRESENT_OBJS) + $(CC) $(CFLAGS) -o $@ $(PRESENT_OBJS) $(LIBS) clean: - rm -f shmfd $(OBJS)
\ No newline at end of file + rm -f shmfd $(SHMFD_OBJS) + rm -f dri3 $(DRI3_OBJS) + rm -f futex $(FUTEX_OBJS) + rm -f present $(PRESENT_OBJS)
\ No newline at end of file @@ -0,0 +1,128 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <xcb/xcb.h> +#include <xcb/xcb_aux.h> +#include <xcb/dri3.h> + +#define WIDTH 128 +#define HEIGHT 128 + +int +main (int argc, char **argv) +{ + xcb_connection_t *c; + int screen_num; + xcb_screen_t *screen; + xcb_gc_t gc; + xcb_dri3_event_t dri3_event; + xcb_window_t window; + xcb_generic_event_t *event; + xcb_generic_error_t *error; + const xcb_query_extension_reply_t *dri3_extension; + uint32_t window_mask; + uint32_t window_values[5]; + xcb_ge_event_t *xge; + + c = xcb_connect(NULL, &screen_num); + if (xcb_connection_has_error(c)) { + printf ("connection error\n"); + exit(1); + } + screen = xcb_aux_get_screen(c, screen_num); + + window_mask = XCB_CW_BACK_PIXEL|XCB_CW_EVENT_MASK; + window_values[0] = 0xffffff; + window_values[1] = XCB_EVENT_MASK_EXPOSURE; + + xcb_create_window(c, + 0, /* depth */ + (window = xcb_generate_id(c)), /* window */ + screen->root, /* root */ + 0, /* x */ + 0, /* y */ + WIDTH * 2, /* width */ + HEIGHT, /* height */ + 0, /* border_width */ + XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ + screen->root_visual, /* visual */ + window_mask, /* mask */ + window_values); /* values */ + xcb_create_gc(c, + (gc = xcb_generate_id(c)), /* gc */ + window, /* drawable */ + 0, /* mask */ + NULL); /* values */ + + xcb_dri3_select_input(c, + (dri3_event = xcb_generate_id(c)), + window, + XCB_DRI3_INPUT_MASK_CONFIGURE_NOTIFY); + + + dri3_extension = xcb_get_extension_data(c, &xcb_dri3_id); + + xcb_register_for_special_event(c, + dri3_extension->major_opcode, + XCB_DRI3_CONFIGURE_NOTIFY, + dri3_event, + NULL); + + xcb_map_window(c, window); + + printf ("mapped\n"); + + for (;;) { + xcb_flush(c); + event = xcb_wait_for_event(c); + if (!event) + break; + printf ("event %d\n", event->response_type); + switch (event->response_type) { + case XCB_EXPOSE: + break; + case 0: + error = (xcb_generic_error_t *) event; + printf ("error %d major %d minor %d\n", + error->error_code, + error->major_code, + error->minor_code); + break; + case XCB_GE: + xge = (xcb_ge_event_t *) event; + if (xge->extension == dri3_extension->major_opcode) { + switch (xge->evtype) { + case XCB_DRI3_CONFIGURE_NOTIFY: { + xcb_dri3_configure_notify_event_t *ce = (void *) event; + printf ("dri3 configure %d %d %d %d\n", + ce->x, ce->y, ce->width, ce->height); + break; + } + } + } + break; + default: + printf ("response %d\n", event->response_type); + break; + } + } + return 0; +} @@ -0,0 +1,146 @@ +#include <stdint.h> +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <linux/futex.h> +#include <sys/time.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/mman.h> +#include <errno.h> +#include <values.h> + +/* Three values: + * + * 1: signaled + * 0: unsignaled + * -1: waiters + */ + +static inline long sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3) +{ + return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); +} + +static inline int futex_wake(int32_t *addr) { + return sys_futex(addr, FUTEX_WAKE, MAXINT, NULL, NULL, 0); +} + +static inline int futex_wait(int32_t *addr, int32_t value) { + return sys_futex(addr, FUTEX_WAIT, value, NULL, NULL, 0); +} + +#define barrier() __asm__ __volatile__("": : :"memory") + +static inline void atomic_store(int32_t *f, int32_t v) +{ + barrier(); + *f = v; + barrier(); +} + +static inline int32_t atomic_fetch(int32_t *a) +{ + int32_t v; + barrier(); + v = *a; + barrier(); + return v; +} + + +int fence_trigger(int32_t *f) +{ + if (__sync_val_compare_and_swap(f, 0, 1) == -1) { + atomic_store(f, 1); + if (futex_wake(f) < 0) + return -1; + } + return 0; +} + + +int fence_await(int32_t *f) +{ + while (__sync_val_compare_and_swap(f, 0, -1) != 1) { + if (futex_wait(f, -1)) { + if (errno != EWOULDBLOCK) + return -1; + } + } + return 0; +} + +int fence_query(int32_t *f) +{ + return atomic_fetch(f) == 1; +} + +void fence_reset(int32_t *f) +{ + __sync_bool_compare_and_swap(f, 1, 0); +} + +int +make_shm(int size) +{ + char template[] = "/run/shm/shmfd-XXXXXX"; + int fd = mkstemp(template); + + if (fd < 0) + return fd; + unlink(template); + ftruncate(fd, size); + return fd; +} + +void * +map_shm(int fd, int size) +{ + void *addr; + addr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + close (fd); + return 0; + } + return addr; +} + +int main(int argc, char **argv) +{ + int fd; + int32_t *x; + int i; + int c; + int pid; + + fd = make_shm(sizeof (int32_t)); + + for (c = 0; c < 5; c++) { + switch (fork()) { + case -1: + printf ("failed\n"); + break; + case 0: + pid = getpid(); + x = map_shm(fd, sizeof (int32_t)); + for (i = 0; i < 10; i++) { + printf ("%6d: waiting\n", pid); + fence_await(x); + printf ("%6d: awoken\n", pid); + usleep(10 * 1000); + fence_reset(x); + } + exit(0); + } + } + x = map_shm(fd, sizeof (int32_t)); + for (i = 0; i < 10; i++) { + printf ("trigger sleep\n"); + usleep(100 * 1000); + printf ("trigger\n"); + fence_trigger(x); + printf ("trigger done\n"); + } + exit(0); +} diff --git a/present.c b/present.c new file mode 100644 index 0000000..81b6b57 --- /dev/null +++ b/present.c @@ -0,0 +1,230 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <time.h> +#include <sys/mman.h> +#include <xcb/xcb.h> +#include <xcb/xcb_aux.h> +#include <xcb/present.h> + +#define WIDTH 128 +#define HEIGHT 128 + +xcb_connection_t *c; +int screen_num; +xcb_screen_t *screen; +xcb_gc_t gc; +xcb_present_event_t present_event; +xcb_window_t window; +xcb_pixmap_t pixmap; +xcb_generic_event_t *event; +xcb_generic_error_t *error; +const xcb_query_extension_reply_t *present_extension; +uint32_t window_mask; +uint32_t window_values[5]; +uint32_t gc_mask; +uint32_t gc_values[5]; +xcb_segment_t segments[2]; +xcb_rectangle_t rectangle; +xcb_ge_event_t *xge; +uint32_t color; +int32_t color_inc; + +static void draw(void) +{ + gc_mask = XCB_GC_FOREGROUND; + gc_values[0] = 0xffffffff; + xcb_change_gc(c, gc, gc_mask, gc_values); + rectangle.x = 0; + rectangle.y = 0; + rectangle.width = WIDTH; + rectangle.height = HEIGHT; + xcb_poly_fill_rectangle(c, pixmap, gc, 1, &rectangle); + + gc_mask = XCB_GC_FOREGROUND; + gc_values[0] = color | (color << 8) | (color << 16); + xcb_change_gc(c, gc, gc_mask, gc_values); + + segments[0].x1 = 0; + segments[0].y1 = 0; + segments[0].x2 = WIDTH; + segments[0].y2 = HEIGHT; + + segments[1].x1 = WIDTH; + segments[1].y1 = 0; + segments[1].x2 = 0; + segments[1].y2 = HEIGHT; + xcb_poly_segment(c, + pixmap, + gc, + 2, + segments); +} + +static void show(int interval) +{ + xcb_present_region (c, + window, + pixmap, + 0, + 0, + 0, + 0, + 0, + interval, + 0, + 0); +} + +int frame_count; +uint32_t start_time; +uint32_t end_time; + +static uint32_t +millis(void) +{ + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC, &tp); + return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); +} + +static void frame(void) +{ + if (frame_count == 0) + start_time = millis(); + if (color_inc > 0) { + color += color_inc; + if (color > 0xff) { + color = 0xff; + color_inc = -color_inc; + } + } else { + if (color < -color_inc) { + color = 0; + color_inc = -color_inc; + } else + color += color_inc; + } + draw(); + show(1); + if (++frame_count == 100) { + end_time = millis(); + printf ("frame rate: %f\n", (double) frame_count / ((double) (end_time - start_time) / 1000.0)); + frame_count = 0; + } +} + +int +main (int argc, char **argv) +{ + c = xcb_connect(NULL, &screen_num); + if (xcb_connection_has_error(c)) { + printf ("connection error\n"); + exit(1); + } + screen = xcb_aux_get_screen(c, screen_num); + + window_mask = XCB_CW_BACK_PIXEL|XCB_CW_EVENT_MASK; + window_values[0] = 0xffffff; + window_values[1] = XCB_EVENT_MASK_EXPOSURE; + + xcb_create_window(c, + 0, /* depth */ + (window = xcb_generate_id(c)), /* window */ + screen->root, /* root */ + 0, /* x */ + 0, /* y */ + WIDTH, /* width */ + HEIGHT, /* height */ + 0, /* border_width */ + XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ + screen->root_visual, /* visual */ + window_mask, /* mask */ + window_values); /* values */ + xcb_create_pixmap(c, + 24, + (pixmap = xcb_generate_id(c)), + window, + WIDTH, + HEIGHT); + + xcb_create_gc(c, + (gc = xcb_generate_id(c)), /* gc */ + window, /* drawable */ + 0, /* mask */ + NULL); /* values */ + + xcb_present_select_input(c, + (present_event = xcb_generate_id(c)), + window, + XCB_PRESENT_INPUT_MASK_CONFIGURE_NOTIFY|XCB_PRESENT_INPUT_MASK_COMPLETE_NOTIFY); + + + present_extension = xcb_get_extension_data(c, &xcb_present_id); + + color = 0; + color_inc = 0x10; + draw(); + + xcb_map_window(c, window); + + printf ("mapped\n"); + + for (;;) { + xcb_flush(c); + event = xcb_wait_for_event(c); + if (!event) + break; + switch (event->response_type) { + case XCB_EXPOSE: + show(0); + break; + case 0: + error = (xcb_generic_error_t *) event; + printf ("error %d major %d minor %d\n", + error->error_code, + error->major_code, + error->minor_code); + break; + case XCB_GE: + xge = (xcb_ge_event_t *) event; + if (xge->extension == present_extension->major_opcode) { + switch (xge->evtype) { + case XCB_PRESENT_CONFIGURE_NOTIFY: { + xcb_present_configure_notify_event_t *ce = (void *) event; + printf ("present configure %d %d %d %d\n", + ce->x, ce->y, ce->width, ce->height); + break; + } + case XCB_PRESENT_COMPLETE_NOTIFY: { + xcb_present_complete_notify_event_t *ce = (void *) event; + frame(); + break; + } + } + } + break; + default: + printf ("response %d\n", event->response_type); + break; + } + } + return 0; +} @@ -22,12 +22,13 @@ #include <xcb/xcb.h> #include <xcb/shm.h> #include <xcb/xcb_aux.h> +#include <unistd.h> int make_shm(int size, void **addrp) { void *addr; - char template[] = "/tmp/shmfd-XXXXXX"; + char template[] = "/run/shm/shmfd-XXXXXX"; int fd = mkstemp(template); if (fd < 0) @@ -77,7 +78,6 @@ main (int argc, char **argv) xcb_shm_seg_t shm_seg; xcb_shm_seg_t shm_server_seg; xcb_gc_t gc; - xcb_pixmap_t pixmap; xcb_window_t window; xcb_generic_event_t *event; xcb_generic_error_t *error; diff --git a/xfence.c b/xfence.c new file mode 100644 index 0000000..3e9f138 --- /dev/null +++ b/xfence.c @@ -0,0 +1,45 @@ +#include <stdint.h> +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <X11/xshmfence.h> +#include <unistd.h> + +int main(int argc, char **argv) +{ + int fd; + int32_t *x; + int i; + int c; + int pid; + + fd = xshmfence_alloc_shm(); + + for (c = 0; c < 5; c++) { + switch (fork()) { + case -1: + printf ("failed\n"); + break; + case 0: + pid = getpid(); + x = xshmfence_map_shm(fd); + for (i = 0; i < 10; i++) { + printf ("%6d: waiting\n", pid); + xshmfence_await(x); + printf ("%6d: awoken\n", pid); + usleep(10 * 1000); + xshmfence_reset(x); + } + exit(0); + } + } + x = xshmfence_map_shm(fd); + for (i = 0; i < 10; i++) { + printf ("trigger sleep\n"); + usleep(100 * 1000); + printf ("trigger\n"); + xshmfence_trigger(x); + printf ("trigger done\n"); + } + exit(0); +} |