intel-virtual-output: Add DRI3 xfer path
Just as proof-of-principle. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
9cf6cd9726
commit
67b37332bd
|
|
@ -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
|
||||
|
|
|
|||
347
tools/virtual.c
347
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.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;
|
||||
clone->shm.shmaddr = NULL;
|
||||
}
|
||||
|
||||
init_image(clone);
|
||||
if (clone->src.pixmap) {
|
||||
XFreePixmap(clone->src.dpy, clone->src.pixmap);
|
||||
clone->src.pixmap = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue