virgl: introduce virgl_drm_fence
authorChia-I Wu <olvaffe@gmail.com>
Tue, 9 Apr 2019 20:16:00 +0000 (20:16 +0000)
committerGurchetan Singh <gurchetansingh@chromium.org>
Mon, 15 Apr 2019 23:25:47 +0000 (23:25 +0000)
virgl_drm_fence can wrap either a fence fd or a virgl_hw_res.  Because a
fence fd is cheaper than a virgl_hw_res, we use it whenever it is
available.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
src/gallium/winsys/virgl/drm/virgl_drm_winsys.c
src/gallium/winsys/virgl/drm/virgl_drm_winsys.h

index 2cd4bf70429ed87943d029f134505435781f960b..e78c0856145d2c777b6ffe263371e87fc52c376e 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -76,9 +77,6 @@ static void virgl_hw_res_destroy(struct virgl_drm_winsys *qdws,
       if (res->ptr)
          os_munmap(res->ptr, res->size);
 
-      if (res->fence_fd != -1)
-         close(res->fence_fd);
-
       memset(&args, 0, sizeof(args));
       args.handle = res->bo_handle;
       drmIoctl(qdws->fd, DRM_IOCTL_GEM_CLOSE, &args);
@@ -231,7 +229,6 @@ virgl_drm_winsys_resource_create(struct virgl_winsys *qws,
    res->stride = stride;
    pipe_reference_init(&res->reference, 1);
    p_atomic_set(&res->num_cs_references, 0);
-   res->fence_fd = -1;
    return res;
 }
 
@@ -467,7 +464,6 @@ virgl_drm_winsys_resource_create_handle(struct virgl_winsys *qws,
    res->stride = info_arg.stride;
    pipe_reference_init(&res->reference, 1);
    res->num_cs_references = 0;
-   res->fence_fd = -1;
 
    util_hash_table_set(qdws->bo_handles, (void *)(uintptr_t)handle, res);
 
@@ -710,18 +706,54 @@ static void virgl_drm_cmd_buf_destroy(struct virgl_cmd_buf *_cbuf)
 }
 
 static struct pipe_fence_handle *
-virgl_drm_fence_create(struct virgl_winsys *vws, int fd)
+virgl_drm_fence_create(struct virgl_winsys *vws, int fd, bool external)
 {
-   struct virgl_hw_res *res;
+   struct virgl_drm_fence *fence;
+
+   assert(vws->supports_fences);
+
+   if (external) {
+      fd = dup(fd);
+      if (fd < 0)
+         return NULL;
+   }
+
+   fence = CALLOC_STRUCT(virgl_drm_fence);
+   if (!fence) {
+      close(fd);
+      return NULL;
+   }
+
+   fence->fd = fd;
+   fence->external = external;
+
+   pipe_reference_init(&fence->reference, 1);
+
+   return (struct pipe_fence_handle *)fence;
+}
+
+static struct pipe_fence_handle *
+virgl_drm_fence_create_legacy(struct virgl_winsys *vws)
+{
+   struct virgl_drm_fence *fence;
+
+   assert(!vws->supports_fences);
+
+   fence = CALLOC_STRUCT(virgl_drm_fence);
+   if (!fence)
+      return NULL;
+   fence->fd = -1;
+
+   fence->hw_res = virgl_drm_winsys_resource_cache_create(vws, PIPE_BUFFER,
+         PIPE_FORMAT_R8_UNORM, VIRGL_BIND_CUSTOM, 8, 1, 1, 0, 0, 0, 8);
+   if (!fence->hw_res) {
+      FREE(fence);
+      return NULL;
+   }
 
-   res = virgl_drm_winsys_resource_cache_create(vws,
-                                                PIPE_BUFFER,
-                                                PIPE_FORMAT_R8_UNORM,
-                                                VIRGL_BIND_CUSTOM,
-                                                8, 1, 1, 0, 0, 0, 8);
+   pipe_reference_init(&fence->reference, 1);
 
-   res->fence_fd = fd;
-   return (struct pipe_fence_handle *)res;
+   return (struct pipe_fence_handle *)fence;
 }
 
 static int virgl_drm_winsys_submit_cmd(struct virgl_winsys *qws,
@@ -767,10 +799,10 @@ static int virgl_drm_winsys_submit_cmd(struct virgl_winsys *qws,
       }
 
       if (fence != NULL && ret == 0)
-         *fence = virgl_drm_fence_create(qws, eb.fence_fd);
+         *fence = virgl_drm_fence_create(qws, eb.fence_fd, false);
    } else {
       if (fence != NULL && ret == 0)
-         *fence = virgl_drm_fence_create(qws, -1);
+         *fence = virgl_drm_fence_create_legacy(qws);
    }
 
    virgl_drm_release_all_res(qdws, cbuf);
@@ -826,35 +858,50 @@ static int handle_compare(void *key1, void *key2)
 static struct pipe_fence_handle *
 virgl_cs_create_fence(struct virgl_winsys *vws, int fd)
 {
-   return virgl_drm_fence_create(vws, fd);
+   if (!vws->supports_fences)
+      return NULL;
+
+   return virgl_drm_fence_create(vws, fd, true);
 }
 
 static bool virgl_fence_wait(struct virgl_winsys *vws,
-                             struct pipe_fence_handle *fence,
+                             struct pipe_fence_handle *_fence,
                              uint64_t timeout)
 {
    struct virgl_drm_winsys *vdws = virgl_drm_winsys(vws);
-   struct virgl_hw_res *res = virgl_hw_res(fence);
+   struct virgl_drm_fence *fence = virgl_drm_fence(_fence);
+
+   if (vws->supports_fences) {
+      uint64_t timeout_ms;
+      int timeout_poll;
+
+      if (timeout == 0)
+         return sync_wait(fence->fd, 0) == 0;
+
+      timeout_ms = timeout / 1000000;
+      /* round up */
+      if (timeout_ms * 1000000 < timeout)
+         timeout_ms++;
+
+      timeout_poll = timeout_ms <= INT_MAX ? (int) timeout_ms : -1;
+
+      return sync_wait(fence->fd, timeout_poll) == 0;
+   }
 
    if (timeout == 0)
-      return !virgl_drm_resource_is_busy(vdws, res);
+      return !virgl_drm_resource_is_busy(vdws, fence->hw_res);
 
    if (timeout != PIPE_TIMEOUT_INFINITE) {
       int64_t start_time = os_time_get();
       timeout /= 1000;
-      while (virgl_drm_resource_is_busy(vdws, res)) {
+      while (virgl_drm_resource_is_busy(vdws, fence->hw_res)) {
          if (os_time_get() - start_time >= timeout)
             return FALSE;
          os_time_sleep(10);
       }
       return TRUE;
    }
-   virgl_drm_resource_wait(vws, res);
-
-   if (res->fence_fd != -1) {
-      int ret = sync_wait(res->fence_fd, timeout / 1000000);
-      return ret == 0;
-   }
+   virgl_drm_resource_wait(vws, fence->hw_res);
 
    return TRUE;
 }
@@ -863,31 +910,48 @@ static void virgl_fence_reference(struct virgl_winsys *vws,
                                   struct pipe_fence_handle **dst,
                                   struct pipe_fence_handle *src)
 {
-   struct virgl_drm_winsys *vdws = virgl_drm_winsys(vws);
-   virgl_drm_resource_reference(vdws, (struct virgl_hw_res **)dst,
-                                virgl_hw_res(src));
+   struct virgl_drm_fence *dfence = virgl_drm_fence(*dst);
+   struct virgl_drm_fence *sfence = virgl_drm_fence(src);
+
+   if (pipe_reference(&dfence->reference, &sfence->reference)) {
+      if (vws->supports_fences) {
+         close(dfence->fd);
+      } else {
+         struct virgl_drm_winsys *vdws = virgl_drm_winsys(vws);
+         virgl_hw_res_destroy(vdws, dfence->hw_res);
+      }
+      FREE(dfence);
+   }
+
+   *dst = src;
 }
 
 static void virgl_fence_server_sync(struct virgl_winsys *vws,
-                                   struct virgl_cmd_buf *_cbuf,
-                                    struct pipe_fence_handle *fence)
+                                    struct virgl_cmd_buf *_cbuf,
+                                    struct pipe_fence_handle *_fence)
 {
    struct virgl_drm_cmd_buf *cbuf = virgl_drm_cmd_buf(_cbuf);
-   struct virgl_hw_res *hw_res = virgl_hw_res(fence);
+   struct virgl_drm_fence *fence = virgl_drm_fence(_fence);
+
+   if (!vws->supports_fences)
+      return;
 
    /* if not an external fence, then nothing more to do without preemption: */
-   if (hw_res->fence_fd == -1)
+   if (!fence->external)
       return;
 
-   sync_accumulate("virgl", &cbuf->in_fence_fd, hw_res->fence_fd);
+   sync_accumulate("virgl", &cbuf->in_fence_fd, fence->fd);
 }
 
 static int virgl_fence_get_fd(struct virgl_winsys *vws,
-                               struct pipe_fence_handle *fence)
+                              struct pipe_fence_handle *_fence)
 {
-        struct virgl_hw_res *hw_res = virgl_hw_res(fence);
+   struct virgl_drm_fence *fence = virgl_drm_fence(_fence);
+
+   if (!vws->supports_fences)
+      return -1;
 
-        return dup(hw_res->fence_fd);
+   return dup(fence->fd);
 }
 
 static int virgl_drm_get_version(int fd)
index 1fbbde2e7d28191951a42ab7cc265c2dd9d69080..d7db03b89da39f5a794def261eaae39286f8de0b 100644 (file)
@@ -50,7 +50,6 @@ struct virgl_hw_res {
    int64_t start, end;
    boolean flinked;
    uint32_t flink;
-   int fence_fd;
 };
 
 struct virgl_drm_winsys
@@ -68,6 +67,13 @@ struct virgl_drm_winsys
    bool has_capset_query_fix;
 };
 
+struct virgl_drm_fence {
+   struct pipe_reference reference;
+   bool external;
+   int fd;
+   struct virgl_hw_res *hw_res;
+};
+
 struct virgl_drm_cmd_buf {
    struct virgl_cmd_buf base;
 
@@ -86,18 +92,18 @@ struct virgl_drm_cmd_buf {
 
 };
 
-static inline struct virgl_hw_res *
-virgl_hw_res(struct pipe_fence_handle *f)
-{
-   return (struct virgl_hw_res *)f;
-}
-
 static inline struct virgl_drm_winsys *
 virgl_drm_winsys(struct virgl_winsys *iws)
 {
    return (struct virgl_drm_winsys *)iws;
 }
 
+static inline struct virgl_drm_fence *
+virgl_drm_fence(struct pipe_fence_handle *f)
+{
+   return (struct virgl_drm_fence *)f;
+}
+
 static inline struct virgl_drm_cmd_buf *
 virgl_drm_cmd_buf(struct virgl_cmd_buf *cbuf)
 {