Merge remote-tracking branch 'aosp/upstream-main' into 'aosp/master'

... to update Minigbm for Cuttlefish to pull in cross domain virtgpu
backend.

Bug: b/189133053
Test: launch_cvd
Test: launch_cvd --gpu_mode=gfxstream
Test: CtsGraphicsTestCases
Change-Id: I8ce1c8b0574bb0ccefc8fd119ffc9a6e410fa3dc
This commit is contained in:
Jason Macnak 2021-05-25 12:59:35 -07:00
commit cab396632e
28 changed files with 1010 additions and 667 deletions

View file

@ -46,9 +46,10 @@ cc_defaults {
"mediatek.c",
"msm.c",
"rockchip.c",
"tegra.c",
"vc4.c",
"virtio_gpu.c",
"virtgpu.c",
"virtgpu_cross_domain.c",
"virtgpu_virgl.c",
],
cflags: [

11
OWNERS
View file

@ -1,11 +1,10 @@
dbehr@chromium.org
dcastagna@chromium.org
ddavenport@chromium.org
gurchetansingh@chromium.org
hoegsberg@chromium.org
ihf@chromium.org
lepton@chromium.org
marcheu@chromium.org
stevensd@chromium.org
tfiga@chromium.org
tutankhamen@chromium.org
# Also natsu@google.com is great for gralloc/Android stuff but doesn't have a
# chromium account.
# So any team members can +2
*

View file

@ -48,9 +48,10 @@ struct amdgpu_linear_vma_priv {
};
const static uint32_t render_target_formats[] = {
DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565,
DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_ABGR2101010,
DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565,
DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_ABGR2101010,
DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ABGR16161616F,
};
const static uint32_t texture_source_formats[] = {
@ -354,10 +355,12 @@ static int amdgpu_init(struct driver *drv)
/* NV12 format for camera, display, decoding and encoding. */
drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata,
BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_SCANOUT |
BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER);
BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER |
BO_USE_PROTECTED);
drv_modify_combination(drv, DRM_FORMAT_P010, &metadata,
BO_USE_SCANOUT | BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER);
BO_USE_SCANOUT | BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER |
BO_USE_PROTECTED);
/* Android CTS tests require this. */
drv_add_combination(drv, DRM_FORMAT_BGR888, &metadata, BO_USE_SW_MASK);
@ -471,6 +474,10 @@ static int amdgpu_create_bo_linear(struct bo *bo, uint32_t width, uint32_t heigh
if ((use_flags & BO_USE_SCANOUT) || !(use_flags & BO_USE_SW_READ_OFTEN))
gem_create.in.domain_flags |= AMDGPU_GEM_CREATE_CPU_GTT_USWC;
/* For protected data Buffer needs to be allocated from TMZ */
if (use_flags & BO_USE_PROTECTED)
gem_create.in.domain_flags |= AMDGPU_GEM_CREATE_ENCRYPTED;
/* Allocate the buffer with the preferred heap. */
ret = drmCommandWriteRead(drv_get_fd(bo->drv), DRM_AMDGPU_GEM_CREATE, &gem_create,
sizeof(gem_create));
@ -489,6 +496,7 @@ static int amdgpu_create_bo(struct bo *bo, uint32_t width, uint32_t height, uint
uint64_t use_flags)
{
struct combination *combo;
struct amdgpu_priv *priv = bo->drv->priv;
combo = drv_get_combination(bo->drv, format, use_flags);
if (!combo)
@ -508,7 +516,7 @@ static int amdgpu_create_bo(struct bo *bo, uint32_t width, uint32_t height, uint
needs_alignment = true;
#endif
// See b/122049612
if (use_flags & (BO_USE_SCANOUT))
if (use_flags & (BO_USE_SCANOUT) && priv->dev_info.family == AMDGPU_FAMILY_CZ)
needs_alignment = true;
if (needs_alignment) {

View file

@ -116,9 +116,10 @@ int32_t cros_gralloc_buffer::unlock()
}
int32_t cros_gralloc_buffer::resource_info(uint32_t strides[DRV_MAX_PLANES],
uint32_t offsets[DRV_MAX_PLANES])
uint32_t offsets[DRV_MAX_PLANES],
uint64_t *format_modifier)
{
return drv_resource_info(bo_, strides, offsets);
return drv_resource_info(bo_, strides, offsets, format_modifier);
}
int32_t cros_gralloc_buffer::invalidate()

View file

@ -27,7 +27,8 @@ class cros_gralloc_buffer
int32_t lock(const struct rectangle *rect, uint32_t map_flags,
uint8_t *addr[DRV_MAX_PLANES]);
int32_t unlock();
int32_t resource_info(uint32_t strides[DRV_MAX_PLANES], uint32_t offsets[DRV_MAX_PLANES]);
int32_t resource_info(uint32_t strides[DRV_MAX_PLANES], uint32_t offsets[DRV_MAX_PLANES],
uint64_t *format_modifier);
int32_t invalidate();
int32_t flush();

View file

@ -170,14 +170,6 @@ int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descripto
resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
use_flags = descriptor->use_flags;
/*
* TODO(b/79682290): ARC++ assumes NV12 is always linear and doesn't
* send modifiers across Wayland protocol, so we or in the
* BO_USE_LINEAR flag here. We need to fix ARC++ to allocate and work
* with tiled buffers.
*/
if (resolved_format == DRM_FORMAT_NV12)
use_flags |= BO_USE_LINEAR;
/*
* This unmask is a backup in the case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED is resolved
@ -217,7 +209,7 @@ int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descripto
* native_handle_clone() copies data based on hnd->base.numInts.
*/
num_bytes = ALIGN(num_bytes, sizeof(int));
num_ints = num_bytes - sizeof(native_handle_t) - num_fds;
num_ints = ((num_bytes - sizeof(native_handle_t)) / sizeof(int)) - num_fds;
hnd =
reinterpret_cast<struct cros_gralloc_handle *>(native_handle_create(num_fds, num_ints));
@ -473,7 +465,8 @@ int32_t cros_gralloc_driver::get_backing_store(buffer_handle_t handle, uint64_t
}
int32_t cros_gralloc_driver::resource_info(buffer_handle_t handle, uint32_t strides[DRV_MAX_PLANES],
uint32_t offsets[DRV_MAX_PLANES])
uint32_t offsets[DRV_MAX_PLANES],
uint64_t *format_modifier)
{
std::lock_guard<std::mutex> lock(mutex_);
@ -489,7 +482,7 @@ int32_t cros_gralloc_driver::resource_info(buffer_handle_t handle, uint32_t stri
return -EINVAL;
}
return buffer->resource_info(strides, offsets);
return buffer->resource_info(strides, offsets, format_modifier);
}
int32_t cros_gralloc_driver::get_reserved_region(buffer_handle_t handle,

View file

@ -37,7 +37,7 @@ class cros_gralloc_driver
int32_t get_backing_store(buffer_handle_t handle, uint64_t *out_store);
int32_t resource_info(buffer_handle_t handle, uint32_t strides[DRV_MAX_PLANES],
uint32_t offsets[DRV_MAX_PLANES]);
uint32_t offsets[DRV_MAX_PLANES], uint64_t *format_modifier);
int32_t get_reserved_region(buffer_handle_t handle, void **reserved_region_addr,
uint64_t *reserved_region_size);

View file

@ -42,6 +42,22 @@ enum {
GRALLOC_DRM_GET_DIMENSIONS,
GRALLOC_DRM_GET_BACKING_STORE,
GRALLOC_DRM_GET_BUFFER_INFO,
GRALLOC_DRM_GET_USAGE,
};
/* This enumeration corresponds to the GRALLOC_DRM_GET_USAGE query op, which
* defines a set of bit flags used by the client to query vendor usage bits.
*
* Here is the common flow:
* 1) EGL/Vulkan calls GRALLOC_DRM_GET_USAGE to append one or multiple vendor
* usage bits to the existing usage and sets onto the ANativeWindow.
* 2) Some implicit GL draw cmd or the explicit vkCreateSwapchainKHR kicks off
* the next dequeueBuffer on the ANativeWindow with the combined usage.
* 3) dequeueBuffer then asks gralloc hal for an allocation/re-allocation, and
* calls into the below `gralloc0_alloc(...)` api.
*/
enum {
GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT = 0x00000001,
};
// clang-format on
@ -50,6 +66,11 @@ enum {
// entirety, so we can detect the video decoder flag passed by IAllocator clients.
#define BUFFER_USAGE_VIDEO_DECODER (1 << 22)
// Reserve the GRALLOC_USAGE_PRIVATE_0 bit for buffers used for front rendering.
// minigbm backend later decides to use BO_USE_FRONT_RENDERING or BO_USE_LINEAR
// upon buffer allocaton.
#define BUFFER_USAGE_FRONT_RENDERING GRALLOC_USAGE_PRIVATE_0
static uint64_t gralloc0_convert_usage(int usage)
{
uint64_t use_flags = BO_USE_NONE;
@ -97,6 +118,8 @@ static uint64_t gralloc0_convert_usage(int usage)
use_flags |= BO_USE_RENDERSCRIPT;
if (usage & BUFFER_USAGE_VIDEO_DECODER)
use_flags |= BO_USE_HW_VIDEO_DECODER;
if (usage & BUFFER_USAGE_FRONT_RENDERING)
use_flags |= BO_USE_FRONT_RENDERING;
return use_flags;
}
@ -151,6 +174,11 @@ static int gralloc0_alloc(alloc_device_t *dev, int w, int h, int format, int usa
drv_log("Retrying format %u allocation without encoder flag", format);
supported = mod->driver->is_supported(&descriptor);
}
if (!supported && (usage & BUFFER_USAGE_FRONT_RENDERING)) {
descriptor.use_flags &= ~BO_USE_FRONT_RENDERING;
descriptor.use_flags |= BO_USE_LINEAR;
supported = mod->driver->is_supported(&descriptor);
}
if (!supported) {
drv_log("Unsupported combination -- HAL format: %u, HAL usage: %u, "
@ -276,11 +304,18 @@ static int gralloc0_perform(struct gralloc_module_t const *module, int op, ...)
int32_t *out_format, ret;
uint64_t *out_store;
buffer_handle_t handle;
cros_gralloc_handle_t hnd;
uint32_t *out_width, *out_height, *out_stride;
uint32_t strides[DRV_MAX_PLANES] = { 0, 0, 0, 0 };
uint32_t offsets[DRV_MAX_PLANES] = { 0, 0, 0, 0 };
uint64_t format_modifier = 0;
struct cros_gralloc0_buffer_info *info;
auto mod = (struct gralloc0_module const *)module;
uint32_t req_usage;
uint32_t gralloc_usage = 0;
uint32_t *out_gralloc_usage;
va_start(args, op);
switch (op) {
case GRALLOC_DRM_GET_STRIDE:
@ -288,25 +323,27 @@ static int gralloc0_perform(struct gralloc_module_t const *module, int op, ...)
case GRALLOC_DRM_GET_DIMENSIONS:
case GRALLOC_DRM_GET_BACKING_STORE:
case GRALLOC_DRM_GET_BUFFER_INFO:
/* retrieve handles for ops with buffer_handle_t */
handle = va_arg(args, buffer_handle_t);
hnd = cros_gralloc_convert_handle(handle);
if (!hnd) {
va_end(args);
drv_log("Invalid handle.\n");
return -EINVAL;
}
break;
case GRALLOC_DRM_GET_USAGE:
break;
default:
va_end(args);
return -EINVAL;
}
va_start(args, op);
ret = 0;
handle = va_arg(args, buffer_handle_t);
auto hnd = cros_gralloc_convert_handle(handle);
if (!hnd) {
drv_log("Invalid handle.\n");
return -EINVAL;
}
switch (op) {
case GRALLOC_DRM_GET_STRIDE:
out_stride = va_arg(args, uint32_t *);
ret = mod->driver->resource_info(handle, strides, offsets);
ret = mod->driver->resource_info(handle, strides, offsets, &format_modifier);
if (ret)
break;
@ -336,13 +373,29 @@ static int gralloc0_perform(struct gralloc_module_t const *module, int op, ...)
info = va_arg(args, struct cros_gralloc0_buffer_info *);
info->drm_fourcc = drv_get_standard_fourcc(hnd->format);
info->num_fds = hnd->num_planes;
info->modifier = hnd->format_modifier;
ret = mod->driver->resource_info(handle, strides, offsets, &format_modifier);
if (ret)
break;
info->modifier = format_modifier ? format_modifier : hnd->format_modifier;
for (uint32_t i = 0; i < hnd->num_planes; i++) {
info->fds[i] = hnd->fds[i];
info->offset[i] = hnd->offsets[i];
info->stride[i] = hnd->strides[i];
if (strides[i]) {
info->stride[i] = strides[i];
info->offset[i] = offsets[i];
} else {
info->stride[i] = hnd->strides[i];
info->offset[i] = hnd->offsets[i];
}
}
break;
case GRALLOC_DRM_GET_USAGE:
req_usage = va_arg(args, uint32_t);
out_gralloc_usage = va_arg(args, uint32_t *);
if (req_usage & GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT)
gralloc_usage |= BUFFER_USAGE_FRONT_RENDERING;
*out_gralloc_usage = gralloc_usage;
break;
default:
ret = -EINVAL;
}
@ -407,6 +460,7 @@ static int gralloc0_lock_async_ycbcr(struct gralloc_module_t const *module, buff
uint32_t map_flags;
uint32_t strides[DRV_MAX_PLANES] = { 0, 0, 0, 0 };
uint32_t offsets[DRV_MAX_PLANES] = { 0, 0, 0, 0 };
uint64_t format_modifier = 0;
uint8_t *addr[DRV_MAX_PLANES] = { nullptr, nullptr, nullptr, nullptr };
auto mod = (struct gralloc0_module const *)module;
struct rectangle rect = { .x = static_cast<uint32_t>(l),
@ -437,7 +491,7 @@ static int gralloc0_lock_async_ycbcr(struct gralloc_module_t const *module, buff
return ret;
if (!map_flags) {
ret = mod->driver->resource_info(handle, strides, offsets);
ret = mod->driver->resource_info(handle, strides, offsets, &format_modifier);
if (ret)
return ret;

View file

@ -41,12 +41,20 @@
} \
} while (0)
#define BUFFER_USAGE_FRONT_RENDERING GRALLOC_USAGE_PRIVATE_0
/* Private API enumeration -- see <gralloc_drm.h> */
enum {
GRALLOC_DRM_GET_STRIDE,
GRALLOC_DRM_GET_FORMAT,
GRALLOC_DRM_GET_DIMENSIONS,
GRALLOC_DRM_GET_BACKING_STORE,
GRALLOC_DRM_GET_BUFFER_INFO,
GRALLOC_DRM_GET_USAGE,
};
enum {
GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT = 0x00000001,
};
struct gralloctest_context {
@ -467,7 +475,7 @@ static int test_perform(struct gralloctest_context *ctx)
{
int32_t format;
uint64_t id1, id2;
uint32_t stride, width, height;
uint32_t stride, width, height, req_usage, gralloc_usage;
struct grallocinfo info, duplicate;
struct gralloc_module_t *mod = ctx->module;
@ -498,6 +506,16 @@ static int test_perform(struct gralloctest_context *ctx)
CHECK(unregister_buffer(mod, &duplicate));
CHECK(deallocate(ctx->device, &info));
req_usage = 0;
gralloc_usage = 0;
CHECK(mod->perform(mod, GRALLOC_DRM_GET_USAGE, req_usage, &gralloc_usage) == 0);
CHECK(gralloc_usage == 0);
req_usage = GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT;
gralloc_usage = 0;
CHECK(mod->perform(mod, GRALLOC_DRM_GET_USAGE, req_usage, &gralloc_usage) == 0);
CHECK(gralloc_usage == BUFFER_USAGE_FRONT_RENDERING);
return 1;
}

1
dri.c
View file

@ -37,6 +37,7 @@ static const struct {
{ DRM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010 },
{ DRM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010 },
{ DRM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010 },
{ DRM_FORMAT_ABGR16161616F, __DRI_IMAGE_FORMAT_ABGR16161616F },
};
static int drm_format_to_dri_format(uint32_t drm_format)

24
drv.c
View file

@ -43,9 +43,6 @@ extern const struct backend backend_msm;
#ifdef DRV_ROCKCHIP
extern const struct backend backend_rockchip;
#endif
#ifdef DRV_TEGRA
extern const struct backend backend_tegra;
#endif
#ifdef DRV_VC4
extern const struct backend backend_vc4;
#endif
@ -58,7 +55,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 +91,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;
@ -694,15 +683,16 @@ void drv_log_prefix(const char *prefix, const char *file, int line, const char *
}
int drv_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLANES],
uint32_t offsets[DRV_MAX_PLANES])
uint32_t offsets[DRV_MAX_PLANES], uint64_t *format_modifier)
{
for (uint32_t plane = 0; plane < bo->meta.num_planes; plane++) {
strides[plane] = bo->meta.strides[plane];
offsets[plane] = bo->meta.offsets[plane];
}
*format_modifier = bo->meta.format_modifier;
if (bo->drv->backend->resource_info)
return bo->drv->backend->resource_info(bo, strides, offsets);
return bo->drv->backend->resource_info(bo, strides, offsets, format_modifier);
return 0;
}

5
drv.h
View file

@ -37,7 +37,8 @@ extern "C" {
#define BO_USE_HW_VIDEO_DECODER (1ull << 13)
#define BO_USE_HW_VIDEO_ENCODER (1ull << 14)
#define BO_USE_TEST_ALLOC (1ull << 15)
#define BO_USE_RENDERSCRIPT (1ull << 16)
#define BO_USE_FRONT_RENDERING (1ull << 16)
#define BO_USE_RENDERSCRIPT (1ull << 17)
/* Quirks for allocating a buffer. */
#define BO_QUIRK_NONE 0
@ -183,7 +184,7 @@ size_t drv_num_planes_from_modifier(struct driver *drv, uint32_t format, uint64_
uint32_t drv_num_buffers_per_bo(struct bo *bo);
int drv_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLANES],
uint32_t offsets[DRV_MAX_PLANES]);
uint32_t offsets[DRV_MAX_PLANES], uint64_t *format_modifier);
#define drv_log(format, ...) \
do { \

View file

@ -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 {
@ -82,20 +93,20 @@ struct backend {
uint32_t (*resolve_format)(struct driver *drv, uint32_t format, uint64_t use_flags);
size_t (*num_planes_from_modifier)(struct driver *drv, uint32_t format, uint64_t modifier);
int (*resource_info)(struct bo *bo, uint32_t strides[DRV_MAX_PLANES],
uint32_t offsets[DRV_MAX_PLANES]);
uint32_t offsets[DRV_MAX_PLANES], uint64_t *format_modifier);
};
// clang-format off
#define BO_USE_RENDER_MASK (BO_USE_LINEAR | BO_USE_RENDERING | BO_USE_RENDERSCRIPT | \
BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN | BO_USE_SW_READ_RARELY | \
BO_USE_SW_WRITE_RARELY | BO_USE_TEXTURE)
BO_USE_SW_WRITE_RARELY | BO_USE_TEXTURE | BO_USE_FRONT_RENDERING)
#define BO_USE_TEXTURE_MASK (BO_USE_LINEAR | BO_USE_RENDERSCRIPT | BO_USE_SW_READ_OFTEN | \
BO_USE_SW_WRITE_OFTEN | BO_USE_SW_READ_RARELY | \
BO_USE_SW_WRITE_RARELY | BO_USE_TEXTURE)
BO_USE_SW_WRITE_RARELY | BO_USE_TEXTURE | BO_USE_FRONT_RENDERING)
#define BO_USE_SW_MASK (BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN | \
BO_USE_SW_READ_RARELY | BO_USE_SW_WRITE_RARELY)
BO_USE_SW_READ_RARELY | BO_USE_SW_WRITE_RARELY | BO_USE_FRONT_RENDERING)
#define BO_USE_NON_GPU_HW (BO_USE_SCANOUT | BO_USE_CAMERA_WRITE | BO_USE_CAMERA_READ | \
BO_USE_HW_VIDEO_ENCODER | BO_USE_HW_VIDEO_DECODER)

View file

@ -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 <stdint.h>
// 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

View file

@ -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,11 @@ 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 */
#define VIRTGPU_PARAM_CREATE_GUEST_HANDLE 8 /* Host OS handle can be created from guest memory. */
#define VIRTGPU_PARAM_RESOURCE_SYNC 9 /* Synchronization resources */
#define VIRTGPU_PARAM_GUEST_VRAM 10 /* All guest allocations happen via virtgpu dedicated heap. */
struct drm_virtgpu_getparam {
__u64 param;
@ -104,7 +114,7 @@ struct drm_virtgpu_resource_info {
__u32 bo_handle;
__u32 res_handle;
__u32 size;
__u32 stride;
__u32 blob_mem;
};
/* CHROMIUM */
@ -172,13 +182,15 @@ 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
#define VIRTGPU_BLOB_FLAG_CREATE_GUEST_HANDLE 0x0008
#define VIRTGPU_BLOB_FLAG_CREATE_GUEST_CONTIG 0x0010
/* zero is invalid blob_mem */
__u32 blob_mem;
__u32 blob_flags;
@ -196,6 +208,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 +267,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

5
gbm.c
View file

@ -328,6 +328,11 @@ PUBLIC union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo, size_t
return (union gbm_bo_handle)drv_bo_get_plane_handle(bo->bo, (size_t)plane).u64;
}
PUBLIC int gbm_bo_get_fd_for_plane(struct gbm_bo *bo, int plane)
{
return drv_bo_get_plane_fd(bo->bo, plane);
}
PUBLIC uint32_t gbm_bo_get_offset(struct gbm_bo *bo, size_t plane)
{
return drv_bo_get_plane_offset(bo->bo, (size_t)plane);

15
gbm.h
View file

@ -72,7 +72,7 @@ union gbm_bo_handle {
/** Format of the allocated buffer */
enum gbm_bo_format {
/** RGB with 8 bits per channel in a 32 bit value */
GBM_BO_FORMAT_XRGB8888,
GBM_BO_FORMAT_XRGB8888,
/** ARGB with 8 bits per channel in a 32 bit value */
GBM_BO_FORMAT_ARGB8888
};
@ -179,6 +179,8 @@ enum gbm_bo_format {
#define GBM_FORMAT_NV16 __gbm_fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
#define GBM_FORMAT_NV61 __gbm_fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
#define GBM_FORMAT_P010 __gbm_fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane */
/*
* 3 plane YCbCr
* index 0: Y plane, [7:0] Y
@ -280,6 +282,14 @@ enum gbm_bo_flags {
* which would otherwise access the underlying buffer will fail.
*/
GBM_TEST_ALLOC = (1 << 15),
/**
* The buffer will be used for front buffer rendering. On some
* platforms this may (for example) disable framebuffer compression
* to avoid problems with compression flags data being out of sync
* with pixel data.
*/
GBM_BO_USE_FRONT_RENDERING = (1 << 16),
};
int
@ -420,6 +430,9 @@ gbm_bo_get_plane_count(struct gbm_bo *bo);
union gbm_bo_handle
gbm_bo_get_handle_for_plane(struct gbm_bo *bo, size_t plane);
int
gbm_bo_get_fd_for_plane(struct gbm_bo *bo, int plane);
int
gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count);

View file

@ -44,6 +44,8 @@ uint64_t gbm_convert_usage(uint32_t usage)
use_flags |= BO_USE_HW_VIDEO_DECODER;
if (usage & GBM_BO_USE_HW_VIDEO_ENCODER)
use_flags |= BO_USE_HW_VIDEO_ENCODER;
if (usage & GBM_BO_USE_FRONT_RENDERING)
use_flags |= BO_USE_FRONT_RENDERING;
return use_flags;
}

View file

@ -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);

148
i915.c
View file

@ -50,30 +50,44 @@ struct i915_device {
int32_t has_llc;
int32_t has_hw_protection;
struct modifier_support_t modifier;
int device_id;
bool is_adlp;
};
static uint32_t i915_get_gen(int device_id)
static void i915_info_from_device_id(struct i915_device *i915)
{
const uint16_t gen3_ids[] = { 0x2582, 0x2592, 0x2772, 0x27A2, 0x27AE,
0x29C2, 0x29B2, 0x29D2, 0xA001, 0xA011 };
const uint16_t gen11_ids[] = { 0x4E71, 0x4E61, 0x4E51, 0x4E55, 0x4E57 };
const uint16_t gen12_ids[] = { 0x9A40, 0x9A49, 0x9A59, 0x9A60, 0x9A68, 0x9A70,
0x9A78, 0x9AC0, 0x9AC9, 0x9AD9, 0x9AF8 };
const uint16_t adlp_ids[] = { 0x46A0, 0x46A1, 0x46A2, 0x46A3, 0x46A6,
0x46A8, 0x46AA, 0x462A, 0x4626, 0x4628,
0x46B0, 0x46B1, 0x46B2, 0x46B3, 0x46C0,
0x46C1, 0x46C2, 0x46C3 };
unsigned i;
i915->gen = 4;
i915->is_adlp = false;
for (i = 0; i < ARRAY_SIZE(gen3_ids); i++)
if (gen3_ids[i] == device_id)
return 3;
if (gen3_ids[i] == i915->device_id)
i915->gen = 3;
/* Gen 11 */
for (i = 0; i < ARRAY_SIZE(gen11_ids); i++)
if (gen11_ids[i] == device_id)
return 11;
if (gen11_ids[i] == i915->device_id)
i915->gen = 11;
/* Gen 12 */
for (i = 0; i < ARRAY_SIZE(gen12_ids); i++)
if (gen12_ids[i] == device_id)
return 12;
if (gen12_ids[i] == i915->device_id)
i915->gen = 12;
return 4;
for (i = 0; i < ARRAY_SIZE(adlp_ids); i++)
if (adlp_ids[i] == i915->device_id) {
i915->is_adlp = true;
i915->gen = 12;
}
}
static void i915_get_modifier_order(struct i915_device *i915)
@ -95,85 +109,88 @@ static uint64_t unset_flags(uint64_t current_flags, uint64_t mask)
static int i915_add_combinations(struct driver *drv)
{
struct format_metadata metadata;
uint64_t render, scanout_and_render, texture_only, hw_protected;
struct i915_device *i915 = drv->priv;
scanout_and_render = BO_USE_RENDER_MASK | BO_USE_SCANOUT;
render = BO_USE_RENDER_MASK;
texture_only = BO_USE_TEXTURE_MASK;
const uint64_t scanout_and_render = BO_USE_RENDER_MASK | BO_USE_SCANOUT;
const uint64_t render = BO_USE_RENDER_MASK;
const uint64_t texture_only = BO_USE_TEXTURE_MASK;
// HW protected buffers also need to be scanned out.
hw_protected = i915->has_hw_protection ? (BO_USE_PROTECTED | BO_USE_SCANOUT) : 0;
const uint64_t hw_protected =
i915->has_hw_protection ? (BO_USE_PROTECTED | BO_USE_SCANOUT) : 0;
uint64_t linear_mask =
BO_USE_RENDERSCRIPT | BO_USE_LINEAR | BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN;
const uint64_t linear_mask = BO_USE_RENDERSCRIPT | BO_USE_LINEAR | BO_USE_SW_READ_OFTEN |
BO_USE_SW_WRITE_OFTEN | BO_USE_SW_READ_RARELY |
BO_USE_SW_WRITE_RARELY;
metadata.tiling = I915_TILING_NONE;
metadata.priority = 1;
metadata.modifier = DRM_FORMAT_MOD_LINEAR;
struct format_metadata metadata_linear = { .tiling = I915_TILING_NONE,
.priority = 1,
.modifier = DRM_FORMAT_MOD_LINEAR };
drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
&metadata, scanout_and_render);
&metadata_linear, scanout_and_render);
drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata, render);
drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata_linear,
render);
drv_add_combinations(drv, texture_only_formats, ARRAY_SIZE(texture_only_formats), &metadata,
texture_only);
drv_add_combinations(drv, texture_only_formats, ARRAY_SIZE(texture_only_formats),
&metadata_linear, texture_only);
drv_modify_linear_combinations(drv);
/* NV12 format for camera, display, decoding and encoding. */
/* IPU3 camera ISP supports only NV12 output. */
drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata,
drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata_linear,
BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_SCANOUT |
BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER |
hw_protected);
/* Android CTS tests require this. */
drv_add_combination(drv, DRM_FORMAT_BGR888, &metadata, BO_USE_SW_MASK);
drv_add_combination(drv, DRM_FORMAT_BGR888, &metadata_linear, BO_USE_SW_MASK);
/*
* 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,
drv_modify_combination(drv, DRM_FORMAT_R8, &metadata_linear,
BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
BO_USE_HW_VIDEO_ENCODER);
render = unset_flags(render, linear_mask);
scanout_and_render = unset_flags(scanout_and_render, linear_mask);
const uint64_t render_not_linear = unset_flags(render, linear_mask);
const uint64_t scanout_and_render_not_linear = render_not_linear | BO_USE_SCANOUT;
metadata.tiling = I915_TILING_X;
metadata.priority = 2;
metadata.modifier = I915_FORMAT_MOD_X_TILED;
struct format_metadata metadata_x_tiled = { .tiling = I915_TILING_X,
.priority = 2,
.modifier = I915_FORMAT_MOD_X_TILED };
drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata, render);
drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata_x_tiled,
render_not_linear);
drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
&metadata, scanout_and_render);
&metadata_x_tiled, scanout_and_render_not_linear);
metadata.tiling = I915_TILING_Y;
metadata.priority = 3;
metadata.modifier = I915_FORMAT_MOD_Y_TILED;
struct format_metadata metadata_y_tiled = { .tiling = I915_TILING_Y,
.priority = 3,
.modifier = I915_FORMAT_MOD_Y_TILED };
scanout_and_render =
unset_flags(scanout_and_render, BO_USE_SW_READ_RARELY | BO_USE_SW_WRITE_RARELY);
/* Support y-tiled NV12 and P010 for libva */
#ifdef I915_SCANOUT_Y_TILED
uint64_t nv12_usage =
const uint64_t nv12_usage =
BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | BO_USE_SCANOUT | hw_protected;
uint64_t p010_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | hw_protected;
const uint64_t p010_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | hw_protected |
(i915->gen >= 11 ? BO_USE_SCANOUT : 0);
#else
uint64_t nv12_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER;
uint64_t p010_usage = nv12_usage;
const uint64_t nv12_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER;
const uint64_t p010_usage = nv12_usage;
#endif
drv_add_combination(drv, DRM_FORMAT_NV12, &metadata, nv12_usage);
drv_add_combination(drv, DRM_FORMAT_P010, &metadata, p010_usage);
drv_add_combination(drv, DRM_FORMAT_NV12, &metadata_y_tiled, nv12_usage);
drv_add_combination(drv, DRM_FORMAT_P010, &metadata_y_tiled, p010_usage);
scanout_and_render = unset_flags(scanout_and_render, BO_USE_SCANOUT);
drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata_y_tiled,
render_not_linear);
drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata, render);
// Y-tiled scanout isn't available on old platforms so we add
// |scanout_render_formats| without that USE flag.
drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
&metadata, scanout_and_render);
&metadata_y_tiled, render_not_linear);
return 0;
}
@ -232,6 +249,10 @@ static int i915_align_dimensions(struct bo *bo, uint32_t tiling, uint32_t *strid
*stride = horizontal_alignment;
}
/* stride must be power-of-two aligned for ADL-P tiled buffers*/
if (i915->is_adlp && (*stride > 1) && (tiling != I915_TILING_NONE))
*stride = 1 << (32 - __builtin_clz(*stride -1));
if (i915->gen <= 3 && *stride > 8192)
return -EINVAL;
@ -253,7 +274,6 @@ static void i915_clflush(void *start, size_t size)
static int i915_init(struct driver *drv)
{
int ret;
int device_id;
struct i915_device *i915;
drm_i915_getparam_t get_param = { 0 };
@ -262,15 +282,16 @@ static int i915_init(struct driver *drv)
return -ENOMEM;
get_param.param = I915_PARAM_CHIPSET_ID;
get_param.value = &device_id;
get_param.value = &(i915->device_id);
ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
if (ret) {
drv_log("Failed to get I915_PARAM_CHIPSET_ID\n");
free(i915);
return -EINVAL;
}
/* must call before i915->gen is used anywhere else */
i915_info_from_device_id(i915);
i915->gen = i915_get_gen(device_id);
i915_get_modifier_order(i915);
memset(&get_param, 0, sizeof(get_param));
@ -290,14 +311,32 @@ static int i915_init(struct driver *drv)
return i915_add_combinations(drv);
}
/*
* Returns true if the height of a buffer of the given format should be aligned
* to the largest coded unit (LCU) assuming that it will be used for video. This
* is based on gmmlib's GmmIsYUVFormatLCUAligned().
*/
static bool i915_format_needs_LCU_alignment(uint32_t format, size_t plane, const struct i915_device* i915)
{
switch (format) {
case DRM_FORMAT_NV12:
case DRM_FORMAT_P010:
case DRM_FORMAT_P016:
return (i915->gen == 11 || i915->gen == 12) && plane == 1;
}
return false;
}
static int i915_bo_from_format(struct bo *bo, uint32_t width, uint32_t height, uint32_t format)
{
uint32_t offset;
size_t plane;
int ret, pagesize;
struct i915_device *i915 = bo->drv->priv;
offset = 0;
pagesize = getpagesize();
for (plane = 0; plane < drv_num_planes_from_format(format); plane++) {
uint32_t stride = drv_stride_from_format(format, width, plane);
uint32_t plane_height = drv_height_from_format(format, height, plane);
@ -309,6 +348,15 @@ static int i915_bo_from_format(struct bo *bo, uint32_t width, uint32_t height, u
if (ret)
return ret;
if (i915_format_needs_LCU_alignment(format, plane, i915)) {
/*
* Align the height of the V plane for certain formats to the
* largest coded unit (assuming that this BO may be used for video)
* to be consistent with gmmlib.
*/
plane_height = ALIGN(plane_height, 64);
}
bo->meta.strides[plane] = stride;
bo->meta.sizes[plane] = stride * plane_height;
bo->meta.offsets[plane] = offset;

View file

@ -275,7 +275,7 @@ static uint32_t mediatek_resolve_format(struct driver *drv, uint32_t format, uin
/*HACK: See b/28671744 */
return DRM_FORMAT_XBGR8888;
case DRM_FORMAT_FLEX_YCbCr_420_888:
#ifdef MTK_MT8183
#if defined(MTK_MT8183) || defined(MTK_MT8192)
// TODO(hiroh): Switch to use NV12 for video decoder on MT8173 as well.
if (use_flags & (BO_USE_HW_VIDEO_DECODER)) {
return DRM_FORMAT_NV12;

View file

@ -169,9 +169,6 @@ static int detect_device_info(unsigned int detect_flags, int fd, struct gbm_devi
} else if (strncmp("nouveau", version->name, version->name_len) == 0) {
info->dev_type_flags |=
GBM_DEV_TYPE_FLAG_DISPLAY | GBM_DEV_TYPE_FLAG_3D | GBM_DEV_TYPE_FLAG_DISCRETE;
} else if (strncmp("tegra", version->name, version->name_len) == 0) {
info->dev_type_flags |=
GBM_DEV_TYPE_FLAG_DISPLAY | GBM_DEV_TYPE_FLAG_3D | GBM_DEV_TYPE_FLAG_ARMSOC;
} else if (strncmp("msm", version->name, version->name_len) == 0) {
info->dev_type_flags |=
GBM_DEV_TYPE_FLAG_DISPLAY | GBM_DEV_TYPE_FLAG_3D | GBM_DEV_TYPE_FLAG_ARMSOC;

12
msm.c
View file

@ -223,7 +223,14 @@ static int msm_init(struct driver *drv)
struct format_metadata metadata;
uint64_t render_use_flags = BO_USE_RENDER_MASK | BO_USE_SCANOUT;
uint64_t texture_use_flags = BO_USE_TEXTURE_MASK | BO_USE_HW_VIDEO_DECODER;
uint64_t sw_flags = (BO_USE_RENDERSCRIPT | BO_USE_SW_MASK | BO_USE_LINEAR);
/*
* NOTE: we actually could use tiled in the BO_USE_FRONT_RENDERING case,
* if we had a modifier for tiled-but-not-compressed. But we *cannot* use
* compressed in this case because the UBWC flags/meta data can be out of
* sync with pixel data while the GPU is writing a frame out to memory.
*/
uint64_t sw_flags =
(BO_USE_RENDERSCRIPT | BO_USE_SW_MASK | BO_USE_LINEAR | BO_USE_FRONT_RENDERING);
drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
&LINEAR_METADATA, render_use_flags);
@ -267,8 +274,7 @@ static int msm_init(struct driver *drv)
&metadata, texture_use_flags);
drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata,
BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_SCANOUT |
BO_USE_HW_VIDEO_ENCODER);
BO_USE_SCANOUT | BO_USE_HW_VIDEO_ENCODER);
return 0;
}

357
tegra.c
View file

@ -1,357 +0,0 @@
/*
* Copyright 2014 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.
*/
#ifdef DRV_TEGRA
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <tegra_drm.h>
#include <xf86drm.h>
#include "drv_priv.h"
#include "helpers.h"
#include "util.h"
/*
* GOB (Group Of Bytes) is the basic unit of the blocklinear layout.
* GOBs are arranged to blocks, where the height of the block (measured
* in GOBs) is configurable.
*/
#define NV_BLOCKLINEAR_GOB_HEIGHT 8
#define NV_BLOCKLINEAR_GOB_WIDTH 64
#define NV_DEFAULT_BLOCK_HEIGHT_LOG2 4
#define NV_PREFERRED_PAGE_SIZE (128 * 1024)
// clang-format off
enum nv_mem_kind
{
NV_MEM_KIND_PITCH = 0,
NV_MEM_KIND_C32_2CRA = 0xdb,
NV_MEM_KIND_GENERIC_16Bx2 = 0xfe,
};
enum tegra_map_type {
TEGRA_READ_TILED_BUFFER = 0,
TEGRA_WRITE_TILED_BUFFER = 1,
};
// clang-format on
struct tegra_private_map_data {
void *tiled;
void *untiled;
};
static const uint32_t render_target_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 };
static int compute_block_height_log2(int height)
{
int block_height_log2 = NV_DEFAULT_BLOCK_HEIGHT_LOG2;
if (block_height_log2 > 0) {
/* Shrink, if a smaller block height could cover the whole
* surface height. */
int proposed = NV_BLOCKLINEAR_GOB_HEIGHT << (block_height_log2 - 1);
while (proposed >= height) {
block_height_log2--;
if (block_height_log2 == 0)
break;
proposed /= 2;
}
}
return block_height_log2;
}
static void compute_layout_blocklinear(int width, int height, int format, enum nv_mem_kind *kind,
uint32_t *block_height_log2, uint32_t *stride,
uint32_t *size)
{
int pitch = drv_stride_from_format(format, width, 0);
/* Align to blocklinear blocks. */
pitch = ALIGN(pitch, NV_BLOCKLINEAR_GOB_WIDTH);
/* Compute padded height. */
*block_height_log2 = compute_block_height_log2(height);
int block_height = 1 << *block_height_log2;
int padded_height = ALIGN(height, NV_BLOCKLINEAR_GOB_HEIGHT * block_height);
int bytes = pitch * padded_height;
/* Pad the allocation to the preferred page size.
* This will reduce the required page table size (see discussion in NV
* bug 1321091), and also acts as a WAR for NV bug 1325421.
*/
bytes = ALIGN(bytes, NV_PREFERRED_PAGE_SIZE);
*kind = NV_MEM_KIND_C32_2CRA;
*stride = pitch;
*size = bytes;
}
static void compute_layout_linear(int width, int height, int format, uint32_t *stride,
uint32_t *size)
{
*stride = ALIGN(drv_stride_from_format(format, width, 0), 64);
*size = *stride * height;
}
static void transfer_tile(struct bo *bo, uint8_t *tiled, uint8_t *untiled, enum tegra_map_type type,
uint32_t bytes_per_pixel, uint32_t gob_top, uint32_t gob_left,
uint32_t gob_size_pixels, uint8_t *tiled_last)
{
uint8_t *tmp;
uint32_t x, y, k;
for (k = 0; k < gob_size_pixels; k++) {
/*
* Given the kth pixel starting from the tile specified by
* gob_top and gob_left, unswizzle to get the standard (x, y)
* representation.
*/
x = gob_left + (((k >> 3) & 8) | ((k >> 1) & 4) | (k & 3));
y = gob_top + ((k >> 7 << 3) | ((k >> 3) & 6) | ((k >> 2) & 1));
if (tiled >= tiled_last)
return;
if (x >= bo->meta.width || y >= bo->meta.height) {
tiled += bytes_per_pixel;
continue;
}
tmp = untiled + y * bo->meta.strides[0] + x * bytes_per_pixel;
if (type == TEGRA_READ_TILED_BUFFER)
memcpy(tmp, tiled, bytes_per_pixel);
else if (type == TEGRA_WRITE_TILED_BUFFER)
memcpy(tiled, tmp, bytes_per_pixel);
/* Move on to next pixel. */
tiled += bytes_per_pixel;
}
}
static void transfer_tiled_memory(struct bo *bo, uint8_t *tiled, uint8_t *untiled,
enum tegra_map_type type)
{
uint32_t gob_width, gob_height, gob_size_bytes, gob_size_pixels, gob_count_x, gob_count_y,
gob_top, gob_left;
uint32_t i, j, offset;
uint8_t *tmp, *tiled_last;
uint32_t bytes_per_pixel = drv_stride_from_format(bo->meta.format, 1, 0);
/*
* The blocklinear format consists of 8*(2^n) x 64 byte sized tiles,
* where 0 <= n <= 4.
*/
gob_width = DIV_ROUND_UP(NV_BLOCKLINEAR_GOB_WIDTH, bytes_per_pixel);
gob_height = NV_BLOCKLINEAR_GOB_HEIGHT * (1 << NV_DEFAULT_BLOCK_HEIGHT_LOG2);
/* Calculate the height from maximum possible gob height */
while (gob_height > NV_BLOCKLINEAR_GOB_HEIGHT && gob_height >= 2 * bo->meta.height)
gob_height /= 2;
gob_size_bytes = gob_height * NV_BLOCKLINEAR_GOB_WIDTH;
gob_size_pixels = gob_height * gob_width;
gob_count_x = DIV_ROUND_UP(bo->meta.strides[0], NV_BLOCKLINEAR_GOB_WIDTH);
gob_count_y = DIV_ROUND_UP(bo->meta.height, gob_height);
tiled_last = tiled + bo->meta.total_size;
offset = 0;
for (j = 0; j < gob_count_y; j++) {
gob_top = j * gob_height;
for (i = 0; i < gob_count_x; i++) {
tmp = tiled + offset;
gob_left = i * gob_width;
transfer_tile(bo, tmp, untiled, type, bytes_per_pixel, gob_top, gob_left,
gob_size_pixels, tiled_last);
offset += gob_size_bytes;
}
}
}
static int tegra_init(struct driver *drv)
{
struct format_metadata metadata;
uint64_t use_flags = BO_USE_RENDER_MASK;
metadata.tiling = NV_MEM_KIND_PITCH;
metadata.priority = 1;
metadata.modifier = DRM_FORMAT_MOD_LINEAR;
drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
&metadata, use_flags);
drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata, BO_USE_CURSOR | BO_USE_SCANOUT);
drv_modify_combination(drv, DRM_FORMAT_ARGB8888, &metadata, BO_USE_CURSOR | BO_USE_SCANOUT);
use_flags &= ~BO_USE_SW_WRITE_OFTEN;
use_flags &= ~BO_USE_SW_READ_OFTEN;
use_flags &= ~BO_USE_LINEAR;
metadata.tiling = NV_MEM_KIND_C32_2CRA;
metadata.priority = 2;
drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
&metadata, use_flags);
drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata, BO_USE_SCANOUT);
drv_modify_combination(drv, DRM_FORMAT_ARGB8888, &metadata, BO_USE_SCANOUT);
return 0;
}
static int tegra_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
uint64_t use_flags)
{
uint32_t size, stride, block_height_log2 = 0;
enum nv_mem_kind kind = NV_MEM_KIND_PITCH;
struct drm_tegra_gem_create gem_create = { 0 };
int ret;
if (use_flags &
(BO_USE_CURSOR | BO_USE_LINEAR | BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN))
compute_layout_linear(width, height, format, &stride, &size);
else
compute_layout_blocklinear(width, height, format, &kind, &block_height_log2,
&stride, &size);
gem_create.size = size;
gem_create.flags = 0;
ret = drmIoctl(bo->drv->fd, DRM_IOCTL_TEGRA_GEM_CREATE, &gem_create);
if (ret) {
drv_log("DRM_IOCTL_TEGRA_GEM_CREATE failed (size=%zu)\n", size);
return -errno;
}
bo->handles[0].u32 = gem_create.handle;
bo->meta.offsets[0] = 0;
bo->meta.total_size = bo->meta.sizes[0] = size;
bo->meta.strides[0] = stride;
if (kind != NV_MEM_KIND_PITCH) {
struct drm_tegra_gem_set_tiling gem_tile = { 0 };
gem_tile.handle = bo->handles[0].u32;
gem_tile.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
gem_tile.value = block_height_log2;
ret = drmCommandWriteRead(bo->drv->fd, DRM_TEGRA_GEM_SET_TILING, &gem_tile,
sizeof(gem_tile));
if (ret < 0) {
drv_gem_bo_destroy(bo);
return ret;
}
/* Encode blocklinear parameters for EGLImage creation. */
bo->meta.tiling = (kind & 0xff) | ((block_height_log2 & 0xf) << 8);
bo->meta.format_modifier = fourcc_mod_code(NV, bo->meta.tiling);
}
return 0;
}
static int tegra_bo_import(struct bo *bo, struct drv_import_fd_data *data)
{
int ret;
struct drm_tegra_gem_get_tiling gem_get_tiling = { 0 };
ret = drv_prime_bo_import(bo, data);
if (ret)
return ret;
/* TODO(gsingh): export modifiers and get rid of backdoor tiling. */
gem_get_tiling.handle = bo->handles[0].u32;
ret = drmIoctl(bo->drv->fd, DRM_IOCTL_TEGRA_GEM_GET_TILING, &gem_get_tiling);
if (ret) {
drv_gem_bo_destroy(bo);
return -errno;
}
/* NOTE(djmk): we only know about one tiled format, so if our drmIoctl call tells us we are
tiled, assume it is this format (NV_MEM_KIND_C32_2CRA) otherwise linear (KIND_PITCH). */
if (gem_get_tiling.mode == DRM_TEGRA_GEM_TILING_MODE_PITCH) {
bo->meta.tiling = NV_MEM_KIND_PITCH;
} else if (gem_get_tiling.mode == DRM_TEGRA_GEM_TILING_MODE_BLOCK) {
bo->meta.tiling = NV_MEM_KIND_C32_2CRA;
} else {
drv_log("%s: unknown tile format %d\n", __func__, gem_get_tiling.mode);
drv_gem_bo_destroy(bo);
assert(0);
}
bo->meta.format_modifier = fourcc_mod_code(NV, bo->meta.tiling);
return 0;
}
static void *tegra_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
{
int ret;
struct drm_tegra_gem_mmap gem_map = { 0 };
struct tegra_private_map_data *priv;
gem_map.handle = bo->handles[0].u32;
ret = drmCommandWriteRead(bo->drv->fd, DRM_TEGRA_GEM_MMAP, &gem_map, sizeof(gem_map));
if (ret < 0) {
drv_log("DRM_TEGRA_GEM_MMAP failed\n");
return MAP_FAILED;
}
void *addr = mmap(0, bo->meta.total_size, drv_get_prot(map_flags), MAP_SHARED, bo->drv->fd,
gem_map.offset);
vma->length = bo->meta.total_size;
if ((bo->meta.tiling & 0xFF) == NV_MEM_KIND_C32_2CRA && addr != MAP_FAILED) {
priv = calloc(1, sizeof(*priv));
priv->untiled = calloc(1, bo->meta.total_size);
priv->tiled = addr;
vma->priv = priv;
transfer_tiled_memory(bo, priv->tiled, priv->untiled, TEGRA_READ_TILED_BUFFER);
addr = priv->untiled;
}
return addr;
}
static int tegra_bo_unmap(struct bo *bo, struct vma *vma)
{
if (vma->priv) {
struct tegra_private_map_data *priv = vma->priv;
vma->addr = priv->tiled;
free(priv->untiled);
free(priv);
vma->priv = NULL;
}
return munmap(vma->addr, vma->length);
}
static int tegra_bo_flush(struct bo *bo, struct mapping *mapping)
{
struct tegra_private_map_data *priv = mapping->vma->priv;
if (priv && (mapping->vma->map_flags & BO_MAP_WRITE))
transfer_tiled_memory(bo, priv->tiled, priv->untiled, TEGRA_WRITE_TILED_BUFFER);
return 0;
}
const struct backend backend_tegra = {
.name = "tegra",
.init = tegra_init,
.bo_create = tegra_bo_create,
.bo_destroy = drv_gem_bo_destroy,
.bo_import = tegra_bo_import,
.bo_map = tegra_bo_map,
.bo_unmap = tegra_bo_unmap,
.bo_flush = tegra_bo_flush,
};
#endif

71
virtgpu.c Normal file
View file

@ -0,0 +1,71 @@
/*
* 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 <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <xf86drm.h>
#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), PARAM(VIRTGPU_PARAM_CREATE_GUEST_HANDLE),
PARAM(VIRTGPU_PARAM_RESOURCE_SYNC), PARAM(VIRTGPU_PARAM_GUEST_VRAM),
};
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)&params[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,
};

25
virtgpu.h Normal file
View file

@ -0,0 +1,25 @@
/*
* 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_create_guest_handle,
param_resource_sync,
param_guest_vram,
param_max,
};

407
virtgpu_cross_domain.c Normal file
View file

@ -0,0 +1,407 @@
/*
* 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 <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <xf86drm.h>
#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;
if (!params[param_resource_blob].value)
return -ENOTSUP;
/// Need zero copy memory
if (!params[param_host_visible].value && !params[param_create_guest_handle].value)
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;
/// It may be possible to have host3d blobs and handles from guest memory at the same time.
/// But for the immediate use cases, we will either have one or the other. For now, just
/// prefer guest memory since adding that feature is more involved (requires --udmabuf
/// flag to crosvm), so developers would likely test that.
if (params[param_create_guest_handle].value) {
drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_GUEST;
blob_flags |= VIRTGPU_BLOB_FLAG_CREATE_GUEST_HANDLE;
} else if (params[param_host_visible].value) {
drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_HOST3D;
}
drm_rc_blob.size = bo->meta.total_size;
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,
};

View file

@ -8,7 +8,6 @@
#include <errno.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <xf86drm.h>
@ -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,71 @@ 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, &params);
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 minigbm 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,
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);
virtio_gpu_add_combination(drv, DRM_FORMAT_P010, &LINEAR_METADATA,
virgl_add_combination(drv, DRM_FORMAT_P010, &LINEAR_METADATA,
BO_USE_SW_MASK | BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
drv_modify_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA,
@ -682,20 +643,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)
@ -740,7 +701,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
@ -770,46 +731,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
@ -824,8 +785,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;
@ -844,7 +804,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,
@ -854,15 +814,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++) {
@ -893,23 +852,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;
@ -927,20 +885,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++) {
@ -975,7 +932,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:
@ -989,7 +946,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;
@ -997,14 +954,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], uint64_t *format_modifier)
{
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;
@ -1025,21 +981,20 @@ static int virtio_gpu_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLAN
offsets[plane] = res_info.offsets[plane];
}
}
*format_modifier = res_info.format_modifier;
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,
.bo_import = drv_prime_bo_import,
.bo_map = virtio_gpu_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,
};
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 = virgl_bo_map,
.bo_unmap = drv_bo_munmap,
.bo_invalidate = virgl_bo_invalidate,
.bo_flush = virgl_bo_flush,
.resolve_format = virgl_resolve_format,
.resource_info = virgl_resource_info };