[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