summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2015-04-04 19:37:11 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2015-04-04 19:38:49 +0100
commit61da72c0761181fb1589e0bae2d1025633ca5071 (patch)
tree44af70f3b53f5d16d8cab3479e82db096085c721 /test
parentea545e05ecefbafd48cac59cce674b3f08a3f130 (diff)
downloadxorg-driver-xf86-video-intel-61da72c0761181fb1589e0bae2d1025633ca5071.tar.gz
test/present-speed: More buffers required to hit maximal framerates
5 buffers are required for swap elision, plus an extra or two for IPC scheduling jitter. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'test')
-rw-r--r--test/present-speed.c203
1 files changed, 150 insertions, 53 deletions
diff --git a/test/present-speed.c b/test/present-speed.c
index 60add810..c89af875 100644
--- a/test/present-speed.c
+++ b/test/present-speed.c
@@ -55,6 +55,63 @@
static int _x_error_occurred;
static uint32_t stamp;
+struct list {
+ struct list *next, *prev;
+};
+
+static void
+list_init(struct list *list)
+{
+ list->next = list->prev = list;
+}
+
+static inline void
+__list_add(struct list *entry,
+ struct list *prev,
+ struct list *next)
+{
+ next->prev = entry;
+ entry->next = next;
+ entry->prev = prev;
+ prev->next = entry;
+}
+
+static inline void
+list_add(struct list *entry, struct list *head)
+{
+ __list_add(entry, head, head->next);
+}
+
+static inline void
+__list_del(struct list *prev, struct list *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void
+_list_del(struct list *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void
+list_move(struct list *list, struct list *head)
+{
+ if (list->prev != head) {
+ _list_del(list);
+ list_add(list, head);
+ }
+}
+
+#define __container_of(ptr, sample, member) \
+ (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
+
+#define list_for_each_entry(pos, head, member) \
+ for (pos = __container_of((head)->next, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.next, pos, member))
+
static int
_check_error_handler(Display *display,
XErrorEvent *event)
@@ -69,124 +126,164 @@ _check_error_handler(Display *display,
return False; /* ignored */
}
-static void *setup_msc(Display *dpy, Window win)
-{
- xcb_connection_t *c = XGetXCBConnection(dpy);
- uint32_t id = xcb_generate_id(c);
-
- xcb_present_select_input(c, id, win, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
- return xcb_register_for_special_xge(c, &xcb_present_id, id, &stamp);
-}
-
-static void teardown_msc(Display *dpy, void *q)
-{
- xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
-}
-
static double elapsed(const struct timespec *start,
const struct timespec *end)
{
return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
}
+struct buffer {
+ struct list link;
+ Pixmap pixmap;
+ struct dri3_fence fence;
+ int busy;
+};
+
static void run(Display *dpy, Window win, const char *name, int use_dri3)
{
xcb_connection_t *c = XGetXCBConnection(dpy);
struct timespec start, end;
- Pixmap pixmap[4];
- int busy[4];
- struct dri3_fence fence[4];
+#define N_BACK 8
+ struct buffer buffer[N_BACK];
+ struct list mru;
Window root;
unsigned int width, height;
unsigned border, depth;
- int i, j, n, back = 0;
int completed = 0;
+ int queued = 0;
+ uint32_t eid;
void *Q;
+ int i, n;
+
+ list_init(&mru);
XGetGeometry(dpy, win,
- &root, &i, &j, &width, &height, &border, &depth);
+ &root, &i, &n, &width, &height, &border, &depth);
_x_error_occurred = 0;
- for (n = 0; n < 4; n++) {
- pixmap[n] = XCreatePixmap(dpy, win, width, height, depth);
+ for (n = 0; n < N_BACK; n++) {
+ buffer[n].pixmap =
+ XCreatePixmap(dpy, win, width, height, depth);
+ buffer[n].fence.xid = 0;
if (use_dri3) {
- if (dri3_create_fence(dpy, win, &fence[n]))
+ if (dri3_create_fence(dpy, win, &buffer[n].fence))
return;
/* start idle */
- xshmfence_trigger(fence[n].addr);
+ xshmfence_trigger(buffer[n].fence.addr);
}
- busy[n] = 0;
+ buffer[n].busy = 0;
+ list_add(&buffer[n].link, &mru);
}
- Q = setup_msc(dpy, win);
+ eid = xcb_generate_id(c);
+ xcb_present_select_input(c, eid, win,
+ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY |
+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
+ Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp);
+
clock_gettime(CLOCK_MONOTONIC, &start);
do {
for (n = 0; n < 1000; n++) {
- Pixmap p = 0;
- for (i = 0; i < 4; i++) {
- j = (back + i) % 4;
- if (!busy[j]) {
- p = pixmap[j];
+ struct buffer *tmp, *b = NULL;
+ list_for_each_entry(tmp, &mru, link) {
+ if (!tmp->busy) {
+ b = tmp;
break;
}
}
- if (p == 0) {
- xcb_present_complete_notify_event_t *ce;
- xcb_generic_event_t *ev;
+ while (b == NULL) {
+ xcb_present_generic_event_t *ev;
- ev = xcb_wait_for_special_event(c, Q);
+ ev = (xcb_present_generic_event_t *)
+ xcb_wait_for_special_event(c, Q);
if (ev == NULL)
abort();
do {
- ce = (xcb_present_complete_notify_event_t *)ev;
- if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
+ switch (ev->evtype) {
+ case XCB_PRESENT_COMPLETE_NOTIFY:
completed++;
- busy[ce->serial] = 0;
- if (p == 0)
- p = pixmap[j = ce->serial];
+ queued--;
+ break;
+
+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
+ {
+ xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
+ assert(ie->serial < N_BACK);
+ buffer[ie->serial].busy = 0;
+ if (b == NULL)
+ b = &buffer[ie->serial];
+ break;
+ }
}
free(ev);
- } while ((ev = xcb_poll_for_special_event(c, Q)));
+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
}
+ assert(p);
- back = j;
- busy[back] = 1;
- if (use_dri3) {
- xshmfence_await(fence[back].addr);
- xshmfence_reset(fence[back].addr);
+ b->busy = 1;
+ if (b->fence.xid) {
+ xshmfence_await(b->fence.addr);
+ xshmfence_reset(b->fence.addr);
}
- xcb_present_pixmap(c, win, p, back,
+ xcb_present_pixmap(c, win, b->pixmap, b - buffer,
0, /* valid */
0, /* update */
0, /* x_off */
0, /* y_off */
None,
None, /* wait fence */
- use_dri3 ? fence[back].xid : None,
+ b->fence.xid,
XCB_PRESENT_OPTION_ASYNC,
0, /* target msc */
0, /* divisor */
0, /* remainder */
0, NULL);
+ list_move(&b->link, &mru);
+ queued++;
xcb_flush(c);
- back++;
}
clock_gettime(CLOCK_MONOTONIC, &end);
} while (end.tv_sec < start.tv_sec + 10);
- for (n = 0; n < 4; n++) {
- if (use_dri3)
- dri3_fence_free(dpy, &fence[n]);
- XFreePixmap(dpy, pixmap[n]);
+ while (queued) {
+ xcb_present_generic_event_t *ev;
+
+ ev = (xcb_present_generic_event_t *)
+ xcb_wait_for_special_event(c, Q);
+ if (ev == NULL)
+ abort();
+
+ do {
+ switch (ev->evtype) {
+ case XCB_PRESENT_COMPLETE_NOTIFY:
+ completed++;
+ queued--;
+ break;
+
+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
+ break;
+ }
+ free(ev);
+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+
+ for (n = 0; n < N_BACK; n++) {
+ if (buffer[n].fence.xid)
+ dri3_fence_free(dpy, &buffer[n].fence);
+ XFreePixmap(dpy, buffer[n].pixmap);
}
XSync(dpy, True);
- teardown_msc(dpy, Q);
if (_x_error_occurred)
abort();
+ xcb_present_select_input(c, eid, win, 0);
+ XSync(dpy, True);
+ xcb_unregister_for_special_event(c, Q);
+
printf("%s%s: Completed %d presents in %.1fs, %.3fus each (%.1f FPS)\n",
name, use_dri3 ? " (dri3)" : "",
completed, elapsed(&start, &end) / 1000000,