test/present: Look at scaling to many tiny windows
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
8d6c8191e5
commit
0ffae5601b
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue