diff options
37 files changed, 832 insertions, 1074 deletions
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index d2247fa..31586c6 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -601,6 +601,11 @@ static const MemoryRegionOps musicpal_lcd_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static const GraphicHwOps musicpal_gfx_ops = { + .invalidate = lcd_invalidate, + .gfx_update = lcd_refresh, +}; + static int musicpal_lcd_init(SysBusDevice *dev) { musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev); @@ -611,8 +616,7 @@ static int musicpal_lcd_init(SysBusDevice *dev) "musicpal-lcd", MP_LCD_SIZE); sysbus_init_mmio(dev, &s->iomem); - s->con = graphic_console_init(lcd_refresh, lcd_invalidate, - NULL, NULL, s); + s->con = graphic_console_init(&musicpal_gfx_ops, s); qemu_console_resize(s->con, 128*3, 64*3); qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3); diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c index de7ccf8..1ca3355 100644 --- a/hw/display/blizzard.c +++ b/hw/display/blizzard.c @@ -933,18 +933,6 @@ static void blizzard_update_display(void *opaque) s->my[1] = 0; } -static void blizzard_screen_dump(void *opaque, const char *filename, - bool cswitch, Error **errp) -{ - BlizzardState *s = (BlizzardState *) opaque; - DisplaySurface *surface = qemu_console_surface(s->con); - - blizzard_update_display(opaque); - if (s && surface_data(surface)) { - ppm_save(filename, surface, errp); - } -} - #define DEPTH 8 #include "blizzard_template.h" #define DEPTH 15 @@ -956,6 +944,11 @@ static void blizzard_screen_dump(void *opaque, const char *filename, #define DEPTH 32 #include "blizzard_template.h" +static const GraphicHwOps blizzard_ops = { + .invalidate = blizzard_invalidate_display, + .gfx_update = blizzard_update_display, +}; + void *s1d13745_init(qemu_irq gpio_int) { BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s)); @@ -963,9 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int) s->fb = g_malloc(0x180000); - s->con = graphic_console_init(blizzard_update_display, - blizzard_invalidate_display, - blizzard_screen_dump, NULL, s); + s->con = graphic_console_init(&blizzard_ops, s); surface = qemu_console_surface(s->con); switch (surface_bits_per_pixel(surface)) { diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index bf2181a..db232af 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -720,7 +720,7 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) /* we have to flush all pending changes so that the copy is generated at the appropriate moment in time */ if (notify) - vga_hw_update(); + graphic_hw_update(s->vga.con); (*s->cirrus_rop) (s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), @@ -2910,9 +2910,7 @@ static int vga_initfn(ISADevice *dev) vga_common_init(s); cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, isa_address_space(dev), isa_address_space_io(dev)); - s->con = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, - s); + s->con = graphic_console_init(s->hw_ops, s); rom_add_vga(VGABIOS_CIRRUS_FILENAME); /* XXX ISA-LFB support */ /* FIXME not qdev yet */ @@ -2959,9 +2957,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) vga_common_init(&s->vga); cirrus_init_common(s, device_id, 1, pci_address_space(dev), pci_address_space_io(dev)); - s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, - &s->vga); + s->vga.con = graphic_console_init(s->vga.hw_ops, &s->vga); /* setup PCI */ diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 49cca4b..e6e7b27 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1242,7 +1242,7 @@ static void exynos4210_update_resolution(Exynos4210fimdState *s) static void exynos4210_fimd_update(void *opaque) { Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; - DisplaySurface *surface = qemu_console_surface(s->console); + DisplaySurface *surface; Exynos4210fimdWindow *w; int i, line; hwaddr fb_line_addr, inc_size; @@ -1255,11 +1255,12 @@ static void exynos4210_fimd_update(void *opaque) const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) & FIMD_VIDTCON2_SIZE_MASK) + 1; - if (!s || !s->console || !surface_bits_per_pixel(surface) || - !s->enabled) { + if (!s || !s->console || !s->enabled || + surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) { return; } exynos4210_update_resolution(s); + surface = qemu_console_surface(s->console); for (i = 0; i < NUM_OF_WINDOWS; i++) { w = &s->window[i]; @@ -1886,6 +1887,11 @@ static const VMStateDescription exynos4210_fimd_vmstate = { } }; +static const GraphicHwOps exynos4210_fimd_ops = { + .invalidate = exynos4210_fimd_invalidate, + .gfx_update = exynos4210_fimd_update, +}; + static int exynos4210_fimd_init(SysBusDevice *dev) { Exynos4210fimdState *s = FROM_SYSBUS(Exynos4210fimdState, dev); @@ -1899,8 +1905,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev) memory_region_init_io(&s->iomem, &exynos4210_fimd_mmio_ops, s, "exynos4210.fimd", FIMD_REGS_SIZE); sysbus_init_mmio(dev, &s->iomem); - s->console = graphic_console_init(exynos4210_fimd_update, - exynos4210_fimd_invalidate, NULL, NULL, s); + s->console = graphic_console_init(&exynos4210_fimd_ops, s); return 0; } diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index f7014e9..03810e9 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -294,77 +294,6 @@ static void g364fb_reset(G364State *s) g364fb_invalidate_display(s); } -static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp) -{ - G364State *s = opaque; - int ret, y, x; - uint8_t index; - uint8_t *data_buffer; - FILE *f; - - qemu_flush_coalesced_mmio_buffer(); - - if (s->depth != 8) { - error_setg(errp, "g364: unknown guest depth %d", s->depth); - return; - } - - f = fopen(filename, "wb"); - if (!f) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - - if (s->ctla & CTLA_FORCE_BLANK) { - /* blank screen */ - ret = fprintf(f, "P4\n%d %d\n", s->width, s->height); - if (ret < 0) { - goto write_err; - } - for (y = 0; y < s->height; y++) - for (x = 0; x < s->width; x++) { - ret = fputc(0, f); - if (ret == EOF) { - goto write_err; - } - } - } else { - data_buffer = s->vram + s->top_of_screen; - ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); - if (ret < 0) { - goto write_err; - } - for (y = 0; y < s->height; y++) - for (x = 0; x < s->width; x++, data_buffer++) { - index = *data_buffer; - ret = fputc(s->color_palette[index][0], f); - if (ret == EOF) { - goto write_err; - } - ret = fputc(s->color_palette[index][1], f); - if (ret == EOF) { - goto write_err; - } - ret = fputc(s->color_palette[index][2], f); - if (ret == EOF) { - goto write_err; - } - } - } - -out: - fclose(f); - return; - -write_err: - error_setg(errp, "failed to write to file '%s': %s", filename, - strerror(errno)); - unlink(filename); - goto out; -} - /* called for accesses to io ports */ static uint64_t g364fb_ctrl_read(void *opaque, hwaddr addr, @@ -546,13 +475,16 @@ static const VMStateDescription vmstate_g364fb = { } }; +static const GraphicHwOps g364fb_ops = { + .invalidate = g364fb_invalidate_display, + .gfx_update = g364fb_update_display, +}; + static void g364fb_init(DeviceState *dev, G364State *s) { s->vram = g_malloc0(s->vram_size); - s->con = graphic_console_init(g364fb_update_display, - g364fb_invalidate_display, - g364fb_screen_dump, NULL, s); + s->con = graphic_console_init(&g364fb_ops, s); memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000); memory_region_init_ram_ptr(&s->mem_vram, "vram", diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index 05528c7..6306d8c 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -254,6 +254,12 @@ static const VMStateDescription vmstate_jazz_led = { } }; +static const GraphicHwOps jazz_led_ops = { + .invalidate = jazz_led_invalidate_display, + .gfx_update = jazz_led_update_display, + .text_update = jazz_led_text_update, +}; + static int jazz_led_init(SysBusDevice *dev) { LedState *s = FROM_SYSBUS(LedState, dev); @@ -261,10 +267,7 @@ static int jazz_led_init(SysBusDevice *dev) memory_region_init_io(&s->iomem, &led_ops, s, "led", 1); sysbus_init_mmio(dev, &s->iomem); - s->con = graphic_console_init(jazz_led_update_display, - jazz_led_invalidate_display, - NULL, - jazz_led_text_update, s); + s->con = graphic_console_init(&jazz_led_ops, s); return 0; } diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c index 3219041..716997c 100644 --- a/hw/display/milkymist-vgafb.c +++ b/hw/display/milkymist-vgafb.c @@ -270,6 +270,11 @@ static void milkymist_vgafb_reset(DeviceState *d) s->regs[R_BASEADDRESS] = 0; } +static const GraphicHwOps vgafb_ops = { + .invalidate = vgafb_invalidate_display, + .gfx_update = vgafb_update_display, +}; + static int milkymist_vgafb_init(SysBusDevice *dev) { MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev); @@ -278,9 +283,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev) "milkymist-vgafb", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); - s->con = graphic_console_init(vgafb_update_display, - vgafb_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(&vgafb_ops, s); return 0; } diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c index be7e9c0..e4a5595 100644 --- a/hw/display/omap_lcdc.c +++ b/hw/display/omap_lcdc.c @@ -227,90 +227,6 @@ static void omap_update_display(void *opaque) omap_lcd->invalidate = 0; } -static void omap_ppm_save(const char *filename, uint8_t *data, - int w, int h, int linesize, Error **errp) -{ - FILE *f; - uint8_t *d, *d1; - unsigned int v; - int ret, y, x, bpp; - - f = fopen(filename, "wb"); - if (!f) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); - if (ret < 0) { - goto write_err; - } - d1 = data; - bpp = linesize / w; - for (y = 0; y < h; y ++) { - d = d1; - for (x = 0; x < w; x ++) { - v = *(uint32_t *) d; - switch (bpp) { - case 2: - ret = fputc((v >> 8) & 0xf8, f); - if (ret == EOF) { - goto write_err; - } - ret = fputc((v >> 3) & 0xfc, f); - if (ret == EOF) { - goto write_err; - } - ret = fputc((v << 3) & 0xf8, f); - if (ret == EOF) { - goto write_err; - } - break; - case 3: - case 4: - default: - ret = fputc((v >> 16) & 0xff, f); - if (ret == EOF) { - goto write_err; - } - ret = fputc((v >> 8) & 0xff, f); - if (ret == EOF) { - goto write_err; - } - ret = fputc((v) & 0xff, f); - if (ret == EOF) { - goto write_err; - } - break; - } - d += bpp; - } - d1 += linesize; - } -out: - fclose(f); - return; - -write_err: - error_setg(errp, "failed to write to file '%s': %s", filename, - strerror(errno)); - unlink(filename); - goto out; -} - -static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp) -{ - struct omap_lcd_panel_s *omap_lcd = opaque; - DisplaySurface *surface = qemu_console_surface(omap_lcd->con); - - omap_update_display(opaque); - if (omap_lcd && surface_data(surface)) - omap_ppm_save(filename, surface_data(surface), - omap_lcd->width, omap_lcd->height, - surface_stride(surface), errp); -} - static void omap_invalidate_display(void *opaque) { struct omap_lcd_panel_s *omap_lcd = opaque; omap_lcd->invalidate = 1; @@ -468,6 +384,11 @@ void omap_lcdc_reset(struct omap_lcd_panel_s *s) s->ctrl = 0; } +static const GraphicHwOps omap_ops = { + .invalidate = omap_invalidate_display, + .gfx_update = omap_update_display, +}; + struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq, @@ -485,9 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100); memory_region_add_subregion(sysmem, base, &s->iomem); - s->con = graphic_console_init(omap_update_display, - omap_invalidate_display, - omap_screen_dump, NULL, s); + s->con = graphic_console_init(&omap_ops, s); return s; } diff --git a/hw/display/pl110.c b/hw/display/pl110.c index 295434e..d232431 100644 --- a/hw/display/pl110.c +++ b/hw/display/pl110.c @@ -444,6 +444,11 @@ static int vmstate_pl110_post_load(void *opaque, int version_id) return 0; } +static const GraphicHwOps pl110_gfx_ops = { + .invalidate = pl110_invalidate_display, + .gfx_update = pl110_update_display, +}; + static int pl110_init(SysBusDevice *dev) { pl110_state *s = FROM_SYSBUS(pl110_state, dev); @@ -452,9 +457,7 @@ static int pl110_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); qdev_init_gpio_in(&s->busdev.qdev, pl110_mux_ctrl_set, 1); - s->con = graphic_console_init(pl110_update_display, - pl110_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(&pl110_gfx_ops, s); return 0; } diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index c9bd42e..12d9cd2 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -991,6 +991,11 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = { #define BITS 32 #include "pxa2xx_template.h" +static const GraphicHwOps pxa2xx_ops = { + .invalidate = pxa2xx_invalidate_display, + .gfx_update = pxa2xx_update_display, +}; + PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq) { @@ -1008,9 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, "pxa2xx-lcd-controller", 0x00100000); memory_region_add_subregion(sysmem, base, &s->iomem); - s->con = graphic_console_init(pxa2xx_update_display, - pxa2xx_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(&pxa2xx_ops, s); surface = qemu_console_surface(s->con); switch (surface_bits_per_pixel(surface)) { diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 930b7cf..437f8d0 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1074,7 +1074,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; vga_dirty_log_start(&d->vga); - vga_hw_update(); + graphic_hw_update(d->vga.con); } static void qxl_exit_vga_mode(PCIQXLDevice *d) @@ -1753,7 +1753,7 @@ static void qxl_hw_update(void *opaque) switch (qxl->mode) { case QXL_MODE_VGA: - vga->update(vga); + vga->hw_ops->gfx_update(vga); break; case QXL_MODE_COMPAT: case QXL_MODE_NATIVE: @@ -1769,26 +1769,9 @@ static void qxl_hw_invalidate(void *opaque) PCIQXLDevice *qxl = opaque; VGACommonState *vga = &qxl->vga; - vga->invalidate(vga); -} - -static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp) -{ - PCIQXLDevice *qxl = opaque; - VGACommonState *vga = &qxl->vga; - - switch (qxl->mode) { - case QXL_MODE_COMPAT: - case QXL_MODE_NATIVE: - qxl_render_update(qxl); - ppm_save(filename, qxl->ssd.ds, errp); - break; - case QXL_MODE_VGA: - vga->screen_dump(vga, filename, cswitch, errp); - break; - default: - break; + if (qxl->mode == QXL_MODE_VGA) { + vga->hw_ops->invalidate(vga); + return; } } @@ -1798,7 +1781,7 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) VGACommonState *vga = &qxl->vga; if (qxl->mode == QXL_MODE_VGA) { - vga->text_update(vga, chardata); + vga->hw_ops->text_update(vga, chardata); return; } } @@ -2058,6 +2041,12 @@ static int qxl_init_common(PCIQXLDevice *qxl) return 0; } +static const GraphicHwOps qxl_ops = { + .invalidate = qxl_hw_invalidate, + .gfx_update = qxl_hw_update, + .text_update = qxl_hw_text_update, +}; + static int qxl_init_primary(PCIDevice *dev) { PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); @@ -2074,10 +2063,7 @@ static int qxl_init_primary(PCIDevice *dev) portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); - vga->con = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, - qxl_hw_screen_dump, qxl_hw_text_update, - qxl); - qxl->ssd.con = vga->con, + vga->con = graphic_console_init(&qxl_ops, qxl); qemu_spice_display_init_common(&qxl->ssd); rc = qxl_init_common(qxl); @@ -2086,6 +2072,7 @@ static int qxl_init_primary(PCIDevice *dev) } qxl->ssd.dcl.ops = &display_listener_ops; + qxl->ssd.dcl.con = vga->con; ds = qemu_console_displaystate(vga->con); register_displaychangelistener(ds, &qxl->ssd.dcl); return rc; @@ -2101,6 +2088,7 @@ static int qxl_init_secondary(PCIDevice *dev) memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size); vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev); qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); + qxl->vga.con = graphic_console_init(&qxl_ops, qxl); return qxl_init_common(qxl); } diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 9878df4..f0e6d70 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1383,6 +1383,10 @@ static void sm501_update_display(void *opaque) sm501_draw_crt(s); } +static const GraphicHwOps sm501_ops = { + .gfx_update = sm501_update_display, +}; + void sm501_init(MemoryRegion *address_space_mem, uint32_t base, uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr) { @@ -1445,6 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, } /* create qemu graphic console */ - s->con = graphic_console_init(sm501_update_display, NULL, - NULL, NULL, s); + s->con = graphic_console_init(&sm501_ops, s); } diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index 183a878..3d7ebbe 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -284,13 +284,16 @@ static const VMStateDescription vmstate_ssd0303 = { } }; +static const GraphicHwOps ssd0303_ops = { + .invalidate = ssd0303_invalidate_display, + .gfx_update = ssd0303_update_display, +}; + static int ssd0303_init(I2CSlave *i2c) { ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c); - s->con = graphic_console_init(ssd0303_update_display, - ssd0303_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(&ssd0303_ops, s); qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY); return 0; } diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 5cf2f70..45e8dc1 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -331,15 +331,18 @@ static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static const GraphicHwOps ssd0323_ops = { + .invalidate = ssd0323_invalidate_display, + .gfx_update = ssd0323_update_display, +}; + static int ssd0323_init(SSISlave *dev) { ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev); s->col_end = 63; s->row_end = 79; - s->con = graphic_console_init(ssd0323_update_display, - ssd0323_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(&ssd0323_ops, s); qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1); diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c index 178a21f..b5b255c 100644 --- a/hw/display/tc6393xb.c +++ b/hw/display/tc6393xb.c @@ -548,6 +548,10 @@ static void tc6393xb_writeb(void *opaque, hwaddr addr, (uint32_t) addr, (int)value & 0xff); } +static const GraphicHwOps tc6393xb_gfx_ops = { + .gfx_update = tc6393xb_update_display, +}; + TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq) { TC6393xbState *s; @@ -583,11 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq) memory_region_add_subregion(sysmem, base + 0x100000, &s->vram); s->scr_width = 480; s->scr_height = 640; - s->con = graphic_console_init(tc6393xb_update_display, - NULL, /* invalidate */ - NULL, /* screen_dump */ - NULL, /* text_update */ - s); + s->con = graphic_console_init(&tc6393xb_gfx_ops, s); return s; } diff --git a/hw/display/tcx.c b/hw/display/tcx.c index c44068e..77c7191 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -56,11 +56,6 @@ typedef struct TCXState { uint8_t dac_index, dac_state; } TCXState; -static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp); -static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp); - static void tcx_set_dirty(TCXState *s) { memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY); @@ -515,6 +510,16 @@ static const MemoryRegionOps dummy_ops = { }, }; +static const GraphicHwOps tcx_ops = { + .invalidate = tcx_invalidate_display, + .gfx_update = tcx_update_display, +}; + +static const GraphicHwOps tcx24_ops = { + .invalidate = tcx24_invalidate_display, + .gfx_update = tcx24_update_display, +}; + static int tcx_init1(SysBusDevice *dev) { TCXState *s = FROM_SYSBUS(TCXState, dev); @@ -567,144 +572,20 @@ static int tcx_init1(SysBusDevice *dev) &s->vram_mem, vram_offset, size); sysbus_init_mmio(dev, &s->vram_cplane); - s->con = graphic_console_init(tcx24_update_display, - tcx24_invalidate_display, - tcx24_screen_dump, NULL, s); + s->con = graphic_console_init(&tcx24_ops, s); } else { /* THC 8 bit (dummy) */ memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8", TCX_THC_NREGS_8); sysbus_init_mmio(dev, &s->thc8); - s->con = graphic_console_init(tcx_update_display, - tcx_invalidate_display, - tcx_screen_dump, NULL, s); + s->con = graphic_console_init(&tcx_ops, s); } qemu_console_resize(s->con, s->width, s->height); return 0; } -static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp) -{ - TCXState *s = opaque; - FILE *f; - uint8_t *d, *d1, v; - int ret, y, x; - - f = fopen(filename, "wb"); - if (!f) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); - if (ret < 0) { - goto write_err; - } - d1 = s->vram; - for(y = 0; y < s->height; y++) { - d = d1; - for(x = 0; x < s->width; x++) { - v = *d; - ret = fputc(s->r[v], f); - if (ret == EOF) { - goto write_err; - } - ret = fputc(s->g[v], f); - if (ret == EOF) { - goto write_err; - } - ret = fputc(s->b[v], f); - if (ret == EOF) { - goto write_err; - } - d++; - } - d1 += MAXX; - } - -out: - fclose(f); - return; - -write_err: - error_setg(errp, "failed to write to file '%s': %s", filename, - strerror(errno)); - unlink(filename); - goto out; -} - -static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp) -{ - TCXState *s = opaque; - FILE *f; - uint8_t *d, *d1, v; - uint32_t *s24, *cptr, dval; - int ret, y, x; - - f = fopen(filename, "wb"); - if (!f) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); - if (ret < 0) { - goto write_err; - } - d1 = s->vram; - s24 = s->vram24; - cptr = s->cplane; - for(y = 0; y < s->height; y++) { - d = d1; - for(x = 0; x < s->width; x++, d++, s24++) { - if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct - dval = *s24 & 0x00ffffff; - ret = fputc((dval >> 16) & 0xff, f); - if (ret == EOF) { - goto write_err; - } - ret = fputc((dval >> 8) & 0xff, f); - if (ret == EOF) { - goto write_err; - } - ret = fputc(dval & 0xff, f); - if (ret == EOF) { - goto write_err; - } - } else { - v = *d; - ret = fputc(s->r[v], f); - if (ret == EOF) { - goto write_err; - } - ret = fputc(s->g[v], f); - if (ret == EOF) { - goto write_err; - } - ret = fputc(s->b[v], f); - if (ret == EOF) { - goto write_err; - } - } - } - d1 += MAXX; - } - -out: - fclose(f); - return; - -write_err: - error_setg(errp, "failed to write to file '%s': %s", filename, - strerror(errno)); - unlink(filename); - goto out; -} - static Property tcx_properties[] = { DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1), DEFINE_PROP_UINT16("width", TCXState, width, -1), diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c index 1c50070..2da08a1 100644 --- a/hw/display/vga-isa-mm.c +++ b/hw/display/vga-isa-mm.c @@ -135,9 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base, vga_common_init(&s->vga); vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space); - s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, - s); + s->vga.con = graphic_console_init(s->vga.hw_ops, s); vga_init_vbe(&s->vga, address_space); return 0; diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 90959eb..d2c548e 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -62,8 +62,7 @@ static int vga_initfn(ISADevice *dev) isa_mem_base + 0x000a0000, vga_io_memory, 1); memory_region_set_coalescing(vga_io_memory); - s->con = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + s->con = graphic_console_init(s->hw_ops, s); vga_init_vbe(s, isa_address_space(dev)); /* ROM BIOS */ diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index a9c69b6..dc73f28 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -150,8 +150,7 @@ static int pci_std_vga_initfn(PCIDevice *dev) vga_common_init(s); vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); - s->con = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + s->con = graphic_console_init(s->hw_ops, s); /* XXX: VGA_RAM_SIZE must be a power of two */ pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); diff --git a/hw/display/vga.c b/hw/display/vga.c index c1b67bb..21a108d 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -166,9 +166,6 @@ static uint32_t expand4[256]; static uint16_t expand2[256]; static uint8_t expand4to8[16]; -static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp); - static void vga_update_memory_access(VGACommonState *s) { MemoryRegion *region, *old_region = s->chain4_alias; @@ -2253,6 +2250,12 @@ const VMStateDescription vmstate_vga_common = { } }; +static const GraphicHwOps vga_ops = { + .invalidate = vga_invalidate_display, + .gfx_update = vga_update_display, + .text_update = vga_update_text, +}; + void vga_common_init(VGACommonState *s) { int i, j, v, b; @@ -2296,10 +2299,7 @@ void vga_common_init(VGACommonState *s) s->get_bpp = vga_get_bpp; s->get_offsets = vga_get_offsets; s->get_resolution = vga_get_resolution; - s->update = vga_update_display; - s->invalidate = vga_invalidate_display; - s->screen_dump = vga_screen_dump; - s->text_update = vga_update_text; + s->hw_ops = &vga_ops; switch (vga_retrace_method) { case VGA_RETRACE_DUMB: s->retrace = vga_dumb_retrace; @@ -2393,65 +2393,3 @@ void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory) &s->vram_vbe); s->vbe_mapped = 1; } -/********************************************************/ -/* vga screen dump */ - -void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp) -{ - int width = pixman_image_get_width(ds->image); - int height = pixman_image_get_height(ds->image); - FILE *f; - int y; - int ret; - pixman_image_t *linebuf; - - trace_ppm_save(filename, ds); - f = fopen(filename, "wb"); - if (!f) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255); - if (ret < 0) { - linebuf = NULL; - goto write_err; - } - linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); - for (y = 0; y < height; y++) { - qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y); - clearerr(f); - ret = fwrite(pixman_image_get_data(linebuf), 1, - pixman_image_get_stride(linebuf), f); - (void)ret; - if (ferror(f)) { - goto write_err; - } - } - -out: - qemu_pixman_image_unref(linebuf); - fclose(f); - return; - -write_err: - error_setg(errp, "failed to write to file '%s': %s", filename, - strerror(errno)); - unlink(filename); - goto out; -} - -/* save the vga display in a PPM image even if no display is - available */ -static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp) -{ - VGACommonState *s = opaque; - DisplaySurface *surface = qemu_console_surface(s->con); - - if (cswitch) { - vga_invalidate_display(s); - } - vga_hw_update(); - ppm_save(filename, surface, errp); -} diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index 260f7d6..66f9f3c 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -152,10 +152,7 @@ typedef struct VGACommonState { uint32_t cursor_offset; unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); - vga_hw_update_ptr update; - vga_hw_invalidate_ptr invalidate; - vga_hw_screen_dump_ptr screen_dump; - vga_hw_text_update_ptr text_update; + const GraphicHwOps *hw_ops; bool full_update_text; bool full_update_gfx; /* hardware mouse cursor support */ @@ -198,7 +195,6 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val); uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr); void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val); void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2); -void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp); int vga_ioport_invalid(VGACommonState *s, uint32_t addr); diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index bcad47a..263bf09 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -39,8 +39,6 @@ struct vmsvga_state_s { VGACommonState vga; int invalidated; - int depth; - int bypp; int enable; int config; struct { @@ -55,6 +53,7 @@ struct vmsvga_state_s { uint32_t *scratch; int new_width; int new_height; + int new_depth; uint32_t guest; uint32_t svgaid; int syncing; @@ -721,61 +720,88 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) uint32_t caps; struct vmsvga_state_s *s = opaque; DisplaySurface *surface = qemu_console_surface(s->vga.con); + PixelFormat pf; + uint32_t ret; switch (s->index) { case SVGA_REG_ID: - return s->svgaid; + ret = s->svgaid; + break; case SVGA_REG_ENABLE: - return s->enable; + ret = s->enable; + break; case SVGA_REG_WIDTH: - return surface_width(surface); + ret = s->new_width ? s->new_width : surface_width(surface); + break; case SVGA_REG_HEIGHT: - return surface_height(surface); + ret = s->new_height ? s->new_height : surface_height(surface); + break; case SVGA_REG_MAX_WIDTH: - return SVGA_MAX_WIDTH; + ret = SVGA_MAX_WIDTH; + break; case SVGA_REG_MAX_HEIGHT: - return SVGA_MAX_HEIGHT; + ret = SVGA_MAX_HEIGHT; + break; case SVGA_REG_DEPTH: - return s->depth; + ret = (s->new_depth == 32) ? 24 : s->new_depth; + break; case SVGA_REG_BITS_PER_PIXEL: - return (s->depth + 7) & ~7; + case SVGA_REG_HOST_BITS_PER_PIXEL: + ret = s->new_depth; + break; case SVGA_REG_PSEUDOCOLOR: - return 0x0; + ret = 0x0; + break; case SVGA_REG_RED_MASK: - return surface->pf.rmask; + pf = qemu_default_pixelformat(s->new_depth); + ret = pf.rmask; + break; case SVGA_REG_GREEN_MASK: - return surface->pf.gmask; + pf = qemu_default_pixelformat(s->new_depth); + ret = pf.gmask; + break; case SVGA_REG_BLUE_MASK: - return surface->pf.bmask; + pf = qemu_default_pixelformat(s->new_depth); + ret = pf.bmask; + break; case SVGA_REG_BYTES_PER_LINE: - return s->bypp * s->new_width; + if (s->new_width) { + ret = (s->new_depth * s->new_width) / 8; + } else { + ret = surface_stride(surface); + } + break; case SVGA_REG_FB_START: { struct pci_vmsvga_state_s *pci_vmsvga = container_of(s, struct pci_vmsvga_state_s, chip); - return pci_get_bar_addr(&pci_vmsvga->card, 1); + ret = pci_get_bar_addr(&pci_vmsvga->card, 1); + break; } case SVGA_REG_FB_OFFSET: - return 0x0; + ret = 0x0; + break; case SVGA_REG_VRAM_SIZE: - return s->vga.vram_size; /* No physical VRAM besides the framebuffer */ + ret = s->vga.vram_size; /* No physical VRAM besides the framebuffer */ + break; case SVGA_REG_FB_SIZE: - return s->vga.vram_size; + ret = s->vga.vram_size; + break; case SVGA_REG_CAPABILITIES: caps = SVGA_CAP_NONE; @@ -791,66 +817,92 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) SVGA_CAP_CURSOR_BYPASS; } #endif - return caps; + ret = caps; + break; case SVGA_REG_MEM_START: { struct pci_vmsvga_state_s *pci_vmsvga = container_of(s, struct pci_vmsvga_state_s, chip); - return pci_get_bar_addr(&pci_vmsvga->card, 2); + ret = pci_get_bar_addr(&pci_vmsvga->card, 2); + break; } case SVGA_REG_MEM_SIZE: - return s->fifo_size; + ret = s->fifo_size; + break; case SVGA_REG_CONFIG_DONE: - return s->config; + ret = s->config; + break; case SVGA_REG_SYNC: case SVGA_REG_BUSY: - return s->syncing; + ret = s->syncing; + break; case SVGA_REG_GUEST_ID: - return s->guest; + ret = s->guest; + break; case SVGA_REG_CURSOR_ID: - return s->cursor.id; + ret = s->cursor.id; + break; case SVGA_REG_CURSOR_X: - return s->cursor.x; + ret = s->cursor.x; + break; case SVGA_REG_CURSOR_Y: - return s->cursor.x; + ret = s->cursor.x; + break; case SVGA_REG_CURSOR_ON: - return s->cursor.on; - - case SVGA_REG_HOST_BITS_PER_PIXEL: - return (s->depth + 7) & ~7; + ret = s->cursor.on; + break; case SVGA_REG_SCRATCH_SIZE: - return s->scratch_size; + ret = s->scratch_size; + break; case SVGA_REG_MEM_REGS: case SVGA_REG_NUM_DISPLAYS: case SVGA_REG_PITCHLOCK: case SVGA_PALETTE_BASE ... SVGA_PALETTE_END: - return 0; + ret = 0; + break; default: if (s->index >= SVGA_SCRATCH_BASE && s->index < SVGA_SCRATCH_BASE + s->scratch_size) { - return s->scratch[s->index - SVGA_SCRATCH_BASE]; + ret = s->scratch[s->index - SVGA_SCRATCH_BASE]; + break; } printf("%s: Bad register %02x\n", __func__, s->index); + ret = 0; + break; } - return 0; + if (s->index >= SVGA_SCRATCH_BASE) { + trace_vmware_scratch_read(s->index, ret); + } else if (s->index >= SVGA_PALETTE_BASE) { + trace_vmware_palette_read(s->index, ret); + } else { + trace_vmware_value_read(s->index, ret); + } + return ret; } static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) { struct vmsvga_state_s *s = opaque; + if (s->index >= SVGA_SCRATCH_BASE) { + trace_vmware_scratch_write(s->index, value); + } else if (s->index >= SVGA_PALETTE_BASE) { + trace_vmware_palette_write(s->index, value); + } else { + trace_vmware_value_write(s->index, value); + } switch (s->index) { case SVGA_REG_ID: if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0) { @@ -861,7 +913,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) case SVGA_REG_ENABLE: s->enable = !!value; s->invalidated = 1; - s->vga.invalidate(&s->vga); + s->vga.hw_ops->invalidate(&s->vga); if (s->enable && s->config) { vga_dirty_log_stop(&s->vga); } else { @@ -888,9 +940,10 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) break; case SVGA_REG_BITS_PER_PIXEL: - if (value != s->depth) { + if (value != 32) { printf("%s: Bad bits per pixel: %i bits\n", __func__, value); s->config = 0; + s->invalidated = 1; } break; @@ -986,8 +1039,14 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s) DisplaySurface *surface = qemu_console_surface(s->vga.con); if (s->new_width != surface_width(surface) || - s->new_height != surface_height(surface)) { - qemu_console_resize(s->vga.con, s->new_width, s->new_height); + s->new_height != surface_height(surface) || + s->new_depth != surface_bits_per_pixel(surface)) { + int stride = (s->new_depth * s->new_width) / 8; + trace_vmware_setmode(s->new_width, s->new_height, s->new_depth); + surface = qemu_create_displaysurface_from(s->new_width, s->new_height, + s->new_depth, stride, + s->vga.vram_ptr, false); + dpy_gfx_replace_surface(s->vga.con, surface); s->invalidated = 1; } } @@ -995,15 +1054,16 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s) static void vmsvga_update_display(void *opaque) { struct vmsvga_state_s *s = opaque; - DisplaySurface *surface = qemu_console_surface(s->vga.con); + DisplaySurface *surface; bool dirty = false; if (!s->enable) { - s->vga.update(&s->vga); + s->vga.hw_ops->gfx_update(&s->vga); return; } vmsvga_check_size(s); + surface = qemu_console_surface(s->vga.con); vmsvga_fifo_run(s); vmsvga_update_rect_flush(s); @@ -1020,8 +1080,6 @@ static void vmsvga_update_display(void *opaque) } if (s->invalidated || dirty) { s->invalidated = 0; - memcpy(surface_data(surface), s->vga.vram_ptr, - surface_stride(surface) * surface_height(surface)); dpy_gfx_update(s->vga.con, 0, 0, surface_width(surface), surface_height(surface)); } @@ -1054,44 +1112,19 @@ static void vmsvga_invalidate_display(void *opaque) { struct vmsvga_state_s *s = opaque; if (!s->enable) { - s->vga.invalidate(&s->vga); + s->vga.hw_ops->invalidate(&s->vga); return; } s->invalidated = 1; } -/* save the vga display in a PPM image even if no display is - available */ -static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch, - Error **errp) -{ - struct vmsvga_state_s *s = opaque; - DisplaySurface *surface = qemu_console_surface(s->vga.con); - - if (!s->enable) { - s->vga.screen_dump(&s->vga, filename, cswitch, errp); - return; - } - - if (surface_bits_per_pixel(surface) == 32) { - DisplaySurface *ds = qemu_create_displaysurface_from( - surface_width(surface), - surface_height(surface), - 32, - surface_stride(surface), - s->vga.vram_ptr, false); - ppm_save(filename, ds, errp); - g_free(ds); - } -} - static void vmsvga_text_update(void *opaque, console_ch_t *chardata) { struct vmsvga_state_s *s = opaque; - if (s->vga.text_update) { - s->vga.text_update(&s->vga, chardata); + if (s->vga.hw_ops->text_update) { + s->vga.hw_ops->text_update(&s->vga, chardata); } } @@ -1113,7 +1146,7 @@ static const VMStateDescription vmstate_vmware_vga_internal = { .minimum_version_id_old = 0, .post_load = vmsvga_post_load, .fields = (VMStateField[]) { - VMSTATE_INT32_EQUAL(depth, struct vmsvga_state_s), + VMSTATE_INT32_EQUAL(new_depth, struct vmsvga_state_s), VMSTATE_INT32(enable, struct vmsvga_state_s), VMSTATE_INT32(config, struct vmsvga_state_s), VMSTATE_INT32(cursor.id, struct vmsvga_state_s), @@ -1146,19 +1179,19 @@ static const VMStateDescription vmstate_vmware_vga = { } }; +static const GraphicHwOps vmsvga_ops = { + .invalidate = vmsvga_invalidate_display, + .gfx_update = vmsvga_update_display, + .text_update = vmsvga_text_update, +}; + static void vmsvga_init(struct vmsvga_state_s *s, MemoryRegion *address_space, MemoryRegion *io) { - DisplaySurface *surface; - s->scratch_size = SVGA_SCRATCH_SIZE; s->scratch = g_malloc(s->scratch_size * 4); - s->vga.con = graphic_console_init(vmsvga_update_display, - vmsvga_invalidate_display, - vmsvga_screen_dump, - vmsvga_text_update, s); - surface = qemu_console_surface(s->vga.con); + s->vga.con = graphic_console_init(&vmsvga_ops, s); s->fifo_size = SVGA_FIFO_SIZE; memory_region_init_ram(&s->fifo_ram, "vmsvga.fifo", s->fifo_size); @@ -1168,10 +1201,7 @@ static void vmsvga_init(struct vmsvga_state_s *s, vga_common_init(&s->vga); vga_init(&s->vga, address_space, io, true); vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); - /* Save some values here in case they are changed later. - * This is suspicious and needs more though why it is needed. */ - s->depth = surface_bits_per_pixel(surface); - s->bypp = surface_bytes_per_pixel(surface); + s->new_depth = 32; } static uint64_t vmsvga_io_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index e371569..f2eb89f 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -78,7 +78,6 @@ struct XenFB { void *pixels; int fbpages; int feature_update; - int refresh_period; int bug_trigger; int have_console; int do_resize; @@ -646,7 +645,7 @@ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) dpy_gfx_update(xenfb->c.con, x, y, w, h); } -#if 0 /* def XENFB_TYPE_REFRESH_PERIOD */ +#ifdef XENFB_TYPE_REFRESH_PERIOD static int xenfb_queue_full(struct XenFB *xenfb) { struct xenfb_page *page = xenfb->c.page; @@ -704,39 +703,7 @@ static void xenfb_update(void *opaque) if (xenfb->c.xendev.be_state != XenbusStateConnected) return; - if (xenfb->feature_update) { -#if 0 /* XENFB_TYPE_REFRESH_PERIOD */ - struct DisplayChangeListener *l; - int period = 99999999; - int idle = 1; - - if (xenfb_queue_full(xenfb)) - return; - - QLIST_FOREACH(l, &xenfb->c.ds->listeners, next) { - if (l->idle) - continue; - idle = 0; - if (!l->gui_timer_interval) { - if (period > GUI_REFRESH_INTERVAL) - period = GUI_REFRESH_INTERVAL; - } else { - if (period > l->gui_timer_interval) - period = l->gui_timer_interval; - } - } - if (idle) - period = XENFB_NO_REFRESH; - - if (xenfb->refresh_period != period) { - xenfb_send_refresh_period(xenfb, period); - xenfb->refresh_period = period; - xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period); - } -#else - ; /* nothing */ -#endif - } else { + if (!xenfb->feature_update) { /* we don't get update notifications, thus use the * sledge hammer approach ... */ xenfb->up_fullscreen = 1; @@ -785,6 +752,20 @@ static void xenfb_update(void *opaque) xenfb->up_fullscreen = 0; } +static void xenfb_update_interval(void *opaque, uint64_t interval) +{ + struct XenFB *xenfb = opaque; + + if (xenfb->feature_update) { +#ifdef XENFB_TYPE_REFRESH_PERIOD + if (xenfb_queue_full(xenfb)) { + return; + } + xenfb_send_refresh_period(xenfb, interval); +#endif + } +} + /* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_invalidate(void *opaque) { @@ -858,10 +839,6 @@ static void xenfb_handle_events(struct XenFB *xenfb) static int fb_init(struct XenDevice *xendev) { - struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev); - - fb->refresh_period = -1; - #ifdef XENFB_TYPE_RESIZE xenstore_write_be_int(xendev, "feature-resize", 1); #endif @@ -977,6 +954,12 @@ struct XenDevOps xen_framebuffer_ops = { .frontend_changed = fb_frontend_changed, }; +static const GraphicHwOps xenfb_ops = { + .invalidate = xenfb_invalidate, + .gfx_update = xenfb_update, + .update_interval = xenfb_update_interval, +}; + /* * FIXME/TODO: Kill this. * Temporary needed while DisplayState reorganization is in flight. @@ -1004,11 +987,7 @@ wait_more: /* vfb */ fb = container_of(xfb, struct XenFB, c.xendev); - fb->c.con = graphic_console_init(xenfb_update, - xenfb_invalidate, - NULL, - NULL, - fb); + fb->c.con = graphic_console_init(&xenfb_ops, fb); fb->have_console = 1; /* vkbd */ diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index 7c8fc36..f8d32bc 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -78,6 +78,8 @@ static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size) memory_region_add_subregion(get_system_memory(), 0, ram_memory); } +static const GraphicHwOps no_ops; + static void puv3_load_kernel(const char *kernel_filename) { int size; @@ -92,7 +94,7 @@ static void puv3_load_kernel(const char *kernel_filename) } /* cheat curses that we have a graphic console, only under ocd console */ - graphic_console_init(NULL, NULL, NULL, NULL, NULL); + graphic_console_init(&no_ops, NULL); } static void puv3_init(QEMUMachineInitArgs *args) diff --git a/include/ui/console.h b/include/ui/console.h index a234c72..e591d74 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -21,7 +21,8 @@ #define QEMU_CAPS_LOCK_LED (1 << 2) /* in ms */ -#define GUI_REFRESH_INTERVAL 30 +#define GUI_REFRESH_INTERVAL_DEFAULT 30 +#define GUI_REFRESH_INTERVAL_IDLE 3000 typedef void QEMUPutKBDEvent(void *opaque, int keycode); typedef void QEMUPutLEDEvent(void *opaque, int ledstate); @@ -174,27 +175,15 @@ typedef struct DisplayChangeListenerOps { } DisplayChangeListenerOps; struct DisplayChangeListener { - int idle; - uint64_t gui_timer_interval; + uint64_t update_interval; const DisplayChangeListenerOps *ops; DisplayState *ds; + QemuConsole *con; QLIST_ENTRY(DisplayChangeListener) next; }; -struct DisplayState { - struct DisplaySurface *surface; - struct QEMUTimer *gui_timer; - bool have_gfx; - bool have_text; - - QLIST_HEAD(, DisplayChangeListener) listeners; - - struct DisplayState *next; -}; - -void register_displaystate(DisplayState *ds); -DisplayState *get_displaystate(void); +DisplayState *init_displaystate(void); DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, int linesize, uint8_t *data, bool byteswap); @@ -217,16 +206,15 @@ static inline int is_buffer_shared(DisplaySurface *surface) return !(surface->flags & QEMU_ALLOCATED_FLAG); } -void gui_setup_refresh(DisplayState *ds); - void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl); +void update_displaychangelistener(DisplayChangeListener *dcl, + uint64_t interval); void unregister_displaychangelistener(DisplayChangeListener *dcl); void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h); void dpy_gfx_replace_surface(QemuConsole *con, DisplaySurface *surface); -void dpy_refresh(DisplayState *s); void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, int dst_x, int dst_y, int w, int h); void dpy_text_cursor(QemuConsole *con, int x, int y); @@ -281,24 +269,25 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) *dest = ch; } -typedef void (*vga_hw_update_ptr)(void *); -typedef void (*vga_hw_invalidate_ptr)(void *); -typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch, - Error **errp); -typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); +typedef struct GraphicHwOps { + void (*invalidate)(void *opaque); + void (*gfx_update)(void *opaque); + void (*text_update)(void *opaque, console_ch_t *text); + void (*update_interval)(void *opaque, uint64_t interval); +} GraphicHwOps; -QemuConsole *graphic_console_init(vga_hw_update_ptr update, - vga_hw_invalidate_ptr invalidate, - vga_hw_screen_dump_ptr screen_dump, - vga_hw_text_update_ptr text_update, +QemuConsole *graphic_console_init(const GraphicHwOps *ops, void *opaque); -void vga_hw_update(void); -void vga_hw_invalidate(void); -void vga_hw_text_update(console_ch_t *chardata); +void graphic_hw_update(QemuConsole *con); +void graphic_hw_invalidate(QemuConsole *con); +void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata); + +QemuConsole *qemu_console_lookup_by_index(unsigned int index); +bool qemu_console_is_visible(QemuConsole *con); +bool qemu_console_is_graphic(QemuConsole *con); +bool qemu_console_is_fixedsize(QemuConsole *con); -int is_graphic_console(void); -int is_fixedsize_console(void); void text_consoles_set_display(DisplayState *ds); void console_select(unsigned int index); void console_color_init(DisplayState *ds); diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index b032f52..f012ec5 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -43,4 +43,13 @@ pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, pixman_image_t *image); void qemu_pixman_image_unref(pixman_image_t *image); +pixman_color_t qemu_pixman_color(PixelFormat *pf, uint32_t color); +pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font, + unsigned int ch); +void qemu_pixman_glyph_render(pixman_image_t *glyph, + pixman_image_t *surface, + pixman_color_t *fgcol, + pixman_color_t *bgcol, + int x, int y, int cw, int ch); + #endif /* QEMU_PIXMAN_H */ diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 7a20fc4..a46bc80 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -71,7 +71,6 @@ typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; struct SimpleSpiceDisplay { - QemuConsole *con; DisplaySurface *ds; DisplayChangeListener dcl; void *buf; diff --git a/trace-events b/trace-events index 412f7e4..968edb6 100644 --- a/trace-events +++ b/trace-events @@ -962,6 +962,10 @@ dma_bdrv_cb(void *dbs, int ret) "dbs=%p ret=%d" dma_map_wait(void *dbs) "dbs=%p" # console.h +console_gfx_new(void) "" +console_txt_new(int w, int h) "%dx%d" +console_select(int nr) "%d" +console_refresh(int interval) "interval %d ms" displaysurface_create(void *display_surface, int w, int h) "surface=%p, %dx%d" displaysurface_create_from(void *display_surface, int w, int h, int bpp, int swap) "surface=%p, %dx%d, bpp %d, bswap %d" displaysurface_free(void *display_surface) "surface=%p" @@ -970,6 +974,13 @@ displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]" # vga.c ppm_save(const char *filename, void *display_surface) "%s surface=%p" +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" +vmware_palette_read(uint32_t index, uint32_t value) "index %d, value 0x%x" +vmware_palette_write(uint32_t index, uint32_t value) "index %d, value 0x%x" +vmware_scratch_read(uint32_t index, uint32_t value) "index %d, value 0x%x" +vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x" +vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp" # savevm.c diff --git a/ui/console.c b/ui/console.c index 0ed4211..4f9219e 100644 --- a/ui/console.c +++ b/ui/console.c @@ -32,9 +32,6 @@ #define MAX_CONSOLES 12 #define CONSOLE_CURSOR_PERIOD 500 -#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) -#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff) - typedef struct TextAttributes { uint8_t fgcol:4; uint8_t bgcol:4; @@ -119,14 +116,12 @@ struct QemuConsole { int index; console_type_t console_type; DisplayState *ds; + DisplaySurface *surface; + int dcls; /* Graphic console state. */ - vga_hw_update_ptr hw_update; - vga_hw_invalidate_ptr hw_invalidate; - vga_hw_screen_dump_ptr hw_screen_dump; - vga_hw_text_update_ptr hw_text_update; + const GraphicHwOps *hw_ops; void *hw; - int g_width, g_height; /* Text console state */ int width; @@ -161,88 +156,192 @@ struct QemuConsole { QEMUTimer *kbd_timer; }; +struct DisplayState { + struct QEMUTimer *gui_timer; + uint64_t last_update; + uint64_t update_interval; + bool refreshing; + bool have_gfx; + bool have_text; + + QLIST_HEAD(, DisplayChangeListener) listeners; +}; + static DisplayState *display_state; static QemuConsole *active_console; static QemuConsole *consoles[MAX_CONSOLES]; static int nb_consoles = 0; -void vga_hw_update(void) +static void text_console_do_init(CharDriverState *chr, DisplayState *ds); +static void dpy_refresh(DisplayState *s); + +static void gui_update(void *opaque) { - if (active_console && active_console->hw_update) - active_console->hw_update(active_console->hw); + uint64_t interval = GUI_REFRESH_INTERVAL_IDLE; + uint64_t dcl_interval; + DisplayState *ds = opaque; + DisplayChangeListener *dcl; + int i; + + ds->refreshing = true; + dpy_refresh(ds); + ds->refreshing = false; + + QLIST_FOREACH(dcl, &ds->listeners, next) { + dcl_interval = dcl->update_interval ? + dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT; + if (interval > dcl_interval) { + interval = dcl_interval; + } + } + if (ds->update_interval != interval) { + ds->update_interval = interval; + for (i = 0; i < nb_consoles; i++) { + if (consoles[i]->hw_ops->update_interval) { + consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval); + } + } + trace_console_refresh(interval); + } + ds->last_update = qemu_get_clock_ms(rt_clock); + qemu_mod_timer(ds->gui_timer, ds->last_update + interval); } -void vga_hw_invalidate(void) +static void gui_setup_refresh(DisplayState *ds) { - if (active_console && active_console->hw_invalidate) - active_console->hw_invalidate(active_console->hw); + DisplayChangeListener *dcl; + bool need_timer = false; + bool have_gfx = false; + bool have_text = false; + + QLIST_FOREACH(dcl, &ds->listeners, next) { + if (dcl->ops->dpy_refresh != NULL) { + need_timer = true; + } + if (dcl->ops->dpy_gfx_update != NULL) { + have_gfx = true; + } + if (dcl->ops->dpy_text_update != NULL) { + have_text = true; + } + } + + if (need_timer && ds->gui_timer == NULL) { + ds->gui_timer = qemu_new_timer_ms(rt_clock, gui_update, ds); + qemu_mod_timer(ds->gui_timer, qemu_get_clock_ms(rt_clock)); + } + if (!need_timer && ds->gui_timer != NULL) { + qemu_del_timer(ds->gui_timer); + qemu_free_timer(ds->gui_timer); + ds->gui_timer = NULL; + } + + ds->have_gfx = have_gfx; + ds->have_text = have_text; } -void qmp_screendump(const char *filename, Error **errp) +void graphic_hw_update(QemuConsole *con) +{ + if (!con) { + con = active_console; + } + if (con && con->hw_ops->gfx_update) { + con->hw_ops->gfx_update(con->hw); + } +} + +void graphic_hw_invalidate(QemuConsole *con) { - QemuConsole *previous_active_console; - bool cswitch; + if (!con) { + con = active_console; + } + if (con && con->hw_ops->invalidate) { + con->hw_ops->invalidate(con->hw); + } +} - previous_active_console = active_console; - cswitch = previous_active_console && previous_active_console->index != 0; +static void ppm_save(const char *filename, struct DisplaySurface *ds, + Error **errp) +{ + int width = pixman_image_get_width(ds->image); + int height = pixman_image_get_height(ds->image); + FILE *f; + int y; + int ret; + pixman_image_t *linebuf; - /* There is currently no way of specifying which screen we want to dump, - so always dump the first one. */ - if (cswitch) { - console_select(0); + trace_ppm_save(filename, ds); + f = fopen(filename, "wb"); + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); + return; } - if (consoles[0] && consoles[0]->hw_screen_dump) { - consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp); - } else { - error_setg(errp, "device doesn't support screendump"); + ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255); + if (ret < 0) { + linebuf = NULL; + goto write_err; + } + linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); + for (y = 0; y < height; y++) { + qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y); + clearerr(f); + ret = fwrite(pixman_image_get_data(linebuf), 1, + pixman_image_get_stride(linebuf), f); + (void)ret; + if (ferror(f)) { + goto write_err; + } } - if (cswitch) { - console_select(previous_active_console->index); +out: + qemu_pixman_image_unref(linebuf); + fclose(f); + return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; +} + +void qmp_screendump(const char *filename, Error **errp) +{ + QemuConsole *con = qemu_console_lookup_by_index(0); + DisplaySurface *surface; + + if (con == NULL) { + error_setg(errp, "There is no QemuConsole I can screendump from."); + return; } + + graphic_hw_update(con); + surface = qemu_console_surface(con); + ppm_save(filename, surface, errp); } -void vga_hw_text_update(console_ch_t *chardata) +void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) { - if (active_console && active_console->hw_text_update) - active_console->hw_text_update(active_console->hw, chardata); + if (!con) { + con = active_console; + } + if (con && con->hw_ops->text_update) { + con->hw_ops->text_update(con->hw, chardata); + } } static void vga_fill_rect(QemuConsole *con, int posx, int posy, int width, int height, - uint32_t color) + pixman_color_t color) { DisplaySurface *surface = qemu_console_surface(con); - uint8_t *d, *d1; - int x, y, bpp; + pixman_rectangle16_t rect = { + .x = posx, .y = posy, .width = width, .height = height + }; - bpp = surface_bytes_per_pixel(surface); - d1 = surface_data(surface) + - surface_stride(surface) * posy + bpp * posx; - for (y = 0; y < height; y++) { - d = d1; - switch(bpp) { - case 1: - for (x = 0; x < width; x++) { - *((uint8_t *)d) = color; - d++; - } - break; - case 2: - for (x = 0; x < width; x++) { - *((uint16_t *)d) = color; - d += 2; - } - break; - case 4: - for (x = 0; x < width; x++) { - *((uint32_t *)d) = color; - d += 4; - } - break; - } - d1 += surface_stride(surface); - } + pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image, + &color, 1, &rect); } /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */ @@ -250,33 +349,10 @@ static void vga_bitblt(QemuConsole *con, int xs, int ys, int xd, int yd, int w, int h) { DisplaySurface *surface = qemu_console_surface(con); - const uint8_t *s; - uint8_t *d; - int wb, y, bpp; - - bpp = surface_bytes_per_pixel(surface); - wb = w * bpp; - if (yd <= ys) { - s = surface_data(surface) + - surface_stride(surface) * ys + bpp * xs; - d = surface_data(surface) + - surface_stride(surface) * yd + bpp * xd; - for (y = 0; y < h; y++) { - memmove(d, s, wb); - d += surface_stride(surface); - s += surface_stride(surface); - } - } else { - s = surface_data(surface) + - surface_stride(surface) * (ys + h - 1) + bpp * xs; - d = surface_data(surface) + - surface_stride(surface) * (yd + h - 1) + bpp * xd; - for (y = 0; y < h; y++) { - memmove(d, s, wb); - d -= surface_stride(surface); - s -= surface_stride(surface); - } - } + + pixman_image_composite(PIXMAN_OP_SRC, + surface->image, NULL, surface->image, + xs, ys, 0, 0, xd, yd, w, h); } /***********************************************************/ @@ -287,45 +363,6 @@ static void vga_bitblt(QemuConsole *con, #include "vgafont.h" -#define cbswap_32(__x) \ -((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) - -#ifdef HOST_WORDS_BIGENDIAN -#define PAT(x) x -#else -#define PAT(x) cbswap_32(x) -#endif - -static const uint32_t dmask16[16] = { - PAT(0x00000000), - PAT(0x000000ff), - PAT(0x0000ff00), - PAT(0x0000ffff), - PAT(0x00ff0000), - PAT(0x00ff00ff), - PAT(0x00ffff00), - PAT(0x00ffffff), - PAT(0xff000000), - PAT(0xff0000ff), - PAT(0xff00ff00), - PAT(0xff00ffff), - PAT(0xffff0000), - PAT(0xffff00ff), - PAT(0xffffff00), - PAT(0xffffffff), -}; - -static const uint32_t dmask4[4] = { - PAT(0x00000000), - PAT(0x0000ffff), - PAT(0xffff0000), - PAT(0xffffffff), -}; - #ifndef CONFIG_CURSES enum color_names { COLOR_BLACK = 0, @@ -339,7 +376,10 @@ enum color_names { }; #endif -static const uint32_t color_table_rgb[2][8] = { +#define QEMU_RGB(r, g, b) \ + { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff } + +static const pixman_color_t color_table_rgb[2][8] = { { /* dark */ QEMU_RGB(0x00, 0x00, 0x00), /* black */ QEMU_RGB(0xaa, 0x00, 0x00), /* red */ @@ -398,17 +438,9 @@ static void console_print_text_attributes(TextAttributes *t_attrib, char ch) static void vga_putcharxy(QemuConsole *s, int x, int y, int ch, TextAttributes *t_attrib) { + static pixman_image_t *glyphs[256]; DisplaySurface *surface = qemu_console_surface(s); - uint8_t *d; - const uint8_t *font_ptr; - unsigned int font_data, linesize, xorcol, bpp; - int i; - unsigned int fgcol, bgcol; - -#ifdef DEBUG_CONSOLE - printf("x: %2i y: %2i", x, y); - console_print_text_attributes(t_attrib, ch); -#endif + pixman_color_t fgcol, bgcol; if (t_attrib->invers) { bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol]; @@ -418,58 +450,11 @@ static void vga_putcharxy(QemuConsole *s, int x, int y, int ch, bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol]; } - bpp = surface_bytes_per_pixel(surface); - d = surface_data(surface) + - surface_stride(surface) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH; - linesize = surface_stride(surface); - font_ptr = vgafont16 + FONT_HEIGHT * ch; - xorcol = bgcol ^ fgcol; - switch (surface_bits_per_pixel(surface)) { - case 8: - for(i = 0; i < FONT_HEIGHT; i++) { - font_data = *font_ptr++; - if (t_attrib->uline - && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) { - font_data = 0xFF; - } - ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; - ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; - d += linesize; - } - break; - case 16: - case 15: - for(i = 0; i < FONT_HEIGHT; i++) { - font_data = *font_ptr++; - if (t_attrib->uline - && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) { - font_data = 0xFF; - } - ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; - ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; - ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; - d += linesize; - } - break; - case 32: - for(i = 0; i < FONT_HEIGHT; i++) { - font_data = *font_ptr++; - if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) { - font_data = 0xFF; - } - ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; - ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; - d += linesize; - } - break; + if (!glyphs[ch]) { + glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch); } + qemu_pixman_glyph_render(glyphs[ch], surface->image, + &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT); } static void text_console_resize(QemuConsole *s) @@ -478,8 +463,8 @@ static void text_console_resize(QemuConsole *s) int w1, x, y, last_width; last_width = s->width; - s->width = s->g_width / FONT_WIDTH; - s->height = s->g_height / FONT_HEIGHT; + s->width = surface_width(s->surface) / FONT_WIDTH; + s->height = surface_height(s->surface) / FONT_HEIGHT; w1 = last_width; if (s->width < w1) @@ -529,7 +514,7 @@ static void update_xy(QemuConsole *s, int x, int y) TextCell *c; int y1, y2; - if (s != active_console) { + if (!qemu_console_is_visible(s)) { return; } @@ -557,7 +542,7 @@ static void console_show_cursor(QemuConsole *s, int show) int y, y1; int x = s->x; - if (s != active_console) { + if (!qemu_console_is_visible(s)) { return; } @@ -593,8 +578,9 @@ static void console_refresh(QemuConsole *s) TextCell *c; int x, y, y1; - if (s != active_console) + if (!qemu_console_is_visible(s)) { return; + } if (s->ds->have_text) { s->text_x[0] = 0; @@ -625,15 +611,10 @@ static void console_refresh(QemuConsole *s) } } -static void console_scroll(int ydelta) +static void console_scroll(QemuConsole *s, int ydelta) { - QemuConsole *s; int i, y1; - s = active_console; - if (!s || (s->console_type == GRAPHIC_CONSOLE)) - return; - if (ydelta > 0) { for(i = 0; i < ydelta; i++) { if (s->y_displayed == s->y_base) @@ -683,7 +664,7 @@ static void console_put_lf(QemuConsole *s) c->t_attrib = s->t_attrib_default; c++; } - if (s == active_console && s->y_displayed == s->y_base) { + if (qemu_console_is_visible(s) && s->y_displayed == s->y_base) { if (s->ds->have_text) { s->text_x[0] = 0; s->text_y[0] = 0; @@ -1040,17 +1021,14 @@ static void console_putchar(QemuConsole *s, int ch) void console_select(unsigned int index) { - DisplaySurface *surface; + DisplayChangeListener *dcl; QemuConsole *s; if (index >= MAX_CONSOLES) return; - if (active_console) { - surface = qemu_console_surface(active_console); - active_console->g_width = surface_width(surface); - active_console->g_height = surface_height(surface); - } - s = consoles[index]; + + trace_console_select(index); + s = qemu_console_lookup_by_index(index); if (s) { DisplayState *ds = s->ds; @@ -1059,8 +1037,16 @@ void console_select(unsigned int index) } active_console = s; if (ds->have_gfx) { - surface = qemu_create_displaysurface(s->g_width, s->g_height); - dpy_gfx_replace_surface(s, surface); + QLIST_FOREACH(dcl, &ds->listeners, next) { + if (dcl->con != NULL) { + continue; + } + if (dcl->ops->dpy_gfx_switch) { + dcl->ops->dpy_gfx_switch(dcl, s->surface); + } + } + dpy_gfx_update(s, 0, 0, surface_width(s->surface), + surface_height(s->surface)); } if (ds->have_text) { dpy_text_resize(s, s->width, s->height); @@ -1069,7 +1055,6 @@ void console_select(unsigned int index) qemu_mod_timer(s->cursor_timer, qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2); } - vga_hw_invalidate(); } } @@ -1130,16 +1115,16 @@ void kbd_put_keysym(int keysym) switch(keysym) { case QEMU_KEY_CTRL_UP: - console_scroll(-1); + console_scroll(s, -1); break; case QEMU_KEY_CTRL_DOWN: - console_scroll(1); + console_scroll(s, 1); break; case QEMU_KEY_CTRL_PAGEUP: - console_scroll(-10); + console_scroll(s, -10); break; case QEMU_KEY_CTRL_PAGEDOWN: - console_scroll(10); + console_scroll(s, 10); break; default: /* convert the QEMU keysym to VT100 key string */ @@ -1176,11 +1161,8 @@ void kbd_put_keysym(int keysym) static void text_console_invalidate(void *opaque) { QemuConsole *s = (QemuConsole *) opaque; - DisplaySurface *surface = qemu_console_surface(s); if (s->ds->have_text && s->console_type == TEXT_CONSOLE) { - s->g_width = surface_width(surface); - s->g_height = surface_height(surface); text_console_resize(s); } console_refresh(s); @@ -1317,12 +1299,31 @@ void qemu_free_displaysurface(DisplaySurface *surface) void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl) { + QemuConsole *con; + trace_displaychangelistener_register(dcl, dcl->ops->dpy_name); dcl->ds = ds; QLIST_INSERT_HEAD(&ds->listeners, dcl, next); gui_setup_refresh(ds); - if (dcl->ops->dpy_gfx_switch) { - dcl->ops->dpy_gfx_switch(dcl, ds->surface); + if (dcl->con) { + dcl->con->dcls++; + con = dcl->con; + } else { + con = active_console; + } + if (dcl->ops->dpy_gfx_switch && con) { + dcl->ops->dpy_gfx_switch(dcl, con->surface); + } +} + +void update_displaychangelistener(DisplayChangeListener *dcl, + uint64_t interval) +{ + DisplayState *ds = dcl->ds; + + dcl->update_interval = interval; + if (!ds->refreshing && ds->update_interval > interval) { + qemu_mod_timer(ds->gui_timer, ds->last_update + interval); } } @@ -1330,6 +1331,9 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl) { DisplayState *ds = dcl->ds; trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name); + if (dcl->con) { + dcl->con->dcls--; + } QLIST_REMOVE(dcl, next); gui_setup_refresh(ds); } @@ -1337,9 +1341,9 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl) void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) { DisplayState *s = con->ds; - struct DisplayChangeListener *dcl; - int width = pixman_image_get_width(s->surface->image); - int height = pixman_image_get_height(s->surface->image); + DisplayChangeListener *dcl; + int width = surface_width(con->surface); + int height = surface_height(con->surface); x = MAX(x, 0); y = MAX(y, 0); @@ -1348,7 +1352,13 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) w = MIN(w, width - x); h = MIN(h, height - y); + if (!qemu_console_is_visible(con)) { + return; + } QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_gfx_update) { dcl->ops->dpy_gfx_update(dcl, x, y, w, h); } @@ -1359,11 +1369,14 @@ void dpy_gfx_replace_surface(QemuConsole *con, DisplaySurface *surface) { DisplayState *s = con->ds; - DisplaySurface *old_surface = s->surface; - struct DisplayChangeListener *dcl; + DisplaySurface *old_surface = con->surface; + DisplayChangeListener *dcl; - s->surface = surface; + con->surface = surface; QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_gfx_switch) { dcl->ops->dpy_gfx_switch(dcl, surface); } @@ -1373,7 +1386,8 @@ void dpy_gfx_replace_surface(QemuConsole *con, void dpy_refresh(DisplayState *s) { - struct DisplayChangeListener *dcl; + DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { if (dcl->ops->dpy_refresh) { dcl->ops->dpy_refresh(dcl); @@ -1385,8 +1399,15 @@ void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { DisplayState *s = con->ds; - struct DisplayChangeListener *dcl; + DisplayChangeListener *dcl; + + if (!qemu_console_is_visible(con)) { + return; + } QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_gfx_copy) { dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h); } else { /* TODO */ @@ -1398,8 +1419,15 @@ void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, void dpy_text_cursor(QemuConsole *con, int x, int y) { DisplayState *s = con->ds; - struct DisplayChangeListener *dcl; + DisplayChangeListener *dcl; + + if (!qemu_console_is_visible(con)) { + return; + } QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_text_cursor) { dcl->ops->dpy_text_cursor(dcl, x, y); } @@ -1409,8 +1437,15 @@ void dpy_text_cursor(QemuConsole *con, int x, int y) void dpy_text_update(QemuConsole *con, int x, int y, int w, int h) { DisplayState *s = con->ds; - struct DisplayChangeListener *dcl; + DisplayChangeListener *dcl; + + if (!qemu_console_is_visible(con)) { + return; + } QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_text_update) { dcl->ops->dpy_text_update(dcl, x, y, w, h); } @@ -1421,7 +1456,14 @@ void dpy_text_resize(QemuConsole *con, int w, int h) { DisplayState *s = con->ds; struct DisplayChangeListener *dcl; + + if (!qemu_console_is_visible(con)) { + return; + } QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_text_resize) { dcl->ops->dpy_text_resize(dcl, w, h); } @@ -1431,8 +1473,15 @@ void dpy_text_resize(QemuConsole *con, int w, int h) void dpy_mouse_set(QemuConsole *con, int x, int y, int on) { DisplayState *s = con->ds; - struct DisplayChangeListener *dcl; + DisplayChangeListener *dcl; + + if (!qemu_console_is_visible(con)) { + return; + } QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_mouse_set) { dcl->ops->dpy_mouse_set(dcl, x, y, on); } @@ -1442,8 +1491,15 @@ void dpy_mouse_set(QemuConsole *con, int x, int y, int on) void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor) { DisplayState *s = con->ds; - struct DisplayChangeListener *dcl; + DisplayChangeListener *dcl; + + if (!qemu_console_is_visible(con)) { + return; + } QLIST_FOREACH(dcl, &s->listeners, next) { + if (con != (dcl->con ? dcl->con : active_console)) { + continue; + } if (dcl->ops->dpy_cursor_define) { dcl->ops->dpy_cursor_define(dcl, cursor); } @@ -1453,7 +1509,8 @@ void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor) bool dpy_cursor_define_supported(QemuConsole *con) { DisplayState *s = con->ds; - struct DisplayChangeListener *dcl; + DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { if (dcl->ops->dpy_cursor_define) { return true; @@ -1462,73 +1519,85 @@ bool dpy_cursor_define_supported(QemuConsole *con) return false; } -static void dumb_display_init(void) -{ - DisplayState *ds = g_malloc0(sizeof(DisplayState)); - int width = 640; - int height = 480; - - if (is_fixedsize_console()) { - width = active_console->g_width; - height = active_console->g_height; - } - ds->surface = qemu_create_displaysurface(width, height); - - register_displaystate(ds); -} - /***********************************************************/ /* register display */ -void register_displaystate(DisplayState *ds) +/* console.c internal use only */ +static DisplayState *get_alloc_displaystate(void) { - DisplayState **s; - s = &display_state; - while (*s != NULL) - s = &(*s)->next; - ds->next = NULL; - *s = ds; + if (!display_state) { + display_state = g_new0(DisplayState, 1); + } + return display_state; } -DisplayState *get_displaystate(void) +/* + * Called by main(), after creating QemuConsoles + * and before initializing ui (sdl/vnc/...). + */ +DisplayState *init_displaystate(void) { + int i; + if (!display_state) { - dumb_display_init (); + display_state = g_new0(DisplayState, 1); + } + + for (i = 0; i < nb_consoles; i++) { + if (consoles[i]->console_type != GRAPHIC_CONSOLE && + consoles[i]->ds == NULL) { + text_console_do_init(consoles[i]->chr, display_state); + } } + return display_state; } -QemuConsole *graphic_console_init(vga_hw_update_ptr update, - vga_hw_invalidate_ptr invalidate, - vga_hw_screen_dump_ptr screen_dump, - vga_hw_text_update_ptr text_update, +QemuConsole *graphic_console_init(const GraphicHwOps *hw_ops, void *opaque) { + int width = 640; + int height = 480; QemuConsole *s; DisplayState *ds; - ds = (DisplayState *) g_malloc0(sizeof(DisplayState)); + ds = get_alloc_displaystate(); + trace_console_gfx_new(); s = new_console(ds, GRAPHIC_CONSOLE); - s->hw_update = update; - s->hw_invalidate = invalidate; - s->hw_screen_dump = screen_dump; - s->hw_text_update = text_update; + s->hw_ops = hw_ops; s->hw = opaque; - ds->surface = qemu_create_displaysurface(640, 480); - - register_displaystate(ds); + s->surface = qemu_create_displaysurface(width, height); return s; } -int is_graphic_console(void) +QemuConsole *qemu_console_lookup_by_index(unsigned int index) { - return active_console && active_console->console_type == GRAPHIC_CONSOLE; + if (index >= MAX_CONSOLES) { + return NULL; + } + return consoles[index]; } -int is_fixedsize_console(void) +bool qemu_console_is_visible(QemuConsole *con) { - return active_console && active_console->console_type != TEXT_CONSOLE; + return (con == active_console) || (con->dcls > 0); +} + +bool qemu_console_is_graphic(QemuConsole *con) +{ + if (con == NULL) { + con = active_console; + } + return con && (con->console_type == GRAPHIC_CONSOLE); +} + +bool qemu_console_is_fixedsize(QemuConsole *con) +{ + if (con == NULL) { + con = active_console; + } + return con && (con->console_type != TEXT_CONSOLE); } static void text_console_set_echo(CharDriverState *chr, bool echo) @@ -1543,14 +1612,21 @@ static void text_console_update_cursor(void *opaque) QemuConsole *s = opaque; s->cursor_visible_phase = !s->cursor_visible_phase; - vga_hw_invalidate(); + graphic_hw_invalidate(s); qemu_mod_timer(s->cursor_timer, qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2); } +static const GraphicHwOps text_console_ops = { + .invalidate = text_console_invalidate, + .text_update = text_console_update, +}; + static void text_console_do_init(CharDriverState *chr, DisplayState *ds) { QemuConsole *s; + int g_width = 80 * FONT_WIDTH; + int g_height = 24 * FONT_HEIGHT; s = chr->opaque; @@ -1566,16 +1642,18 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; - if (s->console_type == TEXT_CONSOLE) { - s->g_width = surface_width(s->ds->surface); - s->g_height = surface_height(s->ds->surface); + if (!s->surface) { + if (active_console && active_console->surface) { + g_width = surface_width(active_console->surface); + g_height = surface_height(active_console->surface); + } + s->surface = qemu_create_displaysurface(g_width, g_height); } s->cursor_timer = qemu_new_timer_ms(rt_clock, text_console_update_cursor, s); - s->hw_invalidate = text_console_invalidate; - s->hw_text_update = text_console_update; + s->hw_ops = &text_console_ops; s->hw = s; /* Set text attribute defaults */ @@ -1626,10 +1704,12 @@ static CharDriverState *text_console_init(ChardevVC *vc) height = vc->rows * FONT_HEIGHT; } + trace_console_txt_new(width, height); if (width == 0 || height == 0) { s = new_console(NULL, TEXT_CONSOLE); } else { s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE); + s->surface = qemu_create_displaysurface(width, height); } if (!s) { @@ -1638,10 +1718,12 @@ static CharDriverState *text_console_init(ChardevVC *vc) } s->chr = chr; - s->g_width = width; - s->g_height = height; chr->opaque = s; chr->chr_set_echo = text_console_set_echo; + + if (display_state) { + text_console_do_init(chr, display_state); + } return chr; } @@ -1657,39 +1739,25 @@ void register_vc_handler(VcHandler *handler) vc_handler = handler; } -void text_consoles_set_display(DisplayState *ds) -{ - int i; - - for (i = 0; i < nb_consoles; i++) { - if (consoles[i]->console_type != GRAPHIC_CONSOLE) { - text_console_do_init(consoles[i]->chr, ds); - } - } -} - void qemu_console_resize(QemuConsole *s, int width, int height) { - s->g_width = width; - s->g_height = height; - if (is_graphic_console()) { - DisplaySurface *surface; - surface = qemu_create_displaysurface(width, height); - dpy_gfx_replace_surface(s, surface); - } + DisplaySurface *surface; + + assert(s->console_type == GRAPHIC_CONSOLE); + surface = qemu_create_displaysurface(width, height); + dpy_gfx_replace_surface(s, surface); } void qemu_console_copy(QemuConsole *con, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { - if (is_graphic_console()) { - dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h); - } + assert(con->console_type == GRAPHIC_CONSOLE); + dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h); } DisplaySurface *qemu_console_surface(QemuConsole *console) { - return console->ds->surface; + return console->surface; } DisplayState *qemu_console_displaystate(QemuConsole *console) diff --git a/ui/curses.c b/ui/curses.c index ff82307..a85a7da 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -56,7 +56,7 @@ static void curses_update(DisplayChangeListener *dcl, static void curses_calc_pad(void) { - if (is_fixedsize_console()) { + if (qemu_console_is_fixedsize(NULL)) { width = gwidth; height = gheight; } else { @@ -143,8 +143,9 @@ static void curses_cursor_position(DisplayChangeListener *dcl, curs_set(1); /* it seems that curs_set(1) must always be called before * curs_set(2) for the latter to have effect */ - if (!is_graphic_console()) + if (!qemu_console_is_graphic(NULL)) { curs_set(2); + } return; } } @@ -166,11 +167,11 @@ static void curses_refresh(DisplayChangeListener *dcl) clear(); refresh(); curses_calc_pad(); - vga_hw_invalidate(); + graphic_hw_invalidate(NULL); invalidate = 0; } - vga_hw_text_update(screen); + graphic_hw_text_update(NULL, screen); nextchr = ERR; while (1) { @@ -252,7 +253,7 @@ static void curses_refresh(DisplayChangeListener *dcl) if (keycode == -1) continue; - if (is_graphic_console()) { + if (qemu_console_is_graphic(NULL)) { /* since terminals don't know about key press and release * events, we need to emit both for each key received */ if (keycode & SHIFT) @@ -327,7 +327,38 @@ static void gd_update(DisplayChangeListener *dcl, static void gd_refresh(DisplayChangeListener *dcl) { - vga_hw_update(); + graphic_hw_update(dcl->con); +} + +static void gd_mouse_set(DisplayChangeListener *dcl, + int x, int y, int visible) +{ + GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl); + gint x_root, y_root; + + gdk_window_get_root_coords(s->drawing_area->window, + x, y, &x_root, &y_root); + gdk_display_warp_pointer(gtk_widget_get_display(s->drawing_area), + gtk_widget_get_screen(s->drawing_area), + x_root, y_root); +} + +static void gd_cursor_define(DisplayChangeListener *dcl, + QEMUCursor *c) +{ + GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl); + GdkPixbuf *pixbuf; + GdkCursor *cursor; + + pixbuf = gdk_pixbuf_new_from_data((guchar *)(c->data), + GDK_COLORSPACE_RGB, true, 8, + c->width, c->height, c->width * 4, + NULL, NULL); + cursor = gdk_cursor_new_from_pixbuf(gtk_widget_get_display(s->drawing_area), + pixbuf, c->hot_x, c->hot_y); + gdk_window_set_cursor(s->drawing_area->window, cursor); + g_object_unref(pixbuf); + g_object_unref(cursor); } static void gd_switch(DisplayChangeListener *dcl, @@ -1358,6 +1389,8 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_gfx_update = gd_update, .dpy_gfx_switch = gd_switch, .dpy_refresh = gd_refresh, + .dpy_mouse_set = gd_mouse_set, + .dpy_cursor_define = gd_cursor_define, }; void gtk_display_init(DisplayState *ds) @@ -1368,6 +1401,7 @@ void gtk_display_init(DisplayState *ds) gtk_init(NULL, NULL); s->dcl.ops = &dcl_ops; + s->dcl.con = qemu_console_lookup_by_index(0); s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); #if GTK_CHECK_VERSION(3, 2, 0) diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 6dcbe90..254bd8c 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -79,3 +79,57 @@ void qemu_pixman_image_unref(pixman_image_t *image) } pixman_image_unref(image); } + +pixman_color_t qemu_pixman_color(PixelFormat *pf, uint32_t color) +{ + pixman_color_t c; + + c.red = ((color & pf->rmask) >> pf->rshift) << (16 - pf->rbits); + c.green = ((color & pf->gmask) >> pf->gshift) << (16 - pf->gbits); + c.blue = ((color & pf->bmask) >> pf->bshift) << (16 - pf->bbits); + c.alpha = ((color & pf->amask) >> pf->ashift) << (16 - pf->abits); + return c; +} + +pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font, + unsigned int ch) +{ + pixman_image_t *glyph; + uint8_t *data; + bool bit; + int x, y; + + glyph = pixman_image_create_bits(PIXMAN_a8, 8, height, + NULL, 0); + data = (uint8_t *)pixman_image_get_data(glyph); + + font += height * ch; + for (y = 0; y < height; y++, font++) { + for (x = 0; x < 8; x++, data++) { + bit = (*font) & (1 << (7-x)); + *data = bit ? 0xff : 0x00; + } + } + return glyph; +} + +void qemu_pixman_glyph_render(pixman_image_t *glyph, + pixman_image_t *surface, + pixman_color_t *fgcol, + pixman_color_t *bgcol, + int x, int y, int cw, int ch) +{ + pixman_image_t *ifg = pixman_image_create_solid_fill(fgcol); + pixman_image_t *ibg = pixman_image_create_solid_fill(bgcol); + + pixman_image_composite(PIXMAN_OP_SRC, ibg, NULL, surface, + 0, 0, 0, 0, + cw * x, ch * y, + cw, ch); + pixman_image_composite(PIXMAN_OP_OVER, ifg, glyph, surface, + 0, 0, 0, 0, + cw * x, ch * y, + cw, ch); + pixman_image_unref(ifg); + pixman_image_unref(ibg); +} @@ -358,7 +358,7 @@ static void sdl_show_cursor(void) if (!cursor_hide) return; - if (!kbd_mouse_is_absolute() || !is_graphic_console()) { + if (!kbd_mouse_is_absolute() || !qemu_console_is_graphic(NULL)) { SDL_ShowCursor(1); if (guest_cursor && (gui_grab || kbd_mouse_is_absolute() || absolute_enabled)) @@ -413,7 +413,7 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data) if (kbd_mouse_is_absolute()) { if (!absolute_enabled) { absolute_enabled = 1; - if (is_graphic_console()) { + if (qemu_console_is_graphic(NULL)) { absolute_mouse_grab(); } } @@ -488,12 +488,12 @@ static void toggle_full_screen(void) } else { do_sdl_resize(width, height, 0); } - if (!gui_saved_grab || !is_graphic_console()) { + if (!gui_saved_grab || !qemu_console_is_graphic(NULL)) { sdl_grab_end(); } } - vga_hw_invalidate(); - vga_hw_update(); + graphic_hw_invalidate(NULL); + graphic_hw_update(NULL); } static void handle_keydown(SDL_Event *ev) @@ -522,8 +522,8 @@ static void handle_keydown(SDL_Event *ev) if (scaling_active) { scaling_active = 0; sdl_switch(dcl, NULL); - vga_hw_invalidate(); - vga_hw_update(); + graphic_hw_invalidate(NULL); + graphic_hw_update(NULL); } gui_keysym = 1; break; @@ -535,7 +535,7 @@ static void handle_keydown(SDL_Event *ev) if (gui_fullscreen) { break; } - if (!is_graphic_console()) { + if (!qemu_console_is_graphic(NULL)) { /* release grab if going to a text console */ if (gui_grab) { sdl_grab_end(); @@ -556,14 +556,14 @@ static void handle_keydown(SDL_Event *ev) surface_width(surface); sdl_scale(width, height); - vga_hw_invalidate(); - vga_hw_update(); + graphic_hw_invalidate(NULL); + graphic_hw_update(NULL); gui_keysym = 1; } default: break; } - } else if (!is_graphic_console()) { + } else if (!qemu_console_is_graphic(NULL)) { int keysym = 0; if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { @@ -637,7 +637,7 @@ static void handle_keydown(SDL_Event *ev) kbd_put_keysym(ev->key.keysym.unicode); } } - if (is_graphic_console() && !gui_keysym) { + if (qemu_console_is_graphic(NULL) && !gui_keysym) { sdl_process_key(&ev->key); } } @@ -656,7 +656,7 @@ static void handle_keyup(SDL_Event *ev) if (gui_keysym == 0) { /* exit/enter grab if pressing Ctrl-Alt */ if (!gui_grab) { - if (is_graphic_console()) { + if (qemu_console_is_graphic(NULL)) { sdl_grab_start(); } } else if (!gui_fullscreen) { @@ -669,7 +669,7 @@ static void handle_keyup(SDL_Event *ev) } gui_keysym = 0; } - if (is_graphic_console() && !gui_keysym) { + if (qemu_console_is_graphic(NULL) && !gui_keysym) { sdl_process_key(&ev->key); } } @@ -678,7 +678,7 @@ static void handle_mousemotion(SDL_Event *ev) { int max_x, max_y; - if (is_graphic_console() && + if (qemu_console_is_graphic(NULL) && (kbd_mouse_is_absolute() || absolute_enabled)) { max_x = real_screen->w - 1; max_y = real_screen->h - 1; @@ -704,7 +704,7 @@ static void handle_mousebutton(SDL_Event *ev) SDL_MouseButtonEvent *bev; int dz; - if (!is_graphic_console()) { + if (!qemu_console_is_graphic(NULL)) { return; } @@ -744,19 +744,19 @@ static void handle_activation(SDL_Event *ev) sdl_grab_end(); } #endif - if (!gui_grab && ev->active.gain && is_graphic_console() && + if (!gui_grab && ev->active.gain && qemu_console_is_graphic(NULL) && (kbd_mouse_is_absolute() || absolute_enabled)) { absolute_mouse_grab(); } if (ev->active.state & SDL_APPACTIVE) { if (ev->active.gain) { /* Back to default interval */ - dcl->gui_timer_interval = 0; - dcl->idle = 0; + update_displaychangelistener(dcl, GUI_REFRESH_INTERVAL_DEFAULT); } else { - /* Sleeping interval */ - dcl->gui_timer_interval = 500; - dcl->idle = 1; + /* Sleeping interval. Not using the long default here as + * sdl_refresh does not only update the guest screen, but + * also checks for gui events. */ + update_displaychangelistener(dcl, 500); } } } @@ -770,8 +770,8 @@ static void sdl_refresh(DisplayChangeListener *dcl) sdl_update_caption(); } - vga_hw_update(); - SDL_EnableUNICODE(!is_graphic_console()); + graphic_hw_update(NULL); + SDL_EnableUNICODE(!qemu_console_is_graphic(NULL)); while (SDL_PollEvent(ev)) { switch (ev->type) { @@ -802,8 +802,8 @@ static void sdl_refresh(DisplayChangeListener *dcl) break; case SDL_VIDEORESIZE: sdl_scale(ev->resize.w, ev->resize.h); - vga_hw_invalidate(); - vga_hw_update(); + graphic_hw_invalidate(NULL); + graphic_hw_update(NULL); break; default: break; diff --git a/ui/spice-display.c b/ui/spice-display.c index eaab19d..53c19be 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -398,14 +398,14 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) { if (ssd->cursor) { - assert(ssd->con); - dpy_cursor_define(ssd->con, ssd->cursor); + assert(ssd->dcl.con); + dpy_cursor_define(ssd->dcl.con, ssd->cursor); cursor_put(ssd->cursor); ssd->cursor = NULL; } if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { - assert(ssd->con); - dpy_mouse_set(ssd->con, ssd->mouse_x, ssd->mouse_y, 1); + assert(ssd->dcl.con); + dpy_mouse_set(ssd->dcl.con, ssd->mouse_x, ssd->mouse_y, 1); ssd->mouse_x = -1; ssd->mouse_y = -1; } @@ -414,7 +414,7 @@ void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) { dprint(3, "%s:\n", __func__); - vga_hw_update(); + graphic_hw_update(ssd->dcl.con); qemu_mutex_lock(&ssd->lock); if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) { @@ -624,6 +624,7 @@ void qemu_spice_display_init(DisplayState *ds) qemu_spice_create_host_memslot(ssd); ssd->dcl.ops = &display_listener_ops; + ssd->dcl.con = qemu_console_lookup_by_index(0); register_displaychangelistener(ds, &ssd->dcl); qemu_spice_create_host_primary(ssd); @@ -34,9 +34,9 @@ #include "qmp-commands.h" #include "qemu/osdep.h" -#define VNC_REFRESH_INTERVAL_BASE 30 +#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT #define VNC_REFRESH_INTERVAL_INC 50 -#define VNC_REFRESH_INTERVAL_MAX 2000 +#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE static const struct timeval VNC_REFRESH_STATS = { 0, 500000 }; static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 }; @@ -419,14 +419,12 @@ out_error: static int vnc_update_client(VncState *vs, int has_dirty); static int vnc_update_client_sync(VncState *vs, int has_dirty); static void vnc_disconnect_start(VncState *vs); -static void vnc_init_timer(VncDisplay *vd); -static void vnc_remove_timer(VncDisplay *vd); static void vnc_colordepth(VncState *vs); static void framebuffer_update_request(VncState *vs, int incremental, int x_position, int y_position, int w, int h); -static void vnc_refresh(void *opaque); +static void vnc_refresh(DisplayChangeListener *dcl); static int vnc_refresh_server_surface(VncDisplay *vd); static void vnc_dpy_update(DisplayChangeListener *dcl, @@ -1064,11 +1062,6 @@ void vnc_disconnect_finish(VncState *vs) qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier); } - if (QTAILQ_EMPTY(&vs->vd->clients)) { - vs->vd->dcl.idle = 1; - } - - vnc_remove_timer(vs->vd); if (vs->vd->lock_key_sync) qemu_remove_led_event_handler(vs->led); vnc_unlock_output(vs); @@ -1616,7 +1609,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) } } - if (is_graphic_console()) { + if (qemu_console_is_graphic(NULL)) { if (keycode & SCANCODE_GREY) kbd_put_keycode(SCANCODE_EMUL0); if (down) @@ -1735,7 +1728,7 @@ static void vnc_release_modifiers(VncState *vs) }; int i, keycode; - if (!is_graphic_console()) { + if (!qemu_console_is_graphic(NULL)) { return; } for (i = 0; i < ARRAY_SIZE(keycodes); i++) { @@ -1755,7 +1748,7 @@ static void key_event(VncState *vs, int down, uint32_t sym) int keycode; int lsym = sym; - if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) { + if (lsym >= 'A' && lsym <= 'Z' && qemu_console_is_graphic(NULL)) { lsym = lsym - 'A' + 'a'; } @@ -1956,8 +1949,8 @@ static void set_pixel_format(VncState *vs, set_pixel_conversion(vs); - vga_hw_invalidate(); - vga_hw_update(); + graphic_hw_invalidate(NULL); + graphic_hw_update(NULL); } static void pixel_format_message (VncState *vs) { @@ -2013,9 +2006,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) VncDisplay *vd = vs->vd; if (data[0] > 3) { - vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; - if (!qemu_timer_expired(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval)) - qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval); + update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); } switch (data[0]) { @@ -2647,18 +2638,16 @@ static int vnc_refresh_server_surface(VncDisplay *vd) return has_dirty; } -static void vnc_refresh(void *opaque) +static void vnc_refresh(DisplayChangeListener *dcl) { - VncDisplay *vd = opaque; + VncDisplay *vd = container_of(dcl, VncDisplay, dcl); VncState *vs, *vn; int has_dirty, rects = 0; - vga_hw_update(); + graphic_hw_update(NULL); if (vnc_trylock_display(vd)) { - vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; - qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + - vd->timer_interval); + update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); return; } @@ -2670,39 +2659,21 @@ static void vnc_refresh(void *opaque) /* vs might be free()ed here */ } - /* vd->timer could be NULL now if the last client disconnected, - * in this case don't update the timer */ - if (vd->timer == NULL) + if (QTAILQ_EMPTY(&vd->clients)) { + update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX); return; + } if (has_dirty && rects) { - vd->timer_interval /= 2; - if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE) - vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; + vd->dcl.update_interval /= 2; + if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) { + vd->dcl.update_interval = VNC_REFRESH_INTERVAL_BASE; + } } else { - vd->timer_interval += VNC_REFRESH_INTERVAL_INC; - if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX) - vd->timer_interval = VNC_REFRESH_INTERVAL_MAX; - } - qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval); -} - -static void vnc_init_timer(VncDisplay *vd) -{ - vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; - if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) { - vd->timer = qemu_new_timer_ms(rt_clock, vnc_refresh, vd); - vga_hw_update(); - vnc_refresh(vd); - } -} - -static void vnc_remove_timer(VncDisplay *vd) -{ - if (vd->timer != NULL && QTAILQ_EMPTY(&vd->clients)) { - qemu_del_timer(vd->timer); - qemu_free_timer(vd->timer); - vd->timer = NULL; + vd->dcl.update_interval += VNC_REFRESH_INTERVAL_INC; + if (vd->dcl.update_interval > VNC_REFRESH_INTERVAL_MAX) { + vd->dcl.update_interval = VNC_REFRESH_INTERVAL_MAX; + } } } @@ -2731,7 +2702,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket) } VNC_DEBUG("New client on socket %d\n", csock); - vd->dcl.idle = 0; + update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); qemu_set_nonblock(vs->csock); #ifdef CONFIG_VNC_WS if (websocket) { @@ -2775,7 +2746,7 @@ void vnc_init_state(VncState *vs) QTAILQ_INSERT_HEAD(&vd->clients, vs, next); - vga_hw_update(); + graphic_hw_update(NULL); vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); @@ -2787,8 +2758,6 @@ void vnc_init_state(VncState *vs) vs->mouse_mode_notifier.notify = check_pointer_type_change; qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier); - vnc_init_timer(vd); - /* vs might be free()ed here */ } @@ -2800,7 +2769,7 @@ static void vnc_listen_read(void *opaque, bool websocket) int csock; /* Catch-up */ - vga_hw_update(); + graphic_hw_update(NULL); #ifdef CONFIG_VNC_WS if (websocket) { csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen); @@ -2829,6 +2798,7 @@ static void vnc_listen_websocket_read(void *opaque) static const DisplayChangeListenerOps dcl_ops = { .dpy_name = "vnc", + .dpy_refresh = vnc_refresh, .dpy_gfx_copy = vnc_dpy_copy, .dpy_gfx_update = vnc_dpy_update, .dpy_gfx_switch = vnc_dpy_switch, @@ -2840,7 +2810,6 @@ void vnc_display_init(DisplayState *ds) { VncDisplay *vs = g_malloc0(sizeof(*vs)); - vs->dcl.idle = 1; vnc_display = vs; vs->lsock = -1; @@ -142,8 +142,6 @@ struct VncDisplay QTAILQ_HEAD(, VncState) clients; int num_exclusive; VncSharePolicy share_policy; - QEMUTimer *timer; - int timer_interval; int lsock; #ifdef CONFIG_VNC_WS int lwebsock; @@ -1626,55 +1626,6 @@ MachineInfoList *qmp_query_machines(Error **errp) /***********************************************************/ /* main execution loop */ -static void gui_update(void *opaque) -{ - uint64_t interval = GUI_REFRESH_INTERVAL; - DisplayState *ds = opaque; - DisplayChangeListener *dcl; - - dpy_refresh(ds); - - QLIST_FOREACH(dcl, &ds->listeners, next) { - if (dcl->gui_timer_interval && - dcl->gui_timer_interval < interval) - interval = dcl->gui_timer_interval; - } - qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock_ms(rt_clock)); -} - -void gui_setup_refresh(DisplayState *ds) -{ - DisplayChangeListener *dcl; - bool need_timer = false; - bool have_gfx = false; - bool have_text = false; - - QLIST_FOREACH(dcl, &ds->listeners, next) { - if (dcl->ops->dpy_refresh != NULL) { - need_timer = true; - } - if (dcl->ops->dpy_gfx_update != NULL) { - have_gfx = true; - } - if (dcl->ops->dpy_text_update != NULL) { - have_text = true; - } - } - - if (need_timer && ds->gui_timer == NULL) { - ds->gui_timer = qemu_new_timer_ms(rt_clock, gui_update, ds); - qemu_mod_timer(ds->gui_timer, qemu_get_clock_ms(rt_clock)); - } - if (!need_timer && ds->gui_timer != NULL) { - qemu_del_timer(ds->gui_timer); - qemu_free_timer(ds->gui_timer); - ds->gui_timer = NULL; - } - - ds->have_gfx = have_gfx; - ds->have_text = have_text; -} - struct vm_change_state_entry { VMChangeStateHandler *cb; void *opaque; @@ -4331,8 +4282,7 @@ int main(int argc, char **argv, char **envp) net_check_clients(); - /* just use the first displaystate for the moment */ - ds = get_displaystate(); + ds = init_displaystate(); /* init local displays */ switch (display_type) { @@ -4388,9 +4338,6 @@ int main(int argc, char **argv, char **envp) } #endif - /* display setup */ - text_consoles_set_display(ds); - if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) { exit(1); } |