summaryrefslogtreecommitdiffstats
path: root/hw/display
diff options
context:
space:
mode:
Diffstat (limited to 'hw/display')
-rw-r--r--hw/display/Kconfig4
-rw-r--r--hw/display/edid-generate.c214
-rw-r--r--hw/display/meson.build21
-rw-r--r--hw/display/milkymist-tmu2.c551
-rw-r--r--hw/display/milkymist-vgafb.c360
-rw-r--r--hw/display/milkymist-vgafb_template.h74
-rw-r--r--hw/display/trace-events10
-rw-r--r--hw/display/vga-pci.c2
-rw-r--r--hw/display/vga.c2
-rw-r--r--hw/display/virtio-gpu-base.c6
-rw-r--r--hw/display/virtio-gpu-gl.c163
-rw-r--r--hw/display/virtio-gpu-pci-gl.c55
-rw-r--r--hw/display/virtio-gpu-virgl.c (renamed from hw/display/virtio-gpu-3d.c)7
-rw-r--r--hw/display/virtio-gpu.c218
-rw-r--r--hw/display/virtio-vga-gl.c47
15 files changed, 517 insertions, 1217 deletions
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index ca46b5830e..a2306b67d8 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -72,10 +72,6 @@ config BLIZZARD
config FRAMEBUFFER
bool
-config MILKYMIST_TMU2
- bool
- depends on OPENGL && X11
-
config SM501
bool
select I2C
diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c
index a1bea9a3aa..f2b874d5e3 100644
--- a/hw/display/edid-generate.c
+++ b/hw/display/edid-generate.c
@@ -45,6 +45,35 @@ static const struct edid_mode {
{ .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)
{
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;
int i;
- for (i = 0; i < 127; i++) {
+ for (i = 0; i < len; i++) {
sum += edid[i];
}
sum &= 0xff;
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)
{
desc[0] = 0;
@@ -181,8 +229,8 @@ static void edid_desc_ranges(uint8_t *desc)
desc[7] = 30;
desc[8] = 160;
- /* max dot clock (1200 MHz) */
- desc[9] = 1200 / 10;
+ /* max dot clock (2550 MHz) */
+ desc[9] = 2550 / 10;
/* no extended timing information */
desc[10] = 0x01;
@@ -204,42 +252,33 @@ static void edid_desc_dummy(uint8_t *desc)
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 xmm, uint32_t ymm)
{
- /* pull some realistic looking timings out of thin air */
- uint32_t xfront = xres * 25 / 100;
- uint32_t xsync = xres * 3 / 100;
- 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);
+ Timings timings;
+ generate_timings(&timings, refresh_rate, xres, yres);
+ stl_le_p(desc, timings.clock);
desc[2] = xres & 0xff;
- desc[3] = xblank & 0xff;
+ desc[3] = timings.xblank & 0xff;
desc[4] = (((xres & 0xf00) >> 4) |
- ((xblank & 0xf00) >> 8));
+ ((timings.xblank & 0xf00) >> 8));
desc[5] = yres & 0xff;
- desc[6] = yblank & 0xff;
+ desc[6] = timings.yblank & 0xff;
desc[7] = (((yres & 0xf00) >> 4) |
- ((yblank & 0xf00) >> 8));
+ ((timings.yblank & 0xf00) >> 8));
- desc[8] = xfront & 0xff;
- desc[9] = xsync & 0xff;
+ desc[8] = timings.xfront & 0xff;
+ desc[9] = timings.xsync & 0xff;
- desc[10] = (((yfront & 0x00f) << 4) |
- ((ysync & 0x00f) << 0));
- desc[11] = (((xfront & 0x300) >> 2) |
- ((xsync & 0x300) >> 4) |
- ((yfront & 0x030) >> 2) |
- ((ysync & 0x030) >> 4));
+ desc[10] = (((timings.yfront & 0x00f) << 4) |
+ ((timings.ysync & 0x00f) << 0));
+ desc[11] = (((timings.xfront & 0x300) >> 2) |
+ ((timings.xsync & 0x300) >> 4) |
+ ((timings.yfront & 0x030) >> 2) |
+ ((timings.ysync & 0x030) >> 4));
desc[12] = xmm & 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;
}
+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,
qemu_edid_info *info)
{
- uint32_t desc = 54;
+ uint8_t *desc = edid + 54;
uint8_t *xtra3 = NULL;
uint8_t *dta = NULL;
+ uint8_t *did = NULL;
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 large_screen = 0;
/* =============== set defaults =============== */
@@ -320,6 +406,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
if (!info->prefy) {
info->prefy = 768;
}
+ if (info->prefx >= 4096 || info->prefy >= 4096) {
+ large_screen = 1;
+ }
if (info->width_mm && info->height_mm) {
width_mm = info->width_mm;
height_mm = info->height_mm;
@@ -337,6 +426,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
edid_ext_dta(dta);
}
+ if (size >= 384 && large_screen) {
+ did = edid + 256;
+ edid[126]++;
+ init_displayid(did);
+ }
+
/* =============== header information =============== */
/* fixed */
@@ -401,40 +496,55 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
/* =============== descriptor blocks =============== */
- edid_desc_timing(edid + desc, info->prefx, info->prefy,
- width_mm, height_mm);
- desc += 18;
+ 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);
+ desc = edid_desc_next(edid, dta, desc);
+ }
- edid_desc_ranges(edid + desc);
- desc += 18;
+ xtra3 = desc;
+ edid_desc_xtra3_std(xtra3);
+ 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 (info->name) {
- edid_desc_text(edid + desc, 0xfc, info->name);
- desc += 18;
+ if (desc && info->name) {
+ edid_desc_text(desc, 0xfc, info->name);
+ desc = edid_desc_next(edid, dta, desc);
}
- if (info->serial) {
- edid_desc_text(edid + desc, 0xff, info->serial);
- desc += 18;
+ if (desc && info->serial) {
+ edid_desc_text(desc, 0xff, info->serial);
+ desc = edid_desc_next(edid, dta, desc);
}
- if (desc < 126) {
- xtra3 = edid + desc;
- edid_desc_xtra3_std(xtra3);
- desc += 18;
+ while (desc) {
+ edid_desc_dummy(desc);
+ desc = edid_desc_next(edid, dta, desc);
}
- while (desc < 126) {
- edid_desc_dummy(edid + desc);
- desc += 18;
+ /* =============== display id extensions =============== */
+
+ if (did && large_screen) {
+ qemu_displayid_generate(did, refresh_rate, info->prefx, info->prefy,
+ width_mm, height_mm);
}
/* =============== finish up =============== */
- edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy);
- edid_checksum(edid);
+ edid_checksum(edid, 127);
if (dta) {
- edid_checksum(dta);
+ edid_checksum(dta, 127);
+ }
+ if (did) {
+ edid_checksum(did, 127);
}
}
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 9d79e3951d..aaf797c5e9 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -48,7 +48,6 @@ endif
softmmu_ss.add(when: 'CONFIG_DPCD', if_true: files('dpcd.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dp.c'))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-vgafb.c'))
softmmu_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c'))
softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d.c', 'ati_dbg.c'))
@@ -56,11 +55,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')
virtio_gpu_ss = ss.source_set()
virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU',
- if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman, virgl])
- virtio_gpu_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL'],
- if_true: [files('virtio-gpu-3d.c'), pixman, virgl])
+ if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman])
virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c'))
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
if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
@@ -70,6 +72,11 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
virtio_gpu_pci_ss.add(when: ['CONFIG_VHOST_USER_GPU', 'CONFIG_VIRTIO_PCI'],
if_true: files('vhost-user-gpu-pci.c'))
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
if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
@@ -79,9 +86,13 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
virtio_vga_ss.add(when: 'CONFIG_VHOST_USER_VGA',
if_true: files('vhost-user-vga.c'))
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
-specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c'))
specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c'))
modules += { 'hw-display': hw_display_modules }
diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c
deleted file mode 100644
index 02a28c807b..0000000000
--- a/hw/display/milkymist-tmu2.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * QEMU model of the Milkymist texture mapping unit.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- * Copyright (c) 2010 Sebastien Bourdeauducq
- * <sebastien.bourdeauducq@lekernel.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/tmu2.pdf
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qapi/error.h"
-#include "hw/display/milkymist_tmu2.h"
-
-#include <X11/Xlib.h>
-#include <epoxy/gl.h>
-#include <epoxy/glx.h>
-#include "qom/object.h"
-
-enum {
- R_CTL = 0,
- R_HMESHLAST,
- R_VMESHLAST,
- R_BRIGHTNESS,
- R_CHROMAKEY,
- R_VERTICESADDR,
- R_TEXFBUF,
- R_TEXHRES,
- R_TEXVRES,
- R_TEXHMASK,
- R_TEXVMASK,
- R_DSTFBUF,
- R_DSTHRES,
- R_DSTVRES,
- R_DSTHOFFSET,
- R_DSTVOFFSET,
- R_DSTSQUAREW,
- R_DSTSQUAREH,
- R_ALPHA,
- R_MAX
-};
-
-enum {
- CTL_START_BUSY = (1<<0),
- CTL_CHROMAKEY = (1<<1),
-};
-
-enum {
- MAX_BRIGHTNESS = 63,
- MAX_ALPHA = 63,
-};
-
-enum {
- MESH_MAXSIZE = 128,
-};
-
-struct vertex {
- int x;
- int y;
-} QEMU_PACKED;
-
-#define TYPE_MILKYMIST_TMU2 "milkymist-tmu2"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistTMU2State, MILKYMIST_TMU2)
-
-struct MilkymistTMU2State {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- Chardev *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-
- Display *dpy;
- GLXFBConfig glx_fb_config;
- GLXContext glx_context;
-};
-
-static const int glx_fbconfig_attr[] = {
- GLX_GREEN_SIZE, 5,
- GLX_GREEN_SIZE, 6,
- GLX_BLUE_SIZE, 5,
- None
-};
-
-static int tmu2_glx_init(MilkymistTMU2State *s)
-{
- GLXFBConfig *configs;
- int nelements;
-
- s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
- if (s->dpy == NULL) {
- return 1;
- }
-
- configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
- if (configs == NULL) {
- return 1;
- }
-
- s->glx_fb_config = *configs;
- XFree(configs);
-
- /* FIXME: call glXDestroyContext() */
- s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
- GLX_RGBA_TYPE, NULL, 1);
- if (s->glx_context == NULL) {
- return 1;
- }
-
- return 0;
-}
-
-static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
- int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
-{
- int x, y;
- int x0, y0, x1, y1;
- int u0, v0, u1, v1, u2, v2, u3, v3;
- double xscale = 1.0 / ((double)(64 * texhres));
- double yscale = 1.0 / ((double)(64 * texvres));
-
- glLoadIdentity();
- glTranslatef(ho, vo, 0);
- glEnable(GL_TEXTURE_2D);
- glBegin(GL_QUADS);
-
- for (y = 0; y < vmeshlast; y++) {
- y0 = y * sh;
- y1 = y0 + sh;
- for (x = 0; x < hmeshlast; x++) {
- x0 = x * sw;
- x1 = x0 + sw;
-
- u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
- v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
- u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
- v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
- u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
- v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
- u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
- v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
-
- glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
- glVertex3i(x0, y0, 0);
- glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
- glVertex3i(x1, y0, 0);
- glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
- glVertex3i(x1, y1, 0);
- glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
- glVertex3i(x0, y1, 0);
- }
- }
-
- glEnd();
-}
-
-static void tmu2_start(MilkymistTMU2State *s)
-{
- int pbuffer_attrib[6] = {
- GLX_PBUFFER_WIDTH,
- 0,
- GLX_PBUFFER_HEIGHT,
- 0,
- GLX_PRESERVED_CONTENTS,
- True
- };
-
- GLXPbuffer pbuffer;
- GLuint texture;
- void *fb;
- hwaddr fb_len;
- void *mesh;
- hwaddr mesh_len;
- float m;
-
- trace_milkymist_tmu2_start();
-
- /* Create and set up a suitable OpenGL context */
- pbuffer_attrib[1] = s->regs[R_DSTHRES];
- pbuffer_attrib[3] = s->regs[R_DSTVRES];
- pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
- glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
-
- /* Fixup endianness. TODO: would it work on BE hosts? */
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- glPixelStorei(GL_PACK_SWAP_BYTES, 1);
-
- /* Row alignment */
- glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
- glPixelStorei(GL_PACK_ALIGNMENT, 2);
-
- /* Read the QEMU source framebuffer into an OpenGL texture */
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- fb_len = 2ULL * s->regs[R_TEXHRES] * s->regs[R_TEXVRES];
- fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, false);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
- glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
- 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
-
- /* Set up texturing options */
- /* WARNING:
- * Many cases of TMU2 masking are not supported by OpenGL.
- * We only implement the most common ones:
- * - full bilinear filtering vs. nearest texel
- * - texture clamping vs. texture wrapping
- */
- if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- }
- if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- }
- if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
-
- /* Translucency and decay */
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
- glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
-
- /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
- fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
- fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, false);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
- glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
- glMatrixMode(GL_MODELVIEW);
-
- /* Map the texture */
- mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
- mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, false);
- if (mesh == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- tmu2_gl_map((struct vertex *)mesh,
- s->regs[R_TEXHRES], s->regs[R_TEXVRES],
- s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
- s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
- s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
- cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
-
- /* Write back the OpenGL framebuffer to the QEMU framebuffer */
- fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
- fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, true);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
-
- /* Free OpenGL allocs */
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
-
- s->regs[R_CTL] &= ~CTL_START_BUSY;
-
- trace_milkymist_tmu2_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static uint64_t tmu2_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistTMU2State *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_BRIGHTNESS:
- case R_CHROMAKEY:
- case R_VERTICESADDR:
- case R_TEXFBUF:
- case R_TEXHRES:
- case R_TEXVRES:
- case R_TEXHMASK:
- case R_TEXVMASK:
- case R_DSTFBUF:
- case R_DSTHRES:
- case R_DSTVRES:
- case R_DSTHOFFSET:
- case R_DSTVOFFSET:
- case R_DSTSQUAREW:
- case R_DSTSQUAREH:
- case R_ALPHA:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_tmu2: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_tmu2_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void tmu2_check_registers(MilkymistTMU2State *s)
-{
- if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
- error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
- }
-
- if (s->regs[R_ALPHA] > MAX_ALPHA) {
- error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
- }
-
- if (s->regs[R_VERTICESADDR] & 0x07) {
- error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
- "aligned");
- }
-
- if (s->regs[R_TEXFBUF] & 0x01) {
- error_report("milkymist_tmu2: texture buffer address has to be "
- "16-bit aligned");
- }
-}
-
-static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistTMU2State *s = opaque;
-
- trace_milkymist_tmu2_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- s->regs[addr] = value;
- if (value & CTL_START_BUSY) {
- tmu2_start(s);
- }
- break;
- case R_BRIGHTNESS:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_CHROMAKEY:
- case R_VERTICESADDR:
- case R_TEXFBUF:
- case R_TEXHRES:
- case R_TEXVRES:
- case R_TEXHMASK:
- case R_TEXVMASK:
- case R_DSTFBUF:
- case R_DSTHRES:
- case R_DSTVRES:
- case R_DSTHOFFSET:
- case R_DSTVOFFSET:
- case R_DSTSQUAREW:
- case R_DSTSQUAREH:
- case R_ALPHA:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_tmu2: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- tmu2_check_registers(s);
-}
-
-static const MemoryRegionOps tmu2_mmio_ops = {
- .read = tmu2_read,
- .write = tmu2_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_tmu2_reset(DeviceState *d)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-}
-
-static void milkymist_tmu2_init(Object *obj)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->regs_region, obj, &tmu2_mmio_ops, s,
- "milkymist-tmu2", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-}
-
-static void milkymist_tmu2_realize(DeviceState *dev, Error **errp)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(dev);
-
- if (tmu2_glx_init(s)) {
- error_setg(errp, "tmu2_glx_init failed");
- }
-}
-
-static const VMStateDescription vmstate_milkymist_tmu2 = {
- .name = "milkymist-tmu2",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_tmu2_realize;
- dc->reset = milkymist_tmu2_reset;
- dc->vmsd = &vmstate_milkymist_tmu2;
-}
-
-static const TypeInfo milkymist_tmu2_info = {
- .name = TYPE_MILKYMIST_TMU2,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistTMU2State),
- .instance_init = milkymist_tmu2_init,
- .class_init = milkymist_tmu2_class_init,
-};
-
-static void milkymist_tmu2_register_types(void)
-{
- type_register_static(&milkymist_tmu2_info);
-}
-
-type_init(milkymist_tmu2_register_types)
-
-DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
- Display *d;
- GLXFBConfig *configs;
- int nelements;
- int ver_major, ver_minor;
-
- /* check that GLX will work */
- d = XOpenDisplay(NULL);
- if (d == NULL) {
- return NULL;
- }
-
- if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
- /*
- * Yeah, sometimes getting the GLX version can fail.
- * Isn't X beautiful?
- */
- XCloseDisplay(d);
- return NULL;
- }
-
- if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
- printf("Your GLX version is %d.%d,"
- "but TMU emulation needs at least 1.3. TMU disabled.\n",
- ver_major, ver_minor);
- XCloseDisplay(d);
- return NULL;
- }
-
- configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
- if (configs == NULL) {
- XCloseDisplay(d);
- return NULL;
- }
-
- XFree(configs);
- XCloseDisplay(d);
-
- dev = qdev_new(TYPE_MILKYMIST_TMU2);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c
deleted file mode 100644
index e2c587e2df..0000000000
--- a/hw/display/milkymist-vgafb.c
+++ /dev/null
@@ -1,360 +0,0 @@
-
-/*
- * QEMU model of the Milkymist VGA framebuffer.
- *
- * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/vgafb.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/qdev-properties.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "framebuffer.h"
-#include "ui/pixel_ops.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define BITS 8
-#include "migration/vmstate.h"
-#include "milkymist-vgafb_template.h"
-#define BITS 15
-#include "milkymist-vgafb_template.h"
-#define BITS 16
-#include "milkymist-vgafb_template.h"
-#define BITS 24
-#include "milkymist-vgafb_template.h"
-#define BITS 32
-#include "milkymist-vgafb_template.h"
-
-enum {
- R_CTRL = 0,
- R_HRES,
- R_HSYNC_START,
- R_HSYNC_END,
- R_HSCAN,
- R_VRES,
- R_VSYNC_START,
- R_VSYNC_END,
- R_VSCAN,
- R_BASEADDRESS,
- R_BASEADDRESS_ACT,
- R_BURST_COUNT,
- R_DDC,
- R_SOURCE_CLOCK,
- R_MAX
-};
-
-enum {
- CTRL_RESET = (1<<0),
-};
-
-#define TYPE_MILKYMIST_VGAFB "milkymist-vgafb"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistVgafbState, MILKYMIST_VGAFB)
-
-struct MilkymistVgafbState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- MemoryRegionSection fbsection;
- QemuConsole *con;
-
- int invalidate;
- uint32_t fb_offset;
- uint32_t fb_mask;
-
- uint32_t regs[R_MAX];
-};
-
-static int vgafb_enabled(MilkymistVgafbState *s)
-{
- return !(s->regs[R_CTRL] & CTRL_RESET);
-}
-
-static void vgafb_update_display(void *opaque)
-{
- MilkymistVgafbState *s = opaque;
- SysBusDevice *sbd;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width;
- int first = 0;
- int last = 0;
- drawfn fn;
-
- if (!vgafb_enabled(s)) {
- return;
- }
-
- sbd = SYS_BUS_DEVICE(s);
- int dest_width = s->regs[R_HRES];
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
- case 8:
- fn = draw_line_8;
- break;
- case 15:
- fn = draw_line_15;
- dest_width *= 2;
- break;
- case 16:
- fn = draw_line_16;
- dest_width *= 2;
- break;
- case 24:
- fn = draw_line_24;
- dest_width *= 3;
- break;
- case 32:
- fn = draw_line_32;
- dest_width *= 4;
- break;
- default:
- hw_error("milkymist_vgafb: bad color depth\n");
- break;
- }
-
- src_width = s->regs[R_HRES] * 2;
- if (s->invalidate) {
- framebuffer_update_memory_section(&s->fbsection,
- sysbus_address_space(sbd),
- s->regs[R_BASEADDRESS] + s->fb_offset,
- s->regs[R_VRES], src_width);
- }
-
- framebuffer_update_display(surface, &s->fbsection,
- s->regs[R_HRES],
- s->regs[R_VRES],
- src_width,
- dest_width,
- 0,
- s->invalidate,
- fn,
- NULL,
- &first, &last);
-
- if (first >= 0) {
- dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
- }
- s->invalidate = 0;
-}
-
-static void vgafb_invalidate_display(void *opaque)
-{
- MilkymistVgafbState *s = opaque;
- s->invalidate = 1;
-}
-
-static void vgafb_resize(MilkymistVgafbState *s)
-{
- if (!vgafb_enabled(s)) {
- return;
- }
-
- qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
- s->invalidate = 1;
-}
-
-static uint64_t vgafb_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistVgafbState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- case R_HRES:
- case R_HSYNC_START:
- case R_HSYNC_END:
- case R_HSCAN:
- case R_VRES:
- case R_VSYNC_START:
- case R_VSYNC_END:
- case R_VSCAN:
- case R_BASEADDRESS:
- case R_BURST_COUNT:
- case R_DDC:
- case R_SOURCE_CLOCK:
- r = s->regs[addr];
- break;
- case R_BASEADDRESS_ACT:
- r = s->regs[R_BASEADDRESS];
- break;
-
- default:
- error_report("milkymist_vgafb: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_vgafb_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistVgafbState *s = opaque;
-
- trace_milkymist_vgafb_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- s->regs[addr] = value;
- vgafb_resize(s);
- break;
- case R_HSYNC_START:
- case R_HSYNC_END:
- case R_HSCAN:
- case R_VSYNC_START:
- case R_VSYNC_END:
- case R_VSCAN:
- case R_BURST_COUNT:
- case R_DDC:
- case R_SOURCE_CLOCK:
- s->regs[addr] = value;
- break;
- case R_BASEADDRESS:
- if (value & 0x1f) {
- error_report("milkymist_vgafb: framebuffer base address have to "
- "be 32 byte aligned");
- break;
- }
- s->regs[addr] = value & s->fb_mask;
- s->invalidate = 1;
- break;
- case R_HRES:
- case R_VRES:
- s->regs[addr] = value;
- vgafb_resize(s);
- break;
- case R_BASEADDRESS_ACT:
- error_report("milkymist_vgafb: write to read-only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
-
- default:
- error_report("milkymist_vgafb: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps vgafb_mmio_ops = {
- .read = vgafb_read,
- .write = vgafb_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_vgafb_reset(DeviceState *d)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_CTRL] = CTRL_RESET;
- s->regs[R_HRES] = 640;
- s->regs[R_VRES] = 480;
- s->regs[R_BASEADDRESS] = 0;
-}
-
-static const GraphicHwOps vgafb_ops = {
- .invalidate = vgafb_invalidate_display,
- .gfx_update = vgafb_update_display,
-};
-
-static void milkymist_vgafb_init(Object *obj)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s,
- "milkymist-vgafb", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-}
-
-static void milkymist_vgafb_realize(DeviceState *dev, Error **errp)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(dev);
-
- s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
-}
-
-static int vgafb_post_load(void *opaque, int version_id)
-{
- vgafb_invalidate_display(opaque);
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_vgafb = {
- .name = "milkymist-vgafb",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = vgafb_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_vgafb_properties[] = {
- DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
- DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = milkymist_vgafb_reset;
- dc->vmsd = &vmstate_milkymist_vgafb;
- device_class_set_props(dc, milkymist_vgafb_properties);
- dc->realize = milkymist_vgafb_realize;
-}
-
-static const TypeInfo milkymist_vgafb_info = {
- .name = TYPE_MILKYMIST_VGAFB,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistVgafbState),
- .instance_init = milkymist_vgafb_init,
- .class_init = milkymist_vgafb_class_init,
-};
-
-static void milkymist_vgafb_register_types(void)
-{
- type_register_static(&milkymist_vgafb_info);
-}
-
-type_init(milkymist_vgafb_register_types)
diff --git a/hw/display/milkymist-vgafb_template.h b/hw/display/milkymist-vgafb_template.h
deleted file mode 100644
index 96137f9709..0000000000
--- a/hw/display/milkymist-vgafb_template.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * QEMU model of the Milkymist VGA framebuffer.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#if BITS == 8
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *to = rgb_to_pixel8(r, g, b); \
- to += 1; \
- } while (0)
-#elif BITS == 15
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
- to += 2; \
- } while (0)
-#elif BITS == 16
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
- to += 2; \
- } while (0)
-#elif BITS == 24
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- uint32_t tmp = rgb_to_pixel24(r, g, b); \
- *(to++) = tmp & 0xff; \
- *(to++) = (tmp >> 8) & 0xff; \
- *(to++) = (tmp >> 16) & 0xff; \
- } while (0)
-#elif BITS == 32
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint32_t *)to = rgb_to_pixel32(r, g, b); \
- to += 4; \
- } while (0)
-#else
-#error unknown bit depth
-#endif
-
-static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
- int width, int deststep)
-{
- uint16_t rgb565;
- uint8_t r, g, b;
-
- while (width--) {
- rgb565 = lduw_be_p(s);
- r = ((rgb565 >> 11) & 0x1f) << 3;
- g = ((rgb565 >> 5) & 0x3f) << 2;
- b = ((rgb565 >> 0) & 0x1f) << 3;
- COPY_PIXEL(d, r, g, b);
- s += 2;
- }
-}
-
-#undef BITS
-#undef COPY_PIXEL
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 957b8ba994..9fccca18a1 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -13,16 +13,6 @@ xenfb_input_connected(void *xendev, int abs_pointer_wanted) "%p abs %d"
g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x"
g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x"
-# milkymist-tmu2.c
-milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_tmu2_start(void) "Start TMU"
-milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
-
-# milkymist-vgafb.c
-milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-
# vmware_vga.c
vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 48d29630ab..62fb5c38c1 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -49,7 +49,7 @@ struct PCIVGAState {
qemu_edid_info edid_info;
MemoryRegion mmio;
MemoryRegion mrs[4];
- uint8_t edid[256];
+ uint8_t edid[384];
};
#define TYPE_PCI_VGA "pci-vga"
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 836ad50c7b..28a90e30d0 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -39,6 +39,8 @@
//#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG
+bool have_vga = true;
+
/* 16 state changes per vertical frame @60 Hz */
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 25f8920fdb..afb3ee7d9a 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -25,7 +25,6 @@ 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;
@@ -162,7 +161,6 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
return false;
}
- g->use_virgl_renderer = false;
if (virtio_gpu_virgl_enabled(g->conf)) {
error_setg(&g->migration_blocker, "virgl is not yet migratable");
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)
{
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);
+ trace_virtio_gpu_features(((features & virgl) == virgl));
}
static void
diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
new file mode 100644
index 0000000000..d971b48080
--- /dev/null
+++ b/hw/display/virtio-gpu-gl.c
@@ -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)
diff --git a/hw/display/virtio-gpu-pci-gl.c b/hw/display/virtio-gpu-pci-gl.c
new file mode 100644
index 0000000000..902dda3452
--- /dev/null
+++ b/hw/display/virtio-gpu-pci-gl.c
@@ -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)
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-virgl.c
index d98964858e..72c14d9132 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
{
struct virtio_gpu_resource_attach_backing att_rb;
struct iovec *res_iovs;
+ uint32_t res_niov;
int ret;
VIRTIO_GPU_FILL_CMD(att_rb);
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) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;
}
ret = virgl_renderer_resource_attach_iov(att_rb.resource_id,
- res_iovs, att_rb.nr_entries);
+ res_iovs, res_niov);
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,
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index c9f5e36fd0..db56f0454a 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -39,26 +39,9 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
static void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
struct virtio_gpu_simple_resource *res);
-#ifdef CONFIG_VIRGL
-#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,
- uint32_t resource_id)
+void virtio_gpu_update_cursor_data(VirtIOGPU *g,
+ struct virtio_gpu_scanout *s,
+ uint32_t resource_id)
{
struct virtio_gpu_simple_resource *res;
uint32_t pixels;
@@ -79,36 +62,10 @@ static void update_cursor_data_simple(VirtIOGPU *g,
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)
{
struct virtio_gpu_scanout *s;
+ VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR;
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;
if (cursor->resource_id > 0) {
- VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple,
- g, s, cursor->resource_id);
+ vgc->update_cursor_data(g, s, cursor->resource_id);
}
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,
struct virtio_gpu_resource_attach_backing *ab,
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;
size_t esize, s;
- int i;
+ int e, v;
if (ab->nr_entries > 16384) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -633,37 +590,53 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
return -1;
}
- *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
+ *iov = NULL;
if (addr) {
- *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
+ *addr = NULL;
}
- for (i = 0; i < ab->nr_entries; i++) {
- uint64_t a = le64_to_cpu(ents[i].addr);
- uint32_t l = le32_to_cpu(ents[i].length);
- hwaddr len = l;
- (*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
- a, &len, DMA_DIRECTION_TO_DEVICE);
- (*iov)[i].iov_len = len;
- 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"
- " resource %d element %d\n",
- __func__, ab->resource_id, i);
- if ((*iov)[i].iov_base) {
- i++; /* cleanup the 'i'th map */
+ for (e = 0, v = 0; e < ab->nr_entries; e++) {
+ uint64_t a = le64_to_cpu(ents[e].addr);
+ uint32_t l = le32_to_cpu(ents[e].length);
+ hwaddr len;
+ void *map;
+
+ do {
+ len = l;
+ map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
+ a, &len, DMA_DIRECTION_TO_DEVICE);
+ if (!map) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
+ " resource %d element %d\n",
+ __func__, ab->resource_id, e);
+ virtio_gpu_cleanup_mapping_iov(g, *iov, v);
+ g_free(ents);
+ *iov = NULL;
+ if (addr) {
+ g_free(*addr);
+ *addr = NULL;
+ }
+ return -1;
}
- virtio_gpu_cleanup_mapping_iov(g, *iov, i);
- g_free(ents);
- *iov = NULL;
+
+ 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) {
- g_free(*addr);
- *addr = NULL;
+ (*addr)[v] = a;
}
- return -1;
- }
+
+ a += len;
+ l -= len;
+ v += 1;
+ } while (l > 0);
}
+ *niov = v;
+
g_free(ents);
return 0;
}
@@ -717,13 +690,12 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
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) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;
}
-
- res->iov_cnt = ab.nr_entries;
}
static void
@@ -747,8 +719,8 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g,
virtio_gpu_cleanup_mapping(g, res);
}
-static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
+void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
{
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
virtio_gpu_ctrl_hdr_bswap(&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)
{
struct virtio_gpu_ctrl_command *cmd;
+ VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
if (g->processing_cmdq) {
return;
@@ -819,8 +792,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
}
/* process command */
- VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd,
- g, cmd);
+ vgc->process_cmd(g, cmd);
QTAILQ_REMOVE(&g->cmdq, cmd, next);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
@@ -843,19 +815,6 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
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)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
@@ -865,13 +824,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
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));
while (cmd) {
cmd->vq = vq;
@@ -882,18 +834,14 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
}
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)
{
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)
@@ -1105,25 +1053,10 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
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);
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,
virtio_gpu_handle_ctrl_cb,
@@ -1141,18 +1074,12 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
QTAILQ_INIT(&g->fenceq);
}
-static void virtio_gpu_reset(VirtIODevice *vdev)
+void virtio_gpu_reset(VirtIODevice *vdev)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
struct virtio_gpu_simple_resource *res, *tmp;
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) {
virtio_gpu_resource_destroy(g, res);
}
@@ -1170,17 +1097,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
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));
}
@@ -1235,12 +1151,6 @@ static Property virtio_gpu_properties[] = {
VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf),
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem,
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(),
};
@@ -1248,9 +1158,12 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = 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->reset = virtio_gpu_reset;
vdc->get_config = virtio_gpu_get_config;
@@ -1264,6 +1177,7 @@ static const TypeInfo virtio_gpu_info = {
.name = TYPE_VIRTIO_GPU,
.parent = TYPE_VIRTIO_GPU_BASE,
.instance_size = sizeof(VirtIOGPU),
+ .class_size = sizeof(VirtIOGPUClass),
.class_init = virtio_gpu_class_init,
};
diff --git a/hw/display/virtio-vga-gl.c b/hw/display/virtio-vga-gl.c
new file mode 100644
index 0000000000..c971340ebb
--- /dev/null
+++ b/hw/display/virtio-vga-gl.c
@@ -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)