From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48472) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YXbPy-00088E-JL for qemu-devel@nongnu.org; Mon, 16 Mar 2015 16:15:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YXbPu-0006pf-C8 for qemu-devel@nongnu.org; Mon, 16 Mar 2015 16:15:18 -0400 Received: from mx1.redhat.com ([209.132.183.28]:40543) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YXbPu-0006n3-13 for qemu-devel@nongnu.org; Mon, 16 Mar 2015 16:15:14 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t2GKFBV2005025 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Mon, 16 Mar 2015 16:15:12 -0400 Message-ID: <550739CE.90903@redhat.com> Date: Mon, 16 Mar 2015 16:15:10 -0400 From: Max Reitz MIME-Version: 1.0 References: <1426240033-24673-1-git-send-email-kraxel@redhat.com> <1426240033-24673-4-git-send-email-kraxel@redhat.com> In-Reply-To: <1426240033-24673-4-git-send-email-kraxel@redhat.com> Content-Type: text/plain; charset=iso-8859-15; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 2/9] virtio-gpu/2d: add virtio gpu core code List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Gerd Hoffmann , qemu-devel@nongnu.org Cc: Dave Airlie , "Michael S. Tsirkin" On 2015-03-13 at 05:47, Gerd Hoffmann wrote: > This patch adds the core code for virtio gpu emulation, > covering 2d support. > > Written by Dave Airlie and Gerd Hoffmann. > > Signed-off-by: Dave Airlie > Signed-off-by: Gerd Hoffmann > --- > hw/display/Makefile.objs | 2 + > hw/display/virtio-gpu.c | 923 +++++++++++++++++++++++++++++++++++++++++ > include/hw/virtio/virtio-gpu.h | 147 +++++++ > trace-events | 14 + > 4 files changed, 1086 insertions(+) > create mode 100644 hw/display/virtio-gpu.c > create mode 100644 include/hw/virtio/virtio-gpu.h > > diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c > new file mode 100644 > index 0000000..ab71291 > --- /dev/null > +++ b/hw/display/virtio-gpu.c [snip] > +static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) > +{ > + VirtIODevice *vdev = VIRTIO_DEVICE(qdev); > + VirtIOGPU *g = VIRTIO_GPU(qdev); > + int i; > + > + g->config_size = sizeof(struct virtio_gpu_config); > + g->virtio_config.num_scanouts = g->conf.max_outputs; > + virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, > + g->config_size); > + > + g->req_state[0].width = 1024; > + g->req_state[0].height = 768; > + > + g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb); > + g->cursor_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_cursor_cb); > + > + g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g); > + g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g); > + QTAILQ_INIT(&g->reslist); > + QTAILQ_INIT(&g->fenceq); > + > + g->enabled_output_bitmask = 1; > + g->qdev = qdev; > + > + 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); GTK can't cope very well with NULL surfaces (read: after patch 7 (when using -vga virtio finally works) "x86_64-softmmu/qemu-system-x86_64 -vga virtio -display gtk" segfaults). With SDL (SDL2), it works fine. A simple block like "if (!surface) { if (vc->gfx.surface) { cairo_surface_destroy(vc->gfx.surface); } vc->gfx.surface = NULL; return; }" at the beginning of gd_switch() in ui/gtk.c seems to work for me, though. A similar problem exists with SDL1: Using Ctrl-Alt-2 segfaults (which is due to new_surface being NULL in sdl_switch(), and thus new_surface->format in the very first statement failing). Max > + } > + } > +} > + > +static void virtio_gpu_instance_init(Object *obj) > +{ > +} > + > +static void virtio_gpu_reset(VirtIODevice *vdev) > +{ > + VirtIOGPU *g = VIRTIO_GPU(vdev); > + struct virtio_gpu_simple_resource *res, *tmp; > + int i; > + > + g->enable = 0; > + > + QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { > + virtio_gpu_resource_destroy(g, res); > + } > + for (i = 0; i < g->conf.max_outputs; i++) { > +#if 0 > + g->req_state[i].x = 0; > + g->req_state[i].y = 0; > + if (i == 0) { > + g->req_state[0].width = 1024; > + g->req_state[0].height = 768; > + } else { > + g->req_state[i].width = 0; > + g->req_state[i].height = 0; > + } > +#endif > + 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; > + } > + g->enabled_output_bitmask = 1; > +} > + > +static Property virtio_gpu_properties[] = { > + DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPU, conf), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void virtio_gpu_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); > + > + vdc->realize = virtio_gpu_device_realize; > + vdc->get_config = virtio_gpu_get_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; > + > + dc->props = virtio_gpu_properties; > +} > + > +static const TypeInfo virtio_gpu_info = { > + .name = TYPE_VIRTIO_GPU, > + .parent = TYPE_VIRTIO_DEVICE, > + .instance_size = sizeof(VirtIOGPU), > + .instance_init = virtio_gpu_instance_init, > + .class_init = virtio_gpu_class_init, > +}; > + > +static void virtio_register_types(void) > +{ > + type_register_static(&virtio_gpu_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); > diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h > new file mode 100644 > index 0000000..5d26ca9 > --- /dev/null > +++ b/include/hw/virtio/virtio-gpu.h > @@ -0,0 +1,147 @@ > +/* > + * Virtio GPU Device > + * > + * Copyright Red Hat, Inc. 2013-2014 > + * > + * Authors: > + * Dave Airlie > + * Gerd Hoffmann > + * > + * This work is licensed under the terms of the GNU GPL, version 2. > + * See the COPYING file in the top-level directory. > + */ > + > +#ifndef _QEMU_VIRTIO_VGA_H > +#define _QEMU_VIRTIO_VGA_H > + > +#include "qemu/queue.h" > +#include "ui/qemu-pixman.h" > +#include "ui/console.h" > +#include "hw/virtio/virtio.h" > +#include "hw/pci/pci.h" > + > +#include "hw/virtio/virtgpu_hw.h" > +#define TYPE_VIRTIO_GPU "virtio-gpu-device" > +#define VIRTIO_GPU(obj) \ > + OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU) > + > +#define VIRTIO_ID_GPU 16 > + > +#define VIRTIO_GPU_MAX_RES 16 > + > +#define VIRTIO_GPU_MAX_SCANOUT 4 > + > +struct virtio_gpu_simple_resource { > + uint32_t resource_id; > + uint32_t width; > + uint32_t height; > + uint32_t format; > + struct iovec *iov; > + unsigned int iov_cnt; > + uint32_t scanout_bitmask; > + pixman_image_t *image; > + QTAILQ_ENTRY(virtio_gpu_simple_resource) next; > +}; > + > +struct virtio_gpu_scanout { > + QemuConsole *con; > + DisplaySurface *ds; > + uint32_t width, height; > + int x, y; > + int invalidate; > + uint32_t resource_id; > + QEMUCursor *current_cursor; > +}; > + > +struct virtio_gpu_requested_state { > + uint32_t width, height; > + int x, y; > +}; > + > +struct virtio_gpu_conf { > + uint32_t max_outputs; > +}; > + > +struct virtio_gpu_ctrl_command { > + VirtQueueElement elem; > + VirtQueue *vq; > + struct virtio_gpu_ctrl_hdr cmd_hdr; > + uint32_t error; > + bool finished; > + QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; > +}; > + > +typedef struct VirtIOGPU { > + VirtIODevice parent_obj; > + > + QEMUBH *ctrl_bh; > + QEMUBH *cursor_bh; > + VirtQueue *ctrl_vq; > + VirtQueue *cursor_vq; > + > + int enable; > + > + int config_size; > + DeviceState *qdev; > + > + QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; > + QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; > + > + struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUT]; > + struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUT]; > + > + struct virtio_gpu_conf conf; > + int enabled_output_bitmask; > + struct virtio_gpu_config virtio_config; > + > + QEMUTimer *fence_poll; > + QEMUTimer *print_stats; > + > + struct { > + uint32_t inflight; > + uint32_t max_inflight; > + uint32_t requests; > + uint32_t req_3d; > + uint32_t bytes_3d; > + } stats; > +} VirtIOGPU; > + > +extern const GraphicHwOps virtio_gpu_ops; > + > +/* to share between PCI and VGA */ > +#define DEFINE_VIRTIO_GPU_PCI_PROPERTIES(_state) \ > + DEFINE_PROP_BIT("ioeventfd", _state, flags, \ > + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), \ > + DEFINE_PROP_UINT32("vectors", _state, nvectors, 3) > + > +#define DEFINE_VIRTIO_GPU_PROPERTIES(_state, _conf_field) \ > + DEFINE_PROP_UINT32("max_outputs", _state, _conf_field.max_outputs, 2) > + > +#define VIRTIO_GPU_FILL_CMD(out) do { \ > + size_t s; \ > + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ > + &out, sizeof(out)); \ > + if (s != sizeof(out)) { \ > + qemu_log_mask(LOG_GUEST_ERROR, \ > + "%s: command size incorrect %zu vs %zu\n", \ > + __func__, s, sizeof(out)); \ > + return; \ > + } \ > + } while (0) > + > +/* virtio-gpu.c */ > +void virtio_gpu_ctrl_response(VirtIOGPU *g, > + struct virtio_gpu_ctrl_command *cmd, > + struct virtio_gpu_ctrl_hdr *resp, > + size_t resp_len); > +void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, > + struct virtio_gpu_ctrl_command *cmd, > + enum virtio_gpu_ctrl_type type); > +void virtio_gpu_get_display_info(VirtIOGPU *g, > + struct virtio_gpu_ctrl_command *cmd); > +int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, > + struct virtio_gpu_ctrl_command *cmd, > + struct iovec **iov); > +void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count); > + > +#endif > diff --git a/trace-events b/trace-events > index 30eba92..a3d6fff 100644 > --- a/trace-events > +++ b/trace-events > @@ -1167,6 +1167,20 @@ vmware_scratch_read(uint32_t index, uint32_t value) "index %d, value 0x%x" > vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x" > vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp" > > +# hw/display/virtio-gpu.c > +virtio_gpu_cmd_get_display_info(void) "" > +virtio_gpu_cmd_get_caps(void) "" > +virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d" > +virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d" > +virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d" > +virtio_gpu_cmd_res_unref(uint32_t res) "res 0x%x" > +virtio_gpu_cmd_res_back_attach(uint32_t res) "res 0x%x" > +virtio_gpu_cmd_res_back_detach(uint32_t res) "res 0x%x" > +virtio_gpu_cmd_res_xfer_toh_2d(uint32_t res) "res 0x%x" > +virtio_gpu_cmd_res_flush(uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "res 0x%x, w %d, h %d, x %d, y %d" > +virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x" > +virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 > + > # savevm.c > qemu_loadvm_state_section(unsigned int section_type) "%d" > qemu_loadvm_state_section_partend(uint32_t section_id) "%u"