xf86-video-intel: 2 commits - src/intel_list.h src/sna/sna_display.c src/sna/sna_dri2.c test/present-speed.c

Chris Wilson ickle at kemper.freedesktop.org
Sat Apr 4 12:11:55 PDT 2015


 src/intel_list.h      |    3 
 src/sna/sna_display.c |   38 +++++++--
 src/sna/sna_dri2.c    |    4 
 test/present-speed.c  |  203 ++++++++++++++++++++++++++++++++++++--------------
 4 files changed, 183 insertions(+), 65 deletions(-)

New commits:
commit 108a09e3db6c9cf86bf0b4eb8574ccc22555edb2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 4 20:11:24 2015 +0100

    sna: Add DBG for why we fallback to sw cursor
    
    References: https://bugs.freedesktop.org/show_bug.cgi?id=89903
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 51e5133..0adb3f8 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -2309,6 +2309,8 @@ static void sna_crtc_randr(xf86CrtcPtr crtc)
 		sna_crtc->hwcursor = true;
 		sna_crtc->cursor_transform = false;
 	}
+	DBG(("%s: hwcursor?=%d, cursor_transform?=%d\n",
+	     __FUNCTION__, sna_crtc->hwcursor, sna_crtc->cursor_transform));
 
 	crtc->crtc_to_framebuffer = crtc_to_fb;
 	crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
@@ -5430,27 +5432,37 @@ transformable_cursor(struct sna *sna, CursorPtr cursor)
 
 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
 		xf86CrtcPtr crtc = config->crtc[i];
-		const struct pixman_f_transform *t;
 		struct pixman_box16 box;
 		int size;
 
-		if (!to_sna_crtc(crtc)->hwcursor)
+		if (!to_sna_crtc(crtc)->hwcursor) {
+			DBG(("%s: hwcursor disabled on CRTC:%d [pipe=%d]\n",
+			     __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe));
 			return false;
+		}
 
-		t = &crtc->f_crtc_to_framebuffer;
-		if (!sna->cursor.use_gtt || !sna->cursor.scratch)
+		if (!sna->cursor.use_gtt || !sna->cursor.scratch) {
+			DBG(("%s: unable to use GTT curosor access [%d] or no scratch [%d]\n",
+			     __FUNCTION__, sna->cursor.use_gtt, sna->cursor.scratch));
 			return false;
+		}
 
 		box.x1 = box.y1 = 0;
 		box.x2 = cursor->bits->width;
 		box.y2 = cursor->bits->height;
 
-		if (!pixman_f_transform_bounds(t, &box))
+		if (!pixman_f_transform_bounds(&crtc->f_crtc_to_framebuffer,
+					       &box)) {
+			DBG(("%s: unable to transform bounds\n", __FUNCTION__));
 			return false;
+		}
 
 		size = __cursor_size(box.x2 - box.x1, box.y2 - box.y1);
-		if (size > sna->cursor.max_size)
+		if (size > sna->cursor.max_size) {
+			DBG(("%s: transformed cursor size=%d too large, max=%d\n",
+			     __FUNCTION__, size, sna->cursor.max_size));
 			return false;
+		}
 	}
 
 	return true;
@@ -5475,14 +5487,22 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
 
 	sna->cursor.size =
 		__cursor_size(cursor->bits->width, cursor->bits->height);
-	if (sna->cursor.size > sna->cursor.max_size)
+	if (sna->cursor.size > sna->cursor.max_size) {
+		DBG(("%s: cursor size=%d too large, max %d: using sw cursor\n",
+		     __FUNCTION__, sna->cursor.size, sna->cursor.max_size));
 		return FALSE;
+	}
 
-	if (sna->mode.rr_active && !transformable_cursor(sna, cursor))
+	if (sna->mode.rr_active && !transformable_cursor(sna, cursor)) {
+		DBG(("%s: RandR active [%d] and non-transformable cursor: using sw cursor\n",
+		     __FUNCTION__, sna->mode.rr_active));
 		return FALSE;
+	}
 
-	if (!sna_cursor_preallocate(sna))
+	if (!sna_cursor_preallocate(sna)) {
+		DBG(("%s: cursor preallocation failed: using sw cursor\n", __FUNCTION__));
 		return FALSE;
+	}
 
 	sna->cursor.ref = cursor;
 	cursor->refcnt++;
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 4eec9db..e8100e4 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -833,8 +833,10 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
 	damage(pixmap, priv, NULL);
 
 	assert(bo->refcnt);
-	if (priv->move_to_gpu)
+	if (priv->move_to_gpu) {
+		DBG(("%s: applying final/discard move-to-gpu\n", __FUNCTION__));
 		priv->move_to_gpu(sna, priv, 0);
+	}
 	if (priv->gpu_bo != bo) {
 		DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
 		priv->gpu_bo->flush = false;
commit 61da72c0761181fb1589e0bae2d1025633ca5071
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 4 19:37:11 2015 +0100

    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 at chris-wilson.co.uk>

diff --git a/src/intel_list.h b/src/intel_list.h
index 51af825..8a8b76f 100644
--- a/src/intel_list.h
+++ b/src/intel_list.h
@@ -306,8 +306,7 @@ list_is_empty(const struct list *head)
     list_entry((ptr)->prev, type, member)
 
 #define __container_of(ptr, sample, member)				\
-    (void *)((char *)(ptr)						\
-	     - ((char *)&(sample)->member - (char *)(sample)))
+    (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
 /**
  * Loop through the list given by head and set pos to struct in the list.
  *
diff --git a/test/present-speed.c b/test/present-speed.c
index 60add81..c89af87 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,


More information about the xorg-commit mailing list