summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--vidtime.c98
2 files changed, 84 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index 65acc36..d29660e 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/vidtime.c b/vidtime.c
index 59cabf7..41a9f25 100644
--- a/vidtime.c
+++ b/vidtime.c
@@ -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);
}
}