summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2018-05-07 15:19:11 -0700
committerKeith Packard <keithp@keithp.com>2018-05-07 15:19:11 -0700
commita288bd28809461adf587cbdb53539f511208c771 (patch)
tree10c428797f78ea830e052d69b2114a48831bfbca
parent9c028895aa8a6ae1a26e2b9d87f6a9675b97434a (diff)
Switch to using PresentHEADmaster
This measures the delta from when present reports the frame as being shown to when the device detects the change in color. Signed-off-by: Keith Packard <keithp@keithp.com>
-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);
}
}