mirror of https://gitee.com/openkylin/qemu.git
virtio-gpu: split virtio-gpu, introduce virtio-gpu-base
Add a base class that is common to virtio-gpu and vhost-user-gpu devices. The VirtIOGPUBase base class provides common functionalities necessary for both virtio-gpu and vhost-user-gpu: - common configuration (max-outputs, initial resolution, flags) - virtio device initialization, including queue setup - device pre-conditions checks (iommu) - migration blocker - virtio device callbacks - hooking up to qemu display subsystem - a few common helper functions to reset the device, retrieve display informations - a class callback to unblock the rendering (for GL updates) What is left to the virtio-gpu subdevice to take care of, in short, are all the virtio queues handling, command processing and migration. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-id: 20190524130946.31736-8-marcandre.lureau@redhat.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
cb0efb7125
commit
50d8e25ea6
|
@ -43,7 +43,7 @@ obj-$(CONFIG_VGA) += vga.o
|
||||||
|
|
||||||
common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.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-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
|
obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
|
||||||
obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
|
obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
|
||||||
virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
|
virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
|
||||||
|
|
|
@ -118,11 +118,11 @@ static void virgl_cmd_context_destroy(VirtIOGPU *g,
|
||||||
static void virtio_gpu_rect_update(VirtIOGPU *g, int idx, int x, int y,
|
static void virtio_gpu_rect_update(VirtIOGPU *g, int idx, int x, int y,
|
||||||
int width, int height)
|
int width, int height)
|
||||||
{
|
{
|
||||||
if (!g->scanout[idx].con) {
|
if (!g->parent_obj.scanout[idx].con) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dpy_gl_update(g->scanout[idx].con, x, y, width, height);
|
dpy_gl_update(g->parent_obj.scanout[idx].con, x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virgl_cmd_resource_flush(VirtIOGPU *g,
|
static void virgl_cmd_resource_flush(VirtIOGPU *g,
|
||||||
|
@ -135,8 +135,8 @@ static void virgl_cmd_resource_flush(VirtIOGPU *g,
|
||||||
trace_virtio_gpu_cmd_res_flush(rf.resource_id,
|
trace_virtio_gpu_cmd_res_flush(rf.resource_id,
|
||||||
rf.r.width, rf.r.height, rf.r.x, rf.r.y);
|
rf.r.width, rf.r.height, rf.r.x, rf.r.y);
|
||||||
|
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||||
if (g->scanout[i].resource_id != rf.resource_id) {
|
if (g->parent_obj.scanout[i].resource_id != rf.resource_id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
virtio_gpu_rect_update(g, i, rf.r.x, rf.r.y, rf.r.width, rf.r.height);
|
virtio_gpu_rect_update(g, i, rf.r.x, rf.r.y, rf.r.width, rf.r.height);
|
||||||
|
@ -154,13 +154,13 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
|
||||||
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
|
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
|
||||||
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
|
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
|
||||||
|
|
||||||
if (ss.scanout_id >= g->conf.max_outputs) {
|
if (ss.scanout_id >= g->parent_obj.conf.max_outputs) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
|
||||||
__func__, ss.scanout_id);
|
__func__, ss.scanout_id);
|
||||||
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g->enable = 1;
|
g->parent_obj.enable = 1;
|
||||||
|
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
|
@ -173,20 +173,22 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
|
||||||
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qemu_console_resize(g->scanout[ss.scanout_id].con,
|
qemu_console_resize(g->parent_obj.scanout[ss.scanout_id].con,
|
||||||
ss.r.width, ss.r.height);
|
ss.r.width, ss.r.height);
|
||||||
virgl_renderer_force_ctx_0();
|
virgl_renderer_force_ctx_0();
|
||||||
dpy_gl_scanout_texture(g->scanout[ss.scanout_id].con, info.tex_id,
|
dpy_gl_scanout_texture(
|
||||||
info.flags & 1 /* FIXME: Y_0_TOP */,
|
g->parent_obj.scanout[ss.scanout_id].con, info.tex_id,
|
||||||
info.width, info.height,
|
info.flags & 1 /* FIXME: Y_0_TOP */,
|
||||||
ss.r.x, ss.r.y, ss.r.width, ss.r.height);
|
info.width, info.height,
|
||||||
|
ss.r.x, ss.r.y, ss.r.width, ss.r.height);
|
||||||
} else {
|
} else {
|
||||||
if (ss.scanout_id != 0) {
|
if (ss.scanout_id != 0) {
|
||||||
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
|
dpy_gfx_replace_surface(
|
||||||
|
g->parent_obj.scanout[ss.scanout_id].con, NULL);
|
||||||
}
|
}
|
||||||
dpy_gl_scanout_disable(g->scanout[ss.scanout_id].con);
|
dpy_gl_scanout_disable(g->parent_obj.scanout[ss.scanout_id].con);
|
||||||
}
|
}
|
||||||
g->scanout[ss.scanout_id].resource_id = ss.resource_id;
|
g->parent_obj.scanout[ss.scanout_id].resource_id = ss.resource_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virgl_cmd_submit_3d(VirtIOGPU *g,
|
static void virgl_cmd_submit_3d(VirtIOGPU *g,
|
||||||
|
@ -209,7 +211,7 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
|
||||||
g->stats.req_3d++;
|
g->stats.req_3d++;
|
||||||
g->stats.bytes_3d += cs.size;
|
g->stats.bytes_3d += cs.size;
|
||||||
}
|
}
|
||||||
|
@ -507,7 +509,7 @@ static void virgl_write_fence(void *opaque, uint32_t fence)
|
||||||
QTAILQ_REMOVE(&g->fenceq, cmd, next);
|
QTAILQ_REMOVE(&g->fenceq, cmd, next);
|
||||||
g_free(cmd);
|
g_free(cmd);
|
||||||
g->inflight--;
|
g->inflight--;
|
||||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
|
||||||
fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
|
fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,7 +526,7 @@ virgl_create_context(void *opaque, int scanout_idx,
|
||||||
qparams.major_ver = params->major_ver;
|
qparams.major_ver = params->major_ver;
|
||||||
qparams.minor_ver = params->minor_ver;
|
qparams.minor_ver = params->minor_ver;
|
||||||
|
|
||||||
ctx = dpy_gl_ctx_create(g->scanout[scanout_idx].con, &qparams);
|
ctx = dpy_gl_ctx_create(g->parent_obj.scanout[scanout_idx].con, &qparams);
|
||||||
return (virgl_renderer_gl_context)ctx;
|
return (virgl_renderer_gl_context)ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,7 +535,7 @@ static void virgl_destroy_context(void *opaque, virgl_renderer_gl_context ctx)
|
||||||
VirtIOGPU *g = opaque;
|
VirtIOGPU *g = opaque;
|
||||||
QEMUGLContext qctx = (QEMUGLContext)ctx;
|
QEMUGLContext qctx = (QEMUGLContext)ctx;
|
||||||
|
|
||||||
dpy_gl_ctx_destroy(g->scanout[0].con, qctx);
|
dpy_gl_ctx_destroy(g->parent_obj.scanout[0].con, qctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virgl_make_context_current(void *opaque, int scanout_idx,
|
static int virgl_make_context_current(void *opaque, int scanout_idx,
|
||||||
|
@ -542,7 +544,8 @@ static int virgl_make_context_current(void *opaque, int scanout_idx,
|
||||||
VirtIOGPU *g = opaque;
|
VirtIOGPU *g = opaque;
|
||||||
QEMUGLContext qctx = (QEMUGLContext)ctx;
|
QEMUGLContext qctx = (QEMUGLContext)ctx;
|
||||||
|
|
||||||
return dpy_gl_ctx_make_current(g->scanout[scanout_idx].con, qctx);
|
return dpy_gl_ctx_make_current(g->parent_obj.scanout[scanout_idx].con,
|
||||||
|
qctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
|
static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
|
||||||
|
@ -594,11 +597,11 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* virgl_renderer_reset() ??? */
|
/* virgl_renderer_reset() ??? */
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
dpy_gfx_replace_surface(g->scanout[i].con, NULL);
|
dpy_gfx_replace_surface(g->parent_obj.scanout[i].con, NULL);
|
||||||
}
|
}
|
||||||
dpy_gl_scanout_disable(g->scanout[i].con);
|
dpy_gl_scanout_disable(g->parent_obj.scanout[i].con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +617,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
|
||||||
g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
|
g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
|
||||||
virtio_gpu_fence_poll, g);
|
virtio_gpu_fence_poll, g);
|
||||||
|
|
||||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
|
||||||
g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
|
g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
|
||||||
virtio_gpu_print_stats, g);
|
virtio_gpu_print_stats, g);
|
||||||
timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
|
timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
|
||||||
|
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*
|
||||||
|
* Virtio GPU Device
|
||||||
|
*
|
||||||
|
* Copyright Red Hat, Inc. 2013-2014
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Dave Airlie <airlied@redhat.com>
|
||||||
|
* Gerd Hoffmann <kraxel@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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "hw/virtio/virtio-gpu.h"
|
||||||
|
#include "migration/blocker.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
virtio_gpu_base_reset(VirtIOGPUBase *g)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g->enable = 0;
|
||||||
|
g->use_virgl_renderer = false;
|
||||||
|
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
g->scanout[i].resource_id = 0;
|
||||||
|
g->scanout[i].width = 0;
|
||||||
|
g->scanout[i].height = 0;
|
||||||
|
g->scanout[i].x = 0;
|
||||||
|
g->scanout[i].y = 0;
|
||||||
|
g->scanout[i].ds = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
virtio_gpu_base_fill_display_info(VirtIOGPUBase *g,
|
||||||
|
struct virtio_gpu_resp_display_info *dpy_info)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
if (g->enabled_output_bitmask & (1 << i)) {
|
||||||
|
dpy_info->pmodes[i].enabled = 1;
|
||||||
|
dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width);
|
||||||
|
dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_invalidate_display(void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_update_display(void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_notify_event(VirtIOGPUBase *g, uint32_t event_type)
|
||||||
|
{
|
||||||
|
g->virtio_config.events_read |= event_type;
|
||||||
|
virtio_notify_config(&g->parent_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
|
||||||
|
{
|
||||||
|
VirtIOGPUBase *g = opaque;
|
||||||
|
|
||||||
|
if (idx >= g->conf.max_outputs) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g->req_state[idx].x = info->xoff;
|
||||||
|
g->req_state[idx].y = info->yoff;
|
||||||
|
g->req_state[idx].width = info->width;
|
||||||
|
g->req_state[idx].height = info->height;
|
||||||
|
|
||||||
|
if (info->width && info->height) {
|
||||||
|
g->enabled_output_bitmask |= (1 << idx);
|
||||||
|
} else {
|
||||||
|
g->enabled_output_bitmask &= ~(1 << idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send event to guest */
|
||||||
|
virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_gl_block(void *opaque, bool block)
|
||||||
|
{
|
||||||
|
VirtIOGPUBase *g = opaque;
|
||||||
|
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_GET_CLASS(g);
|
||||||
|
|
||||||
|
if (block) {
|
||||||
|
g->renderer_blocked++;
|
||||||
|
} else {
|
||||||
|
g->renderer_blocked--;
|
||||||
|
}
|
||||||
|
assert(g->renderer_blocked >= 0);
|
||||||
|
|
||||||
|
if (g->renderer_blocked == 0) {
|
||||||
|
vgc->gl_unblock(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphicHwOps virtio_gpu_ops = {
|
||||||
|
.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,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
virtio_gpu_base_device_realize(DeviceState *qdev,
|
||||||
|
VirtIOHandleOutput ctrl_cb,
|
||||||
|
VirtIOHandleOutput cursor_cb,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) {
|
||||||
|
error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g->use_virgl_renderer = false;
|
||||||
|
if (virtio_gpu_virgl_enabled(g->conf)) {
|
||||||
|
error_setg(&g->migration_blocker, "virgl is not yet migratable");
|
||||||
|
migrate_add_blocker(g->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(g->migration_blocker);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs);
|
||||||
|
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
|
||||||
|
sizeof(struct virtio_gpu_config));
|
||||||
|
|
||||||
|
if (virtio_gpu_virgl_enabled(g->conf)) {
|
||||||
|
/* use larger control queue in 3d mode */
|
||||||
|
virtio_add_queue(vdev, 256, ctrl_cb);
|
||||||
|
virtio_add_queue(vdev, 16, cursor_cb);
|
||||||
|
} else {
|
||||||
|
virtio_add_queue(vdev, 64, ctrl_cb);
|
||||||
|
virtio_add_queue(vdev, 16, cursor_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
g->enabled_output_bitmask = 1;
|
||||||
|
|
||||||
|
g->req_state[0].width = g->conf.xres;
|
||||||
|
g->req_state[0].height = g->conf.yres;
|
||||||
|
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
g->scanout[i].con =
|
||||||
|
graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
|
||||||
|
if (i > 0) {
|
||||||
|
dpy_gfx_replace_surface(g->scanout[i].con, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
|
||||||
|
|
||||||
|
if (virtio_gpu_virgl_enabled(g->conf)) {
|
||||||
|
features |= (1 << VIRTIO_GPU_F_VIRGL);
|
||||||
|
}
|
||||||
|
if (virtio_gpu_edid_enabled(g->conf)) {
|
||||||
|
features |= (1 << VIRTIO_GPU_F_EDID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features)
|
||||||
|
{
|
||||||
|
static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL);
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
|
||||||
|
|
||||||
|
g->use_virgl_renderer = ((features & virgl) == virgl);
|
||||||
|
trace_virtio_gpu_features(g->use_virgl_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_base_device_unrealize(DeviceState *qdev, Error **errp)
|
||||||
|
{
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev);
|
||||||
|
|
||||||
|
if (g->migration_blocker) {
|
||||||
|
migrate_del_blocker(g->migration_blocker);
|
||||||
|
error_free(g->migration_blocker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_base_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
vdc->unrealize = virtio_gpu_base_device_unrealize;
|
||||||
|
vdc->get_features = virtio_gpu_base_get_features;
|
||||||
|
vdc->set_features = virtio_gpu_base_set_features;
|
||||||
|
|
||||||
|
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||||
|
dc->hotpluggable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo virtio_gpu_base_info = {
|
||||||
|
.name = TYPE_VIRTIO_GPU_BASE,
|
||||||
|
.parent = TYPE_VIRTIO_DEVICE,
|
||||||
|
.instance_size = sizeof(VirtIOGPUBase),
|
||||||
|
.class_size = sizeof(VirtIOGPUBaseClass),
|
||||||
|
.class_init = virtio_gpu_base_class_init,
|
||||||
|
.abstract = true
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&virtio_gpu_base_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(virtio_register_types)
|
||||||
|
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408);
|
||||||
|
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24);
|
|
@ -41,7 +41,7 @@ static Property virtio_gpu_pci_properties[] = {
|
||||||
static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
{
|
{
|
||||||
VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
|
VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
|
||||||
VirtIOGPU *g = &vgpu->vdev;
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vgpu->vdev);
|
||||||
DeviceState *vdev = DEVICE(&vgpu->vdev);
|
DeviceState *vdev = DEVICE(&vgpu->vdev);
|
||||||
int i;
|
int i;
|
||||||
Error *local_error = NULL;
|
Error *local_error = NULL;
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
#include "hw/virtio/virtio-gpu-pixman.h"
|
#include "hw/virtio/virtio-gpu-pixman.h"
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
#include "hw/display/edid.h"
|
#include "hw/display/edid.h"
|
||||||
#include "migration/blocker.h"
|
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
#define VIRTIO_GPU_VM_VERSION 1
|
#define VIRTIO_GPU_VM_VERSION 1
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ static void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
|
||||||
#include <virglrenderer.h>
|
#include <virglrenderer.h>
|
||||||
#define VIRGL(_g, _virgl, _simple, ...) \
|
#define VIRGL(_g, _virgl, _simple, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (_g->use_virgl_renderer) { \
|
if (_g->parent_obj.use_virgl_renderer) { \
|
||||||
_virgl(__VA_ARGS__); \
|
_virgl(__VA_ARGS__); \
|
||||||
} else { \
|
} else { \
|
||||||
_simple(__VA_ARGS__); \
|
_simple(__VA_ARGS__); \
|
||||||
|
@ -108,10 +108,10 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
|
||||||
struct virtio_gpu_scanout *s;
|
struct virtio_gpu_scanout *s;
|
||||||
bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR;
|
bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR;
|
||||||
|
|
||||||
if (cursor->pos.scanout_id >= g->conf.max_outputs) {
|
if (cursor->pos.scanout_id >= g->parent_obj.conf.max_outputs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s = &g->scanout[cursor->pos.scanout_id];
|
s = &g->parent_obj.scanout[cursor->pos.scanout_id];
|
||||||
|
|
||||||
trace_virtio_gpu_update_cursor(cursor->pos.scanout_id,
|
trace_virtio_gpu_update_cursor(cursor->pos.scanout_id,
|
||||||
cursor->pos.x,
|
cursor->pos.x,
|
||||||
|
@ -142,53 +142,6 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
|
||||||
cursor->resource_id ? 1 : 0);
|
cursor->resource_id ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
|
|
||||||
{
|
|
||||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
|
||||||
memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
|
|
||||||
{
|
|
||||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
|
||||||
struct virtio_gpu_config vgconfig;
|
|
||||||
|
|
||||||
memcpy(&vgconfig, config, sizeof(g->virtio_config));
|
|
||||||
|
|
||||||
if (vgconfig.events_clear) {
|
|
||||||
g->virtio_config.events_read &= ~vgconfig.events_clear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
|
||||||
|
|
||||||
if (virtio_gpu_virgl_enabled(g->conf)) {
|
|
||||||
features |= (1 << VIRTIO_GPU_F_VIRGL);
|
|
||||||
}
|
|
||||||
if (virtio_gpu_edid_enabled(g->conf)) {
|
|
||||||
features |= (1 << VIRTIO_GPU_F_EDID);
|
|
||||||
}
|
|
||||||
return features;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
|
|
||||||
{
|
|
||||||
static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL);
|
|
||||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
|
||||||
|
|
||||||
g->use_virgl_renderer = ((features & virgl) == virgl);
|
|
||||||
trace_virtio_gpu_features(g->use_virgl_renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type)
|
|
||||||
{
|
|
||||||
g->virtio_config.events_read |= event_type;
|
|
||||||
virtio_notify_config(&g->parent_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct virtio_gpu_simple_resource *
|
static struct virtio_gpu_simple_resource *
|
||||||
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
|
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
|
||||||
{
|
{
|
||||||
|
@ -237,21 +190,6 @@ void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
|
||||||
virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
|
virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
virtio_gpu_fill_display_info(VirtIOGPU *g,
|
|
||||||
struct virtio_gpu_resp_display_info *dpy_info)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
|
||||||
if (g->enabled_output_bitmask & (1 << i)) {
|
|
||||||
dpy_info->pmodes[i].enabled = 1;
|
|
||||||
dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width);
|
|
||||||
dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void virtio_gpu_get_display_info(VirtIOGPU *g,
|
void virtio_gpu_get_display_info(VirtIOGPU *g,
|
||||||
struct virtio_gpu_ctrl_command *cmd)
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
{
|
{
|
||||||
|
@ -260,7 +198,7 @@ void virtio_gpu_get_display_info(VirtIOGPU *g,
|
||||||
trace_virtio_gpu_cmd_get_display_info();
|
trace_virtio_gpu_cmd_get_display_info();
|
||||||
memset(&display_info, 0, sizeof(display_info));
|
memset(&display_info, 0, sizeof(display_info));
|
||||||
display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
|
display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
|
||||||
virtio_gpu_fill_display_info(g, &display_info);
|
virtio_gpu_base_fill_display_info(VIRTIO_GPU_BASE(g), &display_info);
|
||||||
virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
|
virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
|
||||||
sizeof(display_info));
|
sizeof(display_info));
|
||||||
}
|
}
|
||||||
|
@ -269,9 +207,10 @@ static void
|
||||||
virtio_gpu_generate_edid(VirtIOGPU *g, int scanout,
|
virtio_gpu_generate_edid(VirtIOGPU *g, int scanout,
|
||||||
struct virtio_gpu_resp_edid *edid)
|
struct virtio_gpu_resp_edid *edid)
|
||||||
{
|
{
|
||||||
|
VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
|
||||||
qemu_edid_info info = {
|
qemu_edid_info info = {
|
||||||
.prefx = g->req_state[scanout].width,
|
.prefx = b->req_state[scanout].width,
|
||||||
.prefy = g->req_state[scanout].height,
|
.prefy = b->req_state[scanout].height,
|
||||||
};
|
};
|
||||||
|
|
||||||
edid->size = cpu_to_le32(sizeof(edid->edid));
|
edid->size = cpu_to_le32(sizeof(edid->edid));
|
||||||
|
@ -283,11 +222,12 @@ void virtio_gpu_get_edid(VirtIOGPU *g,
|
||||||
{
|
{
|
||||||
struct virtio_gpu_resp_edid edid;
|
struct virtio_gpu_resp_edid edid;
|
||||||
struct virtio_gpu_cmd_get_edid get_edid;
|
struct virtio_gpu_cmd_get_edid get_edid;
|
||||||
|
VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
|
||||||
|
|
||||||
VIRTIO_GPU_FILL_CMD(get_edid);
|
VIRTIO_GPU_FILL_CMD(get_edid);
|
||||||
virtio_gpu_bswap_32(&get_edid, sizeof(get_edid));
|
virtio_gpu_bswap_32(&get_edid, sizeof(get_edid));
|
||||||
|
|
||||||
if (get_edid.scanout >= g->conf.max_outputs) {
|
if (get_edid.scanout >= b->conf.max_outputs) {
|
||||||
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -356,7 +296,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
|
||||||
}
|
}
|
||||||
|
|
||||||
res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
|
res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
|
||||||
if (res->hostmem + g->hostmem < g->conf.max_hostmem) {
|
if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
|
||||||
res->image = pixman_image_create_bits(pformat,
|
res->image = pixman_image_create_bits(pformat,
|
||||||
c2d.width,
|
c2d.width,
|
||||||
c2d.height,
|
c2d.height,
|
||||||
|
@ -378,7 +318,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
|
||||||
|
|
||||||
static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
|
static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
|
||||||
{
|
{
|
||||||
struct virtio_gpu_scanout *scanout = &g->scanout[scanout_id];
|
struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id];
|
||||||
struct virtio_gpu_simple_resource *res;
|
struct virtio_gpu_simple_resource *res;
|
||||||
DisplaySurface *ds = NULL;
|
DisplaySurface *ds = NULL;
|
||||||
|
|
||||||
|
@ -410,7 +350,7 @@ static void virtio_gpu_resource_destroy(VirtIOGPU *g,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (res->scanout_bitmask) {
|
if (res->scanout_bitmask) {
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||||
if (res->scanout_bitmask & (1 << i)) {
|
if (res->scanout_bitmask & (1 << i)) {
|
||||||
virtio_gpu_disable_scanout(g, i);
|
virtio_gpu_disable_scanout(g, i);
|
||||||
}
|
}
|
||||||
|
@ -540,7 +480,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
|
||||||
|
|
||||||
pixman_region_init_rect(&flush_region,
|
pixman_region_init_rect(&flush_region,
|
||||||
rf.r.x, rf.r.y, rf.r.width, rf.r.height);
|
rf.r.x, rf.r.y, rf.r.width, rf.r.height);
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||||
struct virtio_gpu_scanout *scanout;
|
struct virtio_gpu_scanout *scanout;
|
||||||
pixman_region16_t region, finalregion;
|
pixman_region16_t region, finalregion;
|
||||||
pixman_box16_t *extents;
|
pixman_box16_t *extents;
|
||||||
|
@ -548,7 +488,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
|
||||||
if (!(res->scanout_bitmask & (1 << i))) {
|
if (!(res->scanout_bitmask & (1 << i))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
scanout = &g->scanout[i];
|
scanout = &g->parent_obj.scanout[i];
|
||||||
|
|
||||||
pixman_region_init(&finalregion);
|
pixman_region_init(&finalregion);
|
||||||
pixman_region_init_rect(®ion, scanout->x, scanout->y,
|
pixman_region_init_rect(®ion, scanout->x, scanout->y,
|
||||||
|
@ -558,7 +498,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
|
||||||
pixman_region_translate(&finalregion, -scanout->x, -scanout->y);
|
pixman_region_translate(&finalregion, -scanout->x, -scanout->y);
|
||||||
extents = pixman_region_extents(&finalregion);
|
extents = pixman_region_extents(&finalregion);
|
||||||
/* work out the area we need to update for each console */
|
/* work out the area we need to update for each console */
|
||||||
dpy_gfx_update(g->scanout[i].con,
|
dpy_gfx_update(g->parent_obj.scanout[i].con,
|
||||||
extents->x1, extents->y1,
|
extents->x1, extents->y1,
|
||||||
extents->x2 - extents->x1,
|
extents->x2 - extents->x1,
|
||||||
extents->y2 - extents->y1);
|
extents->y2 - extents->y1);
|
||||||
|
@ -589,14 +529,14 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
||||||
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
|
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
|
||||||
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
|
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
|
||||||
|
|
||||||
if (ss.scanout_id >= g->conf.max_outputs) {
|
if (ss.scanout_id >= g->parent_obj.conf.max_outputs) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
|
||||||
__func__, ss.scanout_id);
|
__func__, ss.scanout_id);
|
||||||
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g->enable = 1;
|
g->parent_obj.enable = 1;
|
||||||
if (ss.resource_id == 0) {
|
if (ss.resource_id == 0) {
|
||||||
virtio_gpu_disable_scanout(g, ss.scanout_id);
|
virtio_gpu_disable_scanout(g, ss.scanout_id);
|
||||||
return;
|
return;
|
||||||
|
@ -627,7 +567,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scanout = &g->scanout[ss.scanout_id];
|
scanout = &g->parent_obj.scanout[ss.scanout_id];
|
||||||
|
|
||||||
format = pixman_image_get_format(res->image);
|
format = pixman_image_get_format(res->image);
|
||||||
bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
|
bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
|
||||||
|
@ -650,7 +590,8 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pixman_image_unref(rect);
|
pixman_image_unref(rect);
|
||||||
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
|
dpy_gfx_replace_surface(g->parent_obj.scanout[ss.scanout_id].con,
|
||||||
|
scanout->ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
ores = virtio_gpu_find_resource(g, scanout->resource_id);
|
ores = virtio_gpu_find_resource(g, scanout->resource_id);
|
||||||
|
@ -868,7 +809,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
|
||||||
while (!QTAILQ_EMPTY(&g->cmdq)) {
|
while (!QTAILQ_EMPTY(&g->cmdq)) {
|
||||||
cmd = QTAILQ_FIRST(&g->cmdq);
|
cmd = QTAILQ_FIRST(&g->cmdq);
|
||||||
|
|
||||||
if (g->renderer_blocked) {
|
if (g->parent_obj.renderer_blocked) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,14 +818,14 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
|
||||||
g, cmd);
|
g, cmd);
|
||||||
|
|
||||||
QTAILQ_REMOVE(&g->cmdq, cmd, next);
|
QTAILQ_REMOVE(&g->cmdq, cmd, next);
|
||||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
|
||||||
g->stats.requests++;
|
g->stats.requests++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd->finished) {
|
if (!cmd->finished) {
|
||||||
QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
|
QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
|
||||||
g->inflight++;
|
g->inflight++;
|
||||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
|
||||||
if (g->stats.max_inflight < g->inflight) {
|
if (g->stats.max_inflight < g->inflight) {
|
||||||
g->stats.max_inflight = g->inflight;
|
g->stats.max_inflight = g->inflight;
|
||||||
}
|
}
|
||||||
|
@ -896,6 +837,19 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_gl_unblock(VirtIOGPUBase *b)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(b);
|
||||||
|
|
||||||
|
#ifdef CONFIG_VIRGL
|
||||||
|
if (g->renderer_reset) {
|
||||||
|
g->renderer_reset = false;
|
||||||
|
virtio_gpu_virgl_reset(g);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
virtio_gpu_process_cmdq(g);
|
||||||
|
}
|
||||||
|
|
||||||
static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
{
|
{
|
||||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
@ -906,7 +860,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VIRGL
|
#ifdef CONFIG_VIRGL
|
||||||
if (!g->renderer_inited && g->use_virgl_renderer) {
|
if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) {
|
||||||
virtio_gpu_virgl_init(g);
|
virtio_gpu_virgl_init(g);
|
||||||
g->renderer_inited = true;
|
g->renderer_inited = true;
|
||||||
}
|
}
|
||||||
|
@ -924,7 +878,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
virtio_gpu_process_cmdq(g);
|
virtio_gpu_process_cmdq(g);
|
||||||
|
|
||||||
#ifdef CONFIG_VIRGL
|
#ifdef CONFIG_VIRGL
|
||||||
if (g->use_virgl_renderer) {
|
if (g->parent_obj.use_virgl_renderer) {
|
||||||
virtio_gpu_virgl_fence_poll(g);
|
virtio_gpu_virgl_fence_poll(g);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -933,7 +887,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
static void virtio_gpu_ctrl_bh(void *opaque)
|
static void virtio_gpu_ctrl_bh(void *opaque)
|
||||||
{
|
{
|
||||||
VirtIOGPU *g = opaque;
|
VirtIOGPU *g = opaque;
|
||||||
virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq);
|
virtio_gpu_handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
|
static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
@ -971,75 +925,9 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
static void virtio_gpu_cursor_bh(void *opaque)
|
static void virtio_gpu_cursor_bh(void *opaque)
|
||||||
{
|
{
|
||||||
VirtIOGPU *g = opaque;
|
VirtIOGPU *g = opaque;
|
||||||
virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq);
|
virtio_gpu_handle_cursor(&g->parent_obj.parent_obj, g->cursor_vq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_gpu_invalidate_display(void *opaque)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_update_display(void *opaque)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
|
|
||||||
{
|
|
||||||
VirtIOGPU *g = opaque;
|
|
||||||
|
|
||||||
if (idx >= g->conf.max_outputs) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
g->req_state[idx].x = info->xoff;
|
|
||||||
g->req_state[idx].y = info->yoff;
|
|
||||||
g->req_state[idx].width = info->width;
|
|
||||||
g->req_state[idx].height = info->height;
|
|
||||||
|
|
||||||
if (info->width && info->height) {
|
|
||||||
g->enabled_output_bitmask |= (1 << idx);
|
|
||||||
} else {
|
|
||||||
g->enabled_output_bitmask &= ~(1 << idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send event to guest */
|
|
||||||
virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_gl_block(void *opaque, bool block)
|
|
||||||
{
|
|
||||||
VirtIOGPU *g = opaque;
|
|
||||||
|
|
||||||
if (block) {
|
|
||||||
g->renderer_blocked++;
|
|
||||||
} else {
|
|
||||||
g->renderer_blocked--;
|
|
||||||
}
|
|
||||||
assert(g->renderer_blocked >= 0);
|
|
||||||
|
|
||||||
if (g->renderer_blocked == 0) {
|
|
||||||
#ifdef CONFIG_VIRGL
|
|
||||||
if (g->renderer_reset) {
|
|
||||||
g->renderer_reset = false;
|
|
||||||
virtio_gpu_virgl_reset(g);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
virtio_gpu_process_cmdq(g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const GraphicHwOps virtio_gpu_ops = {
|
|
||||||
.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,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_virtio_gpu_scanout = {
|
static const VMStateDescription vmstate_virtio_gpu_scanout = {
|
||||||
.name = "virtio-gpu-one-scanout",
|
.name = "virtio-gpu-one-scanout",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
|
@ -1062,10 +950,11 @@ static const VMStateDescription vmstate_virtio_gpu_scanouts = {
|
||||||
.name = "virtio-gpu-scanouts",
|
.name = "virtio-gpu-scanouts",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_INT32(enable, struct VirtIOGPU),
|
VMSTATE_INT32(parent_obj.enable, struct VirtIOGPU),
|
||||||
VMSTATE_UINT32_EQUAL(conf.max_outputs, struct VirtIOGPU, NULL),
|
VMSTATE_UINT32_EQUAL(parent_obj.conf.max_outputs,
|
||||||
VMSTATE_STRUCT_VARRAY_UINT32(scanout, struct VirtIOGPU,
|
struct VirtIOGPU, NULL),
|
||||||
conf.max_outputs, 1,
|
VMSTATE_STRUCT_VARRAY_UINT32(parent_obj.scanout, struct VirtIOGPU,
|
||||||
|
parent_obj.conf.max_outputs, 1,
|
||||||
vmstate_virtio_gpu_scanout,
|
vmstate_virtio_gpu_scanout,
|
||||||
struct virtio_gpu_scanout),
|
struct virtio_gpu_scanout),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
@ -1180,8 +1069,8 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
|
||||||
|
|
||||||
/* load & apply scanout state */
|
/* load & apply scanout state */
|
||||||
vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
|
vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||||
scanout = &g->scanout[i];
|
scanout = &g->parent_obj.scanout[i];
|
||||||
if (!scanout->resource_id) {
|
if (!scanout->resource_id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1210,84 +1099,35 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||||
VirtIOGPU *g = VIRTIO_GPU(qdev);
|
VirtIOGPU *g = VIRTIO_GPU(qdev);
|
||||||
bool have_virgl;
|
bool have_virgl;
|
||||||
Error *local_err = NULL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) {
|
|
||||||
error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g->use_virgl_renderer = false;
|
|
||||||
#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
|
#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
|
||||||
have_virgl = false;
|
have_virgl = false;
|
||||||
#else
|
#else
|
||||||
have_virgl = display_opengl;
|
have_virgl = display_opengl;
|
||||||
#endif
|
#endif
|
||||||
if (!have_virgl) {
|
if (!have_virgl) {
|
||||||
g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
|
g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
|
||||||
}
|
|
||||||
|
|
||||||
if (virtio_gpu_virgl_enabled(g->conf)) {
|
|
||||||
error_setg(&g->migration_blocker, "virgl is not yet migratable");
|
|
||||||
migrate_add_blocker(g->migration_blocker, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
error_propagate(errp, local_err);
|
|
||||||
error_free(g->migration_blocker);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs);
|
|
||||||
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
|
|
||||||
sizeof(struct virtio_gpu_config));
|
|
||||||
|
|
||||||
g->req_state[0].width = g->conf.xres;
|
|
||||||
g->req_state[0].height = g->conf.yres;
|
|
||||||
|
|
||||||
if (virtio_gpu_virgl_enabled(g->conf)) {
|
|
||||||
/* use larger control queue in 3d mode */
|
|
||||||
g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
|
|
||||||
g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
|
|
||||||
|
|
||||||
#if defined(CONFIG_VIRGL)
|
|
||||||
g->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g);
|
|
||||||
#else
|
|
||||||
g->virtio_config.num_capsets = 0;
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb);
|
#if defined(CONFIG_VIRGL)
|
||||||
g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
|
VIRTIO_GPU_BASE(g)->virtio_config.num_capsets =
|
||||||
|
virtio_gpu_virgl_get_num_capsets(g);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!virtio_gpu_base_device_realize(qdev,
|
||||||
|
virtio_gpu_handle_ctrl_cb,
|
||||||
|
virtio_gpu_handle_cursor_cb,
|
||||||
|
errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g->ctrl_vq = virtio_get_queue(vdev, 0);
|
||||||
|
g->cursor_vq = virtio_get_queue(vdev, 1);
|
||||||
g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
|
g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
|
||||||
g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
|
g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
|
||||||
QTAILQ_INIT(&g->reslist);
|
QTAILQ_INIT(&g->reslist);
|
||||||
QTAILQ_INIT(&g->cmdq);
|
QTAILQ_INIT(&g->cmdq);
|
||||||
QTAILQ_INIT(&g->fenceq);
|
QTAILQ_INIT(&g->fenceq);
|
||||||
|
|
||||||
g->enabled_output_bitmask = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
|
||||||
g->scanout[i].con =
|
|
||||||
graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
|
|
||||||
if (i > 0) {
|
|
||||||
dpy_gfx_replace_surface(g->scanout[i].con, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp)
|
|
||||||
{
|
|
||||||
VirtIOGPU *g = VIRTIO_GPU(qdev);
|
|
||||||
if (g->migration_blocker) {
|
|
||||||
migrate_del_blocker(g->migration_blocker);
|
|
||||||
error_free(g->migration_blocker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_gpu_instance_init(Object *obj)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_gpu_reset(VirtIODevice *vdev)
|
static void virtio_gpu_reset(VirtIODevice *vdev)
|
||||||
|
@ -1295,21 +1135,16 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
|
||||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
struct virtio_gpu_simple_resource *res, *tmp;
|
struct virtio_gpu_simple_resource *res, *tmp;
|
||||||
struct virtio_gpu_ctrl_command *cmd;
|
struct virtio_gpu_ctrl_command *cmd;
|
||||||
int i;
|
|
||||||
|
|
||||||
g->enable = 0;
|
#ifdef CONFIG_VIRGL
|
||||||
|
if (g->parent_obj.use_virgl_renderer) {
|
||||||
|
virtio_gpu_virgl_reset(g);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
|
QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
|
||||||
virtio_gpu_resource_destroy(g, res);
|
virtio_gpu_resource_destroy(g, res);
|
||||||
}
|
}
|
||||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
|
||||||
g->scanout[i].resource_id = 0;
|
|
||||||
g->scanout[i].width = 0;
|
|
||||||
g->scanout[i].height = 0;
|
|
||||||
g->scanout[i].x = 0;
|
|
||||||
g->scanout[i].y = 0;
|
|
||||||
g->scanout[i].ds = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!QTAILQ_EMPTY(&g->cmdq)) {
|
while (!QTAILQ_EMPTY(&g->cmdq)) {
|
||||||
cmd = QTAILQ_FIRST(&g->cmdq);
|
cmd = QTAILQ_FIRST(&g->cmdq);
|
||||||
|
@ -1325,15 +1160,37 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VIRGL
|
#ifdef CONFIG_VIRGL
|
||||||
if (g->use_virgl_renderer) {
|
if (g->parent_obj.use_virgl_renderer) {
|
||||||
if (g->renderer_blocked) {
|
if (g->parent_obj.renderer_blocked) {
|
||||||
g->renderer_reset = true;
|
g->renderer_reset = true;
|
||||||
} else {
|
} else {
|
||||||
virtio_gpu_virgl_reset(g);
|
virtio_gpu_virgl_reset(g);
|
||||||
}
|
}
|
||||||
g->use_virgl_renderer = 0;
|
g->parent_obj.use_virgl_renderer = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
|
||||||
|
{
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
|
||||||
|
|
||||||
|
memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||||
|
{
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
|
||||||
|
const struct virtio_gpu_config *vgconfig =
|
||||||
|
(const struct virtio_gpu_config *)config;
|
||||||
|
|
||||||
|
if (vgconfig->events_clear) {
|
||||||
|
g->virtio_config.events_read &= ~vgconfig->events_clear;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1364,18 +1221,15 @@ static const VMStateDescription vmstate_virtio_gpu = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static Property virtio_gpu_properties[] = {
|
static Property virtio_gpu_properties[] = {
|
||||||
DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
|
VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf),
|
||||||
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf.max_hostmem, 256 * MiB),
|
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem,
|
||||||
|
256 * MiB),
|
||||||
#ifdef CONFIG_VIRGL
|
#ifdef CONFIG_VIRGL
|
||||||
DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags,
|
DEFINE_PROP_BIT("virgl", VirtIOGPU, parent_obj.conf.flags,
|
||||||
VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),
|
VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),
|
||||||
DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags,
|
DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags,
|
||||||
VIRTIO_GPU_FLAG_STATS_ENABLED, false),
|
VIRTIO_GPU_FLAG_STATS_ENABLED, false),
|
||||||
#endif
|
#endif
|
||||||
DEFINE_PROP_BIT("edid", VirtIOGPU, conf.flags,
|
|
||||||
VIRTIO_GPU_FLAG_EDID_ENABLED, false),
|
|
||||||
DEFINE_PROP_UINT32("xres", VirtIOGPU, conf.xres, 1024),
|
|
||||||
DEFINE_PROP_UINT32("yres", VirtIOGPU, conf.yres, 768),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1383,27 +1237,22 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||||
|
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
|
||||||
|
|
||||||
|
vgc->gl_unblock = virtio_gpu_gl_unblock;
|
||||||
vdc->realize = virtio_gpu_device_realize;
|
vdc->realize = virtio_gpu_device_realize;
|
||||||
vdc->unrealize = virtio_gpu_device_unrealize;
|
vdc->reset = virtio_gpu_reset;
|
||||||
vdc->get_config = virtio_gpu_get_config;
|
vdc->get_config = virtio_gpu_get_config;
|
||||||
vdc->set_config = virtio_gpu_set_config;
|
vdc->set_config = virtio_gpu_set_config;
|
||||||
vdc->get_features = virtio_gpu_get_features;
|
|
||||||
vdc->set_features = virtio_gpu_set_features;
|
|
||||||
|
|
||||||
vdc->reset = virtio_gpu_reset;
|
|
||||||
|
|
||||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
|
||||||
dc->props = virtio_gpu_properties;
|
|
||||||
dc->vmsd = &vmstate_virtio_gpu;
|
dc->vmsd = &vmstate_virtio_gpu;
|
||||||
dc->hotpluggable = false;
|
dc->props = virtio_gpu_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo virtio_gpu_info = {
|
static const TypeInfo virtio_gpu_info = {
|
||||||
.name = TYPE_VIRTIO_GPU,
|
.name = TYPE_VIRTIO_GPU,
|
||||||
.parent = TYPE_VIRTIO_DEVICE,
|
.parent = TYPE_VIRTIO_GPU_BASE,
|
||||||
.instance_size = sizeof(VirtIOGPU),
|
.instance_size = sizeof(VirtIOGPU),
|
||||||
.instance_init = virtio_gpu_instance_init,
|
|
||||||
.class_init = virtio_gpu_class_init,
|
.class_init = virtio_gpu_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1413,26 +1262,3 @@ static void virtio_register_types(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(virtio_register_types)
|
type_init(virtio_register_types)
|
||||||
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408);
|
|
||||||
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32);
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24);
|
|
||||||
|
|
|
@ -32,8 +32,9 @@ typedef struct VirtIOVGAClass {
|
||||||
static void virtio_vga_invalidate_display(void *opaque)
|
static void virtio_vga_invalidate_display(void *opaque)
|
||||||
{
|
{
|
||||||
VirtIOVGA *vvga = opaque;
|
VirtIOVGA *vvga = opaque;
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev);
|
||||||
|
|
||||||
if (vvga->vdev.enable) {
|
if (g->enable) {
|
||||||
virtio_gpu_ops.invalidate(&vvga->vdev);
|
virtio_gpu_ops.invalidate(&vvga->vdev);
|
||||||
} else {
|
} else {
|
||||||
vvga->vga.hw_ops->invalidate(&vvga->vga);
|
vvga->vga.hw_ops->invalidate(&vvga->vga);
|
||||||
|
@ -43,8 +44,9 @@ static void virtio_vga_invalidate_display(void *opaque)
|
||||||
static void virtio_vga_update_display(void *opaque)
|
static void virtio_vga_update_display(void *opaque)
|
||||||
{
|
{
|
||||||
VirtIOVGA *vvga = opaque;
|
VirtIOVGA *vvga = opaque;
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev);
|
||||||
|
|
||||||
if (vvga->vdev.enable) {
|
if (g->enable) {
|
||||||
virtio_gpu_ops.gfx_update(&vvga->vdev);
|
virtio_gpu_ops.gfx_update(&vvga->vdev);
|
||||||
} else {
|
} else {
|
||||||
vvga->vga.hw_ops->gfx_update(&vvga->vga);
|
vvga->vga.hw_ops->gfx_update(&vvga->vga);
|
||||||
|
@ -54,8 +56,9 @@ static void virtio_vga_update_display(void *opaque)
|
||||||
static void virtio_vga_text_update(void *opaque, console_ch_t *chardata)
|
static void virtio_vga_text_update(void *opaque, console_ch_t *chardata)
|
||||||
{
|
{
|
||||||
VirtIOVGA *vvga = opaque;
|
VirtIOVGA *vvga = opaque;
|
||||||
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev);
|
||||||
|
|
||||||
if (vvga->vdev.enable) {
|
if (g->enable) {
|
||||||
if (virtio_gpu_ops.text_update) {
|
if (virtio_gpu_ops.text_update) {
|
||||||
virtio_gpu_ops.text_update(&vvga->vdev, chardata);
|
virtio_gpu_ops.text_update(&vvga->vdev, chardata);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +111,7 @@ static const VMStateDescription vmstate_virtio_vga = {
|
||||||
static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
{
|
{
|
||||||
VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev);
|
VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev);
|
||||||
VirtIOGPU *g = &vvga->vdev;
|
VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev);
|
||||||
VGACommonState *vga = &vvga->vga;
|
VGACommonState *vga = &vvga->vga;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
|
|
@ -22,6 +22,14 @@
|
||||||
|
|
||||||
#include "standard-headers/linux/virtio_gpu.h"
|
#include "standard-headers/linux/virtio_gpu.h"
|
||||||
|
|
||||||
|
#define TYPE_VIRTIO_GPU_BASE "virtio-gpu-base"
|
||||||
|
#define VIRTIO_GPU_BASE(obj) \
|
||||||
|
OBJECT_CHECK(VirtIOGPUBase, (obj), TYPE_VIRTIO_GPU_BASE)
|
||||||
|
#define VIRTIO_GPU_BASE_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(VirtIOGPUBaseClass, obj, TYPE_VIRTIO_GPU_BASE)
|
||||||
|
#define VIRTIO_GPU_BASE_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(VirtIOGPUBaseClass, klass, TYPE_VIRTIO_GPU_BASE)
|
||||||
|
|
||||||
#define TYPE_VIRTIO_GPU "virtio-gpu-device"
|
#define TYPE_VIRTIO_GPU "virtio-gpu-device"
|
||||||
#define VIRTIO_GPU(obj) \
|
#define VIRTIO_GPU(obj) \
|
||||||
OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU)
|
OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU)
|
||||||
|
@ -58,7 +66,7 @@ struct virtio_gpu_requested_state {
|
||||||
int x, y;
|
int x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum virtio_gpu_conf_flags {
|
enum virtio_gpu_base_conf_flags {
|
||||||
VIRTIO_GPU_FLAG_VIRGL_ENABLED = 1,
|
VIRTIO_GPU_FLAG_VIRGL_ENABLED = 1,
|
||||||
VIRTIO_GPU_FLAG_STATS_ENABLED,
|
VIRTIO_GPU_FLAG_STATS_ENABLED,
|
||||||
VIRTIO_GPU_FLAG_EDID_ENABLED,
|
VIRTIO_GPU_FLAG_EDID_ENABLED,
|
||||||
|
@ -71,8 +79,7 @@ enum virtio_gpu_conf_flags {
|
||||||
#define virtio_gpu_edid_enabled(_cfg) \
|
#define virtio_gpu_edid_enabled(_cfg) \
|
||||||
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_EDID_ENABLED))
|
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_EDID_ENABLED))
|
||||||
|
|
||||||
struct virtio_gpu_conf {
|
struct virtio_gpu_base_conf {
|
||||||
uint64_t max_hostmem;
|
|
||||||
uint32_t max_outputs;
|
uint32_t max_outputs;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint32_t xres;
|
uint32_t xres;
|
||||||
|
@ -88,31 +95,55 @@ struct virtio_gpu_ctrl_command {
|
||||||
QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
|
QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct VirtIOGPU {
|
typedef struct VirtIOGPUBase {
|
||||||
VirtIODevice parent_obj;
|
VirtIODevice parent_obj;
|
||||||
|
|
||||||
QEMUBH *ctrl_bh;
|
Error *migration_blocker;
|
||||||
QEMUBH *cursor_bh;
|
|
||||||
|
struct virtio_gpu_base_conf conf;
|
||||||
|
struct virtio_gpu_config virtio_config;
|
||||||
|
|
||||||
|
bool use_virgl_renderer;
|
||||||
|
int renderer_blocked;
|
||||||
|
int enable;
|
||||||
|
|
||||||
|
struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
|
||||||
|
|
||||||
|
int enabled_output_bitmask;
|
||||||
|
struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS];
|
||||||
|
} VirtIOGPUBase;
|
||||||
|
|
||||||
|
typedef struct VirtIOGPUBaseClass {
|
||||||
|
VirtioDeviceClass parent;
|
||||||
|
|
||||||
|
void (*gl_unblock)(VirtIOGPUBase *g);
|
||||||
|
} VirtIOGPUBaseClass;
|
||||||
|
|
||||||
|
#define VIRTIO_GPU_BASE_PROPERTIES(_state, _conf) \
|
||||||
|
DEFINE_PROP_UINT32("max_outputs", _state, _conf.max_outputs, 1), \
|
||||||
|
DEFINE_PROP_BIT("edid", _state, _conf.flags, \
|
||||||
|
VIRTIO_GPU_FLAG_EDID_ENABLED, false), \
|
||||||
|
DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1024), \
|
||||||
|
DEFINE_PROP_UINT32("yres", _state, _conf.yres, 768)
|
||||||
|
|
||||||
|
typedef struct VirtIOGPU {
|
||||||
|
VirtIOGPUBase parent_obj;
|
||||||
|
|
||||||
|
uint64_t conf_max_hostmem;
|
||||||
|
|
||||||
VirtQueue *ctrl_vq;
|
VirtQueue *ctrl_vq;
|
||||||
VirtQueue *cursor_vq;
|
VirtQueue *cursor_vq;
|
||||||
|
|
||||||
int enable;
|
QEMUBH *ctrl_bh;
|
||||||
|
QEMUBH *cursor_bh;
|
||||||
|
|
||||||
QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist;
|
QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist;
|
||||||
QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq;
|
QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq;
|
||||||
QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
|
QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
|
||||||
|
|
||||||
struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
|
|
||||||
struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS];
|
|
||||||
|
|
||||||
struct virtio_gpu_conf conf;
|
|
||||||
uint64_t hostmem;
|
uint64_t hostmem;
|
||||||
int enabled_output_bitmask;
|
|
||||||
struct virtio_gpu_config virtio_config;
|
|
||||||
|
|
||||||
bool use_virgl_renderer;
|
|
||||||
bool renderer_inited;
|
bool renderer_inited;
|
||||||
int renderer_blocked;
|
|
||||||
bool renderer_reset;
|
bool renderer_reset;
|
||||||
QEMUTimer *fence_poll;
|
QEMUTimer *fence_poll;
|
||||||
QEMUTimer *print_stats;
|
QEMUTimer *print_stats;
|
||||||
|
@ -124,8 +155,6 @@ typedef struct VirtIOGPU {
|
||||||
uint32_t req_3d;
|
uint32_t req_3d;
|
||||||
uint32_t bytes_3d;
|
uint32_t bytes_3d;
|
||||||
} stats;
|
} stats;
|
||||||
|
|
||||||
Error *migration_blocker;
|
|
||||||
} VirtIOGPU;
|
} VirtIOGPU;
|
||||||
|
|
||||||
extern const GraphicHwOps virtio_gpu_ops;
|
extern const GraphicHwOps virtio_gpu_ops;
|
||||||
|
@ -148,6 +177,15 @@ extern const GraphicHwOps virtio_gpu_ops;
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/* virtio-gpu-base.c */
|
||||||
|
bool virtio_gpu_base_device_realize(DeviceState *qdev,
|
||||||
|
VirtIOHandleOutput ctrl_cb,
|
||||||
|
VirtIOHandleOutput cursor_cb,
|
||||||
|
Error **errp);
|
||||||
|
void virtio_gpu_base_reset(VirtIOGPUBase *g);
|
||||||
|
void virtio_gpu_base_fill_display_info(VirtIOGPUBase *g,
|
||||||
|
struct virtio_gpu_resp_display_info *dpy_info);
|
||||||
|
|
||||||
/* virtio-gpu.c */
|
/* virtio-gpu.c */
|
||||||
void virtio_gpu_ctrl_response(VirtIOGPU *g,
|
void virtio_gpu_ctrl_response(VirtIOGPU *g,
|
||||||
struct virtio_gpu_ctrl_command *cmd,
|
struct virtio_gpu_ctrl_command *cmd,
|
||||||
|
@ -175,4 +213,5 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g);
|
||||||
void virtio_gpu_virgl_reset(VirtIOGPU *g);
|
void virtio_gpu_virgl_reset(VirtIOGPU *g);
|
||||||
int virtio_gpu_virgl_init(VirtIOGPU *g);
|
int virtio_gpu_virgl_init(VirtIOGPU *g);
|
||||||
int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g);
|
int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue