console: simplify screendump

Screendumps are alot simpler as we can update non-active
QemuConsoles now.  So we only need to update the QemuConsole
we want write out, then dump the DisplaySurface content into
a ppm file.  Done.

No console switching needed.  No special support code in the
gfx card emulation needed.  Zap it all.  Also move ppm_save
out of the vga code and next to the qmp_screendump function.

For now screen dumping is limited to console #0 (like it used
to be), even though it is dead simple to extend it to other
consoles.  I wanna finish the console cleanup before setting
new qapi interfaces into stone.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Tested-by: Igor Mitsyanko <i.mitsyanko@gmail.com>
This commit is contained in:
Gerd Hoffmann 2013-03-12 14:48:31 +01:00
parent 321f048d24
commit 2c62f08ddb
26 changed files with 74 additions and 452 deletions

View File

@ -612,7 +612,7 @@ static int musicpal_lcd_init(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->iomem);
s->con = graphic_console_init(lcd_refresh, lcd_invalidate,
NULL, NULL, s);
NULL, s);
qemu_console_resize(s->con, 128*3, 64*3);
qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3);

View File

@ -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
@ -965,7 +953,7 @@ void *s1d13745_init(qemu_irq gpio_int)
s->con = graphic_console_init(blizzard_update_display,
blizzard_invalidate_display,
blizzard_screen_dump, NULL, s);
NULL, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {

View File

@ -2911,7 +2911,7 @@ static int vga_initfn(ISADevice *dev)
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->text_update,
s);
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
/* XXX ISA-LFB support */
@ -2960,7 +2960,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
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.text_update,
&s->vga);
/* setup PCI */

View File

@ -1901,7 +1901,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
"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);
exynos4210_fimd_invalidate, NULL, s);
return 0;
}

View File

@ -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,
@ -552,7 +481,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
s->con = graphic_console_init(g364fb_update_display,
g364fb_invalidate_display,
g364fb_screen_dump, NULL, s);
NULL, s);
memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
memory_region_init_ram_ptr(&s->mem_vram, "vram",

View File

@ -263,7 +263,6 @@ static int jazz_led_init(SysBusDevice *dev)
s->con = graphic_console_init(jazz_led_update_display,
jazz_led_invalidate_display,
NULL,
jazz_led_text_update, s);
return 0;

View File

@ -280,7 +280,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev)
s->con = graphic_console_init(vgafb_update_display,
vgafb_invalidate_display,
NULL, NULL, s);
NULL, s);
return 0;
}

View File

@ -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;
@ -487,7 +403,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
s->con = graphic_console_init(omap_update_display,
omap_invalidate_display,
omap_screen_dump, NULL, s);
NULL, s);
return s;
}

View File

@ -454,7 +454,7 @@ static int pl110_init(SysBusDevice *dev)
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);
NULL, s);
return 0;
}

View File

@ -1010,7 +1010,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
s->con = graphic_console_init(pxa2xx_update_display,
pxa2xx_invalidate_display,
NULL, NULL, s);
NULL, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {

View File

@ -1772,26 +1772,6 @@ static void qxl_hw_invalidate(void *opaque)
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;
}
}
static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
{
PCIQXLDevice *qxl = opaque;
@ -2075,7 +2055,7 @@ static int qxl_init_primary(PCIDevice *dev)
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_hw_text_update,
qxl);
qxl->ssd.con = vga->con,
qemu_spice_display_init_common(&qxl->ssd);

View File

@ -1446,5 +1446,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);
NULL, s);
}

View File

@ -290,7 +290,7 @@ static int ssd0303_init(I2CSlave *i2c)
s->con = graphic_console_init(ssd0303_update_display,
ssd0303_invalidate_display,
NULL, NULL, s);
NULL, s);
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
return 0;
}

View File

@ -339,7 +339,7 @@ static int ssd0323_init(SSISlave *dev)
s->row_end = 79;
s->con = graphic_console_init(ssd0323_update_display,
ssd0323_invalidate_display,
NULL, NULL, s);
NULL, s);
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);

View File

@ -585,7 +585,6 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
s->scr_height = 640;
s->con = graphic_console_init(tc6393xb_update_display,
NULL, /* invalidate */
NULL, /* screen_dump */
NULL, /* text_update */
s);

View File

@ -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);
@ -569,7 +564,7 @@ static int tcx_init1(SysBusDevice *dev)
s->con = graphic_console_init(tcx24_update_display,
tcx24_invalidate_display,
tcx24_screen_dump, NULL, s);
NULL, s);
} else {
/* THC 8 bit (dummy) */
memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
@ -578,133 +573,13 @@ static int tcx_init1(SysBusDevice *dev)
s->con = graphic_console_init(tcx_update_display,
tcx_invalidate_display,
tcx_screen_dump, NULL, s);
NULL, 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),

View File

@ -136,7 +136,7 @@ int isa_vga_mm_init(hwaddr vram_base,
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->vga.text_update,
s);
vga_init_vbe(&s->vga, address_space);

View File

@ -63,7 +63,7 @@ static int vga_initfn(ISADevice *dev)
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->text_update, s);
vga_init_vbe(s, isa_address_space(dev));
/* ROM BIOS */

View File

@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
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->text_update, s);
/* XXX: VGA_RAM_SIZE must be a power of two */
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);

View File

@ -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;
@ -2298,7 +2295,6 @@ void vga_common_init(VGACommonState *s)
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;
switch (vga_retrace_method) {
case VGA_RETRACE_DUMB:
@ -2393,65 +2389,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);
}
graphic_hw_update(s->con);
ppm_save(filename, surface, errp);
}

View File

@ -154,7 +154,6 @@ typedef struct VGACommonState {
unsigned int g, unsigned b);
graphic_hw_update_ptr update;
graphic_hw_invalidate_ptr invalidate;
graphic_hw_screen_dump_ptr screen_dump;
graphic_hw_text_update_ptr text_update;
bool full_update_text;
bool full_update_gfx;
@ -198,7 +197,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);

View File

@ -1119,31 +1119,6 @@ static void vmsvga_invalidate_display(void *opaque)
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;
@ -1212,7 +1187,6 @@ static void vmsvga_init(struct vmsvga_state_s *s,
s->vga.con = graphic_console_init(vmsvga_update_display,
vmsvga_invalidate_display,
vmsvga_screen_dump,
vmsvga_text_update, s);
s->fifo_size = SVGA_FIFO_SIZE;

View File

@ -1007,7 +1007,6 @@ wait_more:
fb->c.con = graphic_console_init(xenfb_update,
xenfb_invalidate,
NULL,
NULL,
fb);
fb->have_console = 1;

View File

@ -92,7 +92,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(NULL, NULL, NULL, NULL);
}
static void puv3_init(QEMUMachineInitArgs *args)

View File

@ -279,13 +279,10 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
typedef void (*graphic_hw_update_ptr)(void *);
typedef void (*graphic_hw_invalidate_ptr)(void *);
typedef void (*graphic_hw_screen_dump_ptr)(void *, const char *, bool cswitch,
Error **errp);
typedef void (*graphic_hw_text_update_ptr)(void *, console_ch_t *);
QemuConsole *graphic_console_init(graphic_hw_update_ptr update,
graphic_hw_invalidate_ptr invalidate,
graphic_hw_screen_dump_ptr screen_dump,
graphic_hw_text_update_ptr text_update,
void *opaque);

View File

@ -121,7 +121,6 @@ struct QemuConsole {
/* Graphic console state. */
graphic_hw_update_ptr hw_update;
graphic_hw_invalidate_ptr hw_invalidate;
graphic_hw_screen_dump_ptr hw_screen_dump;
graphic_hw_text_update_ptr hw_text_update;
void *hw;
int g_width, g_height;
@ -188,28 +187,65 @@ void graphic_hw_invalidate(QemuConsole *con)
}
}
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;
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;
}
void qmp_screendump(const char *filename, Error **errp)
{
QemuConsole *previous_active_console;
bool cswitch;
QemuConsole *con = consoles[0];
DisplaySurface *surface;
previous_active_console = active_console;
cswitch = previous_active_console && previous_active_console->index != 0;
/* There is currently no way of specifying which screen we want to dump,
so always dump the first one. */
if (cswitch) {
console_select(0);
}
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");
if (con == NULL) {
error_setg(errp, "There is no QemuConsole I can screendump from.");
return;
}
if (cswitch) {
console_select(previous_active_console->index);
}
graphic_hw_update(con);
surface = qemu_console_surface(con);
ppm_save(filename, surface, errp);
}
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
@ -1411,7 +1447,6 @@ DisplayState *init_displaystate(void)
QemuConsole *graphic_console_init(graphic_hw_update_ptr update,
graphic_hw_invalidate_ptr invalidate,
graphic_hw_screen_dump_ptr screen_dump,
graphic_hw_text_update_ptr text_update,
void *opaque)
{
@ -1425,7 +1460,6 @@ QemuConsole *graphic_console_init(graphic_hw_update_ptr update,
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 = opaque;