summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-05-20 15:37:13 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2014-06-02 08:32:11 +0100
commit67b37332bd45dd4cea297107bfdc9df21984fdcd (patch)
tree45a68f5b9658bee3866d14682e338b47a2134d09
parent9cf6cd9726ed5ba73bb8c38c06f7b5c78706309b (diff)
intel-virtual-output: Add DRI3 xfer path
Just as proof-of-principle. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--configure.ac5
-rw-r--r--tools/virtual.c343
2 files changed, 288 insertions, 60 deletions
diff --git a/configure.ac b/configure.ac
index 8b0bd30c..353f942a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -255,6 +255,11 @@ fi
if test "x$tools" != "xno"; then
ivo_requires="xinerama xrandr xdamage xfixes xcursor xtst xrender xext x11 pixman-1"
PKG_CHECK_MODULES(IVO, [$ivo_requires], [ivo="yes"], [ivo="no"])
+ PKG_CHECK_MODULES(IVO_DRI3, [xcb-dri3 xcb-sync x11-xcb xshmfence x11], [ivo_dri3="yes"], [ivo_dri3="no"])
+ if test "x$ivo_dri3" = "xyes"; then
+ IVO_CFLAGS="$IVO_CFLAGS $IVO_DRI3_CFLAGS -DDRI3"
+ IVO_LIBS="$IVO_LIBS $IVO_DRI3_LIBS"
+ fi
AC_CHECK_HEADER([sys/timerfd.h], [], [ivo="no"])
if test "x$ivo" = "xno"; then
if test "x$tools" = "xyes"; then
diff --git a/tools/virtual.c b/tools/virtual.c
index 1d490c5a..a5dccb4f 100644
--- a/tools/virtual.c
+++ b/tools/virtual.c
@@ -85,6 +85,7 @@ struct display {
int xfixes_event, xfixes_error;
int rr_event, rr_error, rr_active;
int xinerama_event, xinerama_error, xinerama_active;
+ int dri3_active;
Window root;
Visual *visual;
Damage damage;
@@ -156,6 +157,11 @@ struct clone {
int width, height, depth;
struct { int x1, x2, y1, y2; } damaged;
int rr_update;
+
+ struct dri3_fence {
+ XID xid;
+ void *addr;
+ } dri3;
};
struct context {
@@ -305,6 +311,143 @@ can_use_shm(Display *dpy,
return has_shm;
}
+#ifdef DRI3
+#include <X11/Xlib-xcb.h>
+#include <X11/xshmfence.h>
+#include <xcb/xcb.h>
+#include <xcb/dri3.h>
+#include <xcb/sync.h>
+static Pixmap dri3_create_pixmap(Display *dpy,
+ Drawable draw,
+ int width, int height, int depth,
+ int fd, int bpp, int stride, int size)
+{
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ xcb_pixmap_t pixmap = xcb_generate_id(c);
+ xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd);
+ return pixmap;
+}
+
+static int dri3_create_fd(Display *dpy,
+ Pixmap pixmap,
+ int *stride)
+{
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ xcb_dri3_buffer_from_pixmap_cookie_t cookie;
+ xcb_dri3_buffer_from_pixmap_reply_t *reply;
+
+ cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
+ reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL);
+ if (!reply)
+ return -1;
+
+ if (reply->nfd != 1)
+ return -1;
+
+ *stride = reply->stride;
+ return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0];
+}
+
+static int dri3_query_version(Display *dpy, int *major, int *minor)
+{
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ xcb_dri3_query_version_reply_t *reply;
+
+ *major = *minor = -1;
+
+ reply = xcb_dri3_query_version_reply(c,
+ xcb_dri3_query_version(c,
+ XCB_DRI3_MAJOR_VERSION,
+ XCB_DRI3_MINOR_VERSION),
+ NULL);
+ if (reply == NULL)
+ return -1;
+
+ *major = reply->major_version;
+ *minor = reply->minor_version;
+ free(reply);
+
+ return 0;
+}
+
+static int dri3_exists(Display *dpy)
+{
+ int major, minor;
+
+ if (dri3_query_version(dpy, &major, &minor) < 0)
+ return 0;
+
+ return major >= 0;
+}
+
+static void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
+{
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ struct dri3_fence f;
+ int fd;
+
+ fd = xshmfence_alloc_shm();
+ if (fd < 0)
+ return;
+
+ f.addr = xshmfence_map_shm(fd);
+ if (f.addr == NULL) {
+ close(fd);
+ return;
+ }
+
+ f.xid = xcb_generate_id(c);
+ xcb_dri3_fence_from_fd(c, d, f.xid, 0, fd);
+
+ *fence = f;
+}
+
+static void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
+{
+ xcb_sync_trigger_fence(XGetXCBConnection(dpy), fence->xid);
+}
+
+static void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
+{
+ xshmfence_unmap_shm(fence->addr);
+ xcb_sync_destroy_fence(XGetXCBConnection(dpy), fence->xid);
+}
+
+#else
+
+static int dri3_exists(Display *dpy)
+{
+ return 0;
+}
+
+static void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
+{
+}
+
+static void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
+{
+}
+
+static void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
+{
+}
+
+static Pixmap dri3_create_pixmap(Display *dpy,
+ Drawable draw,
+ int width, int height, int depth,
+ int fd, int bpp, int stride, int size)
+{
+ return None;
+}
+
+static int dri3_create_fd(Display *dpy,
+ Pixmap pixmap,
+ int *stride)
+{
+ return -1;
+}
+#endif
+
static int timerfd(int hz)
{
struct itimerspec it;
@@ -868,13 +1011,11 @@ static int mode_width(const XRRModeInfo *mode, Rotation rotation)
static void output_init_xfer(struct clone *clone, struct output *output)
{
- if (output->use_shm_pixmap) {
+ if (output->pixmap == None && output->use_shm_pixmap) {
DBG(("%s-%s: creating shm pixmap\n", DisplayString(output->dpy), output->name));
XSync(output->dpy, False);
_x_error_occurred = 0;
- if (output->pixmap)
- XFreePixmap(output->dpy, output->pixmap);
output->pixmap = XShmCreatePixmap(output->dpy, output->window,
clone->shm.shmaddr, &output->shm,
clone->width, clone->height, clone->depth);
@@ -913,35 +1054,34 @@ static void output_init_xfer(struct clone *clone, struct output *output)
}
}
+static int bpp_for_depth(int depth)
+{
+ switch (depth) {
+ case 1: return 1;
+ case 8: return 8;
+ case 15: return 16;
+ case 16: return 16;
+ case 24: return 24;
+ case 32: return 32;
+ default: return 0;
+ }
+}
+
static int clone_init_xfer(struct clone *clone)
{
int width, height;
- if (clone->src.mode.id == 0) {
- if (clone->width == 0 && clone->height == 0)
- return 0;
-
+ if (clone->dst.mode.id == 0) {
clone->width = 0;
clone->height = 0;
-
- if (clone->src.use_shm)
- XShmDetach(clone->src.dpy, &clone->src.shm);
- if (clone->dst.use_shm)
- XShmDetach(clone->dst.dpy, &clone->dst.shm);
-
- if (clone->shm.shmaddr) {
- shmdt(clone->shm.shmaddr);
- clone->shm.shmaddr = 0;
- }
-
- clone->damaged.x2 = clone->damaged.y2 = INT_MIN;
- clone->damaged.x1 = clone->damaged.y1 = INT_MAX;
- return 0;
+ } else if (clone->dri3.xid) {
+ width = clone->dst.display->width;
+ height = clone->dst.display->height;
+ } else {
+ width = mode_width(&clone->src.mode, clone->src.rotation);
+ height = mode_height(&clone->src.mode, clone->src.rotation);
}
- width = mode_width(&clone->src.mode, clone->src.rotation);
- height = mode_height(&clone->src.mode, clone->src.rotation);
-
if (width == clone->width && height == clone->height)
return 0;
@@ -949,40 +1089,93 @@ static int clone_init_xfer(struct clone *clone)
DisplayString(clone->dst.dpy), clone->dst.name,
width, height));
- clone->width = width;
- clone->height = height;
+ if (clone->src.use_shm)
+ XShmDetach(clone->src.dpy, &clone->src.shm);
+ if (clone->dst.use_shm)
+ XShmDetach(clone->dst.dpy, &clone->dst.shm);
- if (clone->shm.shmaddr)
+ if (clone->shm.shmaddr) {
shmdt(clone->shm.shmaddr);
+ clone->shm.shmaddr = NULL;
+ }
- clone->shm.shmid = shmget(IPC_PRIVATE,
- height * stride_for_depth(width, clone->depth),
- IPC_CREAT | 0666);
- if (clone->shm.shmid == -1)
- return errno;
+ if (clone->src.pixmap) {
+ XFreePixmap(clone->src.dpy, clone->src.pixmap);
+ clone->src.pixmap = 0;
+ }
- clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0);
- if (clone->shm.shmaddr == (char *) -1) {
- shmctl(clone->shm.shmid, IPC_RMID, NULL);
- return ENOMEM;
+ if (clone->dst.pixmap) {
+ XFreePixmap(clone->dst.dpy, clone->dst.pixmap);
+ clone->dst.pixmap = 0;
+ }
+
+ if ((width | height) == 0) {
+ clone->damaged.x2 = clone->damaged.y2 = INT_MIN;
+ clone->damaged.x1 = clone->damaged.y1 = INT_MAX;
+ return 0;
}
- init_image(clone);
+ if (clone->dri3.xid) {
+ int fd, stride;
+ Pixmap src;
+
+ _x_error_occurred = 0;
+
+ fd = dri3_create_fd(clone->dst.dpy, clone->dst.window, &stride);
+ src = dri3_create_pixmap(clone->src.dpy, clone->src.window,
+ width, height, clone->depth,
+ fd, bpp_for_depth(clone->depth),
+ stride, lseek(fd, 0, SEEK_END));
- if (clone->src.use_shm) {
- clone->src.shm = clone->shm;
- clone->src.shm.readOnly = False;
- XShmAttach(clone->src.dpy, &clone->src.shm);
XSync(clone->src.dpy, False);
- }
- if (clone->dst.use_shm) {
- clone->dst.shm = clone->shm;
- clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap;
- XShmAttach(clone->dst.dpy, &clone->dst.shm);
- XSync(clone->dst.dpy, False);
+ if (!_x_error_occurred) {
+ clone->src.pixmap = src;
+ clone->width = width;
+ clone->height = height;
+ } else {
+ XFreePixmap(clone->src.dpy, src);
+ close(fd);
+ dri3_fence_free(clone->src.dpy, &clone->dri3);
+ clone->dri3.xid = 0;
+ }
}
- shmctl(clone->shm.shmid, IPC_RMID, NULL);
+ width = mode_width(&clone->src.mode, clone->src.rotation);
+ height = mode_height(&clone->src.mode, clone->src.rotation);
+
+ if (!clone->dri3.xid) {
+ clone->shm.shmid = shmget(IPC_PRIVATE,
+ height * stride_for_depth(width, clone->depth),
+ IPC_CREAT | 0666);
+ if (clone->shm.shmid == -1)
+ return errno;
+
+ clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0);
+ if (clone->shm.shmaddr == (char *) -1) {
+ shmctl(clone->shm.shmid, IPC_RMID, NULL);
+ return ENOMEM;
+ }
+
+ init_image(clone);
+
+ if (clone->src.use_shm) {
+ clone->src.shm = clone->shm;
+ clone->src.shm.readOnly = False;
+ XShmAttach(clone->src.dpy, &clone->src.shm);
+ XSync(clone->src.dpy, False);
+ }
+ if (clone->dst.use_shm) {
+ clone->dst.shm = clone->shm;
+ clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap;
+ XShmAttach(clone->dst.dpy, &clone->dst.shm);
+ XSync(clone->dst.dpy, False);
+ }
+
+ shmctl(clone->shm.shmid, IPC_RMID, NULL);
+
+ clone->width = width;
+ clone->height = height;
+ }
output_init_xfer(clone, &clone->src);
output_init_xfer(clone, &clone->dst);
@@ -1095,8 +1288,6 @@ static int context_update(struct context *ctx)
DBG(("%s-%s output changed? %d\n",
DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed));
- if (changed)
- clone_init_xfer(&ctx->clones[n]);
context_changed |= changed;
}
XRRFreeScreenResources(res);
@@ -1359,6 +1550,8 @@ ungrab:
for (n = 0; n < ctx->nclone; n++) {
struct clone *clone = &ctx->clones[n];
+ clone_init_xfer(clone);
+
if (clone->dst.rr_crtc == 0)
continue;
@@ -1647,8 +1840,6 @@ static void put_dst(struct clone *c, const XRectangle *clip)
clip->width, clip->height);
c->dst.serial = 0;
}
-
- display_mark_flush(c->dst.display);
}
static int clone_paint(struct clone *c)
@@ -1703,15 +1894,37 @@ static int clone_paint(struct clone *c)
c->damaged.y2 = c->src.y + c->height;
}
- clip.x = c->damaged.x1;
- clip.y = c->damaged.y1;
- clip.width = c->damaged.x2 - c->damaged.x1;
- clip.height = c->damaged.y2 - c->damaged.y1;
- get_src(c, &clip);
+ if (c->dri3.xid) {
+ if (c->src.use_render) {
+ XRenderComposite(c->src.dpy, PictOpSrc,
+ c->src.win_picture, 0, c->src.pix_picture,
+ c->damaged.x1, c->damaged.y1,
+ 0, 0,
+ c->damaged.x1 + c->dst.x - c->src.x,
+ c->damaged.y1 + c->dst.y - c->src.y,
+ c->damaged.x2 - c->damaged.x1,
+ c->damaged.y2 - c->damaged.y1);
+ } else {
+ XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
+ c->damaged.x1, c->damaged.y1,
+ c->damaged.x2 - c->damaged.x1,
+ c->damaged.y2 - c->damaged.y1,
+ c->damaged.x1 + c->dst.x - c->src.x,
+ c->damaged.y1 + c->dst.y - c->src.y);
+ }
+ dri3_fence_flush(c->src.dpy, &c->dri3);
+ } else {
+ clip.x = c->damaged.x1;
+ clip.y = c->damaged.y1;
+ clip.width = c->damaged.x2 - c->damaged.x1;
+ clip.height = c->damaged.y2 - c->damaged.y1;
+ get_src(c, &clip);
- clip.x += c->dst.x - c->src.x;
- clip.y += c->dst.y - c->src.y;
- put_dst(c, &clip);
+ clip.x += c->dst.x - c->src.x;
+ clip.y += c->dst.y - c->src.y;
+ put_dst(c, &clip);
+ }
+ display_mark_flush(c->dst.display);
done:
c->damaged.x2 = c->damaged.y2 = INT_MIN;
@@ -2010,6 +2223,11 @@ static int clone_init_depth(struct clone *clone)
clone->src.use_render != NULL,
clone->dst.use_render != NULL));
+ if (!clone->dst.use_render &&
+ clone->src.display->dri3_active &&
+ clone->dst.display->dri3_active)
+ dri3_create_fence(clone->src.dpy, clone->src.window, &clone->dri3);
+
return 0;
}
@@ -2073,6 +2291,11 @@ static int add_display(struct context *ctx, Display *dpy)
display->xinerama_event,
display->xinerama_error));
+ display->dri3_active = dri3_exists(dpy);
+ DBG(("%s: dri3_active?=%d\n",
+ DisplayString(dpy),
+ display->dri3_active));
+
/* first display (source) is slightly special */
if (!first_display) {
display->invisible_cursor = display_load_invisible_cursor(display);