Merge remote-tracking branch 'remotes/kraxel/tags/vga-20190529-pull-request' into staging

vga: add vhost-user-gpu.

# gpg: Signature made Wed 29 May 2019 05:40:02 BST
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/vga-20190529-pull-request:
  hw/display: add vhost-user-vga & gpu-pci
  virtio-gpu: split virtio-gpu-pci & virtio-vga
  virtio-gpu: split virtio-gpu, introduce virtio-gpu-base
  spice-app: fix running when !CONFIG_OPENGL
  contrib: add vhost-user-gpu
  util: compile drm.o on posix
  virtio-gpu: add a pixman helper header
  virtio-gpu: add bswap helpers header
  vhost-user: add vhost_user_gpu_set_socket()
  virtio-gpu: add sanity check

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2019-05-30 13:10:00 +01:00
38 changed files with 4179 additions and 488 deletions
+9 -1
View File
@@ -1675,9 +1675,17 @@ virtio-gpu
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: hw/display/virtio-gpu*
F: hw/display/virtio-vga.c
F: hw/display/virtio-vga.*
F: include/hw/virtio/virtio-gpu.h
vhost-user-gpu
M: Marc-André Lureau <marcandre.lureau@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: docs/interop/vhost-user-gpu.rst
F: contrib/vhost-user-gpu
F: hw/display/vhost-user-*
Cirrus VGA
M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes
+23 -1
View File
@@ -314,8 +314,20 @@ $(call set-vpath, $(SRC_PATH))
LIBS+=-lz $(LIBS_TOOLS)
vhost-user-json-y =
HELPERS-y =
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF)
ifdef CONFIG_LINUX
ifdef CONFIG_VIRGL
ifdef CONFIG_GBM
HELPERS-y += vhost-user-gpu$(EXESUF)
vhost-user-json-y += contrib/vhost-user-gpu/50-qemu-gpu.json
endif
endif
endif
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
@@ -409,6 +421,7 @@ dummy := $(call unnest-vars,, \
vhost-user-scsi-obj-y \
vhost-user-blk-obj-y \
vhost-user-input-obj-y \
vhost-user-gpu-obj-y \
qga-vss-dll-obj-y \
block-obj-y \
block-obj-m \
@@ -426,7 +439,7 @@ dummy := $(call unnest-vars,, \
include $(SRC_PATH)/tests/Makefile.include
all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) $(HELPERS-y) recurse-all modules
all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) $(HELPERS-y) recurse-all modules $(vhost-user-json-y)
qemu-version.h: FORCE
$(call quiet-command, \
@@ -619,6 +632,9 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
$(call LINK, $^)
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a
$(call LINK, $^)
ifdef CONFIG_VHOST_USER_INPUT
ifdef CONFIG_LINUX
vhost-user-input$(EXESUF): $(vhost-user-input-obj-y) libvhost-user.a libqemuutil.a
@@ -827,6 +843,12 @@ endif
ifneq ($(HELPERS-y),)
$(call install-prog,$(HELPERS-y),$(DESTDIR)$(libexecdir))
endif
ifneq ($(vhost-user-json-y),)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/vhost-user/"
for x in $(vhost-user-json-y); do \
$(INSTALL_DATA) $$x "$(DESTDIR)$(qemu_datadir)/vhost-user/"; \
done
endif
ifdef CONFIG_TRACE_SYSTEMTAP
$(INSTALL_PROG) "scripts/qemu-trace-stap" $(DESTDIR)$(bindir)
endif
+1
View File
@@ -123,6 +123,7 @@ vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
vhost-user-blk-obj-y = contrib/vhost-user-blk/
rdmacm-mux-obj-y = contrib/rdmacm-mux/
vhost-user-input-obj-y = contrib/vhost-user-input/
vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
######################################################################
trace-events-subdirs =
Vendored
+17
View File
@@ -4099,6 +4099,13 @@ libs_softmmu="$libs_softmmu $fdt_libs"
##########################################
# opengl probe (for sdl2, gtk, milkymist-tmu2)
gbm="no"
if $pkg_config gbm; then
gbm_cflags="$($pkg_config --cflags gbm)"
gbm_libs="$($pkg_config --libs gbm)"
gbm="yes"
fi
if test "$opengl" != "no" ; then
opengl_pkgs="epoxy gbm"
if $pkg_config $opengl_pkgs; then
@@ -6964,6 +6971,13 @@ if test "$opengl" = "yes" ; then
fi
fi
if test "$gbm" = "yes" ; then
echo "CONFIG_GBM=y" >> $config_host_mak
echo "GBM_LIBS=$gbm_libs" >> $config_host_mak
echo "GBM_CFLAGS=$gbm_cflags" >> $config_host_mak
fi
if test "$malloc_trim" = "yes" ; then
echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak
fi
@@ -7859,6 +7873,9 @@ echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak
done # for target in $targets
echo "PIXMAN_CFLAGS=$pixman_cflags" >> $config_host_mak
echo "PIXMAN_LIBS=$pixman_libs" >> $config_host_mak
if test -n "$enabled_cross_compilers"; then
echo
echo "NOTE: cross-compilers enabled: $enabled_cross_compilers"
+1
View File
@@ -130,6 +130,7 @@ vu_request_to_string(unsigned int req)
REQ(VHOST_USER_POSTCOPY_END),
REQ(VHOST_USER_GET_INFLIGHT_FD),
REQ(VHOST_USER_SET_INFLIGHT_FD),
REQ(VHOST_USER_GPU_SET_SOCKET),
REQ(VHOST_USER_MAX),
};
#undef REQ
+1
View File
@@ -94,6 +94,7 @@ typedef enum VhostUserRequest {
VHOST_USER_POSTCOPY_END = 30,
VHOST_USER_GET_INFLIGHT_FD = 31,
VHOST_USER_SET_INFLIGHT_FD = 32,
VHOST_USER_GPU_SET_SOCKET = 33,
VHOST_USER_MAX
} VhostUserRequest;
@@ -0,0 +1,5 @@
{
"description": "QEMU vhost-user-gpu",
"type": "gpu",
"binary": "@libexecdir@/vhost-user-gpu",
}
+10
View File
@@ -0,0 +1,10 @@
vhost-user-gpu-obj-y = main.o virgl.o vugbm.o
main.o-cflags := $(PIXMAN_CFLAGS) $(GBM_CFLAGS)
main.o-libs := $(PIXMAN_LIBS)
virgl.o-cflags := $(VIRGL_CFLAGS) $(GBM_CFLAGS)
virgl.o-libs := $(VIRGL_LIBS)
vugbm.o-cflags := $(GBM_CFLAGS)
vugbm.o-libs := $(GBM_LIBS)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+25
View File
@@ -0,0 +1,25 @@
/*
* Virtio vhost-user GPU Device
*
* Copyright Red Hat, Inc. 2013-2018
*
* Authors:
* Dave Airlie <airlied@redhat.com>
* Gerd Hoffmann <kraxel@redhat.com>
* Marc-André Lureau <marcandre.lureau@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef VUGPU_VIRGL_H_
#define VUGPU_VIRGL_H_
#include "vugpu.h"
bool vg_virgl_init(VuGpu *g);
uint32_t vg_virgl_get_num_capsets(void);
void vg_virgl_process_cmd(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd);
void vg_virgl_update_cursor_data(VuGpu *g, uint32_t resource_id,
gpointer data);
#endif
+328
View File
@@ -0,0 +1,328 @@
/*
* Virtio vhost-user GPU Device
*
* DRM helpers
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "vugbm.h"
static bool
mem_alloc_bo(struct vugbm_buffer *buf)
{
buf->mmap = g_malloc(buf->width * buf->height * 4);
buf->stride = buf->width * 4;
return true;
}
static void
mem_free_bo(struct vugbm_buffer *buf)
{
g_free(buf->mmap);
}
static bool
mem_map_bo(struct vugbm_buffer *buf)
{
return buf->mmap != NULL;
}
static void
mem_unmap_bo(struct vugbm_buffer *buf)
{
}
static void
mem_device_destroy(struct vugbm_device *dev)
{
}
#ifdef CONFIG_MEMFD
struct udmabuf_create {
uint32_t memfd;
uint32_t flags;
uint64_t offset;
uint64_t size;
};
#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create)
static size_t
udmabuf_get_size(struct vugbm_buffer *buf)
{
return ROUND_UP(buf->width * buf->height * 4, getpagesize());
}
static bool
udmabuf_alloc_bo(struct vugbm_buffer *buf)
{
int ret;
buf->memfd = memfd_create("udmabuf-bo", MFD_ALLOW_SEALING);
if (buf->memfd < 0) {
return false;
}
ret = ftruncate(buf->memfd, udmabuf_get_size(buf));
if (ret < 0) {
close(buf->memfd);
return false;
}
ret = fcntl(buf->memfd, F_ADD_SEALS, F_SEAL_SHRINK);
if (ret < 0) {
close(buf->memfd);
return false;
}
buf->stride = buf->width * 4;
return true;
}
static void
udmabuf_free_bo(struct vugbm_buffer *buf)
{
close(buf->memfd);
}
static bool
udmabuf_map_bo(struct vugbm_buffer *buf)
{
buf->mmap = mmap(NULL, udmabuf_get_size(buf),
PROT_READ | PROT_WRITE, MAP_SHARED, buf->memfd, 0);
if (buf->mmap == MAP_FAILED) {
return false;
}
return true;
}
static bool
udmabuf_get_fd(struct vugbm_buffer *buf, int *fd)
{
struct udmabuf_create create = {
.memfd = buf->memfd,
.offset = 0,
.size = udmabuf_get_size(buf),
};
*fd = ioctl(buf->dev->fd, UDMABUF_CREATE, &create);
return *fd >= 0;
}
static void
udmabuf_unmap_bo(struct vugbm_buffer *buf)
{
munmap(buf->mmap, udmabuf_get_size(buf));
}
static void
udmabuf_device_destroy(struct vugbm_device *dev)
{
close(dev->fd);
}
#endif
#ifdef CONFIG_GBM
static bool
alloc_bo(struct vugbm_buffer *buf)
{
struct gbm_device *dev = buf->dev->dev;
assert(!buf->bo);
buf->bo = gbm_bo_create(dev, buf->width, buf->height,
buf->format,
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
if (buf->bo) {
buf->stride = gbm_bo_get_stride(buf->bo);
return true;
}
return false;
}
static void
free_bo(struct vugbm_buffer *buf)
{
gbm_bo_destroy(buf->bo);
}
static bool
map_bo(struct vugbm_buffer *buf)
{
uint32_t stride;
buf->mmap = gbm_bo_map(buf->bo, 0, 0, buf->width, buf->height,
GBM_BO_TRANSFER_READ_WRITE, &stride,
&buf->mmap_data);
assert(stride == buf->stride);
return buf->mmap != NULL;
}
static void
unmap_bo(struct vugbm_buffer *buf)
{
gbm_bo_unmap(buf->bo, buf->mmap_data);
}
static bool
get_fd(struct vugbm_buffer *buf, int *fd)
{
*fd = gbm_bo_get_fd(buf->bo);
return *fd >= 0;
}
static void
device_destroy(struct vugbm_device *dev)
{
gbm_device_destroy(dev->dev);
}
#endif
void
vugbm_device_destroy(struct vugbm_device *dev)
{
if (!dev->inited) {
return;
}
dev->device_destroy(dev);
}
bool
vugbm_device_init(struct vugbm_device *dev, int fd)
{
dev->fd = fd;
#ifdef CONFIG_GBM
dev->dev = gbm_create_device(fd);
#endif
if (0) {
/* nothing */
}
#ifdef CONFIG_GBM
else if (dev->dev != NULL) {
dev->alloc_bo = alloc_bo;
dev->free_bo = free_bo;
dev->get_fd = get_fd;
dev->map_bo = map_bo;
dev->unmap_bo = unmap_bo;
dev->device_destroy = device_destroy;
}
#endif
#ifdef CONFIG_MEMFD
else if (g_file_test("/dev/udmabuf", G_FILE_TEST_EXISTS)) {
dev->fd = open("/dev/udmabuf", O_RDWR);
if (dev->fd < 0) {
return false;
}
g_debug("Using experimental udmabuf backend");
dev->alloc_bo = udmabuf_alloc_bo;
dev->free_bo = udmabuf_free_bo;
dev->get_fd = udmabuf_get_fd;
dev->map_bo = udmabuf_map_bo;
dev->unmap_bo = udmabuf_unmap_bo;
dev->device_destroy = udmabuf_device_destroy;
}
#endif
else {
g_debug("Using mem fallback");
dev->alloc_bo = mem_alloc_bo;
dev->free_bo = mem_free_bo;
dev->map_bo = mem_map_bo;
dev->unmap_bo = mem_unmap_bo;
dev->device_destroy = mem_device_destroy;
return false;
}
dev->inited = true;
return true;
}
static bool
vugbm_buffer_map(struct vugbm_buffer *buf)
{
struct vugbm_device *dev = buf->dev;
return dev->map_bo(buf);
}
static void
vugbm_buffer_unmap(struct vugbm_buffer *buf)
{
struct vugbm_device *dev = buf->dev;
dev->unmap_bo(buf);
}
bool
vugbm_buffer_can_get_dmabuf_fd(struct vugbm_buffer *buffer)
{
if (!buffer->dev->get_fd) {
return false;
}
return true;
}
bool
vugbm_buffer_get_dmabuf_fd(struct vugbm_buffer *buffer, int *fd)
{
if (!vugbm_buffer_can_get_dmabuf_fd(buffer) ||
!buffer->dev->get_fd(buffer, fd)) {
g_warning("Failed to get dmabuf");
return false;
}
if (*fd < 0) {
g_warning("error: dmabuf_fd < 0");
return false;
}
return true;
}
bool
vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev,
uint32_t width, uint32_t height)
{
buffer->dev = dev;
buffer->width = width;
buffer->height = height;
buffer->format = GBM_FORMAT_XRGB8888;
buffer->stride = 0; /* modified during alloc */
if (!dev->alloc_bo(buffer)) {
g_warning("alloc_bo failed");
return false;
}
if (!vugbm_buffer_map(buffer)) {
g_warning("map_bo failed");
goto err;
}
return true;
err:
dev->free_bo(buffer);
return false;
}
void
vugbm_buffer_destroy(struct vugbm_buffer *buffer)
{
struct vugbm_device *dev = buffer->dev;
vugbm_buffer_unmap(buffer);
dev->free_bo(buffer);
}
+67
View File
@@ -0,0 +1,67 @@
/*
* Virtio vhost-user GPU Device
*
* GBM helpers
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef VHOST_USER_GPU_GBM_H
#define VHOST_USER_GPU_GBM_H
#include "qemu/osdep.h"
#ifdef CONFIG_MEMFD
#include <sys/mman.h>
#include <sys/ioctl.h>
#endif
#ifdef CONFIG_GBM
#include <gbm.h>
#endif
struct vugbm_buffer;
struct vugbm_device {
bool inited;
int fd;
#ifdef CONFIG_GBM
struct gbm_device *dev;
#endif
bool (*alloc_bo)(struct vugbm_buffer *buf);
void (*free_bo)(struct vugbm_buffer *buf);
bool (*get_fd)(struct vugbm_buffer *buf, int *fd);
bool (*map_bo)(struct vugbm_buffer *buf);
void (*unmap_bo)(struct vugbm_buffer *buf);
void (*device_destroy)(struct vugbm_device *dev);
};
struct vugbm_buffer {
struct vugbm_device *dev;
#ifdef CONFIG_MEMFD
int memfd;
#endif
#ifdef CONFIG_GBM
struct gbm_bo *bo;
void *mmap_data;
#endif
uint8_t *mmap;
uint32_t width;
uint32_t height;
uint32_t stride;
uint32_t format;
};
bool vugbm_device_init(struct vugbm_device *dev, int fd);
void vugbm_device_destroy(struct vugbm_device *dev);
bool vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev,
uint32_t width, uint32_t height);
bool vugbm_buffer_can_get_dmabuf_fd(struct vugbm_buffer *buffer);
bool vugbm_buffer_get_dmabuf_fd(struct vugbm_buffer *buffer, int *fd);
void vugbm_buffer_destroy(struct vugbm_buffer *buffer);
#endif
+177
View File
@@ -0,0 +1,177 @@
/*
* Virtio vhost-user GPU Device
*
* Copyright Red Hat, Inc. 2013-2018
*
* Authors:
* Dave Airlie <airlied@redhat.com>
* Gerd Hoffmann <kraxel@redhat.com>
* Marc-André Lureau <marcandre.lureau@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef VUGPU_H_
#define VUGPU_H_
#include "qemu/osdep.h"
#include "contrib/libvhost-user/libvhost-user-glib.h"
#include "standard-headers/linux/virtio_gpu.h"
#include "qemu/queue.h"
#include "qemu/iov.h"
#include "qemu/bswap.h"
#include "vugbm.h"
typedef enum VhostUserGpuRequest {
VHOST_USER_GPU_NONE = 0,
VHOST_USER_GPU_GET_PROTOCOL_FEATURES,
VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
VHOST_USER_GPU_GET_DISPLAY_INFO,
VHOST_USER_GPU_CURSOR_POS,
VHOST_USER_GPU_CURSOR_POS_HIDE,
VHOST_USER_GPU_CURSOR_UPDATE,
VHOST_USER_GPU_SCANOUT,
VHOST_USER_GPU_UPDATE,
VHOST_USER_GPU_DMABUF_SCANOUT,
VHOST_USER_GPU_DMABUF_UPDATE,
} VhostUserGpuRequest;
typedef struct VhostUserGpuDisplayInfoReply {
struct virtio_gpu_resp_display_info info;
} VhostUserGpuDisplayInfoReply;
typedef struct VhostUserGpuCursorPos {
uint32_t scanout_id;
uint32_t x;
uint32_t y;
} QEMU_PACKED VhostUserGpuCursorPos;
typedef struct VhostUserGpuCursorUpdate {
VhostUserGpuCursorPos pos;
uint32_t hot_x;
uint32_t hot_y;
uint32_t data[64 * 64];
} QEMU_PACKED VhostUserGpuCursorUpdate;
typedef struct VhostUserGpuScanout {
uint32_t scanout_id;
uint32_t width;
uint32_t height;
} QEMU_PACKED VhostUserGpuScanout;
typedef struct VhostUserGpuUpdate {
uint32_t scanout_id;
uint32_t x;
uint32_t y;
uint32_t width;
uint32_t height;
uint8_t data[];
} QEMU_PACKED VhostUserGpuUpdate;
typedef struct VhostUserGpuDMABUFScanout {
uint32_t scanout_id;
uint32_t x;
uint32_t y;
uint32_t width;
uint32_t height;
uint32_t fd_width;
uint32_t fd_height;
uint32_t fd_stride;
uint32_t fd_flags;
int fd_drm_fourcc;
} QEMU_PACKED VhostUserGpuDMABUFScanout;
typedef struct VhostUserGpuMsg {
uint32_t request; /* VhostUserGpuRequest */
uint32_t flags;
uint32_t size; /* the following payload size */
union {
VhostUserGpuCursorPos cursor_pos;
VhostUserGpuCursorUpdate cursor_update;
VhostUserGpuScanout scanout;
VhostUserGpuUpdate update;
VhostUserGpuDMABUFScanout dmabuf_scanout;
struct virtio_gpu_resp_display_info display_info;
uint64_t u64;
} payload;
} QEMU_PACKED VhostUserGpuMsg;
static VhostUserGpuMsg m __attribute__ ((unused));
#define VHOST_USER_GPU_HDR_SIZE \
(sizeof(m.request) + sizeof(m.flags) + sizeof(m.size))
#define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
struct virtio_gpu_scanout {
uint32_t width, height;
int x, y;
int invalidate;
uint32_t resource_id;
};
typedef struct VuGpu {
VugDev dev;
struct virtio_gpu_config virtio_config;
struct vugbm_device gdev;
int sock_fd;
int drm_rnode_fd;
GSource *renderer_source;
guint wait_ok;
bool virgl;
bool virgl_inited;
uint32_t inflight;
struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist;
QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
} VuGpu;
struct virtio_gpu_ctrl_command {
VuVirtqElement elem;
VuVirtq *vq;
struct virtio_gpu_ctrl_hdr cmd_hdr;
uint32_t error;
bool finished;
QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
};
#define VUGPU_FILL_CMD(out) do { \
size_t s; \
s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \
&out, sizeof(out)); \
if (s != sizeof(out)) { \
g_critical("%s: command size incorrect %zu vs %zu", \
__func__, s, sizeof(out)); \
return; \
} \
} while (0)
void vg_ctrl_response(VuGpu *g,
struct virtio_gpu_ctrl_command *cmd,
struct virtio_gpu_ctrl_hdr *resp,
size_t resp_len);
void vg_ctrl_response_nodata(VuGpu *g,
struct virtio_gpu_ctrl_command *cmd,
enum virtio_gpu_ctrl_type type);
int vg_create_mapping_iov(VuGpu *g,
struct virtio_gpu_resource_attach_backing *ab,
struct virtio_gpu_ctrl_command *cmd,
struct iovec **iov);
void vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd);
void vg_wait_ok(VuGpu *g);
void vg_send_msg(VuGpu *g, const VhostUserGpuMsg *msg, int fd);
bool vg_recv_msg(VuGpu *g, uint32_t expect_req, uint32_t expect_size,
gpointer payload);
#endif
+1
View File
@@ -16,3 +16,4 @@ Contents:
live-block-operations
pr-helper
vhost-user
vhost-user-gpu
+242
View File
@@ -0,0 +1,242 @@
=======================
Vhost-user-gpu Protocol
=======================
:Licence: This work is licensed under the terms of the GNU GPL,
version 2 or later. See the COPYING file in the top-level
directory.
.. contents:: Table of Contents
Introduction
============
The vhost-user-gpu protocol is aiming at sharing the rendering result
of a virtio-gpu, done from a vhost-user slave process to a vhost-user
master process (such as QEMU). It bears a resemblance to a display
server protocol, if you consider QEMU as the display server and the
slave as the client, but in a very limited way. Typically, it will
work by setting a scanout/display configuration, before sending flush
events for the display updates. It will also update the cursor shape
and position.
The protocol is sent over a UNIX domain stream socket, since it uses
socket ancillary data to share opened file descriptors (DMABUF fds or
shared memory). The socket is usually obtained via
``VHOST_USER_GPU_SET_SOCKET``.
Requests are sent by the *slave*, and the optional replies by the
*master*.
Wire format
===========
Unless specified differently, numbers are in the machine native byte
order.
A vhost-user-gpu message (request and reply) consists of 3 header
fields and a payload.
+---------+-------+------+---------+
| request | flags | size | payload |
+---------+-------+------+---------+
Header
------
:request: ``u32``, type of the request
:flags: ``u32``, 32-bit bit field:
- Bit 2 is the reply flag - needs to be set on each reply
:size: ``u32``, size of the payload
Payload types
-------------
Depending on the request type, **payload** can be:
VhostUserGpuCursorPos
^^^^^^^^^^^^^^^^^^^^^
+------------+---+---+
| scanout-id | x | y |
+------------+---+---+
:scanout-id: ``u32``, the scanout where the cursor is located
:x/y: ``u32``, the cursor postion
VhostUserGpuCursorUpdate
^^^^^^^^^^^^^^^^^^^^^^^^
+-----+-------+-------+--------+
| pos | hot_x | hot_y | cursor |
+-----+-------+-------+--------+
:pos: a ``VhostUserGpuCursorPos``, the cursor location
:hot_x/hot_y: ``u32``, the cursor hot location
:cursor: ``[u32; 64 * 64]``, 64x64 RGBA cursor data (PIXMAN_a8r8g8b8 format)
VhostUserGpuScanout
^^^^^^^^^^^^^^^^^^^
+------------+---+---+
| scanout-id | w | h |
+------------+---+---+
:scanout-id: ``u32``, the scanout configuration to set
:w/h: ``u32``, the scanout width/height size
VhostUserGpuUpdate
^^^^^^^^^^^^^^^^^^
+------------+---+---+---+---+------+
| scanout-id | x | y | w | h | data |
+------------+---+---+---+---+------+
:scanout-id: ``u32``, the scanout content to update
:x/y/w/h: ``u32``, region of the update
:data: RGB data (PIXMAN_x8r8g8b8 format)
VhostUserGpuDMABUFScanout
^^^^^^^^^^^^^^^^^^^^^^^^^
+------------+---+---+---+---+-----+-----+--------+-------+--------+
| scanout-id | x | y | w | h | fdw | fwh | stride | flags | fourcc |
+------------+---+---+---+---+-----+-----+--------+-------+--------+
:scanout-id: ``u32``, the scanout configuration to set
:x/y: ``u32``, the location of the scanout within the DMABUF
:w/h: ``u32``, the scanout width/height size
:fdw/fdh/stride/flags: ``u32``, the DMABUF width/height/stride/flags
:fourcc: ``i32``, the DMABUF fourcc
C structure
-----------
In QEMU the vhost-user-gpu message is implemented with the following struct:
.. code:: c
typedef struct VhostUserGpuMsg {
uint32_t request; /* VhostUserGpuRequest */
uint32_t flags;
uint32_t size; /* the following payload size */
union {
VhostUserGpuCursorPos cursor_pos;
VhostUserGpuCursorUpdate cursor_update;
VhostUserGpuScanout scanout;
VhostUserGpuUpdate update;
VhostUserGpuDMABUFScanout dmabuf_scanout;
struct virtio_gpu_resp_display_info display_info;
uint64_t u64;
} payload;
} QEMU_PACKED VhostUserGpuMsg;
Protocol features
-----------------
None yet.
As the protocol may need to evolve, new messages and communication
changes are negotiated thanks to preliminary
``VHOST_USER_GPU_GET_PROTOCOL_FEATURES`` and
``VHOST_USER_GPU_SET_PROTOCOL_FEATURES`` requests.
Communication
=============
Message types
-------------
``VHOST_USER_GPU_GET_PROTOCOL_FEATURES``
:id: 1
:request payload: N/A
:reply payload: ``u64``
Get the supported protocol features bitmask.
``VHOST_USER_GPU_SET_PROTOCOL_FEATURES``
:id: 2
:request payload: ``u64``
:reply payload: N/A
Enable protocol features using a bitmask.
``VHOST_USER_GPU_GET_DISPLAY_INFO``
:id: 3
:request payload: N/A
:reply payload: ``struct virtio_gpu_resp_display_info`` (from virtio specification)
Get the preferred display configuration.
``VHOST_USER_GPU_CURSOR_POS``
:id: 4
:request payload: ``VhostUserGpuCursorPos``
:reply payload: N/A
Set/show the cursor position.
``VHOST_USER_GPU_CURSOR_POS_HIDE``
:id: 5
:request payload: ``VhostUserGpuCursorPos``
:reply payload: N/A
Set/hide the cursor.
``VHOST_USER_GPU_CURSOR_UPDATE``
:id: 6
:request payload: ``VhostUserGpuCursorUpdate``
:reply payload: N/A
Update the cursor shape and location.
``VHOST_USER_GPU_SCANOUT``
:id: 7
:request payload: ``VhostUserGpuScanout``
:reply payload: N/A
Set the scanout resolution. To disable a scanout, the dimensions
width/height are set to 0.
``VHOST_USER_GPU_UPDATE``
:id: 8
:request payload: ``VhostUserGpuUpdate``
:reply payload: N/A
Update the scanout content. The data payload contains the graphical bits.
The display should be flushed and presented.
``VHOST_USER_GPU_DMABUF_SCANOUT``
:id: 9
:request payload: ``VhostUserGpuDMABUFScanout``
:reply payload: N/A
Set the scanout resolution/configuration, and share a DMABUF file
descriptor for the scanout content, which is passed as ancillary
data. To disable a scanout, the dimensions width/height are set
to 0, there is no file descriptor passed.
``VHOST_USER_GPU_DMABUF_UPDATE``
:id: 10
:request payload: ``VhostUserGpuUpdate``
:reply payload: empty payload
The display should be flushed and presented according to updated
region from ``VhostUserGpuUpdate``.
Note: there is no data payload, since the scanout is shared thanks
to DMABUF, that must have been set previously with
``VHOST_USER_GPU_DMABUF_SCANOUT``.
+9
View File
@@ -1163,6 +1163,15 @@ Master message types
send the shared inflight buffer back to slave so that slave could
get inflight I/O after a crash or restart.
``VHOST_USER_GPU_SET_SOCKET``
:id: 33
:equivalent ioctl: N/A
:master payload: N/A
Sets the GPU protocol socket file descriptor, which is passed as
ancillary data. The GPU protocol is used to inform the master of
rendering state and updates. See vhost-user-gpu.rst for details.
Slave message types
-------------------
+10
View File
@@ -111,6 +111,16 @@ config VIRTIO_VGA
depends on VIRTIO_PCI
select VGA
config VHOST_USER_GPU
bool
default y
depends on VIRTIO_GPU && VHOST_USER
config VHOST_USER_VGA
bool
default y
depends on VIRTIO_VGA && VHOST_USER_GPU
config DPCD
bool
select AUX
+4 -1
View File
@@ -43,9 +43,12 @@ obj-$(CONFIG_VGA) += vga.o
common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu.o virtio-gpu-3d.o
obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o
obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o
obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o
obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o
virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
virtio-gpu.o-libs += $(VIRGL_LIBS)
virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS)
+51
View File
@@ -0,0 +1,51 @@
/*
* vhost-user GPU PCI device
*
* Copyright Red Hat, Inc. 2018
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/virtio/virtio-gpu-pci.h"
#define TYPE_VHOST_USER_GPU_PCI "vhost-user-gpu-pci"
#define VHOST_USER_GPU_PCI(obj) \
OBJECT_CHECK(VhostUserGPUPCI, (obj), TYPE_VHOST_USER_GPU_PCI)
typedef struct VhostUserGPUPCI {
VirtIOGPUPCIBase parent_obj;
VhostUserGPU vdev;
} VhostUserGPUPCI;
static void vhost_user_gpu_pci_initfn(Object *obj)
{
VhostUserGPUPCI *dev = VHOST_USER_GPU_PCI(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VHOST_USER_GPU);
VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
object_property_add_alias(obj, "chardev",
OBJECT(&dev->vdev), "chardev",
&error_abort);
}
static const VirtioPCIDeviceTypeInfo vhost_user_gpu_pci_info = {
.generic_name = TYPE_VHOST_USER_GPU_PCI,
.parent = TYPE_VIRTIO_GPU_PCI_BASE,
.instance_size = sizeof(VhostUserGPUPCI),
.instance_init = vhost_user_gpu_pci_initfn,
};
static void vhost_user_gpu_pci_register_types(void)
{
virtio_pci_types_register(&vhost_user_gpu_pci_info);
}
type_init(vhost_user_gpu_pci_register_types)

Some files were not shown because too many files have changed in this diff Show More