mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
contrib: add vhost-user-gpu
Add a vhost-user gpu backend, based on virtio-gpu/3d device. It is associated with a vhost-user-gpu device. Various TODO and nice to have items: - multi-head support - crash & resume handling - accelerated rendering/display that avoids the waiting round trips - edid support Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-id: 20190524130946.31736-6-marcandre.lureau@redhat.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
committed by
Gerd Hoffmann
parent
b213fee8a7
commit
d52c454aad
@@ -1681,6 +1681,8 @@ M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|||||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: docs/interop/vhost-user-gpu.rst
|
F: docs/interop/vhost-user-gpu.rst
|
||||||
|
F: contrib/vhost-user-gpu
|
||||||
|
F: hw/display/vhost-user-*
|
||||||
|
|
||||||
Cirrus VGA
|
Cirrus VGA
|
||||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
|
|||||||
@@ -314,8 +314,20 @@ $(call set-vpath, $(SRC_PATH))
|
|||||||
|
|
||||||
LIBS+=-lz $(LIBS_TOOLS)
|
LIBS+=-lz $(LIBS_TOOLS)
|
||||||
|
|
||||||
|
vhost-user-json-y =
|
||||||
|
HELPERS-y =
|
||||||
|
|
||||||
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF)
|
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
|
ifdef BUILD_DOCS
|
||||||
DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
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
|
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-scsi-obj-y \
|
||||||
vhost-user-blk-obj-y \
|
vhost-user-blk-obj-y \
|
||||||
vhost-user-input-obj-y \
|
vhost-user-input-obj-y \
|
||||||
|
vhost-user-gpu-obj-y \
|
||||||
qga-vss-dll-obj-y \
|
qga-vss-dll-obj-y \
|
||||||
block-obj-y \
|
block-obj-y \
|
||||||
block-obj-m \
|
block-obj-m \
|
||||||
@@ -426,7 +439,7 @@ dummy := $(call unnest-vars,, \
|
|||||||
|
|
||||||
include $(SRC_PATH)/tests/Makefile.include
|
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
|
qemu-version.h: FORCE
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
@@ -619,6 +632,9 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
|
|||||||
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
|
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
|
||||||
$(call LINK, $^)
|
$(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_VHOST_USER_INPUT
|
||||||
ifdef CONFIG_LINUX
|
ifdef CONFIG_LINUX
|
||||||
vhost-user-input$(EXESUF): $(vhost-user-input-obj-y) libvhost-user.a libqemuutil.a
|
vhost-user-input$(EXESUF): $(vhost-user-input-obj-y) libvhost-user.a libqemuutil.a
|
||||||
@@ -827,6 +843,12 @@ endif
|
|||||||
ifneq ($(HELPERS-y),)
|
ifneq ($(HELPERS-y),)
|
||||||
$(call install-prog,$(HELPERS-y),$(DESTDIR)$(libexecdir))
|
$(call install-prog,$(HELPERS-y),$(DESTDIR)$(libexecdir))
|
||||||
endif
|
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
|
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||||
$(INSTALL_PROG) "scripts/qemu-trace-stap" $(DESTDIR)$(bindir)
|
$(INSTALL_PROG) "scripts/qemu-trace-stap" $(DESTDIR)$(bindir)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
|
|||||||
vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||||
rdmacm-mux-obj-y = contrib/rdmacm-mux/
|
rdmacm-mux-obj-y = contrib/rdmacm-mux/
|
||||||
vhost-user-input-obj-y = contrib/vhost-user-input/
|
vhost-user-input-obj-y = contrib/vhost-user-input/
|
||||||
|
vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
trace-events-subdirs =
|
trace-events-subdirs =
|
||||||
|
|||||||
@@ -4099,6 +4099,13 @@ libs_softmmu="$libs_softmmu $fdt_libs"
|
|||||||
##########################################
|
##########################################
|
||||||
# opengl probe (for sdl2, gtk, milkymist-tmu2)
|
# 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
|
if test "$opengl" != "no" ; then
|
||||||
opengl_pkgs="epoxy gbm"
|
opengl_pkgs="epoxy gbm"
|
||||||
if $pkg_config $opengl_pkgs; then
|
if $pkg_config $opengl_pkgs; then
|
||||||
@@ -6964,6 +6971,13 @@ if test "$opengl" = "yes" ; then
|
|||||||
fi
|
fi
|
||||||
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
|
if test "$malloc_trim" = "yes" ; then
|
||||||
echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak
|
echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -7859,6 +7873,9 @@ echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak
|
|||||||
|
|
||||||
done # for target in $targets
|
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
|
if test -n "$enabled_cross_compilers"; then
|
||||||
echo
|
echo
|
||||||
echo "NOTE: cross-compilers enabled: $enabled_cross_compilers"
|
echo "NOTE: cross-compilers enabled: $enabled_cross_compilers"
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"description": "QEMU vhost-user-gpu",
|
||||||
|
"type": "gpu",
|
||||||
|
"binary": "@libexecdir@/vhost-user-gpu",
|
||||||
|
}
|
||||||
@@ -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
@@ -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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -144,7 +144,7 @@ cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
|
|||||||
cc-c-option = $(if $(shell $(CC) $1 $2 -c -o /dev/null -xc /dev/null \
|
cc-c-option = $(if $(shell $(CC) $1 $2 -c -o /dev/null -xc /dev/null \
|
||||||
>/dev/null 2>&1 && echo OK), $2, $3)
|
>/dev/null 2>&1 && echo OK), $2, $3)
|
||||||
|
|
||||||
VPATH_SUFFIXES = %.c %.h %.S %.cc %.cpp %.m %.mak %.texi %.sh %.rc Kconfig%
|
VPATH_SUFFIXES = %.c %.h %.S %.cc %.cpp %.m %.mak %.texi %.sh %.rc Kconfig% %.json.in
|
||||||
set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
|
set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
|
||||||
|
|
||||||
# install-prog list, dir
|
# install-prog list, dir
|
||||||
@@ -392,3 +392,10 @@ TEXI2MAN = $(call quiet-command, \
|
|||||||
$(call TEXI2MAN)
|
$(call TEXI2MAN)
|
||||||
%.8:
|
%.8:
|
||||||
$(call TEXI2MAN)
|
$(call TEXI2MAN)
|
||||||
|
|
||||||
|
GEN_SUBST = $(call quiet-command, \
|
||||||
|
sed -e "s!@libexecdir@!$(libexecdir)!g" < $< > $@, \
|
||||||
|
"GEN","$@")
|
||||||
|
|
||||||
|
%.json: %.json.in
|
||||||
|
$(call GEN_SUBST)
|
||||||
|
|||||||
Reference in New Issue
Block a user