From 1e71493afa263791b2ff10afd2fbc36a7effa73f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 21 Nov 2013 15:11:46 +1100 Subject: [PATCH] svga/winsys: Implement surface sharing using prime fd handles This needs a prime-aware vmwgfx kernel module to work properly. (With additions by Christopher James Halse Rogers ) Signed-off-by: Christopher James Halse Rogers Signed-off-by: Thomas Hellstrom Signed-off-by: Maarten Lankhorst --- src/gallium/targets/dri-vmwgfx/target.c | 13 ++++ src/gallium/winsys/svga/drm/vmw_screen_dri.c | 79 +++++++++++++++----- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/src/gallium/targets/dri-vmwgfx/target.c b/src/gallium/targets/dri-vmwgfx/target.c index e01e4652ada..aaf37b0c4fc 100644 --- a/src/gallium/targets/dri-vmwgfx/target.c +++ b/src/gallium/targets/dri-vmwgfx/target.c @@ -31,11 +31,24 @@ static const struct drm_conf_ret throttle_ret = { .val.val_int = 2, }; +/* Technically this requires kernel support that is not yet + * widespread. + * + * We could check for support in create_screen and return the correct + * value, but for now just return true in all cases. + */ +static const struct drm_conf_ret share_fd_ret = { + .type = DRM_CONF_BOOL, + .val.val_int = true, +}; + static const struct drm_conf_ret *drm_configuration(enum drm_conf conf) { switch (conf) { case DRM_CONF_THROTTLE: return &throttle_ret; + case DRM_CONF_SHARE_FD: + return &share_fd_ret; default: break; } diff --git a/src/gallium/winsys/svga/drm/vmw_screen_dri.c b/src/gallium/winsys/svga/drm/vmw_screen_dri.c index 6323a8ae2c4..a17cdf7cf92 100644 --- a/src/gallium/winsys/svga/drm/vmw_screen_dri.c +++ b/src/gallium/winsys/svga/drm/vmw_screen_dri.c @@ -40,6 +40,7 @@ #include #include +#include struct dri1_api_version { int major; @@ -160,37 +161,57 @@ vmw_drm_surface_from_handle(struct svga_winsys_screen *sws, union drm_vmw_surface_reference_arg arg; struct drm_vmw_surface_arg *req = &arg.req; struct drm_vmw_surface_create_req *rep = &arg.rep; + uint32_t handle = 0; int ret; int i; - if (whandle->type != DRM_API_HANDLE_TYPE_SHARED) { - vmw_error("Attempt to import unknown handle type %d\n", - whandle->type); - return NULL; + switch (whandle->type) { + case DRM_API_HANDLE_TYPE_SHARED: + case DRM_API_HANDLE_TYPE_KMS: + handle = whandle->handle; + break; + case DRM_API_HANDLE_TYPE_FD: + ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle, + &handle); + if (ret) { + vmw_error("Failed to get handle from prime fd %d.\n", + (int) whandle->handle); + return NULL; + } + break; + default: + vmw_error("Attempt to import unsupported handle type %d.\n", + whandle->type); + return NULL; } - /** - * The vmware device specific handle is the hardware SID. - * FIXME: We probably want to move this to the ioctl implementations. - */ - memset(&arg, 0, sizeof(arg)); - req->sid = whandle->handle; + req->sid = handle; ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE, &arg, sizeof(arg)); + /* + * Need to close the handle we got from prime. + */ + if (whandle->type == DRM_API_HANDLE_TYPE_FD) + vmw_ioctl_surface_destroy(vws, handle); + if (ret) { - vmw_error("Failed referencing shared surface. SID %d.\n" - "Error %d (%s).\n", - whandle->handle, ret, strerror(-ret)); - return NULL; + /* + * Any attempt to share something other than a surface, like a dumb + * kms buffer, should fail here. + */ + vmw_error("Failed referencing shared surface. SID %d.\n" + "Error %d (%s).\n", + handle, ret, strerror(-ret)); + return NULL; } if (rep->mip_levels[0] != 1) { vmw_error("Incorrect number of mipmap levels on shared surface." " SID %d, levels %d\n", - whandle->handle, rep->mip_levels[0]); + handle, rep->mip_levels[0]); goto out_mip; } @@ -198,7 +219,7 @@ vmw_drm_surface_from_handle(struct svga_winsys_screen *sws, if (rep->mip_levels[i] != 0) { vmw_error("Incorrect number of faces levels on shared surface." " SID %d, face %d present.\n", - whandle->handle, i); + handle, i); goto out_mip; } } @@ -210,14 +231,15 @@ vmw_drm_surface_from_handle(struct svga_winsys_screen *sws, pipe_reference_init(&vsrf->refcnt, 1); p_atomic_set(&vsrf->validated, 0); vsrf->screen = vws; - vsrf->sid = whandle->handle; + vsrf->sid = handle; ssrf = svga_winsys_surface(vsrf); *format = rep->format; return ssrf; out_mip: - vmw_ioctl_surface_destroy(vws, whandle->handle); + vmw_ioctl_surface_destroy(vws, handle); + return NULL; } @@ -227,7 +249,9 @@ vmw_drm_surface_get_handle(struct svga_winsys_screen *sws, unsigned stride, struct winsys_handle *whandle) { + struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); struct vmw_svga_winsys_surface *vsrf; + int ret; if (!surface) return FALSE; @@ -236,5 +260,24 @@ vmw_drm_surface_get_handle(struct svga_winsys_screen *sws, whandle->handle = vsrf->sid; whandle->stride = stride; + switch (whandle->type) { + case DRM_API_HANDLE_TYPE_SHARED: + case DRM_API_HANDLE_TYPE_KMS: + whandle->handle = vsrf->sid; + break; + case DRM_API_HANDLE_TYPE_FD: + ret = drmPrimeHandleToFD(vws->ioctl.drm_fd, vsrf->sid, DRM_CLOEXEC, + (int *)&whandle->handle); + if (ret) { + vmw_error("Failed to get file descriptor from prime.\n"); + return FALSE; + } + break; + default: + vmw_error("Attempt to export unsupported handle type %d.\n", + whandle->type); + return FALSE; + } + return TRUE; } -- 2.30.2