diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/ChangeLog xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/ChangeLog --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/ChangeLog 2016-09-22 16:11:36.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/ChangeLog 2016-10-10 06:23:54.000000000 +0000 @@ -1,9 +1,69 @@ -commit 1e7273e048cb860f932bcd3130c5bd1038db4cd4 +commit 028215a25b7f18ad3e0928fb352f9ad332e8e6d3 Author: Rico Tzschichholz -Date: Thu Sep 22 18:11:09 2016 +0200 +Date: Mon Oct 10 08:23:23 2016 +0200 Add debian tree from origin/ubuntu +commit 696f58f69f2bac5717d19f7a1a2278fee50a083e +Author: Chris Wilson +Date: Fri Oct 7 23:32:12 2016 +0100 + + sna: Add an assertion that the flip succeeds + + Upon completion of the flip-event, check that the current scanout + matches our expectations. + + Signed-off-by: Chris Wilson + +commit bd33d0a7e9801e710b77fd32df90b3cc953045fe +Author: Chris Wilson +Date: Sun Oct 2 19:05:58 2016 +0100 + + sna: Force fb release on tiling changes + + Since trying to change tiling with an fb attached causes EBUSY, try + without. + + Signed-off-by: Chris Wilson + +commit d9a32dc657d6359d19427f5c610be54d15ebb1a9 +Author: Chris Wilson +Date: Sun Oct 2 15:24:02 2016 +0100 + + sna/dri2: Assert signal is unset before setting + + Signed-off-by: Chris Wilson + +commit 2579d34713033c75deed3628a50dfcb164028310 +Author: Chris Wilson +Date: Wed Sep 28 18:26:42 2016 +0100 + + sna: Handle GetImage planemask inplace + + As found by Adam Jackson, we can perform the masking of the planemask on + the user buffer and so avoid hitting the fallback paths, so long as we + have no 24bpp Pixmaps. + + Signed-off-by: Chris Wilson + +commit 8f33f80100096f7790c7b819ce37a3ed8ce8b5fa +Author: Chris Wilson +Date: Thu Sep 22 12:53:37 2016 +0100 + + test/present: Busy spin on the idle fence + + Avoid the unix socket + libxcb to maximise the throughput. + + Signed-off-by: Chris Wilson + +commit 0ffae5601bdb00528395f0891a680e69df89a00a +Author: Chris Wilson +Date: Thu Sep 22 11:23:36 2016 +0100 + + test/present: Look at scaling to many tiny windows + + Signed-off-by: Chris Wilson + commit 8d6c8191e5c7e9f06e488576af2d59e2c7669e44 Author: Chris Wilson Date: Tue Sep 20 11:49:23 2016 +0100 @@ -2241,3 +2301,11 @@ Reported-by: Raffael Herzog References: https://bugs.freedesktop.org/show_bug.cgi?id=93562 Signed-off-by: Chris Wilson + +commit ec92e2584ffa0bf2a7f5bd724b69e68687e11c96 +Author: Chris Wilson +Date: Sun Dec 20 18:37:38 2015 +0000 + + sna: Add fault-injection for cursor ioctls + + Signed-off-by: Chris Wilson diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/debian/changelog xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/debian/changelog --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/debian/changelog 2016-10-10 06:29:38.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/debian/changelog 2016-10-10 06:29:39.000000000 +0000 @@ -1,10 +1,10 @@ -xserver-xorg-video-intel (2:2.99.917+git20160922.8d6c8191-0ubuntu0ricotz~xenial) xenial; urgency=medium +xserver-xorg-video-intel (2:2.99.917+git20161010.696f58f6-0ubuntu0ricotz~xenial) xenial; urgency=medium - * Checkout from git 20160922 (master branch) up to commit - 8d6c8191e5c7e9f06e488576af2d59e2c7669e44 + * Checkout from git 20161010 (master branch) up to commit + 696f58f69f2bac5717d19f7a1a2278fee50a083e * Only added debian/ tree from origin/ubuntu - -- Rico Tzschichholz Thu, 22 Sep 2016 18:11:36 +0200 + -- Rico Tzschichholz Mon, 10 Oct 2016 08:23:54 +0200 xserver-xorg-video-intel (2:2.99.917+git20160706-1ubuntu1) yakkety; urgency=medium diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/.lastcommit xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/.lastcommit --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/.lastcommit 2016-09-22 16:11:09.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/.lastcommit 2016-10-10 06:23:23.000000000 +0000 @@ -1 +1 @@ -commit 8d6c8191e5c7e9f06e488576af2d59e2c7669e44 +commit 696f58f69f2bac5717d19f7a1a2278fee50a083e diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/fb/fbimage.c xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/fb/fbimage.c --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/fb/fbimage.c 2012-08-01 06:45:00.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/fb/fbimage.c 2016-10-10 06:23:23.000000000 +0000 @@ -229,13 +229,19 @@ FbBits pm; pm = fbReplicatePixel(planeMask, srcBpp); + dstStride = PixmapBytePad(w, drawable->depth); - if (pm != FB_ALLONES) - memset(d, 0, dstStride * h); dstStride /= sizeof(FbStip); + fbBltStip((FbStip *)(src + (y + srcYoff) * srcStride), srcStride, (x + srcXoff) * srcBpp, - dst, dstStride, 0, w * srcBpp, h, GXcopy, pm, srcBpp); + dst, dstStride, 0, w * srcBpp, h, GXcopy, FB_ALLONES, srcBpp); + + if (pm != FB_ALLONES) { + int i = dstStride * h; + while (i--) + *dst++ &= pm; + } } else { dstStride = BitmapBytePad(w) / sizeof(FbStip); fbBltPlane(src + (y + srcYoff) * srcStride, diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/kgem.c xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/kgem.c --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/kgem.c 2016-07-06 11:46:45.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/kgem.c 2016-10-10 06:23:23.000000000 +0000 @@ -443,6 +443,19 @@ sna_render_flush_solid(sna); } +static bool kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo) +{ + if (bo->scanout && bo->delta) { + DBG(("%s: releasing fb=%d for handle=%d\n", + __FUNCTION__, bo->delta, bo->handle)); + /* XXX will leak if we are not DRM_MASTER. *shrug* */ + do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta); + bo->delta = 0; + return true; + } else + return false; +} + static bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo, int tiling, int stride) { @@ -487,6 +500,9 @@ goto restart; } + if (err == EBUSY && kgem_bo_rmfb(kgem, bo)) + goto restart; + ERR(("%s: failed to set-tiling(tiling=%d, pitch=%d) for handle=%d: %d\n", __FUNCTION__, tiling, stride, bo->handle, err)); return false; @@ -2517,17 +2533,6 @@ } } -static void kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo) -{ - if (bo->scanout && bo->delta) { - DBG(("%s: releasing fb=%d for handle=%d\n", - __FUNCTION__, bo->delta, bo->handle)); - /* XXX will leak if we are not DRM_MASTER. *shrug* */ - do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta); - bo->delta = 0; - } -} - static void kgem_bo_free(struct kgem *kgem, struct kgem_bo *bo) { DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo))); diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/sna_accel.c xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/sna_accel.c --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/sna_accel.c 2016-09-22 16:11:08.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/sna_accel.c 2016-10-10 06:23:23.000000000 +0000 @@ -17191,8 +17191,7 @@ if (ACCEL_GET_IMAGE && !FORCE_FALLBACK && format == ZPixmap && - drawable->bitsPerPixel >= 8 && - PM_IS_SOLID(drawable, mask)) { + drawable->bitsPerPixel >= 8) { PixmapPtr pixmap = get_drawable_pixmap(drawable); int16_t dx, dy; @@ -17204,7 +17203,7 @@ region.data = NULL; if (sna_get_image__fast(pixmap, ®ion, dst, flags)) - return; + goto apply_planemask; if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, flags)) @@ -17222,6 +17221,16 @@ region.extents.x1, region.extents.y1, 0, 0, w, h); sigtrap_put(); } + +apply_planemask: + if (!PM_IS_SOLID(drawable, mask)) { + FbStip pm = fbReplicatePixel(mask, drawable->bitsPerPixel); + FbStip *d = (FbStip *)dst; + int i, n = PixmapBytePad(w, drawable->depth) / sizeof(FbStip) * h; + + for (i = 0; i < n; i++) + d[i] &= pm; + } } else { region.extents.x1 = x + drawable->x; region.extents.y1 = y + drawable->y; diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/sna_display.c xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/sna_display.c --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/sna_display.c 2016-09-22 16:11:39.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/sna_display.c 2016-10-10 06:23:57.000000000 +0000 @@ -1540,7 +1540,8 @@ memcpy(&sna->mode.shadow_events[sna->mode.shadow_nevent++], base, sizeof(struct drm_event_vblank)); - DBG(("%s: deferring event count=%d\n", sna->mode.shadow_nevent)); + DBG(("%s: deferring event count=%d\n", + __func__, sna->mode.shadow_nevent)); } static void flush_events(struct sna *sna) @@ -1550,7 +1551,7 @@ if (!sna->mode.shadow_nevent) return; - DBG(("%s: flushing %d events=%d\n", sna->mode.shadow_nevent)); + DBG(("%s: flushing %d events=%d\n", __func__, sna->mode.shadow_nevent)); for (n = 0; n < sna->mode.shadow_nevent; n++) { struct drm_event_vblank *vb = &sna->mode.shadow_events[n]; @@ -9185,6 +9186,15 @@ crtc->flip_bo->handle, crtc->flip_bo->active_scanout)); assert(crtc->bo->active_scanout); assert(crtc->bo->refcnt >= crtc->bo->active_scanout); + +#ifndef NDEBUG + { + struct drm_mode_crtc mode = { .crtc_id = __sna_crtc_id(crtc) }; + drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode); + assert(mode.fb_id == fb_id(crtc->flip_bo)); + } +#endif + crtc->bo->active_scanout--; kgem_bo_destroy(&sna->kgem, crtc->bo); diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/sna_dri2.c xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/sna_dri2.c --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/src/sna/sna_dri2.c 2016-09-22 16:11:08.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/src/sna/sna_dri2.c 2016-10-10 06:23:23.000000000 +0000 @@ -2697,6 +2697,7 @@ get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout)); assert(info->draw); + assert(!info->signal); info->keepalive++; info->signal = true; } @@ -2847,6 +2848,9 @@ if (info->draw == NULL) return false; + assert(!info->signal); + info->signal = info->type == FLIP_THROTTLE; + if (info->sna->mode.front_active == 0) return false; @@ -2863,7 +2867,6 @@ info->sna->dri2.flip_pending = info; info->queued = true; assert(info->draw); - info->signal = info->type == FLIP_THROTTLE; return true; } diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/test/dri2-race.c xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/test/dri2-race.c --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/test/dri2-race.c 2016-07-06 11:46:45.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/test/dri2-race.c 2016-10-10 06:23:23.000000000 +0000 @@ -144,6 +144,7 @@ for (n = 0; n < N_DIVISORS; n++) { loop = 256 >> ffs(divisors[n]); printf("DRI2SwapBuffers(divisor=%d), loop=%d", divisors[n], loop); + fflush(stdout); do { win = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, width, height, 0, @@ -174,6 +175,7 @@ for (n = 0; n < N_DIVISORS; n++) { loop = 256 >> ffs(divisors[n]); printf("xcb_dri2_swap_buffers(divisor=%d), loops=%d", divisors[n], loop); + fflush(stdout); do { win = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, width, height, 0, @@ -204,6 +206,7 @@ for (n = 0; n < N_DIVISORS; n++) { loop = 256 >> ffs(divisors[n]); printf("DRI2WaitMsc(divisor=%d), loop=%d", divisors[n], loop); + fflush(stdout); do { uint64_t ignore, msc; xcb_connection_t *c = XGetXCBConnection(dpy); @@ -276,6 +279,7 @@ loop = 256 >> ffs(divisors[n]); printf("DRI2SwapBuffers(divisor=%d), loop=%d", divisors[n], loop); + fflush(stdout); do { int w, h; @@ -310,6 +314,7 @@ loop = 256 >> ffs(divisors[n]); printf("xcb_dri2_swap_buffers(divisor=%d), loops=%d", divisors[n], loop); + fflush(stdout); do { int w, h; @@ -344,6 +349,7 @@ loop = 256 >> ffs(divisors[n]); printf("DRI2WaitMsc(divisor=%d), loop=%d", divisors[n], loop); + fflush(stdout); do { uint64_t ignore, msc; xcb_connection_t *c = XGetXCBConnection(dpy); @@ -393,6 +399,7 @@ attr.override_redirect = 1; for (n = 0; n < N_DIVISORS; n++) { printf("DRI2SwapBuffers(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { win = XCreateWindow(dpy, DefaultRootWindow(dpy), @@ -425,6 +432,7 @@ for (n = 0; n < N_DIVISORS; n++) { printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { win = XCreateWindow(dpy, DefaultRootWindow(dpy), @@ -457,6 +465,7 @@ for (n = 0; n < N_DIVISORS; n++) { printf("DRI2WaitMsc(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { uint64_t ignore, msc; @@ -518,6 +527,7 @@ attr.override_redirect = 1; for (n = 0; n < N_DIVISORS; n++) { printf("DRI2SwapBuffers(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { Display *dpy = XOpenDisplay(NULL); @@ -547,6 +557,7 @@ for (n = 0; n < N_DIVISORS; n++) { printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { Display *dpy = XOpenDisplay(NULL); @@ -576,6 +587,7 @@ for (n = 0; n < N_DIVISORS; n++) { printf("DRI2WaitMsc(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { uint64_t ignore, msc; @@ -629,6 +641,7 @@ attr.override_redirect = 1; for (n = 0; n < N_DIVISORS; n++) { printf("DRI2SwapBuffers(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { Display *dpy = XOpenDisplay(NULL); @@ -672,6 +685,7 @@ for (n = 0; n < N_DIVISORS; n++) { printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { Display *dpy = XOpenDisplay(NULL); @@ -715,6 +729,7 @@ for (n = 0; n < N_DIVISORS; n++) { printf("DRI2WaitMsc(divisor=%d)", divisors[n]); + fflush(stdout); loop = 256 >> ffs(divisors[n]); do { Display *dpy = XOpenDisplay(NULL); diff -Nru xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/test/present-speed.c xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/test/present-speed.c --- xserver-xorg-video-intel-2.99.917+git20160922.8d6c8191/test/present-speed.c 2016-09-22 16:11:08.000000000 +0000 +++ xserver-xorg-video-intel-2.99.917+git20161010.696f58f6/test/present-speed.c 2016-10-10 06:23:23.000000000 +0000 @@ -145,6 +145,7 @@ struct dri3_fence fence; int fd; int busy; + int id; }; #define DRI3 1 @@ -165,8 +166,8 @@ xcb_xfixes_region_t update = 0; int completed = 0; int queued = 0; - uint32_t eid; - void *Q; + uint32_t eid = 0; + void *Q = NULL; int i, n; list_init(&mru); @@ -177,10 +178,12 @@ _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 @@ 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; @@ -212,23 +215,35 @@ present_flags |= XCB_PRESENT_OPTION_COPY; } - 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); - Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp); + if (!(options & DRI3)) { + 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); + Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp); + } clock_gettime(CLOCK_MONOTONIC, &start); do { for (n = 0; n < 1000; n++) { struct buffer *tmp, *b = NULL; +retry: list_for_each_entry(tmp, &mru, link) { + if (tmp->fence.xid) + tmp->busy = !xshmfence_query(tmp->fence.addr); if (!tmp->busy) { b = tmp; break; } } - while (b == NULL) { + if (options & DRI3) { + if (b == NULL) + goto retry; + + xshmfence_reset(b->fence.addr); + queued--; + completed++; + } else while (b == NULL) { xcb_present_generic_event_t *ev; ev = (xcb_present_generic_event_t *) @@ -258,11 +273,7 @@ } b->busy = (options & NOCOPY) == 0; - if (b->fence.xid) { - 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 */ @@ -282,7 +293,33 @@ clock_gettime(CLOCK_MONOTONIC, &end); } while (end.tv_sec < start.tv_sec + 10); - while (queued) { + if (options & DRI3) { + struct buffer *b; + XID pixmap; + + pixmap = xcb_generate_id(c); + xcb_create_pixmap(c, depth, pixmap, win, width, height); + xcb_present_pixmap(c, win, pixmap, 0xdeadbeef, + 0, /* valid */ + None, /* update */ + 0, /* x_off */ + 0, /* y_off */ + None, + None, /* wait fence */ + None, + 0, + 0, /* target msc */ + 0, /* divisor */ + 0, /* remainder */ + 0, NULL); + xcb_flush(c); + + list_for_each_entry(b, &mru, link) + xshmfence_await(b->fence.addr); + + xcb_free_pixmap(c, pixmap); + completed += queued; + } else while (queued) { xcb_present_generic_event_t *ev; ev = (xcb_present_generic_event_t *) @@ -312,12 +349,14 @@ 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); - XSync(dpy, True); - xcb_unregister_for_special_event(c, Q); + if (Q) { + xcb_discard_reply(c, xcb_present_select_input_checked(c, eid, win, 0).sequence); + XSync(dpy, True); + xcb_unregister_for_special_event(c, Q); + } test_name[0] = '\0'; if (options) { @@ -333,6 +372,253 @@ 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 = calloc(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); + } + + if (!(options & DRI3)) { + 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; +retry: + list_for_each_entry(tmp, &pp[i].mru, link) { + if (tmp->fence.xid) + tmp->busy = !xshmfence_query(tmp->fence.addr); + if (!tmp->busy) { + b = tmp; + break; + } + } + if (options & DRI3) { + if (b == NULL) + goto retry; + + xshmfence_reset(b->fence.addr); + pp[i].queued--; + completed++; + } else 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; + 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++) { + if (options & DRI3) { + int depth = DefaultDepth(dpy, DefaultScreen(dpy)); + struct buffer *b; + XID pixmap; + + pixmap = xcb_generate_id(c); + xcb_create_pixmap(c, depth, pixmap, pp[i].win, 1, 1); + xcb_present_pixmap(c, pp[i].win, pixmap, 0xdeadbeef, + 0, /* valid */ + None, /* update */ + 0, /* x_off */ + 0, /* y_off */ + None, + None, /* wait fence */ + None, + 0, + 0, /* target msc */ + 0, /* divisor */ + 0, /* remainder */ + 0, NULL); + xcb_flush(c); + + list_for_each_entry(b, &pp[i].mru, link) + xshmfence_await(b->fence.addr); + + xcb_free_pixmap(c, pixmap); + completed += pp[i].queued; + } else 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); + } + + if (pp[i].Q) { + 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 +935,8 @@ XDestroyWindow(dpy, win); XSync(dpy, True); + perpixel(dpy, mode->width, mode->height, options); + siblings(dpy, mode->width, mode->height, sysconf(_SC_NPROCESSORS_ONLN), options);