From 9e4452cfd9cdad9cded9f75cca63036236b8b178 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Fri, 10 May 2019 11:56:46 -0700 Subject: [PATCH] virgl: make resource_wait/resource_is_busy cheaper 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 Reviewed-by: Alexandros Frantzis --- .../winsys/virgl/drm/virgl_drm_winsys.c | 24 +++++++++++++++++++ .../winsys/virgl/drm/virgl_drm_winsys.h | 3 +++ 2 files changed, 27 insertions(+) diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c index 37ded2f1f22..4110901e283 100644 --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c @@ -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); } diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h index 8bc874cb351..2f27c811b67 100644 --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h @@ -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 -- 2.30.2