virgl: introduce virgl_drm_fence

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>
This commit is contained in:
Chia-I Wu
2019-04-09 20:16:00 +00:00
committed by Gurchetan Singh
parent 334103efbf
commit 442e75071b
2 changed files with 116 additions and 46 deletions

View 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;
res = virgl_drm_winsys_resource_cache_create(vws,
PIPE_BUFFER,
PIPE_FORMAT_R8_UNORM,
VIRGL_BIND_CUSTOM,
8, 1, 1, 0, 0, 0, 8);
assert(vws->supports_fences);
res->fence_fd = fd;
return (struct pipe_fence_handle *)res;
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;
}
pipe_reference_init(&fence->reference, 1);
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 not an external fence, then nothing more to do without preemption: */
if (hw_res->fence_fd == -1)
if (!vws->supports_fences)
return;
sync_accumulate("virgl", &cbuf->in_fence_fd, hw_res->fence_fd);
/* if not an external fence, then nothing more to do without preemption: */
if (!fence->external)
return;
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);
return dup(hw_res->fence_fd);
if (!vws->supports_fences)
return -1;
return dup(fence->fd);
}
static int virgl_drm_get_version(int fd)

View 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)
{