summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/present-speed.c231
1 files changed, 223 insertions, 8 deletions
diff --git a/test/present-speed.c b/test/present-speed.c
index bcaa6238..9ab7482a 100644
--- a/test/present-speed.c
+++ b/test/present-speed.c
@@ -145,6 +145,7 @@ struct buffer {
struct dri3_fence fence;
int fd;
int busy;
+ int id;
};
#define DRI3 1
@@ -177,10 +178,12 @@ static void run(Display *dpy, Window win, const char *name, unsigned options)
_x_error_occurred = 0;
for (n = 0; n < N_BACK; n++) {
- buffer[n].pixmap =
- XCreatePixmap(dpy, win, width, height, depth);
+ buffer[n].pixmap = xcb_generate_id(c);
+ xcb_create_pixmap(c, depth, buffer[n].pixmap, win,
+ width, height);
buffer[n].fence.xid = 0;
buffer[n].fd = -1;
+ buffer[n].id = n;
if (options & DRI3) {
xcb_dri3_buffer_from_pixmap_reply_t *reply;
int *fds;
@@ -189,8 +192,8 @@ static void run(Display *dpy, Window win, const char *name, unsigned options)
return;
reply = xcb_dri3_buffer_from_pixmap_reply (c,
- xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
- NULL);
+ xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
+ NULL);
if (reply == NULL)
return;
@@ -214,8 +217,8 @@ static void run(Display *dpy, Window win, const char *name, unsigned options)
eid = xcb_generate_id(c);
xcb_present_select_input(c, eid, win,
- (options & NOCOPY ? 0 : XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY) |
- XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
+ (options & NOCOPY ? 0 : 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);
@@ -262,7 +265,7 @@ static void run(Display *dpy, Window win, const char *name, unsigned options)
xshmfence_await(b->fence.addr);
xshmfence_reset(b->fence.addr);
}
- xcb_present_pixmap(c, win, b->pixmap, b - buffer,
+ xcb_present_pixmap(c, win, b->pixmap, b->id,
0, /* valid */
update, /* update */
0, /* x_off */
@@ -312,7 +315,7 @@ static void run(Display *dpy, Window win, const char *name, unsigned options)
dri3_fence_free(dpy, &buffer[n].fence);
if (buffer[n].fd != -1)
close(buffer[n].fd);
- XFreePixmap(dpy, buffer[n].pixmap);
+ xcb_free_pixmap(c, buffer[n].pixmap);
}
xcb_discard_reply(c, xcb_present_select_input_checked(c, eid, win, 0).sequence);
@@ -333,6 +336,216 @@ static void run(Display *dpy, Window win, const char *name, unsigned options)
completed / (elapsed(&start, &end) / 1000000));
}
+struct perpixel {
+ Window win;
+ struct buffer buffer[N_BACK];
+ struct list mru;
+ uint32_t eid;
+ void *Q;
+ int queued;
+};
+
+static void perpixel(Display *dpy,
+ int max_width, int max_height, unsigned options)
+{
+ //const int sz = max_width * max_height;
+ const int sz = 1048;
+ struct perpixel *pp;
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ struct timespec start, end;
+ char test_name[128];
+ unsigned present_flags = 0;
+ xcb_xfixes_region_t update = 0;
+ int completed = 0;
+ int i, n;
+
+ pp = malloc(sz*sizeof(*pp));
+ if (!pp)
+ return;
+
+ for (i = 0; i < sz; i++) {
+ XSetWindowAttributes attr = { .override_redirect = 1 };
+ int depth = DefaultDepth(dpy, DefaultScreen(dpy));
+ pp[i].win = XCreateWindow(dpy, DefaultRootWindow(dpy),
+ i % max_width, i / max_width, 1, 1, 0, depth,
+ InputOutput,
+ DefaultVisual(dpy, DefaultScreen(dpy)),
+ CWOverrideRedirect, &attr);
+ XMapWindow(dpy, pp[i].win);
+ list_init(&pp[i].mru);
+ for (n = 0; n < N_BACK; n++) {
+ pp[i].buffer[n].pixmap = xcb_generate_id(c);
+ xcb_create_pixmap(c, depth, pp[i].buffer[n].pixmap,
+ pp[i].win, 1, 1);
+ pp[i].buffer[n].fence.xid = 0;
+ pp[i].buffer[n].fd = -1;
+ pp[i].buffer[n].id = n;
+ if (options & DRI3) {
+ xcb_dri3_buffer_from_pixmap_reply_t *reply;
+ int *fds;
+
+ if (dri3_create_fence(dpy, pp[i].win, &pp[i].buffer[n].fence))
+ return;
+
+ reply = xcb_dri3_buffer_from_pixmap_reply(c,
+ xcb_dri3_buffer_from_pixmap(c, pp[i].buffer[n].pixmap),
+ NULL);
+ if (reply == NULL)
+ return;
+
+ fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, reply);
+ pp[i].buffer[n].fd = fds[0];
+ free(reply);
+
+ /* start idle */
+ xshmfence_trigger(pp[i].buffer[n].fence.addr);
+ }
+ pp[i].buffer[n].busy = 0;
+ list_add(&pp[i].buffer[n].link, &pp[i].mru);
+ }
+
+ pp[i].eid = xcb_generate_id(c);
+ xcb_present_select_input(c, pp[i].eid, pp[i].win,
+ (options & NOCOPY ? 0 : XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY) |
+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
+ pp[i].Q = xcb_register_for_special_xge(c, &xcb_present_id, pp[i].eid, &stamp);
+ pp[i].queued = 0;
+ }
+
+ XSync(dpy, True);
+ _x_error_occurred = 0;
+
+ if (options & ASYNC)
+ present_flags |= XCB_PRESENT_OPTION_ASYNC;
+ if (options & NOCOPY) {
+ update = xcb_generate_id(c);
+ xcb_xfixes_create_region(c, update, 0, NULL);
+ present_flags |= XCB_PRESENT_OPTION_COPY;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ do {
+ for (i = 0; i < sz; i++) {
+ struct buffer *tmp, *b = NULL;
+ list_for_each_entry(tmp, &pp[i].mru, link) {
+ if (!tmp->busy) {
+ b = tmp;
+ break;
+ }
+ }
+ while (b == NULL) {
+ xcb_present_generic_event_t *ev;
+
+ ev = (xcb_present_generic_event_t *)
+ xcb_wait_for_special_event(c, pp[i].Q);
+ if (ev == NULL)
+ abort();
+
+ do {
+ switch (ev->evtype) {
+ case XCB_PRESENT_COMPLETE_NOTIFY:
+ completed++;
+ pp[i].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);
+ pp[i].buffer[ie->serial].busy = 0;
+ if (b == NULL)
+ b = &pp[i].buffer[ie->serial];
+ break;
+ }
+ }
+ free(ev);
+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, pp[i].Q)));
+ }
+
+ b->busy = (options & NOCOPY) == 0;
+ if (b->fence.xid) {
+ xshmfence_await(b->fence.addr);
+ xshmfence_reset(b->fence.addr);
+ }
+ xcb_present_pixmap(c, pp[i].win, b->pixmap, b->id,
+ 0, /* valid */
+ update, /* update */
+ 0, /* x_off */
+ 0, /* y_off */
+ None,
+ None, /* wait fence */
+ b->fence.xid,
+ present_flags,
+ 0, /* target msc */
+ 0, /* divisor */
+ 0, /* remainder */
+ 0, NULL);
+ list_move(&b->link, &pp[i].mru);
+ pp[i].queued++;
+ }
+ xcb_flush(c);
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ } while (end.tv_sec < start.tv_sec + 10);
+
+ for (i = 0; i < sz; i++) {
+ while (pp[i].queued) {
+ xcb_present_generic_event_t *ev;
+
+ ev = (xcb_present_generic_event_t *)
+ xcb_wait_for_special_event(c, pp[i].Q);
+ if (ev == NULL)
+ abort();
+
+ do {
+ switch (ev->evtype) {
+ case XCB_PRESENT_COMPLETE_NOTIFY:
+ completed++;
+ pp[i].queued--;
+ break;
+
+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
+ break;
+ }
+ free(ev);
+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, pp[i].Q)));
+ }
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+
+ if (update)
+ xcb_xfixes_destroy_region(c, update);
+
+ for (i = 0; i < sz; i++) {
+ for (n = 0; n < N_BACK; n++) {
+ if (pp[i].buffer[n].fence.xid)
+ dri3_fence_free(dpy, &pp[i].buffer[n].fence);
+ if (pp[i].buffer[n].fd != -1)
+ close(pp[i].buffer[n].fd);
+ xcb_free_pixmap(c, pp[i].buffer[n].pixmap);
+ }
+
+ xcb_discard_reply(c, xcb_present_select_input_checked(c, pp[i].eid, pp[i].win, 0).sequence);
+ XSync(dpy, True);
+ xcb_unregister_for_special_event(c, pp[i].Q);
+
+ XDestroyWindow(dpy, pp[i].win);
+ }
+ free(pp);
+
+ test_name[0] = '\0';
+ if (options) {
+ snprintf(test_name, sizeof(test_name), "(%s%s%s )",
+ options & NOCOPY ? " no-copy" : "",
+ options & DRI3 ? " dri3" : "",
+ options & ASYNC ? " async" : "");
+ }
+ printf("%s%s: Completed %d presents in %.1fs, %.3fus each (%.1f FPS)\n",
+ __func__, test_name,
+ completed, elapsed(&start, &end) / 1000000,
+ elapsed(&start, &end) / completed,
+ completed / (elapsed(&start, &end) / 1000000));
+}
+
static int isqrt(int x)
{
int i;
@@ -649,6 +862,8 @@ static void loop(Display *dpy, XRRScreenResources *res, unsigned options)
XDestroyWindow(dpy, win);
XSync(dpy, True);
+ perpixel(dpy, mode->width, mode->height, options);
+
siblings(dpy, mode->width, mode->height,
sysconf(_SC_NPROCESSORS_ONLN),
options);