test/present: Look at scaling to many tiny windows

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2016-09-22 11:23:36 +01:00
parent 8d6c8191e5
commit 0ffae5601b
1 changed files with 223 additions and 8 deletions

View File

@ -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);