winsys/svga: Fix prime surface references also for guest-backed surfaces
authorThomas Hellstrom <thellstrom@vmware.com>
Mon, 7 Apr 2014 07:56:42 +0000 (00:56 -0700)
committerThomas Hellstrom <thellstrom@vmware.com>
Mon, 7 Apr 2014 10:34:52 +0000 (03:34 -0700)
Implement guest-backed surface sharing using prime fds. Previously only
legacy surfaces could use this functionality. Also use the vmwgfx 2.6
single-ioctl prime fd reference if available.

Cc: "10.1" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
src/gallium/winsys/svga/drm/vmw_screen.h
src/gallium/winsys/svga/drm/vmw_screen_dri.c
src/gallium/winsys/svga/drm/vmw_screen_ioctl.c

index b68bf431e5efecc5e68e5f2537f158eca6d67c39..1a39039aabd6e0273926cbacdfca57a1e27a5641 100644 (file)
@@ -74,6 +74,7 @@ struct vmw_winsys_screen
       struct vmw_cap_3d *cap_3d;
       uint64_t max_mob_memory;
       uint64_t max_surface_memory;
+      boolean have_drm_2_6;
    } ioctl;
 
    struct {
@@ -138,10 +139,11 @@ vmw_ioctl_gb_surface_create(struct vmw_winsys_screen *vws,
 
 int
 vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
-                         uint32_t handle,
+                         const struct winsys_handle *whandle,
                          SVGA3dSurfaceFlags *flags,
                          SVGA3dSurfaceFormat *format,
                          uint32_t *numMipLevels,
+                         uint32_t *handle,
                          struct vmw_region **p_region);
 
 void
index 0f5a9552d85d34957413078198730522663f917a..79a1b3e6dcc4200a41ee1060c89acfb2f7fe6201 100644 (file)
@@ -183,10 +183,11 @@ vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws,
     struct vmw_buffer_desc desc;
     struct pb_manager *provider = vws->pools.gmr;
     struct pb_buffer *pb_buf;
+    uint32_t handle;
     int ret;
 
-    ret = vmw_ioctl_gb_surface_ref(vws, whandle->handle, &flags, format,
-                                   &mip_levels, &desc.region);
+    ret = vmw_ioctl_gb_surface_ref(vws, whandle, &flags, format,
+                                   &mip_levels, &handle, &desc.region);
 
     if (ret) {
        fprintf(stderr, "Failed referencing shared surface. SID %d.\n"
@@ -209,7 +210,7 @@ vmw_drm_gb_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;
     vsrf->size = vmw_region_size(desc.region);
 
     /*
index 2866a29f40218798aca998feba06db908ea3be7e..9c0abe96204b4d5881339c422596b33a6c4e044a 100644 (file)
@@ -37,6 +37,7 @@
 #include "util/u_memory.h"
 #include "util/u_math.h"
 #include "svgadump/svga_dump.h"
+#include "state_tracker/drm_driver.h"
 #include "vmw_screen.h"
 #include "vmw_context.h"
 #include "vmw_fence.h"
@@ -250,6 +251,63 @@ out_fail_create:
    return SVGA3D_INVALID_ID;
 }
 
+/**
+ * vmw_ioctl_surface_req - Fill in a struct surface_req
+ *
+ * @vws: Winsys screen
+ * @whandle: Surface handle
+ * @req: The struct surface req to fill in
+ * @needs_unref: This call takes a kernel surface reference that needs to
+ * be unreferenced.
+ *
+ * Returns 0 on success, negative error type otherwise.
+ * Fills in the surface_req structure according to handle type and kernel
+ * capabilities.
+ */
+static int
+vmw_ioctl_surface_req(const struct vmw_winsys_screen *vws,
+                      const struct winsys_handle *whandle,
+                      struct drm_vmw_surface_arg *req,
+                      boolean *needs_unref)
+{
+   int ret;
+
+   switch(whandle->type) {
+   case DRM_API_HANDLE_TYPE_SHARED:
+   case DRM_API_HANDLE_TYPE_KMS:
+      *needs_unref = FALSE;
+      req->handle_type = DRM_VMW_HANDLE_LEGACY;
+      req->sid = whandle->handle;
+      break;
+   case DRM_API_HANDLE_TYPE_FD:
+      if (!vws->ioctl.have_drm_2_6) {
+         uint32_t handle;
+
+         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 -EINVAL;
+         }
+
+         *needs_unref = TRUE;
+         req->handle_type = DRM_VMW_HANDLE_LEGACY;
+         req->sid = handle;
+      } else {
+         *needs_unref = FALSE;
+         req->handle_type = DRM_VMW_HANDLE_PRIME;
+         req->sid = whandle->handle;
+      }
+      break;
+   default:
+      vmw_error("Attempt to import unsupported handle type %d.\n",
+                whandle->type);
+      return -EINVAL;
+   }
+
+   return 0;
+}
+
 /**
  * vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and
  * get surface information
@@ -266,16 +324,18 @@ out_fail_create:
  */
 int
 vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
-                         uint32_t handle,
+                         const struct winsys_handle *whandle,
                          SVGA3dSurfaceFlags *flags,
                          SVGA3dSurfaceFormat *format,
                          uint32_t *numMipLevels,
+                         uint32_t *handle,
                          struct vmw_region **p_region)
 {
    union drm_vmw_gb_surface_reference_arg s_arg;
    struct drm_vmw_surface_arg *req = &s_arg.req;
    struct drm_vmw_gb_surface_ref_rep *rep = &s_arg.rep;
    struct vmw_region *region = NULL;
+   boolean needs_unref = FALSE;
    int ret;
 
    vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
@@ -286,8 +346,11 @@ vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
       return -ENOMEM;
 
    memset(&s_arg, 0, sizeof(s_arg));
-   req->sid = handle;
+   ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
+   if (ret)
+      goto out_fail_req;
 
+   *handle = req->sid;
    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF,
                             &s_arg, sizeof(s_arg));
 
@@ -300,12 +363,19 @@ vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
    region->size = rep->crep.backup_size;
    *p_region = region;
 
+   *handle = rep->crep.handle;
    *flags = rep->creq.svga3d_flags;
    *format = rep->creq.format;
    *numMipLevels = rep->creq.mip_levels;
 
+   if (needs_unref)
+      vmw_ioctl_surface_destroy(vws, *handle);
+
    return 0;
 out_fail_ref:
+   if (needs_unref)
+      vmw_ioctl_surface_destroy(vws, *handle);
+out_fail_req:
    if (region)
       FREE(region);
    return ret;
@@ -772,6 +842,8 @@ vmw_ioctl_init(struct vmw_winsys_screen *vws)
 
    have_drm_2_5 = version->version_major > 2 ||
       (version->version_major == 2 && version->version_minor > 4);
+   vws->ioctl.have_drm_2_6 = version->version_major > 2 ||
+      (version->version_major == 2 && version->version_minor > 5);
 
    memset(&gp_arg, 0, sizeof(gp_arg));
    gp_arg.param = DRM_VMW_PARAM_3D;