diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2015-04-04 19:37:11 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2015-04-04 19:38:49 +0100 |
commit | 61da72c0761181fb1589e0bae2d1025633ca5071 (patch) | |
tree | 44af70f3b53f5d16d8cab3479e82db096085c721 /test | |
parent | ea545e05ecefbafd48cac59cce674b3f08a3f130 (diff) | |
download | xorg-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.c | 203 |
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, |