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