diff options
Diffstat (limited to 'src/virglrenderer.c')
-rw-r--r-- | src/virglrenderer.c | 262 |
1 files changed, 233 insertions, 29 deletions
diff --git a/src/virglrenderer.c b/src/virglrenderer.c index 44982d71..c0294f6d 100644 --- a/src/virglrenderer.c +++ b/src/virglrenderer.c @@ -36,8 +36,11 @@ #include "pipe/p_state.h" #include "util/u_format.h" #include "util/u_math.h" +#include "vkr_allocator.h" #include "vkr_renderer.h" +#include "drm_renderer.h" #include "vrend_renderer.h" +#include "proxy/proxy_renderer.h" #include "vrend_winsys.h" #include "virglrenderer.h" @@ -58,6 +61,8 @@ struct global_state { bool winsys_initialized; bool vrend_initialized; bool vkr_initialized; + bool proxy_initialized; + bool external_winsys_initialized; }; static struct global_state state; @@ -171,19 +176,22 @@ void virgl_renderer_fill_caps(uint32_t set, uint32_t version, if (state.vkr_initialized) vkr_get_capset(caps); break; + case VIRGL_RENDERER_CAPSET_DRM: + drm_renderer_capset(caps); + break; default: break; } } static void per_context_fence_retire(struct virgl_context *ctx, - uint64_t queue_id, - void *fence_cookie) + uint32_t ring_idx, + uint64_t fence_id) { state.cbs->write_context_fence(state.cookie, ctx->ctx_id, - queue_id, - fence_cookie); + ring_idx, + fence_id); } int virgl_renderer_context_create_with_flags(uint32_t ctx_id, @@ -219,9 +227,15 @@ int virgl_renderer_context_create_with_flags(uint32_t ctx_id, ctx = vrend_renderer_context_create(ctx_id, nlen, name); break; case VIRGL_RENDERER_CAPSET_VENUS: - if (!state.vkr_initialized) + if (state.proxy_initialized) + ctx = proxy_context_create(ctx_id, ctx_flags, nlen, name); + else if (state.vkr_initialized) + ctx = vkr_context_create(nlen, name); + else return EINVAL; - ctx = vkr_context_create(nlen, name); + break; + case VIRGL_RENDERER_CAPSET_DRM: + ctx = drm_renderer_create(nlen, name); break; default: return EINVAL; @@ -391,15 +405,16 @@ int virgl_renderer_create_fence(int client_fence_id, UNUSED uint32_t ctx_id) int virgl_renderer_context_create_fence(uint32_t ctx_id, uint32_t flags, - uint64_t queue_id, - void *fence_cookie) + uint32_t ring_idx, + uint64_t fence_id) { + TRACE_FUNC(); struct virgl_context *ctx = virgl_context_lookup(ctx_id); if (!ctx) return -EINVAL; assert(state.cbs->version >= 3 && state.cbs->write_context_fence); - return ctx->submit_fence(ctx, flags, queue_id, fence_cookie); + return ctx->submit_fence(ctx, flags, ring_idx, fence_id); } void virgl_renderer_context_poll(uint32_t ctx_id) @@ -422,7 +437,6 @@ int virgl_renderer_context_get_poll_fd(uint32_t ctx_id) void virgl_renderer_force_ctx_0(void) { - TRACE_FUNC(); if (state.vrend_initialized) vrend_renderer_force_ctx_0(); } @@ -486,6 +500,10 @@ void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, *max_ver = 0; *max_size = vkr_get_capset(NULL); break; + case VIRGL_RENDERER_CAPSET_DRM: + *max_ver = 0; + *max_size = drm_renderer_capset(NULL); + break; default: *max_ver = 0; *max_size = 0; @@ -506,11 +524,12 @@ void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int nu } -static void ctx0_fence_retire(void *fence_cookie, - UNUSED void *retire_data) +static void ctx0_fence_retire(uint64_t fence_id, UNUSED void *retire_data) { - const uint32_t fence_id = (uint32_t)(uintptr_t)fence_cookie; - state.cbs->write_fence(state.cookie, fence_id); + // ctx0 fence_id is created from uint32_t but stored internally as uint64_t, + // so casting back to uint32_t doesn't result in data loss. + assert((fence_id >> 32) == 0); + state.cbs->write_fence(state.cookie, (uint32_t)fence_id); } static virgl_renderer_gl_context create_gl_context(int scanout_idx, struct virgl_gl_ctx_param *param) @@ -545,11 +564,33 @@ static int make_current(virgl_renderer_gl_context ctx) return state.cbs->make_current(state.cookie, 0, ctx); } +static int get_drm_fd(void) +{ + if (state.cbs->get_drm_fd) + return state.cbs->get_drm_fd(state.cookie); + + return -1; +} + static const struct vrend_if_cbs vrend_cbs = { ctx0_fence_retire, create_gl_context, destroy_gl_context, make_current, + get_drm_fd, +}; + +static int +proxy_renderer_cb_get_server_fd(uint32_t version) +{ + if (state.cbs && state.cbs->version >= 3 && state.cbs->get_server_fd) + return state.cbs->get_server_fd(state.cookie, version); + else + return -1; +} + +static const struct proxy_renderer_cbs proxy_cbs = { + proxy_renderer_cb_get_server_fd, }; void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height) @@ -564,11 +605,29 @@ void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint height); } +static bool +virgl_context_foreach_retire_fences(struct virgl_context *ctx, + UNUSED void* data) +{ + /* vrend contexts are polled explicitly by the caller */ + if (ctx->capset_id != VIRGL_RENDERER_CAPSET_VIRGL && + ctx->capset_id != VIRGL_RENDERER_CAPSET_VIRGL2) + { + assert(ctx->retire_fences); + ctx->retire_fences(ctx); + } + return true; +} + void virgl_renderer_poll(void) { TRACE_FUNC(); if (state.vrend_initialized) - vrend_renderer_check_fences(); + vrend_renderer_poll(); + + struct virgl_context_foreach_args args; + args.callback = virgl_context_foreach_retire_fences; + virgl_context_foreach(&args); } void virgl_renderer_cleanup(UNUSED void *cookie) @@ -583,15 +642,23 @@ void virgl_renderer_cleanup(UNUSED void *cookie) if (state.resource_initialized) virgl_resource_table_cleanup(); - if (state.vkr_initialized) + if (state.proxy_initialized) + proxy_renderer_fini(); + + if (state.vkr_initialized) { vkr_renderer_fini(); + /* vkr_allocator_init is called on-demand upon the first map */ + vkr_allocator_fini(); + } if (state.vrend_initialized) vrend_renderer_fini(); - if (state.winsys_initialized) + if (state.winsys_initialized || state.external_winsys_initialized) vrend_winsys_cleanup(); + drm_renderer_fini(); + memset(&state, 0, sizeof(state)); } @@ -612,8 +679,9 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks return -EBUSY; if (!state.client_initialized) { - if (cbs && (cbs->version < 1 || - cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION)) + if (!cbs || + cbs->version < 1 || + cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION) return -1; state.cookie = cookie; @@ -658,6 +726,32 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks state.winsys_initialized = true; } + if (!state.winsys_initialized && !state.external_winsys_initialized && + state.cbs && state.cbs->version >= 4 && state.cbs->get_egl_display) { + void *egl_display = NULL; + + if (!cbs->create_gl_context || !cbs->destroy_gl_context || + !cbs->make_current) { + ret = EINVAL; + goto fail; + } + + egl_display = state.cbs->get_egl_display(cookie); + + if (!egl_display) { + ret = -1; + goto fail; + } + ret = vrend_winsys_init_external(egl_display); + + if (ret) { + ret = -1; + goto fail; + } + + state.external_winsys_initialized = true; + } + if (!state.vrend_initialized && !(flags & VIRGL_RENDERER_NO_VIRGL)) { uint32_t renderer_flags = 0; @@ -672,6 +766,8 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks renderer_flags |= VREND_USE_ASYNC_FENCE_CB; if (flags & VIRGL_RENDERER_USE_EXTERNAL_BLOB) renderer_flags |= VREND_USE_EXTERNAL_BLOB; + if (flags & VIRGL_RENDERER_USE_VIDEO) + renderer_flags |= VREND_USE_VIDEO; ret = vrend_renderer_init(&vrend_cbs, renderer_flags); if (ret) @@ -685,6 +781,8 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks vkr_flags |= VKR_RENDERER_THREAD_SYNC; if (flags & VIRGL_RENDERER_ASYNC_FENCE_CB) vkr_flags |= VKR_RENDERER_ASYNC_FENCE_CB; + if (flags & VIRGL_RENDERER_RENDER_SERVER) + vkr_flags |= VKR_RENDERER_RENDER_SERVER; ret = vkr_renderer_init(vkr_flags); if (ret) @@ -692,6 +790,23 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks state.vkr_initialized = true; } + if (!state.proxy_initialized && (flags & VIRGL_RENDERER_RENDER_SERVER)) { + ret = proxy_renderer_init(&proxy_cbs, flags | VIRGL_RENDERER_NO_VIRGL); + if (ret) + goto fail; + state.proxy_initialized = true; + } + + if ((flags & VIRGL_RENDERER_ASYNC_FENCE_CB) && + (flags & VIRGL_RENDERER_DRM)) { + int drm_fd = -1; + + if (cbs->version >= 2 && cbs->get_drm_fd) + drm_fd = cbs->get_drm_fd(cookie); + + drm_renderer_init(drm_fd); + } + return 0; fail: @@ -727,11 +842,16 @@ void virgl_renderer_reset(void) if (state.resource_initialized) virgl_resource_table_reset(); + if (state.proxy_initialized) + proxy_renderer_reset(); + if (state.vkr_initialized) vkr_renderer_reset(); if (state.vrend_initialized) vrend_renderer_reset(); + + drm_renderer_reset(); } int virgl_renderer_get_poll_fd(void) @@ -851,6 +971,10 @@ int virgl_renderer_resource_create_blob(const struct virgl_renderer_resource_cre if (args->res_handle == 0) return -EINVAL; + /* user resource id must be unique */ + if (virgl_resource_lookup(args->res_handle)) + return -EINVAL; + if (args->size == 0) return -EINVAL; if (has_guest_storage) { @@ -877,16 +1001,22 @@ int virgl_renderer_resource_create_blob(const struct virgl_renderer_resource_cre if (!ctx) return -EINVAL; - ret = ctx->get_blob(ctx, args->blob_id, args->blob_flags, &blob); + ret = ctx->get_blob(ctx, args->res_handle, args->blob_id, args->size, args->blob_flags, &blob); if (ret) return ret; - if (blob.type != VIRGL_RESOURCE_FD_INVALID) { + if (blob.type == VIRGL_RESOURCE_OPAQUE_HANDLE) { + assert(!(args->blob_flags & VIRGL_RENDERER_BLOB_FLAG_USE_SHAREABLE)); + res = virgl_resource_create_from_opaque_handle(ctx, args->res_handle, blob.u.opaque_handle); + if (!res) + return -ENOMEM; + } else if (blob.type != VIRGL_RESOURCE_FD_INVALID) { res = virgl_resource_create_from_fd(args->res_handle, blob.type, blob.u.fd, args->iovecs, - args->num_iovs); + args->num_iovs, + &blob.opaque_fd_metadata); if (!res) { close(blob.u.fd); return -ENOMEM; @@ -905,9 +1035,6 @@ int virgl_renderer_resource_create_blob(const struct virgl_renderer_resource_cre res->map_info = blob.map_info; res->map_size = args->size; - if (ctx->get_blob_done) - ctx->get_blob_done(ctx, args->res_handle, &blob); - return 0; } @@ -916,19 +1043,25 @@ int virgl_renderer_resource_map(uint32_t res_handle, void **out_map, uint64_t *o TRACE_FUNC(); int ret = 0; void *map = NULL; + uint64_t map_size = 0; struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!res || res->mapped) return -EINVAL; if (res->pipe_resource) { - ret = vrend_renderer_resource_map(res->pipe_resource, &map, &res->map_size); + ret = vrend_renderer_resource_map(res->pipe_resource, &map, &map_size); + if (!ret) + res->map_size = map_size; } else { switch (res->fd_type) { case VIRGL_RESOURCE_FD_DMABUF: + case VIRGL_RESOURCE_FD_SHM: map = mmap(NULL, res->map_size, PROT_WRITE | PROT_READ, MAP_SHARED, res->fd, 0); + map_size = res->map_size; break; case VIRGL_RESOURCE_FD_OPAQUE: - /* TODO support mapping opaque FD. Fallthrough for now. */ + ret = vkr_allocator_resource_map(res, &map, &map_size); + break; default: break; } @@ -939,7 +1072,7 @@ int virgl_renderer_resource_map(uint32_t res_handle, void **out_map, uint64_t *o res->mapped = map; *out_map = map; - *out_size = res->map_size; + *out_size = map_size; return ret; } @@ -954,7 +1087,17 @@ int virgl_renderer_resource_unmap(uint32_t res_handle) if (res->pipe_resource) { ret = vrend_renderer_resource_unmap(res->pipe_resource); } else { - ret = munmap(res->mapped, res->map_size); + switch (res->fd_type) { + case VIRGL_RESOURCE_FD_DMABUF: + ret = munmap(res->mapped, res->map_size); + break; + case VIRGL_RESOURCE_FD_OPAQUE: + ret = vkr_allocator_resource_unmap(res); + break; + default: + ret = -EINVAL; + break; + } } assert(!ret); @@ -980,6 +1123,7 @@ int virgl_renderer_resource_get_map_info(uint32_t res_handle, uint32_t *map_info int virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(res_id); if (!res) return EINVAL; @@ -991,6 +1135,9 @@ virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd) case VIRGL_RESOURCE_FD_OPAQUE: *fd_type = VIRGL_RENDERER_BLOB_FD_TYPE_OPAQUE; break; + case VIRGL_RESOURCE_FD_SHM: + *fd_type = VIRGL_RENDERER_BLOB_FD_TYPE_SHM; + break; default: return EINVAL; } @@ -999,6 +1146,63 @@ virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd) } int +virgl_renderer_resource_import_blob(const struct virgl_renderer_resource_import_blob_args *args) +{ + TRACE_FUNC(); + struct virgl_resource *res; + + /* user resource id must be greater than 0 */ + if (args->res_handle == 0) + return -EINVAL; + + /* user resource id must be unique */ + if (virgl_resource_lookup(args->res_handle)) + return -EINVAL; + + switch (args->blob_mem) { + case VIRGL_RENDERER_BLOB_MEM_HOST3D: + case VIRGL_RENDERER_BLOB_MEM_GUEST_VRAM: + break; + default: + return -EINVAL; + } + + enum virgl_resource_fd_type fd_type = VIRGL_RESOURCE_FD_INVALID; + switch (args->fd_type) { + case VIRGL_RENDERER_BLOB_FD_TYPE_DMABUF: + fd_type = VIRGL_RESOURCE_FD_DMABUF; + break; + case VIRGL_RENDERER_BLOB_FD_TYPE_OPAQUE: + fd_type = VIRGL_RESOURCE_FD_OPAQUE; + break; + case VIRGL_RENDERER_BLOB_FD_TYPE_SHM: + fd_type = VIRGL_RESOURCE_FD_SHM; + break; + default: + return -EINVAL; + } + + if (args->fd < 0) + return -EINVAL; + if (args->size == 0) + return -EINVAL; + + res = virgl_resource_create_from_fd(args->res_handle, + fd_type, + args->fd, + NULL, + 0, + NULL); + if (!res) + return -ENOMEM; + + res->map_info = 0; + res->map_size = args->size; + + return 0; +} + +int virgl_renderer_export_fence(uint32_t client_fence_id, int *fd) { TRACE_FUNC(); |