edid: display id support (for 5k+), bugfixes.

virtio-gpu: iommu fix, device split.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmCZMyQACgkQTLbY7tPo
 cThXcQ//RnVazAQjvHHw+IEwmoNuz2y6ips68JwRBcYwk6JXzjorG/Lur+qf4hAr
 GJlhTOMH6jf2fkb+f69PgRbKnS0eO69OFLlZvgCYhi7rKwIVIZI3cuMScpEDBhu5
 yxVGgjWF8x8WfQOOugC5lEZ8GDOkXub4HTzPxd3kVb821KlojPr/HJH/DrzDaoTT
 h4l/Xko94vgTQhT788KRE97TjsejkpsfdWJUfa3/mlj+9zyU/TYtV2XxsQW5fWxJ
 D+BbgyuJ80B6EX8yHHCTQkL4ZsgHwuZdGpMS8ybqpkZlUaHUZcf01a0T9/Piobmr
 XgSvbO862VLIijJrD8EbQEaFgjSoivbpdUK5ed+cKyMuRd2nmMvZjEGHNd6/GVL5
 XRmpxYZY8SLHNjUwQWO4UwaNFkMPJnpDNbHJ5uk0ZnlXAhNfNogJWo/ULJhktIbc
 J6hMaYJiDGEiCnZU5TmvX+JEiq6DtE+Af362DrOt+PbF/0Ujf9injA8fvos0qFEA
 rSa2+oNqlV+pEIEnY6P7RBKa5nYgRcp4TxvyELjY6m8mbavH3UM1+yLJ3p0Lr15i
 rspQXgCENcXr/XGJ/DoshFTBNTLM60s99BtXx107Qju0Jrhl2XwiJIdBcrVt6Bu+
 gLxQ6gfNxnCbKE6wDm3BQiWRC5pNCCVsal0OUDQBUzBCWwwvtU4=
 =l8i5
 -----END PGP SIGNATURE-----

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

edid: display id support (for 5k+), bugfixes.
virtio-gpu: iommu fix, device split.

# gpg: Signature made Mon 10 May 2021 14:20:36 BST
# 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-20210510-pull-request: (25 commits)
  virtio-gpu: add virtio-vga-gl
  modules: add have_vga
  virtio-gpu: add virtio-gpu-gl-pci
  virtio-gpu: move fields to struct VirtIOGPUGL
  virtio-gpu: drop use_virgl_renderer
  virtio-gpu: move virtio-gpu-gl-device to separate module
  virtio-gpu: drop VIRGL() macro
  virtio-gpu: move update_cursor_data
  virtio-gpu: move virgl process_cmd
  virtio-gpu: move virgl gl_flushed
  virtio-gpu: move virgl handle_ctrl
  virtio-gpu: use class function for ctrl queue handlers
  virtio-gpu: move virgl reset
  virtio-gpu: move virgl realize + properties
  virtio-gpu: add virtio-gpu-gl-device
  virtio-gpu: rename virgl source file.
  virtio-gpu: handle partial maps properly
  edid: add support for DisplayID extension (5k resolution)
  edid: allow arbitrary-length checksums
  edid: move timing generation into a separate function
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-05-12 14:45:21 +01:00
commit a5ccdccc97
15 changed files with 572 additions and 230 deletions

View file

@ -45,6 +45,35 @@ static const struct edid_mode {
{ .xres = 640, .yres = 480, .byte = 35, .bit = 5 }, { .xres = 640, .yres = 480, .byte = 35, .bit = 5 },
}; };
typedef struct Timings {
uint32_t xfront;
uint32_t xsync;
uint32_t xblank;
uint32_t yfront;
uint32_t ysync;
uint32_t yblank;
uint64_t clock;
} Timings;
static void generate_timings(Timings *timings, uint32_t refresh_rate,
uint32_t xres, uint32_t yres)
{
/* pull some realistic looking timings out of thin air */
timings->xfront = xres * 25 / 100;
timings->xsync = xres * 3 / 100;
timings->xblank = xres * 35 / 100;
timings->yfront = yres * 5 / 1000;
timings->ysync = yres * 5 / 1000;
timings->yblank = yres * 35 / 1000;
timings->clock = ((uint64_t)refresh_rate *
(xres + timings->xblank) *
(yres + timings->yblank)) / 10000000;
}
static void edid_ext_dta(uint8_t *dta) static void edid_ext_dta(uint8_t *dta)
{ {
dta[0] = 0x02; dta[0] = 0x02;
@ -130,20 +159,39 @@ static void edid_fill_modes(uint8_t *edid, uint8_t *xtra3, uint8_t *dta,
} }
} }
static void edid_checksum(uint8_t *edid) static void edid_checksum(uint8_t *edid, size_t len)
{ {
uint32_t sum = 0; uint32_t sum = 0;
int i; int i;
for (i = 0; i < 127; i++) { for (i = 0; i < len; i++) {
sum += edid[i]; sum += edid[i];
} }
sum &= 0xff; sum &= 0xff;
if (sum) { if (sum) {
edid[127] = 0x100 - sum; edid[len] = 0x100 - sum;
} }
} }
static uint8_t *edid_desc_next(uint8_t *edid, uint8_t *dta, uint8_t *desc)
{
if (desc == NULL) {
return NULL;
}
if (desc + 18 + 18 < edid + 127) {
return desc + 18;
}
if (dta) {
if (desc < edid + 127) {
return dta + dta[2];
}
if (desc + 18 + 18 < dta + 127) {
return desc + 18;
}
}
return NULL;
}
static void edid_desc_type(uint8_t *desc, uint8_t type) static void edid_desc_type(uint8_t *desc, uint8_t type)
{ {
desc[0] = 0; desc[0] = 0;
@ -181,8 +229,8 @@ static void edid_desc_ranges(uint8_t *desc)
desc[7] = 30; desc[7] = 30;
desc[8] = 160; desc[8] = 160;
/* max dot clock (1200 MHz) */ /* max dot clock (2550 MHz) */
desc[9] = 1200 / 10; desc[9] = 2550 / 10;
/* no extended timing information */ /* no extended timing information */
desc[10] = 0x01; desc[10] = 0x01;
@ -204,42 +252,33 @@ static void edid_desc_dummy(uint8_t *desc)
edid_desc_type(desc, 0x10); edid_desc_type(desc, 0x10);
} }
static void edid_desc_timing(uint8_t *desc, static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate,
uint32_t xres, uint32_t yres, uint32_t xres, uint32_t yres,
uint32_t xmm, uint32_t ymm) uint32_t xmm, uint32_t ymm)
{ {
/* pull some realistic looking timings out of thin air */ Timings timings;
uint32_t xfront = xres * 25 / 100; generate_timings(&timings, refresh_rate, xres, yres);
uint32_t xsync = xres * 3 / 100; stl_le_p(desc, timings.clock);
uint32_t xblank = xres * 35 / 100;
uint32_t yfront = yres * 5 / 1000;
uint32_t ysync = yres * 5 / 1000;
uint32_t yblank = yres * 35 / 1000;
uint32_t clock = 75 * (xres + xblank) * (yres + yblank);
stl_le_p(desc, clock / 10000);
desc[2] = xres & 0xff; desc[2] = xres & 0xff;
desc[3] = xblank & 0xff; desc[3] = timings.xblank & 0xff;
desc[4] = (((xres & 0xf00) >> 4) | desc[4] = (((xres & 0xf00) >> 4) |
((xblank & 0xf00) >> 8)); ((timings.xblank & 0xf00) >> 8));
desc[5] = yres & 0xff; desc[5] = yres & 0xff;
desc[6] = yblank & 0xff; desc[6] = timings.yblank & 0xff;
desc[7] = (((yres & 0xf00) >> 4) | desc[7] = (((yres & 0xf00) >> 4) |
((yblank & 0xf00) >> 8)); ((timings.yblank & 0xf00) >> 8));
desc[8] = xfront & 0xff; desc[8] = timings.xfront & 0xff;
desc[9] = xsync & 0xff; desc[9] = timings.xsync & 0xff;
desc[10] = (((yfront & 0x00f) << 4) | desc[10] = (((timings.yfront & 0x00f) << 4) |
((ysync & 0x00f) << 0)); ((timings.ysync & 0x00f) << 0));
desc[11] = (((xfront & 0x300) >> 2) | desc[11] = (((timings.xfront & 0x300) >> 2) |
((xsync & 0x300) >> 4) | ((timings.xsync & 0x300) >> 4) |
((yfront & 0x030) >> 2) | ((timings.yfront & 0x030) >> 2) |
((ysync & 0x030) >> 4)); ((timings.ysync & 0x030) >> 4));
desc[12] = xmm & 0xff; desc[12] = xmm & 0xff;
desc[13] = ymm & 0xff; desc[13] = ymm & 0xff;
@ -297,14 +336,61 @@ uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res)
return res * 254 / 10 / dpi; return res * 254 / 10 / dpi;
} }
static void init_displayid(uint8_t *did)
{
did[0] = 0x70; /* display id extension */
did[1] = 0x13; /* version 1.3 */
did[2] = 4; /* length */
did[3] = 0x03; /* product type (0x03 == standalone display device) */
edid_checksum(did + 1, did[2] + 4);
}
static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate,
uint32_t xres, uint32_t yres,
uint32_t xmm, uint32_t ymm)
{
Timings timings;
generate_timings(&timings, refresh_rate, xres, yres);
did[0] = 0x70; /* display id extension */
did[1] = 0x13; /* version 1.3 */
did[2] = 23; /* length */
did[3] = 0x03; /* product type (0x03 == standalone display device) */
did[5] = 0x03; /* Detailed Timings Data Block */
did[6] = 0x00; /* revision */
did[7] = 0x14; /* block length */
did[8] = timings.clock & 0xff;
did[9] = (timings.clock & 0xff00) >> 8;
did[10] = (timings.clock & 0xff0000) >> 16;
did[11] = 0x88; /* leave aspect ratio undefined */
stw_le_p(did + 12, 0xffff & (xres - 1));
stw_le_p(did + 14, 0xffff & (timings.xblank - 1));
stw_le_p(did + 16, 0xffff & (timings.xfront - 1));
stw_le_p(did + 18, 0xffff & (timings.xsync - 1));
stw_le_p(did + 20, 0xffff & (yres - 1));
stw_le_p(did + 22, 0xffff & (timings.yblank - 1));
stw_le_p(did + 24, 0xffff & (timings.yfront - 1));
stw_le_p(did + 26, 0xffff & (timings.ysync - 1));
edid_checksum(did + 1, did[2] + 4);
}
void qemu_edid_generate(uint8_t *edid, size_t size, void qemu_edid_generate(uint8_t *edid, size_t size,
qemu_edid_info *info) qemu_edid_info *info)
{ {
uint32_t desc = 54; uint8_t *desc = edid + 54;
uint8_t *xtra3 = NULL; uint8_t *xtra3 = NULL;
uint8_t *dta = NULL; uint8_t *dta = NULL;
uint8_t *did = NULL;
uint32_t width_mm, height_mm; uint32_t width_mm, height_mm;
uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000;
uint32_t dpi = 100; /* if no width_mm/height_mm */ uint32_t dpi = 100; /* if no width_mm/height_mm */
uint32_t large_screen = 0;
/* =============== set defaults =============== */ /* =============== set defaults =============== */
@ -320,6 +406,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
if (!info->prefy) { if (!info->prefy) {
info->prefy = 768; info->prefy = 768;
} }
if (info->prefx >= 4096 || info->prefy >= 4096) {
large_screen = 1;
}
if (info->width_mm && info->height_mm) { if (info->width_mm && info->height_mm) {
width_mm = info->width_mm; width_mm = info->width_mm;
height_mm = info->height_mm; height_mm = info->height_mm;
@ -337,6 +426,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
edid_ext_dta(dta); edid_ext_dta(dta);
} }
if (size >= 384 && large_screen) {
did = edid + 256;
edid[126]++;
init_displayid(did);
}
/* =============== header information =============== */ /* =============== header information =============== */
/* fixed */ /* fixed */
@ -401,40 +496,55 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
/* =============== descriptor blocks =============== */ /* =============== descriptor blocks =============== */
edid_desc_timing(edid + desc, info->prefx, info->prefy, if (!large_screen) {
/* The DTD section has only 12 bits to store the resolution */
edid_desc_timing(desc, refresh_rate, info->prefx, info->prefy,
width_mm, height_mm); width_mm, height_mm);
desc += 18; desc = edid_desc_next(edid, dta, desc);
edid_desc_ranges(edid + desc);
desc += 18;
if (info->name) {
edid_desc_text(edid + desc, 0xfc, info->name);
desc += 18;
} }
if (info->serial) { xtra3 = desc;
edid_desc_text(edid + desc, 0xff, info->serial);
desc += 18;
}
if (desc < 126) {
xtra3 = edid + desc;
edid_desc_xtra3_std(xtra3); edid_desc_xtra3_std(xtra3);
desc += 18; desc = edid_desc_next(edid, dta, desc);
edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy);
/*
* dta video data block is finished at thus point,
* so dta descriptor offsets don't move any more.
*/
edid_desc_ranges(desc);
desc = edid_desc_next(edid, dta, desc);
if (desc && info->name) {
edid_desc_text(desc, 0xfc, info->name);
desc = edid_desc_next(edid, dta, desc);
} }
while (desc < 126) { if (desc && info->serial) {
edid_desc_dummy(edid + desc); edid_desc_text(desc, 0xff, info->serial);
desc += 18; desc = edid_desc_next(edid, dta, desc);
}
while (desc) {
edid_desc_dummy(desc);
desc = edid_desc_next(edid, dta, desc);
}
/* =============== display id extensions =============== */
if (did && large_screen) {
qemu_displayid_generate(did, refresh_rate, info->prefx, info->prefy,
width_mm, height_mm);
} }
/* =============== finish up =============== */ /* =============== finish up =============== */
edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy); edid_checksum(edid, 127);
edid_checksum(edid);
if (dta) { if (dta) {
edid_checksum(dta); edid_checksum(dta, 127);
}
if (did) {
edid_checksum(did, 127);
} }
} }

View file

@ -56,11 +56,14 @@ softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d
if config_all_devices.has_key('CONFIG_VIRTIO_GPU') if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
virtio_gpu_ss = ss.source_set() virtio_gpu_ss = ss.source_set()
virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU', virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU',
if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman, virgl]) if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman])
virtio_gpu_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL'],
if_true: [files('virtio-gpu-3d.c'), pixman, virgl])
virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c')) virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c'))
hw_display_modules += {'virtio-gpu': virtio_gpu_ss} hw_display_modules += {'virtio-gpu': virtio_gpu_ss}
virtio_gpu_gl_ss = ss.source_set()
virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL', opengl],
if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl])
hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss}
endif endif
if config_all_devices.has_key('CONFIG_VIRTIO_PCI') if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
@ -70,6 +73,11 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
virtio_gpu_pci_ss.add(when: ['CONFIG_VHOST_USER_GPU', 'CONFIG_VIRTIO_PCI'], virtio_gpu_pci_ss.add(when: ['CONFIG_VHOST_USER_GPU', 'CONFIG_VIRTIO_PCI'],
if_true: files('vhost-user-gpu-pci.c')) if_true: files('vhost-user-gpu-pci.c'))
hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss} hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss}
virtio_gpu_pci_gl_ss = ss.source_set()
virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', 'CONFIG_VIRGL', opengl],
if_true: [files('virtio-gpu-pci-gl.c'), pixman])
hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss}
endif endif
if config_all_devices.has_key('CONFIG_VIRTIO_VGA') if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
@ -79,6 +87,11 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
virtio_vga_ss.add(when: 'CONFIG_VHOST_USER_VGA', virtio_vga_ss.add(when: 'CONFIG_VHOST_USER_VGA',
if_true: files('vhost-user-vga.c')) if_true: files('vhost-user-vga.c'))
hw_display_modules += {'virtio-vga': virtio_vga_ss} hw_display_modules += {'virtio-vga': virtio_vga_ss}
virtio_vga_gl_ss = ss.source_set()
virtio_vga_gl_ss.add(when: ['CONFIG_VIRTIO_VGA', 'CONFIG_VIRGL', opengl],
if_true: [files('virtio-vga-gl.c'), pixman])
hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss}
endif endif
specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c')) specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c'))

View file

@ -49,7 +49,7 @@ struct PCIVGAState {
qemu_edid_info edid_info; qemu_edid_info edid_info;
MemoryRegion mmio; MemoryRegion mmio;
MemoryRegion mrs[4]; MemoryRegion mrs[4];
uint8_t edid[256]; uint8_t edid[384];
}; };
#define TYPE_PCI_VGA "pci-vga" #define TYPE_PCI_VGA "pci-vga"

View file

@ -39,6 +39,8 @@
//#define DEBUG_VGA_MEM //#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG //#define DEBUG_VGA_REG
bool have_vga = true;
/* 16 state changes per vertical frame @60 Hz */ /* 16 state changes per vertical frame @60 Hz */
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60) #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)

View file

@ -25,7 +25,6 @@ virtio_gpu_base_reset(VirtIOGPUBase *g)
int i; int i;
g->enable = 0; g->enable = 0;
g->use_virgl_renderer = false;
for (i = 0; i < g->conf.max_outputs; i++) { for (i = 0; i < g->conf.max_outputs; i++) {
g->scanout[i].resource_id = 0; g->scanout[i].resource_id = 0;
@ -162,7 +161,6 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
return false; return false;
} }
g->use_virgl_renderer = false;
if (virtio_gpu_virgl_enabled(g->conf)) { if (virtio_gpu_virgl_enabled(g->conf)) {
error_setg(&g->migration_blocker, "virgl is not yet migratable"); error_setg(&g->migration_blocker, "virgl is not yet migratable");
if (migrate_add_blocker(g->migration_blocker, errp) < 0) { if (migrate_add_blocker(g->migration_blocker, errp) < 0) {
@ -218,10 +216,8 @@ static void
virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features)
{ {
static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); 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(((features & virgl) == virgl));
trace_virtio_gpu_features(g->use_virgl_renderer);
} }
static void static void

163
hw/display/virtio-gpu-gl.c Normal file
View file

@ -0,0 +1,163 @@
/*
* 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 "qemu/iov.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-gpu.h"
#include "hw/virtio/virtio-gpu-bswap.h"
#include "hw/virtio/virtio-gpu-pixman.h"
#include "hw/qdev-properties.h"
#include <virglrenderer.h>
static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g,
struct virtio_gpu_scanout *s,
uint32_t resource_id)
{
uint32_t width, height;
uint32_t pixels, *data;
data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
if (!data) {
return;
}
if (width != s->current_cursor->width ||
height != s->current_cursor->height) {
free(data);
return;
}
pixels = s->current_cursor->width * s->current_cursor->height;
memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
free(data);
}
static void virtio_gpu_gl_flushed(VirtIOGPUBase *b)
{
VirtIOGPU *g = VIRTIO_GPU(b);
VirtIOGPUGL *gl = VIRTIO_GPU_GL(b);
if (gl->renderer_reset) {
gl->renderer_reset = false;
virtio_gpu_virgl_reset(g);
}
virtio_gpu_process_cmdq(g);
}
static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev);
struct virtio_gpu_ctrl_command *cmd;
if (!virtio_queue_ready(vq)) {
return;
}
if (!gl->renderer_inited) {
virtio_gpu_virgl_init(g);
gl->renderer_inited = true;
}
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
while (cmd) {
cmd->vq = vq;
cmd->error = 0;
cmd->finished = false;
QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
}
virtio_gpu_process_cmdq(g);
virtio_gpu_virgl_fence_poll(g);
}
static void virtio_gpu_gl_reset(VirtIODevice *vdev)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev);
virtio_gpu_reset(vdev);
if (gl->renderer_inited) {
if (g->parent_obj.renderer_blocked) {
gl->renderer_reset = true;
} else {
virtio_gpu_virgl_reset(g);
}
}
}
static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp)
{
VirtIOGPU *g = VIRTIO_GPU(qdev);
#if defined(HOST_WORDS_BIGENDIAN)
error_setg(errp, "virgl is not supported on bigendian platforms");
return;
#endif
if (!display_opengl) {
error_setg(errp, "opengl is not available");
return;
}
g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
VIRTIO_GPU_BASE(g)->virtio_config.num_capsets =
virtio_gpu_virgl_get_num_capsets(g);
virtio_gpu_device_realize(qdev, errp);
}
static Property virtio_gpu_gl_properties[] = {
DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags,
VIRTIO_GPU_FLAG_STATS_ENABLED, false),
DEFINE_PROP_END_OF_LIST(),
};
static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass);
VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
vbc->gl_flushed = virtio_gpu_gl_flushed;
vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl;
vgc->process_cmd = virtio_gpu_virgl_process_cmd;
vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data;
vdc->realize = virtio_gpu_gl_device_realize;
vdc->reset = virtio_gpu_gl_reset;
device_class_set_props(dc, virtio_gpu_gl_properties);
}
static const TypeInfo virtio_gpu_gl_info = {
.name = TYPE_VIRTIO_GPU_GL,
.parent = TYPE_VIRTIO_GPU,
.instance_size = sizeof(VirtIOGPUGL),
.class_init = virtio_gpu_gl_class_init,
};
static void virtio_register_types(void)
{
type_register_static(&virtio_gpu_gl_info);
}
type_init(virtio_register_types)

View file

@ -0,0 +1,55 @@
/*
* Virtio video device
*
* Copyright Red Hat
*
* Authors:
* Dave Airlie
*
* 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 "qapi/error.h"
#include "qemu/module.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-gpu-pci.h"
#include "qom/object.h"
#define TYPE_VIRTIO_GPU_GL_PCI "virtio-gpu-gl-pci"
typedef struct VirtIOGPUGLPCI VirtIOGPUGLPCI;
DECLARE_INSTANCE_CHECKER(VirtIOGPUGLPCI, VIRTIO_GPU_GL_PCI,
TYPE_VIRTIO_GPU_GL_PCI)
struct VirtIOGPUGLPCI {
VirtIOGPUPCIBase parent_obj;
VirtIOGPUGL vdev;
};
static void virtio_gpu_gl_initfn(Object *obj)
{
VirtIOGPUGLPCI *dev = VIRTIO_GPU_GL_PCI(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_GPU_GL);
VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
}
static const VirtioPCIDeviceTypeInfo virtio_gpu_gl_pci_info = {
.generic_name = TYPE_VIRTIO_GPU_GL_PCI,
.parent = TYPE_VIRTIO_GPU_PCI_BASE,
.instance_size = sizeof(VirtIOGPUGLPCI),
.instance_init = virtio_gpu_gl_initfn,
};
static void virtio_gpu_gl_pci_register_types(void)
{
virtio_pci_types_register(&virtio_gpu_gl_pci_info);
}
type_init(virtio_gpu_gl_pci_register_types)

View file

@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
{ {
struct virtio_gpu_resource_attach_backing att_rb; struct virtio_gpu_resource_attach_backing att_rb;
struct iovec *res_iovs; struct iovec *res_iovs;
uint32_t res_niov;
int ret; int ret;
VIRTIO_GPU_FILL_CMD(att_rb); VIRTIO_GPU_FILL_CMD(att_rb);
trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id); trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs); ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs, &res_niov);
if (ret != 0) { if (ret != 0) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return; return;
} }
ret = virgl_renderer_resource_attach_iov(att_rb.resource_id, ret = virgl_renderer_resource_attach_iov(att_rb.resource_id,
res_iovs, att_rb.nr_entries); res_iovs, res_niov);
if (ret != 0) if (ret != 0)
virtio_gpu_cleanup_mapping_iov(g, res_iovs, att_rb.nr_entries); virtio_gpu_cleanup_mapping_iov(g, res_iovs, res_niov);
} }
static void virgl_resource_detach_backing(VirtIOGPU *g, static void virgl_resource_detach_backing(VirtIOGPU *g,

View file

@ -39,24 +39,7 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
static void virtio_gpu_cleanup_mapping(VirtIOGPU *g, static void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
struct virtio_gpu_simple_resource *res); struct virtio_gpu_simple_resource *res);
#ifdef CONFIG_VIRGL void virtio_gpu_update_cursor_data(VirtIOGPU *g,
#include <virglrenderer.h>
#define VIRGL(_g, _virgl, _simple, ...) \
do { \
if (_g->parent_obj.use_virgl_renderer) { \
_virgl(__VA_ARGS__); \
} else { \
_simple(__VA_ARGS__); \
} \
} while (0)
#else
#define VIRGL(_g, _virgl, _simple, ...) \
do { \
_simple(__VA_ARGS__); \
} while (0)
#endif
static void update_cursor_data_simple(VirtIOGPU *g,
struct virtio_gpu_scanout *s, struct virtio_gpu_scanout *s,
uint32_t resource_id) uint32_t resource_id)
{ {
@ -79,36 +62,10 @@ static void update_cursor_data_simple(VirtIOGPU *g,
pixels * sizeof(uint32_t)); pixels * sizeof(uint32_t));
} }
#ifdef CONFIG_VIRGL
static void update_cursor_data_virgl(VirtIOGPU *g,
struct virtio_gpu_scanout *s,
uint32_t resource_id)
{
uint32_t width, height;
uint32_t pixels, *data;
data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
if (!data) {
return;
}
if (width != s->current_cursor->width ||
height != s->current_cursor->height) {
free(data);
return;
}
pixels = s->current_cursor->width * s->current_cursor->height;
memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
free(data);
}
#endif
static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
{ {
struct virtio_gpu_scanout *s; struct virtio_gpu_scanout *s;
VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
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->parent_obj.conf.max_outputs) { if (cursor->pos.scanout_id >= g->parent_obj.conf.max_outputs) {
@ -131,8 +88,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
s->current_cursor->hot_y = cursor->hot_y; s->current_cursor->hot_y = cursor->hot_y;
if (cursor->resource_id > 0) { if (cursor->resource_id > 0) {
VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple, vgc->update_cursor_data(g, s, cursor->resource_id);
g, s, cursor->resource_id);
} }
dpy_cursor_define(s->con, s->current_cursor); dpy_cursor_define(s->con, s->current_cursor);
@ -608,11 +564,12 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
int virtio_gpu_create_mapping_iov(VirtIOGPU *g, int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
struct virtio_gpu_resource_attach_backing *ab, struct virtio_gpu_resource_attach_backing *ab,
struct virtio_gpu_ctrl_command *cmd, struct virtio_gpu_ctrl_command *cmd,
uint64_t **addr, struct iovec **iov) uint64_t **addr, struct iovec **iov,
uint32_t *niov)
{ {
struct virtio_gpu_mem_entry *ents; struct virtio_gpu_mem_entry *ents;
size_t esize, s; size_t esize, s;
int i; int e, v;
if (ab->nr_entries > 16384) { if (ab->nr_entries > 16384) {
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
@ -633,28 +590,25 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
return -1; return -1;
} }
*iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries); *iov = NULL;
if (addr) { if (addr) {
*addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries); *addr = NULL;
} }
for (i = 0; i < ab->nr_entries; i++) { for (e = 0, v = 0; e < ab->nr_entries; e++) {
uint64_t a = le64_to_cpu(ents[i].addr); uint64_t a = le64_to_cpu(ents[e].addr);
uint32_t l = le32_to_cpu(ents[i].length); uint32_t l = le32_to_cpu(ents[e].length);
hwaddr len = l; hwaddr len;
(*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, void *map;
do {
len = l;
map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
a, &len, DMA_DIRECTION_TO_DEVICE); a, &len, DMA_DIRECTION_TO_DEVICE);
(*iov)[i].iov_len = len; if (!map) {
if (addr) {
(*addr)[i] = a;
}
if (!(*iov)[i].iov_base || len != l) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
" resource %d element %d\n", " resource %d element %d\n",
__func__, ab->resource_id, i); __func__, ab->resource_id, e);
if ((*iov)[i].iov_base) { virtio_gpu_cleanup_mapping_iov(g, *iov, v);
i++; /* cleanup the 'i'th map */
}
virtio_gpu_cleanup_mapping_iov(g, *iov, i);
g_free(ents); g_free(ents);
*iov = NULL; *iov = NULL;
if (addr) { if (addr) {
@ -663,7 +617,26 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
} }
return -1; return -1;
} }
if (!(v % 16)) {
*iov = g_realloc(*iov, sizeof(struct iovec) * (v + 16));
if (addr) {
*addr = g_realloc(*addr, sizeof(uint64_t) * (v + 16));
} }
}
(*iov)[v].iov_base = map;
(*iov)[v].iov_len = len;
if (addr) {
(*addr)[v] = a;
}
a += len;
l -= len;
v += 1;
} while (l > 0);
}
*niov = v;
g_free(ents); g_free(ents);
return 0; return 0;
} }
@ -717,13 +690,12 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
return; return;
} }
ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov); ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs,
&res->iov, &res->iov_cnt);
if (ret != 0) { if (ret != 0) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return; return;
} }
res->iov_cnt = ab.nr_entries;
} }
static void static void
@ -747,7 +719,7 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g,
virtio_gpu_cleanup_mapping(g, res); virtio_gpu_cleanup_mapping(g, res);
} }
static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd) struct virtio_gpu_ctrl_command *cmd)
{ {
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
@ -806,6 +778,7 @@ static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
void virtio_gpu_process_cmdq(VirtIOGPU *g) void virtio_gpu_process_cmdq(VirtIOGPU *g)
{ {
struct virtio_gpu_ctrl_command *cmd; struct virtio_gpu_ctrl_command *cmd;
VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
if (g->processing_cmdq) { if (g->processing_cmdq) {
return; return;
@ -819,8 +792,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
} }
/* process command */ /* process command */
VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, vgc->process_cmd(g, cmd);
g, cmd);
QTAILQ_REMOVE(&g->cmdq, cmd, next); QTAILQ_REMOVE(&g->cmdq, cmd, next);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
@ -843,19 +815,6 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
g->processing_cmdq = false; g->processing_cmdq = false;
} }
static void virtio_gpu_gl_flushed(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);
@ -865,13 +824,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
return; return;
} }
#ifdef CONFIG_VIRGL
if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) {
virtio_gpu_virgl_init(g);
g->renderer_inited = true;
}
#endif
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
while (cmd) { while (cmd) {
cmd->vq = vq; cmd->vq = vq;
@ -882,18 +834,14 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
} }
virtio_gpu_process_cmdq(g); virtio_gpu_process_cmdq(g);
#ifdef CONFIG_VIRGL
if (g->parent_obj.use_virgl_renderer) {
virtio_gpu_virgl_fence_poll(g);
}
#endif
} }
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.parent_obj, g->ctrl_vq); VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
vgc->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)
@ -1105,25 +1053,10 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
return 0; return 0;
} }
static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) 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;
#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
have_virgl = false;
#else
have_virgl = display_opengl;
#endif
if (!have_virgl) {
g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
} else {
#if defined(CONFIG_VIRGL)
VIRTIO_GPU_BASE(g)->virtio_config.num_capsets =
virtio_gpu_virgl_get_num_capsets(g);
#endif
}
if (!virtio_gpu_base_device_realize(qdev, if (!virtio_gpu_base_device_realize(qdev,
virtio_gpu_handle_ctrl_cb, virtio_gpu_handle_ctrl_cb,
@ -1141,18 +1074,12 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
QTAILQ_INIT(&g->fenceq); QTAILQ_INIT(&g->fenceq);
} }
static void virtio_gpu_reset(VirtIODevice *vdev) 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;
#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);
} }
@ -1170,17 +1097,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
g_free(cmd); g_free(cmd);
} }
#ifdef CONFIG_VIRGL
if (g->parent_obj.use_virgl_renderer) {
if (g->parent_obj.renderer_blocked) {
g->renderer_reset = true;
} else {
virtio_gpu_virgl_reset(g);
}
g->parent_obj.use_virgl_renderer = false;
}
#endif
virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev)); virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
} }
@ -1235,12 +1151,6 @@ static Property virtio_gpu_properties[] = {
VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf), VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf),
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem, DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem,
256 * MiB), 256 * MiB),
#ifdef CONFIG_VIRGL
DEFINE_PROP_BIT("virgl", VirtIOGPU, parent_obj.conf.flags,
VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),
DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags,
VIRTIO_GPU_FLAG_STATS_ENABLED, false),
#endif
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -1248,9 +1158,12 @@ 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); VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
vgc->handle_ctrl = virtio_gpu_handle_ctrl;
vgc->process_cmd = virtio_gpu_simple_process_cmd;
vgc->update_cursor_data = virtio_gpu_update_cursor_data;
vgc->gl_flushed = virtio_gpu_gl_flushed;
vdc->realize = virtio_gpu_device_realize; vdc->realize = virtio_gpu_device_realize;
vdc->reset = virtio_gpu_reset; vdc->reset = virtio_gpu_reset;
vdc->get_config = virtio_gpu_get_config; vdc->get_config = virtio_gpu_get_config;
@ -1264,6 +1177,7 @@ static const TypeInfo virtio_gpu_info = {
.name = TYPE_VIRTIO_GPU, .name = TYPE_VIRTIO_GPU,
.parent = TYPE_VIRTIO_GPU_BASE, .parent = TYPE_VIRTIO_GPU_BASE,
.instance_size = sizeof(VirtIOGPU), .instance_size = sizeof(VirtIOGPU),
.class_size = sizeof(VirtIOGPUClass),
.class_init = virtio_gpu_class_init, .class_init = virtio_gpu_class_init,
}; };

View file

@ -0,0 +1,47 @@
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio-gpu.h"
#include "hw/display/vga.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-vga.h"
#include "qom/object.h"
#define TYPE_VIRTIO_VGA_GL "virtio-vga-gl"
typedef struct VirtIOVGAGL VirtIOVGAGL;
DECLARE_INSTANCE_CHECKER(VirtIOVGAGL, VIRTIO_VGA_GL,
TYPE_VIRTIO_VGA_GL)
struct VirtIOVGAGL {
VirtIOVGABase parent_obj;
VirtIOGPUGL vdev;
};
static void virtio_vga_gl_inst_initfn(Object *obj)
{
VirtIOVGAGL *dev = VIRTIO_VGA_GL(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_GPU_GL);
VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
}
static VirtioPCIDeviceTypeInfo virtio_vga_gl_info = {
.generic_name = TYPE_VIRTIO_VGA_GL,
.parent = TYPE_VIRTIO_VGA_BASE,
.instance_size = sizeof(VirtIOVGAGL),
.instance_init = virtio_vga_gl_inst_initfn,
};
static void virtio_vga_register_types(void)
{
if (have_vga) {
virtio_pci_types_register(&virtio_vga_gl_info);
}
}
type_init(virtio_vga_register_types)

View file

@ -11,6 +11,7 @@ typedef struct qemu_edid_info {
uint32_t prefy; uint32_t prefy;
uint32_t maxx; uint32_t maxx;
uint32_t maxy; uint32_t maxy;
uint32_t refresh_rate;
} qemu_edid_info; } qemu_edid_info;
void qemu_edid_generate(uint8_t *edid, size_t size, void qemu_edid_generate(uint8_t *edid, size_t size,
@ -25,6 +26,7 @@ uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res);
DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0), \ DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0), \
DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0), \ DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0), \
DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0), \ DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0), \
DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0) DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0), \
DEFINE_PROP_UINT32("refresh_rate", _state, _edid_info.refresh_rate, 0)
#endif /* EDID_H */ #endif /* EDID_H */

View file

@ -11,6 +11,12 @@
#include "exec/hwaddr.h" #include "exec/hwaddr.h"
/*
* modules can reference this symbol to avoid being loaded
* into system emulators without vga support
*/
extern bool have_vga;
enum vga_retrace_method { enum vga_retrace_method {
VGA_RETRACE_DUMB, VGA_RETRACE_DUMB,
VGA_RETRACE_PRECISE VGA_RETRACE_PRECISE

View file

@ -29,7 +29,10 @@ OBJECT_DECLARE_TYPE(VirtIOGPUBase, VirtIOGPUBaseClass,
VIRTIO_GPU_BASE) VIRTIO_GPU_BASE)
#define TYPE_VIRTIO_GPU "virtio-gpu-device" #define TYPE_VIRTIO_GPU "virtio-gpu-device"
OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPU, VIRTIO_GPU) OBJECT_DECLARE_TYPE(VirtIOGPU, VirtIOGPUClass, VIRTIO_GPU)
#define TYPE_VIRTIO_GPU_GL "virtio-gpu-gl-device"
OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL)
#define TYPE_VHOST_USER_GPU "vhost-user-gpu" #define TYPE_VHOST_USER_GPU "vhost-user-gpu"
OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU) OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU)
@ -108,7 +111,6 @@ struct VirtIOGPUBase {
struct virtio_gpu_config virtio_config; struct virtio_gpu_config virtio_config;
const GraphicHwOps *hw_ops; const GraphicHwOps *hw_ops;
bool use_virgl_renderer;
int renderer_blocked; int renderer_blocked;
int enable; int enable;
@ -149,8 +151,6 @@ struct VirtIOGPU {
uint64_t hostmem; uint64_t hostmem;
bool processing_cmdq; bool processing_cmdq;
bool renderer_inited;
bool renderer_reset;
QEMUTimer *fence_poll; QEMUTimer *fence_poll;
QEMUTimer *print_stats; QEMUTimer *print_stats;
@ -163,6 +163,23 @@ struct VirtIOGPU {
} stats; } stats;
}; };
struct VirtIOGPUClass {
VirtIOGPUBaseClass parent;
void (*handle_ctrl)(VirtIODevice *vdev, VirtQueue *vq);
void (*process_cmd)(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd);
void (*update_cursor_data)(VirtIOGPU *g,
struct virtio_gpu_scanout *s,
uint32_t resource_id);
};
struct VirtIOGPUGL {
struct VirtIOGPU parent_obj;
bool renderer_inited;
bool renderer_reset;
};
struct VhostUserGPU { struct VhostUserGPU {
VirtIOGPUBase parent_obj; VirtIOGPUBase parent_obj;
@ -209,10 +226,17 @@ void virtio_gpu_get_edid(VirtIOGPU *g,
int virtio_gpu_create_mapping_iov(VirtIOGPU *g, int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
struct virtio_gpu_resource_attach_backing *ab, struct virtio_gpu_resource_attach_backing *ab,
struct virtio_gpu_ctrl_command *cmd, struct virtio_gpu_ctrl_command *cmd,
uint64_t **addr, struct iovec **iov); uint64_t **addr, struct iovec **iov,
uint32_t *niov);
void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
struct iovec *iov, uint32_t count); struct iovec *iov, uint32_t count);
void virtio_gpu_process_cmdq(VirtIOGPU *g); void virtio_gpu_process_cmdq(VirtIOGPU *g);
void virtio_gpu_device_realize(DeviceState *qdev, Error **errp);
void virtio_gpu_reset(VirtIODevice *vdev);
void virtio_gpu_simple_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd);
void virtio_gpu_update_cursor_data(VirtIOGPU *g,
struct virtio_gpu_scanout *s,
uint32_t resource_id);
/* virtio-gpu-3d.c */ /* virtio-gpu-3d.c */
void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,

View file

@ -41,7 +41,8 @@ static void usage(FILE *out)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
FILE *outfile = NULL; FILE *outfile = NULL;
uint8_t blob[256]; uint8_t blob[512];
size_t size;
uint32_t dpi = 100; uint32_t dpi = 100;
int rc; int rc;
@ -119,7 +120,8 @@ int main(int argc, char *argv[])
memset(blob, 0, sizeof(blob)); memset(blob, 0, sizeof(blob));
qemu_edid_generate(blob, sizeof(blob), &info); qemu_edid_generate(blob, sizeof(blob), &info);
fwrite(blob, sizeof(blob), 1, outfile); size = qemu_edid_size(blob);
fwrite(blob, size, 1, outfile);
fflush(outfile); fflush(outfile);
exit(0); exit(0);

View file

@ -182,6 +182,10 @@ static const struct {
{ "ui-spice-app", "ui-spice-core" }, { "ui-spice-app", "ui-spice-core" },
{ "ui-spice-app", "chardev-spice" }, { "ui-spice-app", "chardev-spice" },
{ "hw-display-virtio-gpu-gl", "hw-display-virtio-gpu" },
{ "hw-display-virtio-gpu-pci-gl", "hw-display-virtio-gpu-pci" },
{ "hw-display-virtio-vga-gl", "hw-display-virtio-vga" },
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
{ "ui-egl-headless", "ui-opengl" }, { "ui-egl-headless", "ui-opengl" },
{ "ui-gtk", "ui-opengl" }, { "ui-gtk", "ui-opengl" },
@ -301,13 +305,16 @@ static struct {
{ "qxl-vga", "hw-", "display-qxl" }, { "qxl-vga", "hw-", "display-qxl" },
{ "qxl", "hw-", "display-qxl" }, { "qxl", "hw-", "display-qxl" },
{ "virtio-gpu-device", "hw-", "display-virtio-gpu" }, { "virtio-gpu-device", "hw-", "display-virtio-gpu" },
{ "virtio-gpu-gl-device", "hw-", "display-virtio-gpu-gl" },
{ "vhost-user-gpu", "hw-", "display-virtio-gpu" }, { "vhost-user-gpu", "hw-", "display-virtio-gpu" },
{ "virtio-gpu-pci-base", "hw-", "display-virtio-gpu-pci" }, { "virtio-gpu-pci-base", "hw-", "display-virtio-gpu-pci" },
{ "virtio-gpu-pci", "hw-", "display-virtio-gpu-pci" }, { "virtio-gpu-pci", "hw-", "display-virtio-gpu-pci" },
{ "virtio-gpu-gl-pci", "hw-", "display-virtio-gpu-pci-gl" },
{ "vhost-user-gpu-pci", "hw-", "display-virtio-gpu-pci" }, { "vhost-user-gpu-pci", "hw-", "display-virtio-gpu-pci" },
{ "virtio-gpu-ccw", "hw-", "s390x-virtio-gpu-ccw" }, { "virtio-gpu-ccw", "hw-", "s390x-virtio-gpu-ccw" },
{ "virtio-vga-base", "hw-", "display-virtio-vga" }, { "virtio-vga-base", "hw-", "display-virtio-vga" },
{ "virtio-vga", "hw-", "display-virtio-vga" }, { "virtio-vga", "hw-", "display-virtio-vga" },
{ "virtio-vga-gl", "hw-", "display-virtio-vga-gl" },
{ "vhost-user-vga", "hw-", "display-virtio-vga" }, { "vhost-user-vga", "hw-", "display-virtio-vga" },
{ "chardev-braille", "chardev-", "baum" }, { "chardev-braille", "chardev-", "baum" },
{ "chardev-spicevmc", "chardev-", "spice" }, { "chardev-spicevmc", "chardev-", "spice" },