[Mesa-dev] [RFC 10/10] virgl: native fence fd support
Robert Foss
robert.foss at collabora.com
Fri Nov 18 15:50:15 UTC 2016
Thanks for upstreaming this, this patch has been tested and confirmed
working on a qemu setup.
Tested-by: Robert Foss <robert.foss at collabora.com>
On Fri, 2016-11-18 at 08:39 -0500, Rob Clark wrote:
> From: Gustavo Padovan <gustavo.padovan at collabora.co.uk>
>
> ---
> src/gallium/drivers/virgl/virgl_context.c | 47 +++++++++++-
> -
> src/gallium/drivers/virgl/virgl_screen.c | 12 +++-
> src/gallium/drivers/virgl/virgl_winsys.h | 16 ++++-
> src/gallium/winsys/virgl/drm/virgl_drm_winsys.c | 78
> +++++++++++++++++++++-
> src/gallium/winsys/virgl/drm/virgl_drm_winsys.h | 2 +
> src/gallium/winsys/virgl/drm/virtgpu_drm.h | 16 ++++-
> .../winsys/virgl/vtest/virgl_vtest_winsys.c | 8 ++-
> 7 files changed, 162 insertions(+), 17 deletions(-)
>
> diff --git a/src/gallium/drivers/virgl/virgl_context.c
> b/src/gallium/drivers/virgl/virgl_context.c
> index bda9515..66bd4e8 100644
> --- a/src/gallium/drivers/virgl/virgl_context.c
> +++ b/src/gallium/drivers/virgl/virgl_context.c
> @@ -21,6 +21,8 @@
> * USE OR OTHER DEALINGS IN THE SOFTWARE.
> */
>
> +#include <libsync.h>
> +
> #include "pipe/p_shader_tokens.h"
>
> #include "pipe/p_context.h"
> @@ -623,13 +625,20 @@ static void virgl_draw_vbo(struct pipe_context
> *ctx,
>
> }
>
> -static void virgl_flush_eq(struct virgl_context *ctx, void *closure)
> +static void virgl_flush_eq(struct virgl_context *ctx, void *closure,
> + struct pipe_fence_handle **fence)
> {
> struct virgl_screen *rs = virgl_screen(ctx->base.screen);
> + int out_fence_fd = -1;
>
> /* send the buffer to the remote side for decoding */
> ctx->num_transfers = ctx->num_draws = 0;
> - rs->vws->submit_cmd(rs->vws, ctx->cbuf);
> +
> + rs->vws->submit_cmd(rs->vws, ctx->cbuf, ctx->cbuf->in_fence_fd,
> + ctx->cbuf->needs_out_fence_fd ? &out_fence_fd
> : NULL);
> +
> + if (fence)
> + *fence = rs->vws->cs_create_fence(rs->vws, out_fence_fd);
>
> virgl_encoder_set_sub_ctx(ctx, ctx->hw_sub_ctx_id);
>
> @@ -642,11 +651,10 @@ static void virgl_flush_from_st(struct
> pipe_context *ctx,
> enum pipe_flush_flags flags)
> {
> struct virgl_context *vctx = virgl_context(ctx);
> - struct virgl_screen *rs = virgl_screen(ctx->screen);
> struct virgl_buffer *buf, *tmp;
>
> - if (fence)
> - *fence = rs->vws->cs_create_fence(rs->vws);
> + if (flags & PIPE_FLUSH_FENCE_FD)
> + vctx->cbuf->needs_out_fence_fd = true;
>
> LIST_FOR_EACH_ENTRY_SAFE(buf, tmp, &vctx->to_flush_bufs,
> flush_list) {
> struct pipe_resource *res = &buf->base.u.b;
> @@ -656,7 +664,13 @@ static void virgl_flush_from_st(struct
> pipe_context *ctx,
> pipe_resource_reference(&res, NULL);
>
> }
> - virgl_flush_eq(vctx, vctx);
> + virgl_flush_eq(vctx, vctx, fence);
> +
> + if (vctx->cbuf->in_fence_fd != -1) {
> + close(vctx->cbuf->in_fence_fd);
> + vctx->cbuf->in_fence_fd = -1;
> + }
> + vctx->cbuf->needs_out_fence_fd = false;
> }
>
> static struct pipe_sampler_view *virgl_create_sampler_view(struct
> pipe_context *ctx,
> @@ -846,6 +860,23 @@ static void virgl_blit(struct pipe_context *ctx,
> blit);
> }
>
> +static void virgl_create_fence_fd(struct pipe_context *ctx,
> + struct pipe_fence_handle **fence,
> int fd)
> +{
> + struct virgl_screen *rs = virgl_screen(ctx->screen);
> +
> + *fence = rs->vws->cs_create_fence(rs->vws, fd);
> +}
> +
> +static void virgl_fence_server_sync(struct pipe_context *ctx,
> + struct pipe_fence_handle *fence)
> +{
> + struct virgl_context *vctx = virgl_context(ctx);
> + struct virgl_screen *rs = virgl_screen(ctx->screen);
> +
> + rs->vws->fence_server_sync(rs->vws, vctx->cbuf, fence);
> +}
> +
> static void
> virgl_context_destroy( struct pipe_context *ctx )
> {
> @@ -855,7 +886,7 @@ virgl_context_destroy( struct pipe_context *ctx )
> vctx->framebuffer.zsbuf = NULL;
> vctx->framebuffer.nr_cbufs = 0;
> virgl_encoder_destroy_sub_ctx(vctx, vctx->hw_sub_ctx_id);
> - virgl_flush_eq(vctx, vctx);
> + virgl_flush_eq(vctx, vctx, NULL);
>
> rs->vws->cmd_buf_destroy(vctx->cbuf);
> if (vctx->uploader)
> @@ -937,6 +968,8 @@ struct pipe_context *virgl_context_create(struct
> pipe_screen *pscreen,
> vctx->base.resource_copy_region = virgl_resource_copy_region;
> vctx->base.flush_resource = virgl_flush_resource;
> vctx->base.blit = virgl_blit;
> + vctx->base.create_fence_fd = virgl_create_fence_fd;
> + vctx->base.fence_server_sync = virgl_fence_server_sync;
>
> virgl_init_context_resource_functions(&vctx->base);
> virgl_init_query_functions(vctx);
> diff --git a/src/gallium/drivers/virgl/virgl_screen.c
> b/src/gallium/drivers/virgl/virgl_screen.c
> index 0edaa22..aa8a336 100644
> --- a/src/gallium/drivers/virgl/virgl_screen.c
> +++ b/src/gallium/drivers/virgl/virgl_screen.c
> @@ -261,7 +261,7 @@ virgl_get_param(struct pipe_screen *screen, enum
> pipe_cap param)
> case PIPE_CAP_VIDEO_MEMORY:
> return 0;
> case PIPE_CAP_NATIVE_FENCE_FD:
> - return 0;
> + return vscreen->vws->driver_version(vscreen->vws) >= 1;
> }
> /* should only get here on unhandled cases */
> debug_printf("Unexpected PIPE_CAP %d query\n", param);
> @@ -540,6 +540,15 @@ static boolean virgl_fence_finish(struct
> pipe_screen *screen,
> return vws->fence_wait(vws, fence, timeout);
> }
>
> +static int virgl_fence_get_fd(struct pipe_screen *screen,
> + struct pipe_fence_handle *fence)
> +{
> + struct virgl_screen *vscreen = virgl_screen(screen);
> + struct virgl_winsys *vws = vscreen->vws;
> +
> + return vws->fence_get_fd(vws, fence);
> +}
> +
> static uint64_t
> virgl_get_timestamp(struct pipe_screen *_screen)
> {
> @@ -581,6 +590,7 @@ virgl_create_screen(struct virgl_winsys *vws)
> screen->base.fence_reference = virgl_fence_reference;
> //screen->base.fence_signalled = virgl_fence_signalled;
> screen->base.fence_finish = virgl_fence_finish;
> + screen->base.fence_get_fd = virgl_fence_get_fd;
>
> virgl_init_screen_resource_functions(&screen->base);
>
> diff --git a/src/gallium/drivers/virgl/virgl_winsys.h
> b/src/gallium/drivers/virgl/virgl_winsys.h
> index ea21f2b..01caf73 100644
> --- a/src/gallium/drivers/virgl/virgl_winsys.h
> +++ b/src/gallium/drivers/virgl/virgl_winsys.h
> @@ -40,6 +40,8 @@ struct virgl_drm_caps {
> struct virgl_cmd_buf {
> unsigned cdw;
> uint32_t *buf;
> + int in_fence_fd;
> + bool needs_out_fence_fd;
> };
>
> struct virgl_winsys {
> @@ -83,7 +85,8 @@ struct virgl_winsys {
> void (*cmd_buf_destroy)(struct virgl_cmd_buf *buf);
>
> void (*emit_res)(struct virgl_winsys *vws, struct virgl_cmd_buf
> *buf, struct virgl_hw_res *res, boolean write_buffer);
> - int (*submit_cmd)(struct virgl_winsys *vws, struct virgl_cmd_buf
> *buf);
> + int (*submit_cmd)(struct virgl_winsys *vws, struct virgl_cmd_buf
> *buf,
> + int32_t in_fence_fd, int32_t *out_fence_fd);
>
> boolean (*res_is_referenced)(struct virgl_winsys *vws,
> struct virgl_cmd_buf *buf,
> @@ -92,7 +95,7 @@ struct virgl_winsys {
> int (*get_caps)(struct virgl_winsys *vws, struct virgl_drm_caps
> *caps);
>
> /* fence */
> - struct pipe_fence_handle *(*cs_create_fence)(struct virgl_winsys
> *vws);
> + struct pipe_fence_handle *(*cs_create_fence)(struct virgl_winsys
> *vws, int fd);
> bool (*fence_wait)(struct virgl_winsys *vws,
> struct pipe_fence_handle *fence,
> uint64_t timeout);
> @@ -107,6 +110,15 @@ struct virgl_winsys {
> unsigned level, unsigned layer,
> void *winsys_drawable_handle,
> struct pipe_box *sub_box);
> +
> + void (*fence_server_sync)(struct virgl_winsys *vws,
> + struct virgl_cmd_buf *cbuf,
> + struct pipe_fence_handle *fence);
> +
> + int (*fence_get_fd)(struct virgl_winsys *vws,
> + struct pipe_fence_handle *fence);
> +
> + int (*driver_version)(struct virgl_winsys *vws);
> };
>
>
> diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c
> b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c
> index 86e0470..3e3ca4e 100644
> --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c
> +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c
> @@ -38,6 +38,7 @@
> #include "virgl/virgl_public.h"
>
> #include <xf86drm.h>
> +#include <libsync.h>
> #include "virtgpu_drm.h"
>
> #include "virgl_drm_winsys.h"
> @@ -70,6 +71,9 @@ 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);
> @@ -222,6 +226,8 @@ virgl_drm_winsys_resource_create(struct
> virgl_winsys *qws,
> res->stride = stride;
> pipe_reference_init(&res->reference, 1);
> res->num_cs_references = 0;
> + res->fence_fd = -1;
> +
> return res;
> }
>
> @@ -449,6 +455,9 @@ 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;
> +
> + fprintf(stderr, "!!! virgl_drm_winsys_resource_create_handle\n");
>
> util_hash_table_set(qdws->bo_handles, (void *)(uintptr_t)handle,
> res);
>
> @@ -569,6 +578,8 @@ static struct virgl_cmd_buf
> *virgl_drm_cmd_buf_create(struct virgl_winsys *qws)
> }
>
> cbuf->base.buf = cbuf->buf;
> + cbuf->base.in_fence_fd = -1;
> +
> return &cbuf->base;
> }
>
> @@ -662,7 +673,8 @@ static boolean virgl_drm_res_is_ref(struct
> virgl_winsys *qws,
> }
>
> static int virgl_drm_winsys_submit_cmd(struct virgl_winsys *qws,
> - struct virgl_cmd_buf *_cbuf)
> + struct virgl_cmd_buf *_cbuf,
> + int in_fence_fd, int
> *out_fence_fd)
> {
> struct virgl_drm_winsys *qdws = virgl_drm_winsys(qws);
> struct virgl_drm_cmd_buf *cbuf = virgl_drm_cmd_buf(_cbuf);
> @@ -677,12 +689,24 @@ static int virgl_drm_winsys_submit_cmd(struct
> virgl_winsys *qws,
> eb.size = cbuf->base.cdw * 4;
> eb.num_bo_handles = cbuf->cres;
> eb.bo_handles = (unsigned long)(void *)cbuf->res_hlist;
> + eb.fence_fd = -1;
> +
> + if (in_fence_fd != -1) {
> + eb.flags |= VIRTGPU_EXECBUF_FENCE_FD_IN;
> + eb.fence_fd = in_fence_fd;
> + }
> +
> + if (out_fence_fd != NULL)
> + eb.flags |= VIRTGPU_EXECBUF_FENCE_FD_OUT;
>
> ret = drmIoctl(qdws->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &eb);
> if (ret == -1)
> fprintf(stderr,"got error from kernel - expect bad rendering
> %d\n", errno);
> cbuf->base.cdw = 0;
>
> + if (out_fence_fd != NULL)
> + *out_fence_fd = eb.fence_fd;
> +
> virgl_drm_release_all_res(qdws, cbuf);
>
> memset(cbuf->is_handle_added, 0, sizeof(cbuf->is_handle_added));
> @@ -716,7 +740,7 @@ static int handle_compare(void *key1, void *key2)
> }
>
> static struct pipe_fence_handle *
> -virgl_cs_create_fence(struct virgl_winsys *vws)
> +virgl_cs_create_fence(struct virgl_winsys *vws, int fd)
> {
> struct virgl_hw_res *res;
>
> @@ -726,6 +750,7 @@ virgl_cs_create_fence(struct virgl_winsys *vws)
> VIRGL_BIND_CUSTOM,
> 8, 1, 1, 0, 0, 0,
> 8);
>
> + res->fence_fd = fd;
> return (struct pipe_fence_handle *)res;
> }
>
> @@ -750,6 +775,12 @@ static bool virgl_fence_wait(struct virgl_winsys
> *vws,
> 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;
> + }
> +
> return TRUE;
> }
>
> @@ -762,6 +793,45 @@ static void virgl_fence_reference(struct
> virgl_winsys *vws,
> virgl_hw_res(src));
> }
>
> +static void virgl_fence_server_sync(struct virgl_winsys *vws,
> + struct virgl_cmd_buf *cbuf,
> + struct pipe_fence_handle *fence)
> +{
> + struct virgl_hw_res *hw_res = virgl_hw_res(fence);
> +
> + if (sync_accumulate("virgl", &cbuf->in_fence_fd, hw_res-
> >fence_fd)) {
> + /* error */
> + }
> +}
> +
> +static int virgl_fence_get_fd(struct virgl_winsys *vws,
> + struct pipe_fence_handle *fence)
> +{
> + struct virgl_hw_res *hw_res = virgl_hw_res(fence);
> +
> + return dup(hw_res->fence_fd);
> +}
> +
> +static int virgl_driver_version(struct virgl_winsys *vws)
> +{
> + struct virgl_drm_winsys *vdws = virgl_drm_winsys(vws);
> +
> + return vdws->drm_version;
> +}
> +
> +static int virgl_drm_get_version(int fd)
> +{
> + drmVersionPtr version;
> +
> + version = drmGetVersion(fd);
> + if (!version)
> + return -EFAULT;
> +
> + if (version->version_major != 0)
> + return -EINVAL;
> +
> + return version->version_minor;
> +}
>
> static struct virgl_winsys *
> virgl_drm_winsys_create(int drmFD)
> @@ -773,6 +843,7 @@ virgl_drm_winsys_create(int drmFD)
> return NULL;
>
> qdws->fd = drmFD;
> + qdws->drm_version = virgl_drm_get_version(drmFD);
> qdws->num_delayed = 0;
> qdws->usecs = 1000000;
> LIST_INITHEAD(&qdws->delayed);
> @@ -799,6 +870,9 @@ virgl_drm_winsys_create(int drmFD)
> qdws->base.cs_create_fence = virgl_cs_create_fence;
> qdws->base.fence_wait = virgl_fence_wait;
> qdws->base.fence_reference = virgl_fence_reference;
> + qdws->base.fence_server_sync = virgl_fence_server_sync;
> + qdws->base.fence_get_fd = virgl_fence_get_fd;
> + qdws->base.driver_version = virgl_driver_version;
>
> qdws->base.get_caps = virgl_drm_get_caps;
> return &qdws->base;
> diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h
> b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h
> index ffd7658..72cd319 100644
> --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h
> +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h
> @@ -50,12 +50,14 @@ struct virgl_hw_res {
> int64_t start, end;
> boolean flinked;
> uint32_t flink;
> + int fence_fd;
> };
>
> struct virgl_drm_winsys
> {
> struct virgl_winsys base;
> int fd;
> + int drm_version;
> struct list_head delayed;
> int num_delayed;
> unsigned usecs;
> diff --git a/src/gallium/winsys/virgl/drm/virtgpu_drm.h
> b/src/gallium/winsys/virgl/drm/virtgpu_drm.h
> index 30bc3af..8094192 100644
> --- a/src/gallium/winsys/virgl/drm/virtgpu_drm.h
> +++ b/src/gallium/winsys/virgl/drm/virtgpu_drm.h
> @@ -44,6 +44,16 @@
> #define DRM_VIRTGPU_WAIT 0x08
> #define DRM_VIRTGPU_GET_CAPS 0x09
>
> +/*
> + * virtgpu execbuffer flags
> + */
> +#define VIRTGPU_EXECBUF_FENCE_FD_IN 0x01
> +#define VIRTGPU_EXECBUF_FENCE_FD_OUT 0x02
> +#define VIRTGPU_EXECBUF_FLAGS (\
> + VIRTGPU_EXECBUF_FENCE_FD_IN |\
> + VIRTGPU_EXECBUF_FENCE_FD_OUT |\
> + 0)
> +
> struct drm_virtgpu_map {
> uint64_t offset; /* use for mmap system call */
> uint32_t handle;
> @@ -51,12 +61,12 @@ struct drm_virtgpu_map {
> };
>
> struct drm_virtgpu_execbuffer {
> - uint32_t flags; /* for future
> use */
> + uint32_t flags;
> uint32_t size;
> uint64_t command; /* void* */
> uint64_t bo_handles;
> uint32_t num_bo_handles;
> - uint32_t pad;
> + int32_t fence_fd;
> };
>
> #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the
> hw */
> @@ -129,7 +139,7 @@ struct drm_virtgpu_get_caps {
> DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct
> drm_virtgpu_map)
>
> #define DRM_IOCTL_VIRTGPU_EXECBUFFER \
> - DRM_IOW(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\
> + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\
> struct drm_virtgpu_execbuffer)
>
> #define DRM_IOCTL_VIRTGPU_GETPARAM \
> diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
> b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
> index ce8ac97..c0fa445 100644
> --- a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
> +++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
> @@ -474,7 +474,8 @@ static void virgl_vtest_add_res(struct
> virgl_vtest_winsys *vtws,
> }
>
> static int virgl_vtest_winsys_submit_cmd(struct virgl_winsys *vws,
> - struct virgl_cmd_buf
> *_cbuf)
> + struct virgl_cmd_buf
> *_cbuf,
> + int in_fence_fd, int
> *out_fence_fd)
> {
> struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
> struct virgl_vtest_cmd_buf *cbuf = virgl_vtest_cmd_buf(_cbuf);
> @@ -483,6 +484,9 @@ static int virgl_vtest_winsys_submit_cmd(struct
> virgl_winsys *vws,
> if (cbuf->base.cdw == 0)
> return 0;
>
> + assert(in_fence_fd == -1);
> + assert(out_fence_fd == NULL);
> +
> ret = virgl_vtest_submit_cmd(vtws, cbuf);
>
> virgl_vtest_release_all_res(vtws, cbuf);
> @@ -523,7 +527,7 @@ static int virgl_vtest_get_caps(struct
> virgl_winsys *vws,
> }
>
> static struct pipe_fence_handle *
> -virgl_cs_create_fence(struct virgl_winsys *vws)
> +virgl_cs_create_fence(struct virgl_winsys *vws, int fd)
> {
> struct virgl_hw_res *res;
>
More information about the mesa-dev
mailing list