virgl: make resource_wait/resource_is_busy cheaper
authorChia-I Wu <olvaffe@gmail.com>
Fri, 10 May 2019 18:56:46 +0000 (11:56 -0700)
committerChia-I Wu <olvaffe@gmail.com>
Tue, 11 Jun 2019 17:03:54 +0000 (10:03 -0700)
The round trip to the kernel is expensive.  Add a local cache to
avoid it when possible.

There is a race condition when two contexts access the same resource
at the same time (e.g., ctx1 submits a cmdbuf that accesses a
resource while ctx2 maps the resource).  But that is probably an app
bug in the first place.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
Reviewed-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
src/gallium/winsys/virgl/drm/virgl_drm_winsys.c
src/gallium/winsys/virgl/drm/virgl_drm_winsys.h

index 37ded2f1f227de5100455905a7c666b7ddb370c7..4110901e283abe072aee074dc1d56b97c7129a53 100644 (file)
@@ -87,6 +87,9 @@ static boolean virgl_drm_resource_is_busy(struct virgl_winsys *vws,
    struct drm_virtgpu_3d_wait waitcmd;
    int ret;
 
+   if (!p_atomic_read(&res->maybe_busy) && !p_atomic_read(&res->external))
+      return false;
+
    memset(&waitcmd, 0, sizeof(waitcmd));
    waitcmd.handle = res->bo_handle;
    waitcmd.flags = VIRTGPU_WAIT_NOWAIT;
@@ -94,6 +97,9 @@ static boolean virgl_drm_resource_is_busy(struct virgl_winsys *vws,
    ret = drmIoctl(vdws->fd, DRM_IOCTL_VIRTGPU_WAIT, &waitcmd);
    if (ret && errno == EBUSY)
       return TRUE;
+
+   p_atomic_set(&res->maybe_busy, false);
+
    return FALSE;
 }
 
@@ -229,6 +235,12 @@ virgl_drm_winsys_resource_create(struct virgl_winsys *qws,
    pipe_reference_init(&res->reference, 1);
    p_atomic_set(&res->external, false);
    p_atomic_set(&res->num_cs_references, 0);
+
+   /* A newly created resource is consdiered busy by the kernel until the
+    * command is retired.
+    */
+   p_atomic_set(&res->maybe_busy, true);
+
    return res;
 }
 
@@ -263,6 +275,8 @@ virgl_bo_transfer_put(struct virgl_winsys *vws,
    struct virgl_drm_winsys *vdws = virgl_drm_winsys(vws);
    struct drm_virtgpu_3d_transfer_to_host tohostcmd;
 
+   p_atomic_set(&res->maybe_busy, true);
+
    memset(&tohostcmd, 0, sizeof(tohostcmd));
    tohostcmd.bo_handle = res->bo_handle;
    tohostcmd.box.x = box->x;
@@ -288,6 +302,8 @@ virgl_bo_transfer_get(struct virgl_winsys *vws,
    struct virgl_drm_winsys *vdws = virgl_drm_winsys(vws);
    struct drm_virtgpu_3d_transfer_from_host fromhostcmd;
 
+   p_atomic_set(&res->maybe_busy, true);
+
    memset(&fromhostcmd, 0, sizeof(fromhostcmd));
    fromhostcmd.bo_handle = res->bo_handle;
    fromhostcmd.level = level;
@@ -552,12 +568,17 @@ static void virgl_drm_resource_wait(struct virgl_winsys *qws,
    struct drm_virtgpu_3d_wait waitcmd;
    int ret;
 
+   if (!p_atomic_read(&res->maybe_busy) && !p_atomic_read(&res->external))
+      return;
+
    memset(&waitcmd, 0, sizeof(waitcmd));
    waitcmd.handle = res->bo_handle;
  again:
    ret = drmIoctl(qdws->fd, DRM_IOCTL_VIRTGPU_WAIT, &waitcmd);
    if (ret == -EAGAIN)
       goto again;
+
+   p_atomic_set(&res->maybe_busy, false);
 }
 
 static bool virgl_drm_alloc_res_list(struct virgl_drm_cmd_buf *cbuf,
@@ -658,6 +679,9 @@ static void virgl_drm_clear_res_list(struct virgl_drm_cmd_buf *cbuf)
    int i;
 
    for (i = 0; i < cbuf->cres; i++) {
+      /* mark all BOs busy after submission */
+      p_atomic_set(&cbuf->res_bo[i]->maybe_busy, true);
+
       p_atomic_dec(&cbuf->res_bo[i]->num_cs_references);
       virgl_drm_resource_reference(qdws, &cbuf->res_bo[i], NULL);
    }
index 8bc874cb351e0f9c5ffa17f60b94a68247082359..2f27c811b6771b8423d4f50107e10ccc2e8f2200 100644 (file)
@@ -50,6 +50,9 @@ struct virgl_hw_res {
 
    /* true when the resource is imported or exported */
    int external;
+
+   /* false when the resource is known to be idle */
+   int maybe_busy;
 };
 
 struct virgl_drm_winsys