aboutsummaryrefslogtreecommitdiff
path: root/hw/display/virtio-gpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/display/virtio-gpu.c')
-rw-r--r--hw/display/virtio-gpu.c183
1 files changed, 96 insertions, 87 deletions
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 3281842..0a1a625 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -14,12 +14,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/iov.h"
-#include "sysemu/cpus.h"
+#include "system/cpus.h"
#include "ui/console.h"
#include "ui/rect.h"
#include "trace.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
+#include "system/dma.h"
+#include "system/system.h"
#include "hw/virtio/virtio.h"
#include "migration/qemu-file-types.h"
#include "hw/virtio/virtio-gpu.h"
@@ -28,6 +28,7 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
+#include "qemu/memfd.h"
#include "qemu/module.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -238,16 +239,6 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
return height * stride;
}
-#ifdef WIN32
-static void
-win32_pixman_image_destroy(pixman_image_t *image, void *data)
-{
- HANDLE handle = data;
-
- qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn);
-}
-#endif
-
static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
@@ -294,28 +285,20 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
- void *bits = NULL;
-#ifdef WIN32
- bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
- if (!bits) {
+ if (!qemu_pixman_image_new_shareable(
+ &res->image,
+ &res->share_handle,
+ "virtio-gpu res",
+ pformat,
+ c2d.width,
+ c2d.height,
+ c2d.height ? res->hostmem / c2d.height : 0,
+ &error_warn)) {
goto end;
}
-#endif
- res->image = pixman_image_create_bits(
- pformat,
- c2d.width,
- c2d.height,
- bits, c2d.height ? res->hostmem / c2d.height : 0);
-#ifdef WIN32
- if (res->image) {
- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
- }
-#endif
}
-#ifdef WIN32
end:
-#endif
if (!res->image) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: resource creation failed %d %d %d\n",
@@ -379,7 +362,7 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
}
-static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
+void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
{
struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id];
struct virtio_gpu_simple_resource *res;
@@ -596,11 +579,11 @@ static void virtio_unref_resource(pixman_image_t *image, void *data)
pixman_image_unref(data);
}
-static void virtio_gpu_update_scanout(VirtIOGPU *g,
- uint32_t scanout_id,
- struct virtio_gpu_simple_resource *res,
- struct virtio_gpu_framebuffer *fb,
- struct virtio_gpu_rect *r)
+void virtio_gpu_update_scanout(VirtIOGPU *g,
+ uint32_t scanout_id,
+ struct virtio_gpu_simple_resource *res,
+ struct virtio_gpu_framebuffer *fb,
+ struct virtio_gpu_rect *r)
{
struct virtio_gpu_simple_resource *ores;
struct virtio_gpu_scanout *scanout;
@@ -686,9 +669,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
/* realloc the surface ptr */
scanout->ds = qemu_create_displaysurface_pixman(rect);
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset);
-#endif
+ qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, fb->offset);
pixman_image_unref(rect);
dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con,
@@ -740,13 +721,47 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
&fb, res, &ss.r, &cmd->error);
}
+bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
+ struct virtio_gpu_set_scanout_blob *ss,
+ uint64_t blob_size)
+{
+ uint64_t fbend;
+
+ fb->format = virtio_gpu_get_pixman_format(ss->format);
+ if (!fb->format) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: host couldn't handle guest format %d\n",
+ __func__, ss->format);
+ return false;
+ }
+
+ fb->bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb->format), 8);
+ fb->width = ss->width;
+ fb->height = ss->height;
+ fb->stride = ss->strides[0];
+ fb->offset = ss->offsets[0] + ss->r.x * fb->bytes_pp + ss->r.y * fb->stride;
+
+ fbend = fb->offset;
+ fbend += (uint64_t) fb->stride * ss->r.height;
+
+ if (fbend > blob_size) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: fb end out of range\n",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+
+
static void virtio_gpu_set_scanout_blob(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
struct virtio_gpu_simple_resource *res;
struct virtio_gpu_framebuffer fb = { 0 };
struct virtio_gpu_set_scanout_blob ss;
- uint64_t fbend;
VIRTIO_GPU_FILL_CMD(ss);
virtio_gpu_scanout_blob_bswap(&ss);
@@ -772,28 +787,7 @@ static void virtio_gpu_set_scanout_blob(VirtIOGPU *g,
return;
}
- fb.format = virtio_gpu_get_pixman_format(ss.format);
- if (!fb.format) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: host couldn't handle guest format %d\n",
- __func__, ss.format);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
- return;
- }
-
- fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8);
- fb.width = ss.width;
- fb.height = ss.height;
- fb.stride = ss.strides[0];
- fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride;
-
- fbend = fb.offset;
- fbend += fb.stride * (ss.r.height - 1);
- fbend += fb.bytes_pp * ss.r.width;
- if (fbend > res->blob_size) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: fb end out of range\n",
- __func__);
+ if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->blob_size)) {
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
return;
}
@@ -1053,6 +1047,12 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
/* process command */
vgc->process_cmd(g, cmd);
+ /* command suspended */
+ if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
+ trace_virtio_gpu_cmd_suspended(cmd->cmd_hdr.type);
+ break;
+ }
+
QTAILQ_REMOVE(&g->cmdq, cmd, next);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
g->stats.requests++;
@@ -1065,7 +1065,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
if (g->stats.max_inflight < g->inflight) {
g->stats.max_inflight = g->inflight;
}
- fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
+ trace_virtio_gpu_inc_inflight_fences(g->inflight);
}
} else {
g_free(cmd);
@@ -1085,7 +1085,7 @@ static void virtio_gpu_process_fenceq(VirtIOGPU *g)
g_free(cmd);
g->inflight--;
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
- fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
+ trace_virtio_gpu_dec_inflight_fences(g->inflight);
}
}
}
@@ -1284,7 +1284,6 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
VirtIOGPU *g = opaque;
struct virtio_gpu_simple_resource *res;
uint32_t resource_id, pformat;
- void *bits = NULL;
int i;
g->hostmem = 0;
@@ -1311,24 +1310,17 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
}
res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
-#ifdef WIN32
- bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
- if (!bits) {
- g_free(res);
- return -EINVAL;
- }
-#endif
- res->image = pixman_image_create_bits(
- pformat,
- res->width, res->height,
- bits, res->height ? res->hostmem / res->height : 0);
- if (!res->image) {
+ if (!qemu_pixman_image_new_shareable(&res->image,
+ &res->share_handle,
+ "virtio-gpu res",
+ pformat,
+ res->width,
+ res->height,
+ res->height ? res->hostmem / res->height : 0,
+ &error_warn)) {
g_free(res);
return -EINVAL;
}
-#ifdef WIN32
- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
-#endif
res->addrs = g_new(uint64_t, res->iov_cnt);
res->iov = g_new(struct iovec, res->iov_cnt);
@@ -1461,9 +1453,7 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
return -EINVAL;
}
scanout->ds = qemu_create_displaysurface_pixman(res->image);
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
-#endif
+ qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, 0);
dpy_gfx_replace_surface(scanout->con, scanout->ds);
}
@@ -1484,15 +1474,35 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
if (virtio_gpu_blob_enabled(g->parent_obj.conf)) {
if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) &&
+ !virtio_gpu_virgl_enabled(g->parent_obj.conf) &&
!virtio_gpu_have_udmabuf()) {
error_setg(errp, "need rutabaga or udmabuf for blob resources");
return;
}
+#ifdef VIRGL_VERSION_MAJOR
+ #if VIRGL_VERSION_MAJOR < 1
if (virtio_gpu_virgl_enabled(g->parent_obj.conf)) {
- error_setg(errp, "blobs and virgl are not compatible (yet)");
+ error_setg(errp, "old virglrenderer, blob resources unsupported");
return;
}
+ #endif
+#endif
+ }
+
+ if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
+#ifdef VIRGL_VERSION_MAJOR
+ #if VIRGL_VERSION_MAJOR >= 1
+ if (!virtio_gpu_blob_enabled(g->parent_obj.conf) ||
+ !virtio_gpu_hostmem_enabled(g->parent_obj.conf)) {
+ error_setg(errp, "venus requires enabled blob and hostmem options");
+ return;
+ }
+ #else
+ error_setg(errp, "old virglrenderer, venus unsupported");
+ return;
+ #endif
+#endif
}
if (!virtio_gpu_base_device_realize(qdev,
@@ -1664,7 +1674,7 @@ static const VMStateDescription vmstate_virtio_gpu = {
.post_load = virtio_gpu_post_load,
};
-static Property virtio_gpu_properties[] = {
+static const Property virtio_gpu_properties[] = {
VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf),
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem,
256 * MiB),
@@ -1672,10 +1682,9 @@ static Property virtio_gpu_properties[] = {
VIRTIO_GPU_FLAG_BLOB_ENABLED, false),
DEFINE_PROP_SIZE("hostmem", VirtIOGPU, parent_obj.conf.hostmem, 0),
DEFINE_PROP_UINT8("x-scanout-vmstate-version", VirtIOGPU, scanout_vmstate_version, 2),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_gpu_class_init(ObjectClass *klass, void *data)
+static void virtio_gpu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);