diff --git a/drv.c b/drv.c index 5489ee6..b1a231e 100644 --- a/drv.c +++ b/drv.c @@ -58,7 +58,7 @@ extern const struct backend backend_nouveau; extern const struct backend backend_komeda; extern const struct backend backend_radeon; extern const struct backend backend_synaptics; -extern const struct backend backend_virtio_gpu; +extern const struct backend backend_virtgpu; extern const struct backend backend_udl; extern const struct backend backend_vkms; @@ -94,21 +94,13 @@ static const struct backend *drv_get_backend(int fd) #ifdef DRV_VC4 &backend_vc4, #endif - &backend_evdi, &backend_marvell, &backend_meson, &backend_nouveau, - &backend_komeda, &backend_radeon, &backend_synaptics, &backend_virtio_gpu, - &backend_udl, &backend_virtio_gpu, &backend_vkms + &backend_evdi, &backend_marvell, &backend_meson, &backend_nouveau, + &backend_komeda, &backend_radeon, &backend_synaptics, &backend_virtgpu, + &backend_udl, &backend_virtgpu, &backend_vkms }; for (i = 0; i < ARRAY_SIZE(backend_list); i++) { const struct backend *b = backend_list[i]; - // Exactly one of the main create functions must be defined. - assert((b->bo_create != NULL) ^ (b->bo_create_from_metadata != NULL)); - // Either both or neither must be implemented. - assert((b->bo_compute_metadata != NULL) == (b->bo_create_from_metadata != NULL)); - // Both can't be defined, but it's okay for neither to be (i.e. only bo_create). - assert((b->bo_create_with_modifiers == NULL) || - (b->bo_create_from_metadata == NULL)); - if (!strcmp(drm_version->name, b->name)) { drmFreeVersion(drm_version); return b; diff --git a/drv_priv.h b/drv_priv.h index 825ec79..16ddbed 100644 --- a/drv_priv.h +++ b/drv_priv.h @@ -27,6 +27,17 @@ struct bo_metadata { uint64_t format_modifier; uint64_t use_flags; size_t total_size; + + /* + * Most of the following metadata is virtgpu cross_domain specific. However, that backend + * needs to know traditional metadata (strides, offsets) in addition to this backend + * specific metadata. It's easiest just to stuff all the metadata here rather than + * having two metadata structs. + */ + uint64_t blob_id; + uint32_t map_info; + int32_t memory_idx; + int32_t physical_device_idx; }; struct bo { diff --git a/external/virtgpu_cross_domain_protocol.h b/external/virtgpu_cross_domain_protocol.h new file mode 100644 index 0000000..eaeebd3 --- /dev/null +++ b/external/virtgpu_cross_domain_protocol.h @@ -0,0 +1,58 @@ +// Copyright 2021 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef VIRTGPU_CROSS_DOMAIN_PROTOCOL_H +#define VIRTGPU_CROSS_DOMAIN_PROTOCOL_H + +#include + +// Cross-domain commands (only a maximum of 255 supported) +#define CROSS_DOMAIN_CMD_INIT 1 +#define CROSS_DOMAIN_CMD_GET_IMAGE_REQUIREMENTS 2 + +// Channel types (must match rutabaga channel types) +#define CROSS_DOMAIN_CHANNEL_TYPE_WAYLAND 0x0001 +#define CROSS_DOMAIN_CHANNEL_TYPE_CAMERA 0x0002 + +struct CrossDomainCapabilities { + uint32_t version; + uint32_t supported_channels; + uint32_t supports_dmabuf; + uint32_t supports_external_gpu_memory; +}; + +struct CrossDomainImageRequirements { + uint32_t strides[4]; + uint32_t offsets[4]; + uint64_t modifier; + uint64_t size; + uint64_t blob_id; + uint32_t map_info; + uint32_t pad; + int32_t memory_idx; + int32_t physical_device_idx; +}; + +struct CrossDomainHeader { + uint8_t cmd; + uint8_t fence_ctx_idx; + uint16_t cmd_size; + uint32_t pad; +}; + +struct CrossDomainInit { + struct CrossDomainHeader hdr; + uint32_t ring_id; + uint32_t channel_type; +}; + +struct CrossDomainGetImageRequirements { + struct CrossDomainHeader hdr; + uint32_t width; + uint32_t height; + uint32_t drm_format; + uint32_t flags; +}; + +#endif diff --git a/external/virtgpu_drm.h b/external/virtgpu_drm.h index 5d53b37..0317e36 100644 --- a/external/virtgpu_drm.h +++ b/external/virtgpu_drm.h @@ -47,12 +47,15 @@ extern "C" { #define DRM_VIRTGPU_WAIT 0x08 #define DRM_VIRTGPU_GET_CAPS 0x09 #define DRM_VIRTGPU_RESOURCE_CREATE_BLOB 0x0a +#define DRM_VIRTGPU_CONTEXT_INIT 0x0b #define VIRTGPU_EXECBUF_FENCE_FD_IN 0x01 #define VIRTGPU_EXECBUF_FENCE_FD_OUT 0x02 +#define VIRTGPU_EXECBUF_FENCE_CONTEXT 0x04 #define VIRTGPU_EXECBUF_FLAGS (\ VIRTGPU_EXECBUF_FENCE_FD_IN |\ VIRTGPU_EXECBUF_FENCE_FD_OUT |\ + VIRTGPU_EXECBUF_FENCE_CONTEXT |\ 0) struct drm_virtgpu_map { @@ -68,6 +71,8 @@ struct drm_virtgpu_execbuffer { __u64 bo_handles; __u32 num_bo_handles; __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */ + __u32 fence_ctx_idx; /* which fence timeline to use */ + __u32 pad; }; #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ @@ -75,6 +80,8 @@ struct drm_virtgpu_execbuffer { #define VIRTGPU_PARAM_RESOURCE_BLOB 3 /* DRM_VIRTGPU_RESOURCE_CREATE_BLOB */ #define VIRTGPU_PARAM_HOST_VISIBLE 4 /* Host blob resources are mappable */ #define VIRTGPU_PARAM_CROSS_DEVICE 5 /* Cross virtio-device resource sharing */ +#define VIRTGPU_PARAM_CONTEXT_INIT 6 /* DRM_VIRTGPU_CONTEXT_INIT */ +#define VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs 7 /* Bitmask of supported capability set ids */ struct drm_virtgpu_getparam { __u64 param; @@ -104,7 +111,7 @@ struct drm_virtgpu_resource_info { __u32 bo_handle; __u32 res_handle; __u32 size; - __u32 stride; + __u32 blob_mem; }; /* CHROMIUM */ @@ -172,13 +179,13 @@ struct drm_virtgpu_get_caps { }; struct drm_virtgpu_resource_create_blob { -#define VIRTGPU_BLOB_MEM_GUEST 0x0001 -#define VIRTGPU_BLOB_MEM_HOST3D 0x0002 -#define VIRTGPU_BLOB_MEM_HOST3D_GUEST 0x0003 +#define VIRTGPU_BLOB_MEM_GUEST 0x0001 +#define VIRTGPU_BLOB_MEM_HOST3D 0x0002 +#define VIRTGPU_BLOB_MEM_HOST3D_GUEST 0x0003 -#define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001 -#define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002 -#define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 +#define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001 +#define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002 +#define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 /* zero is invalid blob_mem */ __u32 blob_mem; __u32 blob_flags; @@ -196,6 +203,21 @@ struct drm_virtgpu_resource_create_blob { __u64 blob_id; }; +#define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001 +#define VIRTGPU_CONTEXT_PARAM_NUM_FENCE_CONTEXTS 0x0002 +struct drm_virtgpu_context_set_param { + __u64 param; + __u64 value; +}; + +struct drm_virtgpu_context_init { + __u32 num_params; + __u32 pad; + + /* pointer to drm_virtgpu_context_set_param array */ + __u64 ctx_set_params; +}; + #define DRM_IOCTL_VIRTGPU_MAP \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map) @@ -240,6 +262,10 @@ struct drm_virtgpu_resource_create_blob { DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE_BLOB, \ struct drm_virtgpu_resource_create_blob) +#define DRM_IOCTL_VIRTGPU_CONTEXT_INIT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_CONTEXT_INIT, \ + struct drm_virtgpu_context_init) + #if defined(__cplusplus) } #endif diff --git a/helpers.h b/helpers.h index 1919016..d906dcf 100644 --- a/helpers.h +++ b/helpers.h @@ -16,6 +16,10 @@ extern "C" { #include "drv.h" #include "helpers_array.h" +#ifndef PAGE_SIZE +#define PAGE_SIZE 0x1000 +#endif + uint32_t drv_height_from_format(uint32_t format, uint32_t height, size_t plane); uint32_t drv_vertical_subsampling_from_format(uint32_t format, size_t plane); uint32_t drv_size_from_format(uint32_t format, uint32_t stride, uint32_t height, size_t plane); diff --git a/virtgpu.c b/virtgpu.c new file mode 100644 index 0000000..e250906 --- /dev/null +++ b/virtgpu.c @@ -0,0 +1,70 @@ +/* + * Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include + +#include "drv_priv.h" +#include "external/virtgpu_drm.h" +#include "helpers.h" +#include "util.h" +#include "virtgpu.h" + +#define PARAM(x) \ + (struct virtgpu_param) \ + { \ + x, #x, 0 \ + } + +struct virtgpu_param params[] = { + PARAM(VIRTGPU_PARAM_3D_FEATURES), PARAM(VIRTGPU_PARAM_CAPSET_QUERY_FIX), + PARAM(VIRTGPU_PARAM_RESOURCE_BLOB), PARAM(VIRTGPU_PARAM_HOST_VISIBLE), + PARAM(VIRTGPU_PARAM_CROSS_DEVICE), PARAM(VIRTGPU_PARAM_CONTEXT_INIT), + PARAM(VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs), +}; + +extern const struct backend virtgpu_virgl; +extern const struct backend virtgpu_cross_domain; + +static int virtgpu_init(struct driver *drv) +{ + int ret = 0; + const struct backend *virtgpu_backends[2] = { + &virtgpu_cross_domain, + &virtgpu_virgl, + }; + + for (uint32_t i = 0; i < ARRAY_SIZE(params); i++) { + struct drm_virtgpu_getparam get_param = { 0 }; + + get_param.param = params[i].param; + get_param.value = (uint64_t)(uintptr_t)¶ms[i].value; + int ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GETPARAM, &get_param); + if (ret) + drv_log("DRM_IOCTL_VIRTGPU_GET_PARAM failed with %s\n", strerror(errno)); + } + + for (uint32_t i = 0; i < ARRAY_SIZE(virtgpu_backends); i++) { + const struct backend *backend = virtgpu_backends[i]; + ret = backend->init(drv); + if (ret) + continue; + + drv->backend = backend; + return 0; + } + + return ret; +} + +const struct backend backend_virtgpu = { + .name = "virtio_gpu", + .init = virtgpu_init, +}; diff --git a/virtgpu.h b/virtgpu.h new file mode 100644 index 0000000..28b8ee6 --- /dev/null +++ b/virtgpu.h @@ -0,0 +1,22 @@ +/* + * Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +struct virtgpu_param { + uint64_t param; + const char *name; + uint32_t value; +}; + +enum virtgpu_param_id { + param_3d, + param_capset_fix, + param_resource_blob, + param_host_visible, + param_cross_device, + param_context_init, + param_supported_capset_ids, + param_max, +}; diff --git a/virtgpu_cross_domain.c b/virtgpu_cross_domain.c new file mode 100644 index 0000000..d1702a7 --- /dev/null +++ b/virtgpu_cross_domain.c @@ -0,0 +1,390 @@ +/* + * Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include + +#include "drv_priv.h" +#include "external/virtgpu_cross_domain_protocol.h" +#include "external/virtgpu_drm.h" +#include "helpers.h" +#include "util.h" +#include "virtgpu.h" + +#define CAPSET_CROSS_DOMAIN 5 +#define CAPSET_CROSS_FAKE 30 + +static const uint32_t scanout_render_formats[] = { DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888, + DRM_FORMAT_ARGB2101010, DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB565, DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XRGB8888 }; + +static const uint32_t render_formats[] = { DRM_FORMAT_ABGR16161616F }; + +static const uint32_t texture_only_formats[] = { DRM_FORMAT_R8, DRM_FORMAT_NV12, DRM_FORMAT_P010, + DRM_FORMAT_YVU420, DRM_FORMAT_YVU420_ANDROID }; + +extern struct virtgpu_param params[]; + +struct cross_domain_private { + uint32_t ring_handle; + void *ring_addr; + struct drv_array *metadata_cache; +}; + +static void cross_domain_release_private(struct driver *drv) +{ + int ret; + struct cross_domain_private *priv = drv->priv; + struct drm_gem_close gem_close = { 0 }; + + if (priv->ring_addr != MAP_FAILED) + munmap(priv->ring_addr, PAGE_SIZE); + + if (priv->ring_handle) { + gem_close.handle = priv->ring_handle; + + ret = drmIoctl(drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close); + if (ret) { + drv_log("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n", + priv->ring_handle, ret); + } + } + + drv_array_destroy(priv->metadata_cache); + free(priv); +} + +static void add_combinations(struct driver *drv) +{ + struct format_metadata metadata; + + // Linear metadata always supported. + metadata.tiling = 0; + metadata.priority = 1; + metadata.modifier = DRM_FORMAT_MOD_LINEAR; + + drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats), + &metadata, BO_USE_RENDER_MASK | BO_USE_SCANOUT); + + drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata, + BO_USE_RENDER_MASK); + + drv_add_combinations(drv, texture_only_formats, ARRAY_SIZE(texture_only_formats), &metadata, + BO_USE_TEXTURE_MASK); + + /* Android CTS tests require this. */ + drv_add_combination(drv, DRM_FORMAT_BGR888, &metadata, BO_USE_SW_MASK); + + drv_modify_combination(drv, DRM_FORMAT_YVU420, &metadata, BO_USE_HW_VIDEO_ENCODER); + drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata, + BO_USE_HW_VIDEO_DECODER | BO_USE_SCANOUT | BO_USE_HW_VIDEO_ENCODER); + + /* + * R8 format is used for Android's HAL_PIXEL_FORMAT_BLOB and is used for JPEG snapshots + * from camera and input/output from hardware decoder/encoder. + */ + drv_modify_combination(drv, DRM_FORMAT_R8, &metadata, + BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER | + BO_USE_HW_VIDEO_ENCODER); + + drv_modify_linear_combinations(drv); +} + +static int cross_domain_submit_cmd(struct driver *drv, uint32_t *cmd, uint32_t cmd_size, bool wait) +{ + int ret; + struct drm_virtgpu_3d_wait wait_3d = { 0 }; + struct drm_virtgpu_execbuffer exec = { 0 }; + struct cross_domain_private *priv = drv->priv; + + exec.command = (uint64_t)&cmd[0]; + exec.size = cmd_size; + if (wait) { + exec.flags = VIRTGPU_EXECBUF_FENCE_CONTEXT; + exec.bo_handles = (uint64_t)&priv->ring_handle; + exec.num_bo_handles = 1; + } + + ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &exec); + if (ret < 0) { + drv_log("DRM_IOCTL_VIRTGPU_EXECBUFFER failed with %s\n", strerror(errno)); + return -EINVAL; + } + + ret = -EAGAIN; + while (ret == -EAGAIN) { + wait_3d.handle = priv->ring_handle; + ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_WAIT, &wait_3d); + } + + if (ret < 0) { + drv_log("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno)); + return ret; + } + + return 0; +} + +static bool metadata_equal(struct bo_metadata *current, struct bo_metadata *cached) +{ + if ((current->width == cached->width) && (current->height == cached->height) && + (current->format == cached->format) && (current->use_flags == cached->use_flags)) + return true; + return false; +} + +static int cross_domain_metadata_query(struct driver *drv, struct bo_metadata *metadata) +{ + int ret = 0; + struct bo_metadata *cached_data = NULL; + struct cross_domain_private *priv = drv->priv; + struct CrossDomainGetImageRequirements cmd_get_reqs; + uint32_t *addr = (uint32_t *)priv->ring_addr; + uint32_t plane, remaining_size; + + memset(&cmd_get_reqs, 0, sizeof(cmd_get_reqs)); + pthread_mutex_lock(&drv->driver_lock); + for (uint32_t i = 0; i < drv_array_size(priv->metadata_cache); i++) { + cached_data = (struct bo_metadata *)drv_array_at_idx(priv->metadata_cache, i); + if (!metadata_equal(metadata, cached_data)) + continue; + + memcpy(metadata, cached_data, sizeof(*cached_data)); + goto out_unlock; + } + + cmd_get_reqs.hdr.cmd = CROSS_DOMAIN_CMD_GET_IMAGE_REQUIREMENTS; + cmd_get_reqs.hdr.cmd_size = sizeof(struct CrossDomainGetImageRequirements); + + cmd_get_reqs.width = metadata->width; + cmd_get_reqs.height = metadata->height; + cmd_get_reqs.drm_format = + (metadata->format == DRM_FORMAT_YVU420_ANDROID) ? DRM_FORMAT_YVU420 : metadata->format; + cmd_get_reqs.flags = metadata->use_flags; + + /* + * It is possible to avoid blocking other bo_create() calls by unlocking before + * cross_domain_submit_cmd() and re-locking afterwards. However, that would require + * another scan of the metadata cache before drv_array_append in case two bo_create() calls + * do the same metadata query. Until cross_domain functionality is more widely tested, + * leave this optimization out for now. + */ + ret = cross_domain_submit_cmd(drv, (uint32_t *)&cmd_get_reqs, cmd_get_reqs.hdr.cmd_size, + true); + if (ret < 0) + goto out_unlock; + + memcpy(&metadata->strides, &addr[0], 4 * sizeof(uint32_t)); + memcpy(&metadata->offsets, &addr[4], 4 * sizeof(uint32_t)); + memcpy(&metadata->format_modifier, &addr[8], sizeof(uint64_t)); + memcpy(&metadata->total_size, &addr[10], sizeof(uint64_t)); + memcpy(&metadata->blob_id, &addr[12], sizeof(uint64_t)); + + metadata->map_info = addr[14]; + metadata->memory_idx = addr[16]; + metadata->physical_device_idx = addr[17]; + + remaining_size = metadata->total_size; + for (plane = 0; plane < metadata->num_planes; plane++) { + if (plane != 0) { + metadata->sizes[plane - 1] = metadata->offsets[plane]; + remaining_size -= metadata->offsets[plane]; + } + } + + metadata->sizes[plane - 1] = remaining_size; + drv_array_append(priv->metadata_cache, metadata); + +out_unlock: + pthread_mutex_unlock(&drv->driver_lock); + return ret; +} + +static int cross_domain_init(struct driver *drv) +{ + int ret; + struct cross_domain_private *priv; + struct drm_virtgpu_map map = { 0 }; + struct drm_virtgpu_get_caps args = { 0 }; + struct drm_virtgpu_context_init init = { 0 }; + struct drm_virtgpu_resource_create_blob drm_rc_blob = { 0 }; + struct drm_virtgpu_context_set_param ctx_set_params[2] = { { 0 } }; + + struct CrossDomainInit cmd_init; + struct CrossDomainCapabilities cross_domain_caps; + + memset(&cmd_init, 0, sizeof(cmd_init)); + if (!params[param_context_init].value) + return -ENOTSUP; + + if ((params[param_supported_capset_ids].value & (1 << CAPSET_CROSS_DOMAIN)) == 0) + return -ENOTSUP; + + /* + * crosvm never reports the fake capset. This is just an extra check to make sure we + * don't use the cross-domain context by accident. Developers may remove this for + * testing purposes. + */ + if ((params[param_supported_capset_ids].value & (1 << CAPSET_CROSS_FAKE)) == 0) + return -ENOTSUP; + + priv = calloc(1, sizeof(*priv)); + priv->metadata_cache = drv_array_init(sizeof(struct bo_metadata)); + priv->ring_addr = MAP_FAILED; + drv->priv = priv; + + args.cap_set_id = CAPSET_CROSS_DOMAIN; + args.size = sizeof(struct CrossDomainCapabilities); + args.addr = (unsigned long long)&cross_domain_caps; + + ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GET_CAPS, &args); + if (ret) { + drv_log("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno)); + goto free_private; + } + + // When 3D features are avilable, but the host does not support external memory, fall back + // to the virgl minigbm backend. This typically means the guest side minigbm resource will + // be backed by a host OpenGL texture. + if (!cross_domain_caps.supports_external_gpu_memory && params[param_3d].value) { + ret = -ENOTSUP; + goto free_private; + } + + // Intialize the cross domain context. Create one fence context to wait for metadata + // queries. + ctx_set_params[0].param = VIRTGPU_CONTEXT_PARAM_CAPSET_ID; + ctx_set_params[0].value = CAPSET_CROSS_DOMAIN; + ctx_set_params[1].param = VIRTGPU_CONTEXT_PARAM_NUM_FENCE_CONTEXTS; + ctx_set_params[1].value = 1; + + init.ctx_set_params = (unsigned long long)&ctx_set_params[0]; + init.num_params = 2; + ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_CONTEXT_INIT, &init); + if (ret) { + drv_log("DRM_IOCTL_VIRTGPU_CONTEXT_INIT failed with %s\n", strerror(errno)); + goto free_private; + } + + // Create a shared ring buffer to read metadata queries. + drm_rc_blob.size = PAGE_SIZE; + drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_GUEST; + drm_rc_blob.blob_flags = VIRTGPU_BLOB_FLAG_USE_MAPPABLE; + + ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob); + if (ret < 0) { + drv_log("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno)); + goto free_private; + } + + priv->ring_handle = drm_rc_blob.bo_handle; + + // Map shared ring buffer. + map.handle = priv->ring_handle; + ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_MAP, &map); + if (ret < 0) { + drv_log("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno)); + goto free_private; + } + + priv->ring_addr = + mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, drv->fd, map.offset); + + if (priv->ring_addr == MAP_FAILED) { + drv_log("mmap failed with %s\n", strerror(errno)); + goto free_private; + } + + // Notify host about ring buffer + cmd_init.hdr.cmd = CROSS_DOMAIN_CMD_INIT; + cmd_init.hdr.cmd_size = sizeof(struct CrossDomainInit); + cmd_init.ring_id = drm_rc_blob.res_handle; + ret = cross_domain_submit_cmd(drv, (uint32_t *)&cmd_init, cmd_init.hdr.cmd_size, false); + if (ret < 0) + goto free_private; + + // minigbm bookkeeping + add_combinations(drv); + return 0; + +free_private: + cross_domain_release_private(drv); + return ret; +} + +static void cross_domain_close(struct driver *drv) +{ + cross_domain_release_private(drv); +} + +static int cross_domain_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, + uint64_t use_flags) +{ + int ret; + uint32_t blob_flags = VIRTGPU_BLOB_FLAG_USE_SHAREABLE; + struct drm_virtgpu_resource_create_blob drm_rc_blob = { 0 }; + + ret = cross_domain_metadata_query(bo->drv, &bo->meta); + if (ret < 0) { + drv_log("Metadata query failed"); + return ret; + } + + if (use_flags & BO_USE_SW_MASK) + blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE; + + if (params[param_cross_device].value && (use_flags & BO_USE_NON_GPU_HW)) + blob_flags |= VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE; + + drm_rc_blob.size = bo->meta.total_size; + drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_HOST3D; + drm_rc_blob.blob_flags = blob_flags; + drm_rc_blob.blob_id = bo->meta.blob_id; + + ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob); + if (ret < 0) { + drv_log("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno)); + return -errno; + } + + for (uint32_t plane = 0; plane < bo->meta.num_planes; plane++) + bo->handles[plane].u32 = drm_rc_blob.bo_handle; + + return 0; +} + +static void *cross_domain_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags) +{ + int ret; + struct drm_virtgpu_map gem_map = { 0 }; + + gem_map.handle = bo->handles[0].u32; + ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_MAP, &gem_map); + if (ret) { + drv_log("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno)); + return MAP_FAILED; + } + + vma->length = bo->meta.total_size; + return mmap(0, bo->meta.total_size, drv_get_prot(map_flags), MAP_SHARED, bo->drv->fd, + gem_map.offset); +} + +const struct backend virtgpu_cross_domain = { + .name = "virtgpu_cross_domain", + .init = cross_domain_init, + .close = cross_domain_close, + .bo_create = cross_domain_bo_create, + .bo_import = drv_prime_bo_import, + .bo_destroy = drv_gem_bo_destroy, + .bo_map = cross_domain_bo_map, + .bo_unmap = drv_bo_munmap, + .resolve_format = drv_resolve_format_helper, +}; diff --git a/virtio_gpu.c b/virtgpu_virgl.c similarity index 74% rename from virtio_gpu.c rename to virtgpu_virgl.c index bf5aed3..aac4677 100644 --- a/virtio_gpu.c +++ b/virtgpu_virgl.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -19,42 +18,13 @@ #include "external/virtgpu_drm.h" #include "helpers.h" #include "util.h" +#include "virtgpu.h" -#ifndef PAGE_SIZE -#define PAGE_SIZE 0x1000 -#endif #define PIPE_TEXTURE_2D 2 #define MESA_LLVMPIPE_TILE_ORDER 6 #define MESA_LLVMPIPE_TILE_SIZE (1 << MESA_LLVMPIPE_TILE_ORDER) -struct feature { - uint64_t feature; - const char *name; - uint32_t enabled; -}; - -enum feature_id { - feat_3d, - feat_capset_fix, - feat_resource_blob, - feat_host_visible, - feat_host_cross_device, - feat_max, -}; - -#define FEATURE(x) \ - (struct feature) \ - { \ - x, #x, 0 \ - } - -static struct feature features[] = { - FEATURE(VIRTGPU_PARAM_3D_FEATURES), FEATURE(VIRTGPU_PARAM_CAPSET_QUERY_FIX), - FEATURE(VIRTGPU_PARAM_RESOURCE_BLOB), FEATURE(VIRTGPU_PARAM_HOST_VISIBLE), - FEATURE(VIRTGPU_PARAM_CROSS_DEVICE), -}; - static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888 }; @@ -68,7 +38,9 @@ static const uint32_t texture_source_formats[] = { DRM_FORMAT_NV12, DRM_FORMAT_N DRM_FORMAT_R8, DRM_FORMAT_R16, DRM_FORMAT_RG88, DRM_FORMAT_YVU420_ANDROID }; -struct virtio_gpu_priv { +extern struct virtgpu_param params[]; + +struct virgl_priv { int caps_is_v2; union virgl_caps caps; int host_gbm_enabled; @@ -112,8 +84,8 @@ static uint32_t translate_format(uint32_t drm_fourcc) } } -static bool virtio_gpu_bitmask_supports_format(struct virgl_supported_format_mask *supported, - uint32_t drm_format) +static bool virgl_bitmask_supports_format(struct virgl_supported_format_mask *supported, + uint32_t drm_format) { uint32_t virgl_format = translate_format(drm_format); if (!virgl_format) @@ -165,7 +137,7 @@ static bool virtio_gpu_bitmask_supports_format(struct virgl_supported_format_mas // Additional note: the V-plane is not placed to the right of the U-plane due to some // observed failures in media framework code which assumes the V-plane is not // "row-interlaced" with the U-plane. -static void virtio_gpu_get_emulated_metadata(const struct bo *bo, struct bo_metadata *metadata) +static void virgl_get_emulated_metadata(const struct bo *bo, struct bo_metadata *metadata) { uint32_t y_plane_height; uint32_t c_plane_height; @@ -235,9 +207,9 @@ struct virtio_transfers_params { struct rectangle xfer_boxes[DRV_MAX_PLANES]; }; -static void virtio_gpu_get_emulated_transfers_params(const struct bo *bo, - const struct rectangle *transfer_box, - struct virtio_transfers_params *xfer_params) +static void virgl_get_emulated_transfers_params(const struct bo *bo, + const struct rectangle *transfer_box, + struct virtio_transfers_params *xfer_params) { uint32_t y_plane_height; uint32_t c_plane_height; @@ -245,7 +217,7 @@ static void virtio_gpu_get_emulated_transfers_params(const struct bo *bo, if (transfer_box->x == 0 && transfer_box->y == 0 && transfer_box->width == bo->meta.width && transfer_box->height == bo->meta.height) { - virtio_gpu_get_emulated_metadata(bo, &emulated_metadata); + virgl_get_emulated_metadata(bo, &emulated_metadata); xfer_params->xfers_needed = 1; xfer_params->xfer_boxes[0].x = 0; @@ -308,24 +280,24 @@ static void virtio_gpu_get_emulated_transfers_params(const struct bo *bo, } } -static bool virtio_gpu_supports_combination_natively(struct driver *drv, uint32_t drm_format, - uint64_t use_flags) +static bool virgl_supports_combination_natively(struct driver *drv, uint32_t drm_format, + uint64_t use_flags) { - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)drv->priv; if (priv->caps.max_version == 0) return true; if ((use_flags & BO_USE_RENDERING) && - !virtio_gpu_bitmask_supports_format(&priv->caps.v1.render, drm_format)) + !virgl_bitmask_supports_format(&priv->caps.v1.render, drm_format)) return false; if ((use_flags & BO_USE_TEXTURE) && - !virtio_gpu_bitmask_supports_format(&priv->caps.v1.sampler, drm_format)) + !virgl_bitmask_supports_format(&priv->caps.v1.sampler, drm_format)) return false; if ((use_flags & BO_USE_SCANOUT) && priv->caps_is_v2 && - !virtio_gpu_bitmask_supports_format(&priv->caps.v2.scanout, drm_format)) + !virgl_bitmask_supports_format(&priv->caps.v2.scanout, drm_format)) return false; return true; @@ -334,11 +306,10 @@ static bool virtio_gpu_supports_combination_natively(struct driver *drv, uint32_ // For virtio backends that do not support formats natively (e.g. multi-planar formats are not // supported in virglrenderer when gbm is unavailable on the host machine), whether or not the // format and usage combination can be handled as a blob (byte buffer). -static bool virtio_gpu_supports_combination_through_emulation(struct driver *drv, - uint32_t drm_format, - uint64_t use_flags) +static bool virgl_supports_combination_through_emulation(struct driver *drv, uint32_t drm_format, + uint64_t use_flags) { - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)drv->priv; // Only enable emulation on non-gbm virtio backends. if (priv->host_gbm_enabled) @@ -347,7 +318,7 @@ static bool virtio_gpu_supports_combination_through_emulation(struct driver *drv if (use_flags & (BO_USE_RENDERING | BO_USE_SCANOUT)) return false; - if (!virtio_gpu_supports_combination_natively(drv, DRM_FORMAT_R8, use_flags)) + if (!virgl_supports_combination_natively(drv, DRM_FORMAT_R8, use_flags)) return false; return drm_format == DRM_FORMAT_NV12 || drm_format == DRM_FORMAT_NV21 || @@ -356,21 +327,20 @@ static bool virtio_gpu_supports_combination_through_emulation(struct driver *drv // Adds the given buffer combination to the list of supported buffer combinations if the // combination is supported by the virtio backend. -static void virtio_gpu_add_combination(struct driver *drv, uint32_t drm_format, - struct format_metadata *metadata, uint64_t use_flags) +static void virgl_add_combination(struct driver *drv, uint32_t drm_format, + struct format_metadata *metadata, uint64_t use_flags) { - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)drv->priv; - if (features[feat_3d].enabled && priv->caps.max_version >= 1) { + if (params[param_3d].value && priv->caps.max_version >= 1) { if ((use_flags & BO_USE_SCANOUT) && priv->caps_is_v2 && - !virtio_gpu_supports_combination_natively(drv, drm_format, use_flags)) { + !virgl_supports_combination_natively(drv, drm_format, use_flags)) { drv_log("Scanout format: %d\n", drm_format); use_flags &= ~BO_USE_SCANOUT; } - if (!virtio_gpu_supports_combination_natively(drv, drm_format, use_flags) && - !virtio_gpu_supports_combination_through_emulation(drv, drm_format, - use_flags)) { + if (!virgl_supports_combination_natively(drv, drm_format, use_flags) && + !virgl_supports_combination_through_emulation(drv, drm_format, use_flags)) { drv_log("Skipping unsupported combination format:%d\n", drm_format); return; } @@ -381,14 +351,14 @@ static void virtio_gpu_add_combination(struct driver *drv, uint32_t drm_format, // Adds each given buffer combination to the list of supported buffer combinations if the // combination supported by the virtio backend. -static void virtio_gpu_add_combinations(struct driver *drv, const uint32_t *drm_formats, - uint32_t num_formats, struct format_metadata *metadata, - uint64_t use_flags) +static void virgl_add_combinations(struct driver *drv, const uint32_t *drm_formats, + uint32_t num_formats, struct format_metadata *metadata, + uint64_t use_flags) { uint32_t i; for (i = 0; i < num_formats; i++) - virtio_gpu_add_combination(drv, drm_formats[i], metadata, use_flags); + virgl_add_combination(drv, drm_formats[i], metadata, use_flags); } static int virtio_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, @@ -464,8 +434,8 @@ static uint32_t compute_virgl_bind_flags(uint64_t use_flags, uint32_t format) return bind; } -static int virtio_virgl_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, - uint64_t use_flags) +static int virgl_3d_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, + uint64_t use_flags) { int ret; size_t i; @@ -473,14 +443,13 @@ static int virtio_virgl_bo_create(struct bo *bo, uint32_t width, uint32_t height struct drm_virtgpu_resource_create res_create = { 0 }; struct bo_metadata emulated_metadata; - if (virtio_gpu_supports_combination_natively(bo->drv, format, use_flags)) { + if (virgl_supports_combination_natively(bo->drv, format, use_flags)) { stride = drv_stride_from_format(format, width, 0); drv_bo_from_format(bo, stride, height, format); } else { - assert( - virtio_gpu_supports_combination_through_emulation(bo->drv, format, use_flags)); + assert(virgl_supports_combination_through_emulation(bo->drv, format, use_flags)); - virtio_gpu_get_emulated_metadata(bo, &emulated_metadata); + virgl_get_emulated_metadata(bo, &emulated_metadata); format = emulated_metadata.format; width = emulated_metadata.width; @@ -526,7 +495,7 @@ static int virtio_virgl_bo_create(struct bo *bo, uint32_t width, uint32_t height return 0; } -static void *virtio_virgl_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags) +static void *virgl_3d_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags) { int ret; struct drm_virtgpu_map gem_map = { 0 }; @@ -543,14 +512,14 @@ static void *virtio_virgl_bo_map(struct bo *bo, struct vma *vma, size_t plane, u gem_map.offset); } -static int virtio_gpu_get_caps(struct driver *drv, union virgl_caps *caps, int *caps_is_v2) +static int virgl_get_caps(struct driver *drv, union virgl_caps *caps, int *caps_is_v2) { int ret; struct drm_virtgpu_get_caps cap_args = { 0 }; *caps_is_v2 = 0; cap_args.addr = (unsigned long long)caps; - if (features[feat_capset_fix].enabled) { + if (params[param_capset_fix].value) { *caps_is_v2 = 1; cap_args.cap_set_id = 2; cap_args.size = sizeof(union virgl_caps); @@ -576,79 +545,69 @@ static int virtio_gpu_get_caps(struct driver *drv, union virgl_caps *caps, int * return ret; } -static void virtio_gpu_init_features_and_caps(struct driver *drv) +static void virgl_init_params_and_caps(struct driver *drv) { - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)drv->priv; + if (params[param_3d].value) { + virgl_get_caps(drv, &priv->caps, &priv->caps_is_v2); - for (uint32_t i = 0; i < ARRAY_SIZE(features); i++) { - struct drm_virtgpu_getparam params = { 0 }; - - params.param = features[i].feature; - params.value = (uint64_t)(uintptr_t)&features[i].enabled; - int ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GETPARAM, ¶ms); - if (ret) - drv_log("DRM_IOCTL_VIRTGPU_GET_PARAM failed with %s\n", strerror(errno)); + // We use two criteria to determine whether host minigbm is used on the host for + // swapchain allocations. + // + // (1) Host minigbmgbm is only available via virglrenderer, and only virglrenderer + // advertises capabilities. + // (2) Only host minigbm doesn't emulate YUV formats. Checking this is a bit of a + // proxy, but it works. + priv->host_gbm_enabled = priv->caps.max_version > 0 && + virgl_supports_combination_natively(drv, DRM_FORMAT_NV12, BO_USE_TEXTURE); } - - if (features[feat_3d].enabled) - virtio_gpu_get_caps(drv, &priv->caps, &priv->caps_is_v2); - - priv->host_gbm_enabled = - // 2D mode does not create resources on the host so it does not enable host gbm. - features[feat_3d].enabled && - // Gfxstream does not enable host gbm. Virglrenderer sets caps while Gfxstream does not - // so filter out if we are running with Gfxstream. - priv->caps.max_version > 0 && - // Virglrenderer only supports multi-planar formats through host gbm. - virtio_gpu_supports_combination_natively(drv, DRM_FORMAT_NV12, BO_USE_TEXTURE); } -static int virtio_gpu_init(struct driver *drv) +static int virgl_init(struct driver *drv) { - struct virtio_gpu_priv *priv; + struct virgl_priv *priv; priv = calloc(1, sizeof(*priv)); drv->priv = priv; - virtio_gpu_init_features_and_caps(drv); + virgl_init_params_and_caps(drv); - if (features[feat_3d].enabled) { + if (params[param_3d].value) { /* This doesn't mean host can scanout everything, it just means host * hypervisor can show it. */ - virtio_gpu_add_combinations(drv, render_target_formats, - ARRAY_SIZE(render_target_formats), &LINEAR_METADATA, - BO_USE_RENDER_MASK | BO_USE_SCANOUT); - virtio_gpu_add_combinations(drv, texture_source_formats, - ARRAY_SIZE(texture_source_formats), &LINEAR_METADATA, - BO_USE_TEXTURE_MASK); + virgl_add_combinations(drv, render_target_formats, + ARRAY_SIZE(render_target_formats), &LINEAR_METADATA, + BO_USE_RENDER_MASK | BO_USE_SCANOUT); + virgl_add_combinations(drv, texture_source_formats, + ARRAY_SIZE(texture_source_formats), &LINEAR_METADATA, + BO_USE_TEXTURE_MASK); } else { /* Virtio primary plane only allows this format. */ - virtio_gpu_add_combination(drv, DRM_FORMAT_XRGB8888, &LINEAR_METADATA, - BO_USE_RENDER_MASK | BO_USE_SCANOUT); + virgl_add_combination(drv, DRM_FORMAT_XRGB8888, &LINEAR_METADATA, + BO_USE_RENDER_MASK | BO_USE_SCANOUT); /* Virtio cursor plane only allows this format and Chrome cannot live without * ARGB888 renderable format. */ - virtio_gpu_add_combination(drv, DRM_FORMAT_ARGB8888, &LINEAR_METADATA, - BO_USE_RENDER_MASK | BO_USE_CURSOR); + virgl_add_combination(drv, DRM_FORMAT_ARGB8888, &LINEAR_METADATA, + BO_USE_RENDER_MASK | BO_USE_CURSOR); /* Android needs more, but they cannot be bound as scanouts anymore after * "drm/virtio: fix DRM_FORMAT_* handling" */ - virtio_gpu_add_combinations(drv, render_target_formats, - ARRAY_SIZE(render_target_formats), &LINEAR_METADATA, - BO_USE_RENDER_MASK); - virtio_gpu_add_combinations(drv, dumb_texture_source_formats, - ARRAY_SIZE(dumb_texture_source_formats), - &LINEAR_METADATA, BO_USE_TEXTURE_MASK); - virtio_gpu_add_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA, - BO_USE_SW_MASK | BO_USE_LINEAR); - virtio_gpu_add_combination(drv, DRM_FORMAT_NV21, &LINEAR_METADATA, - BO_USE_SW_MASK | BO_USE_LINEAR); + virgl_add_combinations(drv, render_target_formats, + ARRAY_SIZE(render_target_formats), &LINEAR_METADATA, + BO_USE_RENDER_MASK); + virgl_add_combinations(drv, dumb_texture_source_formats, + ARRAY_SIZE(dumb_texture_source_formats), &LINEAR_METADATA, + BO_USE_TEXTURE_MASK); + virgl_add_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA, + BO_USE_SW_MASK | BO_USE_LINEAR); + virgl_add_combination(drv, DRM_FORMAT_NV21, &LINEAR_METADATA, + BO_USE_SW_MASK | BO_USE_LINEAR); } /* Android CTS tests require this. */ - virtio_gpu_add_combination(drv, DRM_FORMAT_RGB888, &LINEAR_METADATA, BO_USE_SW_MASK); - virtio_gpu_add_combination(drv, DRM_FORMAT_BGR888, &LINEAR_METADATA, BO_USE_SW_MASK); - virtio_gpu_add_combination(drv, DRM_FORMAT_ABGR16161616F, &LINEAR_METADATA, - BO_USE_SW_MASK | BO_USE_TEXTURE_MASK); - + virgl_add_combination(drv, DRM_FORMAT_RGB888, &LINEAR_METADATA, BO_USE_SW_MASK); + virgl_add_combination(drv, DRM_FORMAT_BGR888, &LINEAR_METADATA, BO_USE_SW_MASK); + virgl_add_combination(drv, DRM_FORMAT_ABGR16161616F, &LINEAR_METADATA, + BO_USE_SW_MASK | BO_USE_TEXTURE_MASK); drv_modify_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA, BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER); @@ -680,20 +639,20 @@ static int virtio_gpu_init(struct driver *drv) return drv_modify_linear_combinations(drv); } -static void virtio_gpu_close(struct driver *drv) +static void virgl_close(struct driver *drv) { free(drv->priv); drv->priv = NULL; } -static int virtio_gpu_bo_create_blob(struct driver *drv, struct bo *bo) +static int virgl_bo_create_blob(struct driver *drv, struct bo *bo) { int ret; uint32_t stride; uint32_t cur_blob_id; uint32_t cmd[VIRGL_PIPE_RES_CREATE_SIZE + 1] = { 0 }; struct drm_virtgpu_resource_create_blob drm_rc_blob = { 0 }; - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)drv->priv; uint32_t blob_flags = VIRTGPU_BLOB_FLAG_USE_SHAREABLE; if (bo->meta.use_flags & BO_USE_SW_MASK) @@ -738,7 +697,7 @@ static int virtio_gpu_bo_create_blob(struct driver *drv, struct bo *bo) static bool should_use_blob(struct driver *drv, uint32_t format, uint64_t use_flags) { - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)drv->priv; // TODO(gurchetansingh): remove once all minigbm users are blob-safe #ifndef VIRTIO_GPU_NEXT @@ -768,46 +727,46 @@ static bool should_use_blob(struct driver *drv, uint32_t format, uint64_t use_fl } } -static int virtio_gpu_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, - uint64_t use_flags) +static int virgl_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, + uint64_t use_flags) { - if (features[feat_resource_blob].enabled && features[feat_host_visible].enabled && + if (params[param_resource_blob].value && params[param_host_visible].value && should_use_blob(bo->drv, format, use_flags)) - return virtio_gpu_bo_create_blob(bo->drv, bo); + return virgl_bo_create_blob(bo->drv, bo); - if (features[feat_3d].enabled) - return virtio_virgl_bo_create(bo, width, height, format, use_flags); + if (params[param_3d].value) + return virgl_3d_bo_create(bo, width, height, format, use_flags); else return virtio_dumb_bo_create(bo, width, height, format, use_flags); } -static int virtio_gpu_bo_destroy(struct bo *bo) +static int virgl_bo_destroy(struct bo *bo) { - if (features[feat_3d].enabled) + if (params[param_3d].value) return drv_gem_bo_destroy(bo); else return drv_dumb_bo_destroy(bo); } -static void *virtio_gpu_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags) +static void *virgl_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags) { - if (features[feat_3d].enabled) - return virtio_virgl_bo_map(bo, vma, plane, map_flags); + if (params[param_3d].value) + return virgl_3d_bo_map(bo, vma, plane, map_flags); else return drv_dumb_bo_map(bo, vma, plane, map_flags); } -static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) +static int virgl_bo_invalidate(struct bo *bo, struct mapping *mapping) { int ret; size_t i; struct drm_virtgpu_3d_transfer_from_host xfer = { 0 }; struct drm_virtgpu_3d_wait waitcmd = { 0 }; struct virtio_transfers_params xfer_params; - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)bo->drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)bo->drv->priv; uint64_t host_write_flags; - if (!features[feat_3d].enabled) + if (!params[param_3d].value) return 0; // Invalidate is only necessary if the host writes to the buffer. The encoder and @@ -822,8 +781,7 @@ static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) if ((bo->meta.use_flags & host_write_flags) == 0) return 0; - if (features[feat_resource_blob].enabled && - (bo->meta.tiling & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) + if (params[param_resource_blob].value && (bo->meta.tiling & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) return 0; xfer.bo_handle = mapping->vma->handle; @@ -842,7 +800,7 @@ static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) if ((bo->meta.use_flags & BO_USE_RENDERING) == 0) { // Unfortunately, the kernel doesn't actually pass the guest layer_stride - // and guest stride to the host (compare virtio_gpu.h and virtgpu_drm.h). + // and guest stride to the host (compare virgl.h and virtgpu_drm.h). // For gbm based resources, we can work around this by using the level field // to pass the stride to virglrenderer's gbm transfer code. However, we need // to avoid doing this for resources which don't rely on that transfer code, @@ -852,15 +810,14 @@ static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) xfer.level = bo->meta.strides[0]; } - if (virtio_gpu_supports_combination_natively(bo->drv, bo->meta.format, - bo->meta.use_flags)) { + if (virgl_supports_combination_natively(bo->drv, bo->meta.format, bo->meta.use_flags)) { xfer_params.xfers_needed = 1; xfer_params.xfer_boxes[0] = mapping->rect; } else { - assert(virtio_gpu_supports_combination_through_emulation(bo->drv, bo->meta.format, - bo->meta.use_flags)); + assert(virgl_supports_combination_through_emulation(bo->drv, bo->meta.format, + bo->meta.use_flags)); - virtio_gpu_get_emulated_transfers_params(bo, &mapping->rect, &xfer_params); + virgl_get_emulated_transfers_params(bo, &mapping->rect, &xfer_params); } for (i = 0; i < xfer_params.xfers_needed; i++) { @@ -891,23 +848,22 @@ static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) return 0; } -static int virtio_gpu_bo_flush(struct bo *bo, struct mapping *mapping) +static int virgl_bo_flush(struct bo *bo, struct mapping *mapping) { int ret; size_t i; struct drm_virtgpu_3d_transfer_to_host xfer = { 0 }; struct drm_virtgpu_3d_wait waitcmd = { 0 }; struct virtio_transfers_params xfer_params; - struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)bo->drv->priv; + struct virgl_priv *priv = (struct virgl_priv *)bo->drv->priv; - if (!features[feat_3d].enabled) + if (!params[param_3d].value) return 0; if (!(mapping->vma->map_flags & BO_MAP_WRITE)) return 0; - if (features[feat_resource_blob].enabled && - (bo->meta.tiling & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) + if (params[param_resource_blob].value && (bo->meta.tiling & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) return 0; xfer.bo_handle = mapping->vma->handle; @@ -925,20 +881,19 @@ static int virtio_gpu_bo_flush(struct bo *bo, struct mapping *mapping) } // Unfortunately, the kernel doesn't actually pass the guest layer_stride and - // guest stride to the host (compare virtio_gpu.h and virtgpu_drm.h). We can use + // guest stride to the host (compare virgl.h and virtgpu_drm.h). We can use // the level to work around this. if (priv->host_gbm_enabled) xfer.level = bo->meta.strides[0]; - if (virtio_gpu_supports_combination_natively(bo->drv, bo->meta.format, - bo->meta.use_flags)) { + if (virgl_supports_combination_natively(bo->drv, bo->meta.format, bo->meta.use_flags)) { xfer_params.xfers_needed = 1; xfer_params.xfer_boxes[0] = mapping->rect; } else { - assert(virtio_gpu_supports_combination_through_emulation(bo->drv, bo->meta.format, - bo->meta.use_flags)); + assert(virgl_supports_combination_through_emulation(bo->drv, bo->meta.format, + bo->meta.use_flags)); - virtio_gpu_get_emulated_transfers_params(bo, &mapping->rect, &xfer_params); + virgl_get_emulated_transfers_params(bo, &mapping->rect, &xfer_params); } for (i = 0; i < xfer_params.xfers_needed; i++) { @@ -973,7 +928,7 @@ static int virtio_gpu_bo_flush(struct bo *bo, struct mapping *mapping) return 0; } -static uint32_t virtio_gpu_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags) +static uint32_t virgl_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags) { switch (format) { case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED: @@ -987,7 +942,7 @@ static uint32_t virtio_gpu_resolve_format(struct driver *drv, uint32_t format, u * All of our host drivers prefer NV12 as their flexible media format. * If that changes, this will need to be modified. */ - if (features[feat_3d].enabled) + if (params[param_3d].value) return DRM_FORMAT_NV12; else return DRM_FORMAT_YVU420_ANDROID; @@ -995,14 +950,13 @@ static uint32_t virtio_gpu_resolve_format(struct driver *drv, uint32_t format, u return format; } } - -static int virtio_gpu_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLANES], - uint32_t offsets[DRV_MAX_PLANES]) +static int virgl_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLANES], + uint32_t offsets[DRV_MAX_PLANES]) { int ret; struct drm_virtgpu_resource_info_cros res_info = { 0 }; - if (!features[feat_3d].enabled) + if (!params[param_3d].value) return 0; res_info.bo_handle = bo->handles[0].u32; @@ -1027,17 +981,17 @@ static int virtio_gpu_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLAN return 0; } -const struct backend backend_virtio_gpu = { - .name = "virtio_gpu", - .init = virtio_gpu_init, - .close = virtio_gpu_close, - .bo_create = virtio_gpu_bo_create, - .bo_destroy = virtio_gpu_bo_destroy, +const struct backend virtgpu_virgl = { + .name = "virtgpu_virgl", + .init = virgl_init, + .close = virgl_close, + .bo_create = virgl_bo_create, + .bo_destroy = virgl_bo_destroy, .bo_import = drv_prime_bo_import, - .bo_map = virtio_gpu_bo_map, + .bo_map = virgl_bo_map, .bo_unmap = drv_bo_munmap, - .bo_invalidate = virtio_gpu_bo_invalidate, - .bo_flush = virtio_gpu_bo_flush, - .resolve_format = virtio_gpu_resolve_format, - .resource_info = virtio_gpu_resource_info, + .bo_invalidate = virgl_bo_invalidate, + .bo_flush = virgl_bo_flush, + .resolve_format = virgl_resolve_format, + .resource_info = virgl_resource_info };