diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | vidtime.c | 98 |
2 files changed, 84 insertions, 21 deletions
@@ -1,7 +1,10 @@ SRCS=vidtime.c OBJS=$(SRCS:.c=.o) -LIBS=-lX11 -lpthread -CFLAGS=-O0 -g +LIBS=$(shell pkg-config x11 xpresent --libs) -lpthread +CFLAGS=-O0 -g $(shell pkg-config x11 xpresent --cflags) vidtime: $(OBJS) $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) + +clean: + rm -f $(OBJS) vidtime @@ -13,6 +13,7 @@ */ #include <X11/Xlib.h> +#include <X11/extensions/Xpresent.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> @@ -31,11 +32,14 @@ struct monitor { int fd; }; +#define BILLION 1000000000ULL +#define MILLION 1000000ULL + static uint64_t vid_clock(void) { struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - return ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec); + clock_gettime(CLOCK_MONOTONIC, &ts); + return ((uint64_t) ts.tv_sec * BILLION + (uint64_t) ts.tv_nsec); } static void flush(int fd) @@ -52,6 +56,7 @@ static void flush(int fd) } static uint64_t vid_time[2]; +static int vid_value; static pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t time_cond = PTHREAD_COND_INITIALIZER; @@ -65,6 +70,7 @@ static void *monitor_device(void *arg) int n; struct termios termios; uint64_t t; + int v; tcgetattr(fd, &termios); cfmakeraw(&termios); @@ -86,10 +92,12 @@ static void *monitor_device(void *arg) switch(buf[0]) { case '1': case '0': + v = buf[0] - '0'; pthread_mutex_lock(&time_mutex); - vid_time[buf[0] - '0'] = t; - pthread_cond_signal(&time_cond); + vid_value = v; + vid_time[v] = t; pthread_mutex_unlock(&time_mutex); + pthread_cond_signal(&time_cond); break; } } @@ -104,14 +112,22 @@ int main(int argc, char **argv) Display *dpy; int scr; Window root; - Window w; + Window win; GC gc; Pixmap pix; int v = 0; - struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100 * MILLION }; pthread_t monitor_thread; struct monitor monitor; - uint64_t put, got; + uint64_t put, show, got; + uint32_t serial = 0; + XEvent ev; + int ge_event_base, ge_error_base; + int present_opcode, present_event_base, present_error_base; + bool got_event, exposed; + XSetWindowAttributes swa = { + .event_mask = ExposureMask + }; monitor.fd = open(DEV, O_RDWR); if (monitor.fd < 0) { @@ -123,24 +139,68 @@ int main(int argc, char **argv) dpy = XOpenDisplay(NULL); scr = DefaultScreen(dpy); root = RootWindow(dpy, scr); - w = XCreateSimpleWindow(dpy, root, 0, 0, W, H, 0, 0, 0); - gc = XCreateGC(dpy, w, 0, NULL); - XMapWindow(dpy, w); + win = XCreateWindow(dpy, root, + 0, 0, W, H, 0, DefaultDepth(dpy, scr), + InputOutput, CopyFromParent, + CWEventMask, &swa); + pix = XCreatePixmap(dpy, win, W, H, DefaultDepth(dpy, scr)); + gc = XCreateGC(dpy, win, 0, NULL); + XMapWindow(dpy, win); + XPresentQueryExtension(dpy, &present_opcode, &present_event_base, &present_error_base); + XPresentSelectInput(dpy, win, PresentCompleteNotifyMask); for (;;) { XSetForeground(dpy, gc, v ? WhitePixel(dpy, scr) : BlackPixel(dpy, scr)); - XFillRectangle(dpy, w, gc, 0, 0, W, H); + XFillRectangle(dpy, pix, gc, 0, 0, W, H); + XPresentPixmap(dpy, win, pix, ++serial, + None, None, 0, 0, None, None, None, + PresentOptionNone, + 0, + 0, 0, NULL, 0); put = vid_clock(); XFlush(dpy); - pthread_mutex_lock(&time_mutex); - for (;;) { - if (vid_time[v] > put) { - got = vid_time[v]; - break; + got_event = false; + exposed = false; + while (!got_event) { + XGenericEventCookie *cookie = (void *) &ev; + XNextEvent(dpy, &ev); + if (XGetEventData(dpy, cookie)) { + if (cookie->extension == present_opcode && + cookie->evtype == PresentCompleteNotify) { + XPresentCompleteNotifyEvent *ce = cookie->data; + if (ce->serial_number == serial) { + show = ce->ust * 1000; + got_event = true; + } + } + XFreeEventData(dpy, cookie); + } else { + switch (ev.type) { + case Expose: + if (ev.xexpose.count == 0) + exposed = true; + break; + } + } + } + if (!exposed) { + pthread_mutex_lock(&time_mutex); + for (;;) { + if (vid_value == v) { + got = vid_time[v]; + break; + } + pthread_cond_wait (&time_cond, &time_mutex); + } + pthread_mutex_unlock(&time_mutex); + if (show >= put && got >= show) { + printf("%d delay put->show %f show->got %f\n", v, + (show - put) / 1e9, + (got - show) / 1e9); + } else { + printf("%d invalid\n", v); } - pthread_cond_wait (&time_cond, &time_mutex); } - pthread_mutex_unlock(&time_mutex); - printf("delay %f\n", (got - put) / 1e9); v = 1-v; + nanosleep(&ts, NULL); } } |