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

ui+virtio-gpu: opengl cleanups and fixes.
qxl+spice: bugfixes

# gpg: Signature made Fri 05 Feb 2021 06:56:04 GMT
# gpg:                using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138
# 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-ui-20210205-pull-request: (24 commits)
  tests: add some virtio-gpu & vhost-user-gpu acceptance test
  chardev: check if the chardev is registered for yanking
  display/ui: add a callback to indicate GL state is flushed
  virtio-gpu: avoid re-entering cmdq processing
  ui: add egl dmabuf import to gtkglarea
  ui: check gtk-egl dmabuf support
  ui: add qemu_egl_has_dmabuf helper
  ui: check hw requirements during DCL registration
  ui: add a DCLOps callback to check dmabuf support
  ui: add an optional get_flags callback to GraphicHwOps
  vhost-user-gpu: add a configuration flag for dmabuf usage
  ui: remove console_has_gl_dmabuf()
  ui: annotate DCLOps callback requirements
  ui: add gd_gl_area_scanout_disable
  ui: remove gl_ctx_get_current
  ui: remove extra #ifdef CONFIG_OPENGL
  vhost-user-gpu: handle display-info in a callback
  vhost-user-gpu: use an extandable state enum for commands
  vhost-user-gpu: handle vhost-user-gpu features in a callback
  vhost-user-gpu: check backend for EDID support
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2021-02-05 10:09:16 +00:00
31 changed files with 517 additions and 105 deletions
+33 -20
View File
@@ -417,8 +417,9 @@ static void tcp_chr_free_connection(Chardev *chr)
tcp_set_msgfds(chr, NULL, 0);
remove_fd_in_watch(chr);
if (s->state == TCP_CHARDEV_STATE_CONNECTING
|| s->state == TCP_CHARDEV_STATE_CONNECTED) {
if (s->registered_yank &&
(s->state == TCP_CHARDEV_STATE_CONNECTING
|| s->state == TCP_CHARDEV_STATE_CONNECTED)) {
yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(s->sioc));
@@ -940,9 +941,11 @@ static int tcp_chr_add_client(Chardev *chr, int fd)
}
tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
tcp_chr_set_client_ioc_name(chr, sioc);
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
if (s->registered_yank) {
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
}
ret = tcp_chr_new_client(chr, sioc);
object_unref(OBJECT(sioc));
return ret;
@@ -957,9 +960,11 @@ static void tcp_chr_accept(QIONetListener *listener,
tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
tcp_chr_set_client_ioc_name(chr, cioc);
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(cioc));
if (s->registered_yank) {
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(cioc));
}
tcp_chr_new_client(chr, cioc);
}
@@ -975,9 +980,11 @@ static int tcp_chr_connect_client_sync(Chardev *chr, Error **errp)
object_unref(OBJECT(sioc));
return -1;
}
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
if (s->registered_yank) {
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
}
tcp_chr_new_client(chr, sioc);
object_unref(OBJECT(sioc));
return 0;
@@ -993,9 +1000,11 @@ static void tcp_chr_accept_server_sync(Chardev *chr)
tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
sioc = qio_net_listener_wait_client(s->listener);
tcp_chr_set_client_ioc_name(chr, sioc);
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
if (s->registered_yank) {
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
}
tcp_chr_new_client(chr, sioc);
object_unref(OBJECT(sioc));
}
@@ -1124,9 +1133,11 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
if (qio_task_propagate_error(task, &err)) {
tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
if (s->registered_yank) {
yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
}
check_report_connect_error(chr, err);
goto cleanup;
}
@@ -1160,9 +1171,11 @@ static void tcp_chr_connect_client_async(Chardev *chr)
tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
sioc = qio_channel_socket_new();
tcp_chr_set_client_ioc_name(chr, sioc);
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
if (s->registered_yank) {
yank_register_function(CHARDEV_YANK_INSTANCE(chr->label),
yank_generic_iochannel,
QIO_CHANNEL(sioc));
}
/*
* Normally code would use the qio_channel_socket_connect_async
* method which uses a QIOTask + qio_task_set_error internally
+58 -20
View File
@@ -124,7 +124,7 @@ source_wait_cb(gint fd, GIOCondition condition, gpointer user_data)
}
/* resume */
g->wait_ok = 0;
g->wait_in = 0;
vg_handle_ctrl(&g->dev.parent, 0);
return G_SOURCE_REMOVE;
@@ -133,8 +133,8 @@ source_wait_cb(gint fd, GIOCondition condition, gpointer user_data)
void
vg_wait_ok(VuGpu *g)
{
assert(g->wait_ok == 0);
g->wait_ok = g_unix_fd_add(g->sock_fd, G_IO_IN | G_IO_HUP,
assert(g->wait_in == 0);
g->wait_in = g_unix_fd_add(g->sock_fd, G_IO_IN | G_IO_HUP,
source_wait_cb, g);
}
@@ -246,7 +246,7 @@ vg_ctrl_response(VuGpu *g,
}
vu_queue_push(&g->dev.parent, cmd->vq, &cmd->elem, s);
vu_queue_notify(&g->dev.parent, cmd->vq);
cmd->finished = true;
cmd->state = VG_CMD_STATE_FINISHED;
}
void
@@ -261,23 +261,44 @@ vg_ctrl_response_nodata(VuGpu *g,
vg_ctrl_response(g, cmd, &resp, sizeof(resp));
}
static gboolean
get_display_info_cb(gint fd, GIOCondition condition, gpointer user_data)
{
struct virtio_gpu_resp_display_info dpy_info = { {} };
VuGpu *vg = user_data;
struct virtio_gpu_ctrl_command *cmd = QTAILQ_LAST(&vg->fenceq);
g_debug("disp info cb");
assert(cmd->cmd_hdr.type == VIRTIO_GPU_CMD_GET_DISPLAY_INFO);
if (!vg_recv_msg(vg, VHOST_USER_GPU_GET_DISPLAY_INFO,
sizeof(dpy_info), &dpy_info)) {
return G_SOURCE_CONTINUE;
}
QTAILQ_REMOVE(&vg->fenceq, cmd, next);
vg_ctrl_response(vg, cmd, &dpy_info.hdr, sizeof(dpy_info));
vg->wait_in = 0;
vg_handle_ctrl(&vg->dev.parent, 0);
return G_SOURCE_REMOVE;
}
void
vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
{
struct virtio_gpu_resp_display_info dpy_info = { {} };
VhostUserGpuMsg msg = {
.request = VHOST_USER_GPU_GET_DISPLAY_INFO,
.size = 0,
};
assert(vg->wait_ok == 0);
assert(vg->wait_in == 0);
vg_send_msg(vg, &msg, -1);
if (!vg_recv_msg(vg, msg.request, sizeof(dpy_info), &dpy_info)) {
return;
}
vg_ctrl_response(vg, cmd, &dpy_info.hdr, sizeof(dpy_info));
vg->wait_in = g_unix_fd_add(vg->sock_fd, G_IO_IN | G_IO_HUP,
get_display_info_cb, vg);
cmd->state = VG_CMD_STATE_PENDING;
}
static void
@@ -800,7 +821,7 @@ vg_process_cmd(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
break;
}
if (!cmd->finished) {
if (cmd->state == VG_CMD_STATE_NEW) {
vg_ctrl_response_nodata(vg, cmd, cmd->error ? cmd->error :
VIRTIO_GPU_RESP_OK_NODATA);
}
@@ -815,7 +836,7 @@ vg_handle_ctrl(VuDev *dev, int qidx)
size_t len;
for (;;) {
if (vg->wait_ok != 0) {
if (vg->wait_in != 0) {
return;
}
@@ -825,7 +846,7 @@ vg_handle_ctrl(VuDev *dev, int qidx)
}
cmd->vq = vq;
cmd->error = 0;
cmd->finished = false;
cmd->state = VG_CMD_STATE_NEW;
len = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
0, &cmd->cmd_hdr, sizeof(cmd->cmd_hdr));
@@ -844,7 +865,7 @@ vg_handle_ctrl(VuDev *dev, int qidx)
vg_process_cmd(vg, cmd);
}
if (!cmd->finished) {
if (cmd->state != VG_CMD_STATE_FINISHED) {
QTAILQ_INSERT_TAIL(&vg->fenceq, cmd, next);
vg->inflight++;
} else {
@@ -969,18 +990,17 @@ vg_queue_set_started(VuDev *dev, int qidx, bool started)
}
}
static void
set_gpu_protocol_features(VuGpu *g)
static gboolean
protocol_features_cb(gint fd, GIOCondition condition, gpointer user_data)
{
VuGpu *g = user_data;
uint64_t u64;
VhostUserGpuMsg msg = {
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES
};
assert(g->wait_ok == 0);
vg_send_msg(g, &msg, -1);
if (!vg_recv_msg(g, msg.request, sizeof(u64), &u64)) {
return;
return G_SOURCE_CONTINUE;
}
msg = (VhostUserGpuMsg) {
@@ -989,6 +1009,24 @@ set_gpu_protocol_features(VuGpu *g)
.payload.u64 = 0
};
vg_send_msg(g, &msg, -1);
g->wait_in = 0;
vg_handle_ctrl(&g->dev.parent, 0);
return G_SOURCE_REMOVE;
}
static void
set_gpu_protocol_features(VuGpu *g)
{
VhostUserGpuMsg msg = {
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES
};
vg_send_msg(g, &msg, -1);
assert(g->wait_in == 0);
g->wait_in = g_unix_fd_add(g->sock_fd, G_IO_IN | G_IO_HUP,
protocol_features_cb, g);
}
static int
+1 -1
View File
@@ -482,7 +482,7 @@ void vg_virgl_process_cmd(VuGpu *g, struct virtio_gpu_ctrl_command *cmd)
break;
}
if (cmd->finished) {
if (cmd->state != VG_CMD_STATE_NEW) {
return;
}
+8 -2
View File
@@ -118,7 +118,7 @@ typedef struct VuGpu {
int sock_fd;
int drm_rnode_fd;
GSource *renderer_source;
guint wait_ok;
guint wait_in;
bool virgl;
bool virgl_inited;
@@ -129,12 +129,18 @@ typedef struct VuGpu {
QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
} VuGpu;
enum {
VG_CMD_STATE_NEW,
VG_CMD_STATE_PENDING,
VG_CMD_STATE_FINISHED,
};
struct virtio_gpu_ctrl_command {
VuVirtqElement elem;
VuVirtq *vq;
struct virtio_gpu_ctrl_hdr cmd_hdr;
uint32_t error;
bool finished;
int state;
QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
};
+2 -2
View File
@@ -189,7 +189,7 @@ static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
qxl_name(qxl_surface_cmd, cmd->type),
cmd->surface_id);
if (cmd->type == QXL_SURFACE_CMD_CREATE) {
fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
fprintf(stderr, " size %dx%d stride %d format %s (count %u, max %u)",
cmd->u.surface_create.width,
cmd->u.surface_create.height,
cmd->u.surface_create.stride,
@@ -197,7 +197,7 @@ static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
qxl->guest_surfaces.count, qxl->guest_surfaces.max);
}
if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
fprintf(stderr, " (count %u)", qxl->guest_surfaces.count);
}
}
+1
View File
@@ -181,6 +181,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
qxl->mode == QXL_MODE_UNDEFINED) {
qxl_render_update_area_unlocked(qxl);
qemu_mutex_unlock(&qxl->ssd.lock);
graphic_hw_update_done(qxl->ssd.dcl.con);
return;
}
+2 -1
View File
@@ -944,7 +944,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id);
break;
default:
fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__,
fprintf(stderr, "qxl: %s: unexpected current_async %u\n", __func__,
current_async);
}
qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
@@ -2266,6 +2266,7 @@ static void qxl_realize_secondary(PCIDevice *dev, Error **errp)
qxl->vga.vram_size, &error_fatal);
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
qxl->ssd.dcl.con = qxl->vga.con;
qxl->id = qemu_console_get_index(qxl->vga.con); /* == channel_id */
qxl_realize_common(qxl, errp);
+10 -7
View File
@@ -224,11 +224,6 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
close(dmabuf->fd);
dmabuf->fd = -1;
}
if (!console_has_gl_dmabuf(con)) {
/* it would be nice to report that error earlier */
error_report("console doesn't support dmabuf!");
break;
}
dpy_gl_release_dmabuf(con, dmabuf);
if (fd == -1) {
dpy_gl_scanout_disable(con);
@@ -365,7 +360,7 @@ vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked)
}
static void
vhost_user_gpu_gl_unblock(VirtIOGPUBase *b)
vhost_user_gpu_gl_flushed(VirtIOGPUBase *b)
{
VhostUserGPU *g = VHOST_USER_GPU(b);
@@ -552,9 +547,17 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
return;
}
/* existing backend may send DMABUF, so let's add that requirement */
g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_DMABUF_ENABLED;
if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_VIRGL)) {
g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED;
}
if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_EDID)) {
g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_EDID_ENABLED;
} else {
error_report("EDID requested but the backend doesn't support it.");
g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_EDID_ENABLED);
}
if (!virtio_gpu_base_device_realize(qdev, NULL, NULL, errp)) {
return;
@@ -575,7 +578,7 @@ vhost_user_gpu_class_init(ObjectClass *klass, void *data)
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
vgc->gl_unblock = vhost_user_gpu_gl_unblock;
vgc->gl_flushed = vhost_user_gpu_gl_flushed;
vdc->realize = vhost_user_gpu_device_realize;
vdc->reset = vhost_user_gpu_reset;
+28 -3
View File
@@ -97,29 +97,54 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
}
static void
virtio_gpu_gl_block(void *opaque, bool block)
virtio_gpu_gl_flushed(void *opaque)
{
VirtIOGPUBase *g = opaque;
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_GET_CLASS(g);
if (vgc->gl_flushed) {
vgc->gl_flushed(g);
}
}
static void
virtio_gpu_gl_block(void *opaque, bool block)
{
VirtIOGPUBase *g = opaque;
if (block) {
g->renderer_blocked++;
} else {
g->renderer_blocked--;
}
assert(g->renderer_blocked >= 0);
}
if (g->renderer_blocked == 0) {
vgc->gl_unblock(g);
static int
virtio_gpu_get_flags(void *opaque)
{
VirtIOGPUBase *g = opaque;
int flags = GRAPHIC_FLAGS_NONE;
if (virtio_gpu_virgl_enabled(g->conf)) {
flags |= GRAPHIC_FLAGS_GL;
}
if (virtio_gpu_dmabuf_enabled(g->conf)) {
flags |= GRAPHIC_FLAGS_DMABUF;
}
return flags;
}
static const GraphicHwOps virtio_gpu_ops = {
.get_flags = virtio_gpu_get_flags,
.invalidate = virtio_gpu_invalidate_display,
.gfx_update = virtio_gpu_update_display,
.text_update = virtio_gpu_text_update,
.ui_info = virtio_gpu_ui_info,
.gl_block = virtio_gpu_gl_block,
.gl_flushed = virtio_gpu_gl_flushed,
};
bool
+7 -2
View File
@@ -814,6 +814,10 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
{
struct virtio_gpu_ctrl_command *cmd;
if (g->processing_cmdq) {
return;
}
g->processing_cmdq = true;
while (!QTAILQ_EMPTY(&g->cmdq)) {
cmd = QTAILQ_FIRST(&g->cmdq);
@@ -843,9 +847,10 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
g_free(cmd);
}
}
g->processing_cmdq = false;
}
static void virtio_gpu_gl_unblock(VirtIOGPUBase *b)
static void virtio_gpu_gl_flushed(VirtIOGPUBase *b)
{
VirtIOGPU *g = VIRTIO_GPU(b);
@@ -1252,7 +1257,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
vgc->gl_unblock = virtio_gpu_gl_unblock;
vgc->gl_flushed = virtio_gpu_gl_flushed;
vdc->realize = virtio_gpu_device_realize;
vdc->reset = virtio_gpu_reset;
vdc->get_config = virtio_gpu_get_config;
+20
View File
@@ -68,12 +68,32 @@ static void virtio_vga_base_gl_block(void *opaque, bool block)
}
}
static void virtio_vga_base_gl_flushed(void *opaque)
{
VirtIOVGABase *vvga = opaque;
VirtIOGPUBase *g = vvga->vgpu;
if (g->hw_ops->gl_flushed) {
g->hw_ops->gl_flushed(g);
}
}
static int virtio_vga_base_get_flags(void *opaque)
{
VirtIOVGABase *vvga = opaque;
VirtIOGPUBase *g = vvga->vgpu;
return g->hw_ops->get_flags(g);
}
static const GraphicHwOps virtio_vga_base_ops = {
.get_flags = virtio_vga_base_get_flags,
.invalidate = virtio_vga_base_invalidate_display,
.gfx_update = virtio_vga_base_update_display,
.text_update = virtio_vga_base_text_update,
.ui_info = virtio_vga_base_ui_info,
.gl_block = virtio_vga_base_gl_block,
.gl_flushed = virtio_vga_base_gl_flushed,
};
static const VMStateDescription vmstate_virtio_vga_base = {
+6
View File
@@ -335,7 +335,13 @@ static void vfio_display_dmabuf_update(void *opaque)
}
}
static int vfio_display_get_flags(void *opaque)
{
return GRAPHIC_FLAGS_GL | GRAPHIC_FLAGS_DMABUF;
}
static const GraphicHwOps vfio_display_dmabuf_ops = {
.get_flags = vfio_display_get_flags,
.gfx_update = vfio_display_dmabuf_update,
.ui_info = vfio_display_edid_ui_info,
};
+5 -1
View File
@@ -71,6 +71,7 @@ enum virtio_gpu_base_conf_flags {
VIRTIO_GPU_FLAG_VIRGL_ENABLED = 1,
VIRTIO_GPU_FLAG_STATS_ENABLED,
VIRTIO_GPU_FLAG_EDID_ENABLED,
VIRTIO_GPU_FLAG_DMABUF_ENABLED,
};
#define virtio_gpu_virgl_enabled(_cfg) \
@@ -79,6 +80,8 @@ enum virtio_gpu_base_conf_flags {
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_STATS_ENABLED))
#define virtio_gpu_edid_enabled(_cfg) \
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_EDID_ENABLED))
#define virtio_gpu_dmabuf_enabled(_cfg) \
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_DMABUF_ENABLED))
struct virtio_gpu_base_conf {
uint32_t max_outputs;
@@ -118,7 +121,7 @@ struct VirtIOGPUBase {
struct VirtIOGPUBaseClass {
VirtioDeviceClass parent;
void (*gl_unblock)(VirtIOGPUBase *g);
void (*gl_flushed)(VirtIOGPUBase *g);
};
#define VIRTIO_GPU_BASE_PROPERTIES(_state, _conf) \
@@ -145,6 +148,7 @@ struct VirtIOGPU {
uint64_t hostmem;
bool processing_cmdq;
bool renderer_inited;
bool renderer_reset;
QEMUTimer *fence_poll;
+32 -3
View File
@@ -174,36 +174,49 @@ typedef struct DisplayState DisplayState;
typedef struct DisplayChangeListenerOps {
const char *dpy_name;
/* optional */
void (*dpy_refresh)(DisplayChangeListener *dcl);
/* optional */
void (*dpy_gfx_update)(DisplayChangeListener *dcl,
int x, int y, int w, int h);
/* optional */
void (*dpy_gfx_switch)(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface);
/* optional */
bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl,
pixman_format_code_t format);
/* optional */
void (*dpy_text_cursor)(DisplayChangeListener *dcl,
int x, int y);
/* optional */
void (*dpy_text_resize)(DisplayChangeListener *dcl,
int w, int h);
/* optional */
void (*dpy_text_update)(DisplayChangeListener *dcl,
int x, int y, int w, int h);
/* optional */
void (*dpy_mouse_set)(DisplayChangeListener *dcl,
int x, int y, int on);
/* optional */
void (*dpy_cursor_define)(DisplayChangeListener *dcl,
QEMUCursor *cursor);
/* required if GL */
QEMUGLContext (*dpy_gl_ctx_create)(DisplayChangeListener *dcl,
QEMUGLParams *params);
/* required if GL */
void (*dpy_gl_ctx_destroy)(DisplayChangeListener *dcl,
QEMUGLContext ctx);
/* required if GL */
int (*dpy_gl_ctx_make_current)(DisplayChangeListener *dcl,
QEMUGLContext ctx);
QEMUGLContext (*dpy_gl_ctx_get_current)(DisplayChangeListener *dcl);
/* required if GL */
void (*dpy_gl_scanout_disable)(DisplayChangeListener *dcl);
/* required if GL */
void (*dpy_gl_scanout_texture)(DisplayChangeListener *dcl,
uint32_t backing_id,
bool backing_y_0_top,
@@ -211,15 +224,22 @@ typedef struct DisplayChangeListenerOps {
uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h);
/* optional (default to true if has dpy_gl_scanout_dmabuf) */
bool (*dpy_has_dmabuf)(DisplayChangeListener *dcl);
/* optional */
void (*dpy_gl_scanout_dmabuf)(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf);
/* optional */
void (*dpy_gl_cursor_dmabuf)(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf, bool have_hot,
uint32_t hot_x, uint32_t hot_y);
/* optional */
void (*dpy_gl_cursor_position)(DisplayChangeListener *dcl,
uint32_t pos_x, uint32_t pos_y);
/* optional */
void (*dpy_gl_release_dmabuf)(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf);
/* required if GL */
void (*dpy_gl_update)(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
@@ -303,10 +323,8 @@ QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
QEMUGLParams *params);
void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx);
int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx);
QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con);
bool console_has_gl(QemuConsole *con);
bool console_has_gl_dmabuf(QemuConsole *con);
static inline int surface_stride(DisplaySurface *s)
{
@@ -352,7 +370,16 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
*dest = ch;
}
enum {
GRAPHIC_FLAGS_NONE = 0,
/* require a console/display with GL callbacks */
GRAPHIC_FLAGS_GL = 1 << 0,
/* require a console/display with DMABUF import */
GRAPHIC_FLAGS_DMABUF = 1 << 1,
};
typedef struct GraphicHwOps {
int (*get_flags)(void *opaque); /* optional, default 0 */
void (*invalidate)(void *opaque);
void (*gfx_update)(void *opaque);
bool gfx_update_async; /* if true, calls graphic_hw_update_done() */
@@ -360,6 +387,7 @@ typedef struct GraphicHwOps {
void (*update_interval)(void *opaque, uint64_t interval);
int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
void (*gl_block)(void *opaque, bool block);
void (*gl_flushed)(void *opaque);
} GraphicHwOps;
QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
@@ -375,6 +403,7 @@ void graphic_hw_update_done(QemuConsole *con);
void graphic_hw_invalidate(QemuConsole *con);
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
void graphic_hw_gl_block(QemuConsole *con, bool block);
void graphic_hw_gl_flushed(QemuConsole *con);
void qemu_console_early_init(void);
-1
View File
@@ -9,6 +9,5 @@ QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl,
void qemu_egl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx);
int qemu_egl_make_context_current(DisplayChangeListener *dcl,
QEMUGLContext ctx);
QEMUGLContext qemu_egl_get_current_context(DisplayChangeListener *dcl);
#endif /* EGL_CONTEXT_H */
+1
View File
@@ -51,5 +51,6 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win);
int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode);
int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode);
EGLContext qemu_egl_init_ctx(void);
bool qemu_egl_has_dmabuf(void);
#endif /* EGL_HELPERS_H */
+4
View File
@@ -48,6 +48,7 @@ typedef struct VirtualGfxConsole {
int cursor_y;
bool y0_top;
bool scanout_mode;
bool has_dmabuf;
#endif
} VirtualGfxConsole;
@@ -133,6 +134,8 @@ QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl,
QEMUGLParams *params);
void gd_gl_area_destroy_context(DisplayChangeListener *dcl,
QEMUGLContext ctx);
void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf);
void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_id,
bool backing_y_0_top,
@@ -140,6 +143,7 @@ void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h);
void gd_gl_area_scanout_disable(DisplayChangeListener *dcl);
void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void gtk_gl_area_init(void);
+1
View File
@@ -28,6 +28,7 @@
void qemu_spice_input_init(void);
void qemu_spice_display_init(void);
void qemu_spice_display_init_done(void);
bool qemu_spice_have_display_interface(QemuConsole *con);
int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con);
int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
-1
View File
@@ -70,7 +70,6 @@ QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl,
void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx);
int sdl2_gl_make_context_current(DisplayChangeListener *dcl,
QEMUGLContext ctx);
QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl);
void sdl2_gl_scanout_disable(DisplayChangeListener *dcl);
void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
+161
View File
@@ -0,0 +1,161 @@
# virtio-gpu tests
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
from avocado_qemu import Test
from avocado_qemu import BUILD_DIR
from avocado_qemu import wait_for_console_pattern
from avocado_qemu import exec_command_and_wait_for_pattern
from avocado_qemu import is_readable_executable_file
from qemu.accel import kvm_available
import os
import socket
import subprocess
ACCEL_NOT_AVAILABLE_FMT = "%s accelerator does not seem to be available"
KVM_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "KVM"
def pick_default_vug_bin():
relative_path = "./contrib/vhost-user-gpu/vhost-user-gpu"
if is_readable_executable_file(relative_path):
return relative_path
bld_dir_path = os.path.join(BUILD_DIR, relative_path)
if is_readable_executable_file(bld_dir_path):
return bld_dir_path
class VirtioGPUx86(Test):
"""
:avocado: tags=virtio-gpu
"""
KERNEL_COMMON_COMMAND_LINE = "printk.time=0 "
KERNEL_URL = (
"https://archives.fedoraproject.org/pub/fedora"
"/linux/releases/33/Everything/x86_64/os/images"
"/pxeboot/vmlinuz"
)
INITRD_URL = (
"https://archives.fedoraproject.org/pub/fedora"
"/linux/releases/33/Everything/x86_64/os/images"
"/pxeboot/initrd.img"
)
def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(
self,
success_message,
failure_message="Kernel panic - not syncing",
vm=vm,
)
def test_virtio_vga_virgl(self):
"""
:avocado: tags=arch:x86_64
:avocado: tags=device:virtio-vga
"""
kernel_command_line = (
self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash"
)
# FIXME: should check presence of virtio, virgl etc
if not kvm_available(self.arch, self.qemu_bin):
self.cancel(KVM_NOT_AVAILABLE)
kernel_path = self.fetch_asset(self.KERNEL_URL)
initrd_path = self.fetch_asset(self.INITRD_URL)
self.vm.set_console()
self.vm.add_args("-cpu", "host")
self.vm.add_args("-m", "2G")
self.vm.add_args("-machine", "pc,accel=kvm")
self.vm.add_args("-device", "virtio-vga,virgl=on")
self.vm.add_args("-display", "egl-headless")
self.vm.add_args(
"-kernel",
kernel_path,
"-initrd",
initrd_path,
"-append",
kernel_command_line,
)
self.vm.launch()
self.wait_for_console_pattern("as init process")
exec_command_and_wait_for_pattern(
self, "/usr/sbin/modprobe virtio_gpu", ""
)
self.wait_for_console_pattern("features: +virgl +edid")
def test_vhost_user_vga_virgl(self):
"""
:avocado: tags=arch:x86_64
:avocado: tags=device:vhost-user-vga
"""
kernel_command_line = (
self.KERNEL_COMMON_COMMAND_LINE + "console=ttyS0 rdinit=/bin/bash"
)
# FIXME: should check presence of vhost-user-gpu, virgl, memfd etc
if not kvm_available(self.arch, self.qemu_bin):
self.cancel(KVM_NOT_AVAILABLE)
vug = pick_default_vug_bin()
if not vug:
self.cancel("Could not find vhost-user-gpu")
kernel_path = self.fetch_asset(self.KERNEL_URL)
initrd_path = self.fetch_asset(self.INITRD_URL)
# Create socketpair to connect proxy and remote processes
qemu_sock, vug_sock = socket.socketpair(
socket.AF_UNIX, socket.SOCK_STREAM
)
os.set_inheritable(qemu_sock.fileno(), True)
os.set_inheritable(vug_sock.fileno(), True)
self._vug_log_path = os.path.join(
self.vm._test_dir, "vhost-user-gpu.log"
)
self._vug_log_file = open(self._vug_log_path, "wb")
print(self._vug_log_path)
vugp = subprocess.Popen(
[vug, "--virgl", "--fd=%d" % vug_sock.fileno()],
stdin=subprocess.DEVNULL,
stdout=self._vug_log_file,
stderr=subprocess.STDOUT,
shell=False,
close_fds=False,
)
self.vm.set_console()
self.vm.add_args("-cpu", "host")
self.vm.add_args("-m", "2G")
self.vm.add_args("-object", "memory-backend-memfd,id=mem,size=2G")
self.vm.add_args("-machine", "pc,memory-backend=mem,accel=kvm")
self.vm.add_args("-chardev", "socket,id=vug,fd=%d" % qemu_sock.fileno())
self.vm.add_args("-device", "vhost-user-vga,chardev=vug")
self.vm.add_args("-display", "egl-headless")
self.vm.add_args(
"-kernel",
kernel_path,
"-initrd",
initrd_path,
"-append",
kernel_command_line,
)
self.vm.launch()
self.wait_for_console_pattern("as init process")
exec_command_and_wait_for_pattern(
self, "/usr/sbin/modprobe virtio_gpu", ""
)
self.wait_for_console_pattern("features: +virgl -edid")
self.vm.shutdown()
qemu_sock.close()
vugp.terminate()
vugp.wait()

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