aboutsummaryrefslogtreecommitdiff
path: root/src/virglrenderer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/virglrenderer.c')
-rw-r--r--src/virglrenderer.c262
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();