summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2013-07-11 17:02:01 -0700
committerKeith Packard <keithp@keithp.com>2013-07-11 17:02:22 -0700
commit0de6411c1702e81f54ebaed3a6c34e2aeaafa8cd (patch)
tree6eaf1532c43a107b5549fb5d7d94344a7385f29d
parentcd8a9edcd04033941baedc66003dda4e58a80493 (diff)
Add lots more examples
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--Makefile37
-rw-r--r--dri3.c128
-rw-r--r--futex.c146
-rw-r--r--present.c230
-rw-r--r--shmfd.c4
-rw-r--r--xfence.c45
6 files changed, 582 insertions, 8 deletions
diff --git a/Makefile b/Makefile
index 73bd712..7b79b87 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/dri3.c b/dri3.c
new file mode 100644
index 0000000..f1fc20b
--- /dev/null
+++ b/dri3.c
@@ -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;
+}
diff --git a/futex.c b/futex.c
new file mode 100644
index 0000000..25f74f5
--- /dev/null
+++ b/futex.c
@@ -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;
+}
diff --git a/shmfd.c b/shmfd.c
index 6bf9003..a7fb8e4 100644
--- a/shmfd.c
+++ b/shmfd.c
@@ -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);
+}