console: screendump improvements
Hi, The following patches have been extracted from the "[PATCH v6 00/25] monitor: add asynchronous command type", as they are reviewable/mergeable independantly. They introduce some internal API changes, and fix qemu_open()/qemu_close()/unlink() misusages which should be quite harmless. -----BEGIN PGP SIGNATURE----- iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAl4PBGccHG1hcmNhbmRy ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5XtXD/4rqC3qSO62L2vYzi7V 38unjXNMAETqr/dplFuMKapqjZZaRP+yjx2/u3xcXvixLrzlbNOy9vwNy0T0fkRw og8bZM8vOgMP8jCfXFEysAsXmTtiJ2tOKlKURedqQLLP4JNz4vEXkmtP4OAidjcR AoNEg6uqVQJpidNhN+3+w3SNYlsL4JpXYy8iZ2PPCnlvLBkRc7EFWVvwWvCdpCgL a1pMamqbbnxNIwxVe232gpXAbKXzmGCRIvwB7ZIV+USTF3IUH06bIGH4WPFAsD2w 7wxOxV7G4z16aYmoMHwLP9RyUqb8K4Cb00qOf8jEF04tVAFwCp1czfOYQ6lrO0Qc 1RU6OaFsHUlVUxu0OHBfIz5tXmwtG97tlN8Oglu8ujqSkhbH0u3uythaid23UEfg dF+jqXF1Ex93KkSoqVnT76UqJchdZU+BXYJt3Ir+X6nro3FvAwQB2c4KFAlVOo1w trc3NqWNZvxZ6N1LI8cG15d0EfdKG8rL5p49MtgfUNZk5XNqAul+huFr2UAEFykC +pnmTIYlc1mrZUZXX6h5Cokj65zYIEYuqK/2ZS6uUC8oWvH8aMo1b5kPxqrvisCl TWmXnh5j9k+hhj5d/X7TnR9TGJQiljj4zvfUrYTIG6hKAoEbZIocaPjtNSaflF2P 3SVhe4g7QkQSJhdq6dpDfHUEPA== =aSgS -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/elmarco/tags/screendump-pull-request' into staging console: screendump improvements Hi, The following patches have been extracted from the "[PATCH v6 00/25] monitor: add asynchronous command type", as they are reviewable/mergeable independantly. They introduce some internal API changes, and fix qemu_open()/qemu_close()/unlink() misusages which should be quite harmless. # gpg: Signature made Fri 03 Jan 2020 09:07:51 GMT # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * remotes/elmarco/tags/screendump-pull-request: screendump: use qemu_unlink() osdep: add qemu_unlink() screendump: replace FILE with QIOChannel and fix close()/qemu_close() object: add g_autoptr support ui: add pixman image g_autoptr support ppm-save: pass opened fd console: add graphic_hw_update_done() Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
81e6a7345a
@ -109,7 +109,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
||||
qxl->guest_primary.surface.mem,
|
||||
MEMSLOT_GROUP_GUEST);
|
||||
if (!qxl->guest_primary.data) {
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
|
||||
qxl->num_dirty_rects = 1;
|
||||
@ -137,7 +137,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
||||
}
|
||||
|
||||
if (!qxl->guest_primary.data) {
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
for (i = 0; i < qxl->num_dirty_rects; i++) {
|
||||
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
|
||||
@ -158,6 +158,11 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
||||
qxl->dirty[i].bottom - qxl->dirty[i].top);
|
||||
}
|
||||
qxl->num_dirty_rects = 0;
|
||||
|
||||
end:
|
||||
if (qxl->render_update_cookie_num == 0) {
|
||||
graphic_hw_update_done(qxl->ssd.dcl.con);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1181,6 +1181,7 @@ static const QXLInterface qxl_interface = {
|
||||
|
||||
static const GraphicHwOps qxl_ops = {
|
||||
.gfx_update = qxl_hw_update,
|
||||
.gfx_update_async = true,
|
||||
};
|
||||
|
||||
static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
||||
|
@ -462,6 +462,7 @@ int qemu_mprotect_none(void *addr, size_t size);
|
||||
|
||||
int qemu_open(const char *name, int flags, ...);
|
||||
int qemu_close(int fd);
|
||||
int qemu_unlink(const char *name);
|
||||
#ifndef _WIN32
|
||||
int qemu_dup(int fd);
|
||||
#endif
|
||||
|
@ -1766,4 +1766,7 @@ Object *container_get(Object *root, const char *path);
|
||||
* Returns the instance_size of the given @typename.
|
||||
*/
|
||||
size_t object_type_get_instance_size(const char *typename);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(Object, object_unref)
|
||||
|
||||
#endif
|
||||
|
@ -365,6 +365,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
|
||||
typedef struct GraphicHwOps {
|
||||
void (*invalidate)(void *opaque);
|
||||
void (*gfx_update)(void *opaque);
|
||||
bool gfx_update_async; /* if true, calls graphic_hw_update_done() */
|
||||
void (*text_update)(void *opaque, console_ch_t *text);
|
||||
void (*update_interval)(void *opaque, uint64_t interval);
|
||||
int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
|
||||
@ -380,6 +381,7 @@ void graphic_console_set_hwops(QemuConsole *con,
|
||||
void graphic_console_close(QemuConsole *con);
|
||||
|
||||
void graphic_hw_update(QemuConsole *con);
|
||||
void graphic_hw_update_done(QemuConsole *con);
|
||||
void graphic_hw_invalidate(QemuConsole *con);
|
||||
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
|
||||
void graphic_hw_gl_block(QemuConsole *con, bool block);
|
||||
|
@ -90,4 +90,6 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph,
|
||||
pixman_color_t *bgcol,
|
||||
int x, int y, int cw, int ch);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref)
|
||||
|
||||
#endif /* QEMU_PIXMAN_H */
|
||||
|
73
ui/console.c
73
ui/console.c
@ -33,6 +33,7 @@
|
||||
#include "chardev/char-fe.h"
|
||||
#include "trace.h"
|
||||
#include "exec/memory.h"
|
||||
#include "io/channel-file.h"
|
||||
|
||||
#define DEFAULT_BACKSCROLL 512
|
||||
#define CONSOLE_CURSOR_PERIOD 500
|
||||
@ -193,6 +194,7 @@ static void dpy_refresh(DisplayState *s);
|
||||
static DisplayState *get_alloc_displaystate(void);
|
||||
static void text_console_update_cursor_timer(void);
|
||||
static void text_console_update_cursor(void *opaque);
|
||||
static bool ppm_save(int fd, DisplaySurface *ds, Error **errp);
|
||||
|
||||
static void gui_update(void *opaque)
|
||||
{
|
||||
@ -259,13 +261,22 @@ static void gui_setup_refresh(DisplayState *ds)
|
||||
ds->have_text = have_text;
|
||||
}
|
||||
|
||||
void graphic_hw_update_done(QemuConsole *con)
|
||||
{
|
||||
}
|
||||
|
||||
void graphic_hw_update(QemuConsole *con)
|
||||
{
|
||||
bool async = false;
|
||||
if (!con) {
|
||||
con = active_console;
|
||||
}
|
||||
if (con && con->hw_ops->gfx_update) {
|
||||
con->hw_ops->gfx_update(con->hw);
|
||||
async = con->hw_ops->gfx_update_async;
|
||||
}
|
||||
if (!async) {
|
||||
graphic_hw_update_done(con);
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,52 +310,34 @@ void graphic_hw_invalidate(QemuConsole *con)
|
||||
}
|
||||
}
|
||||
|
||||
static void ppm_save(const char *filename, DisplaySurface *ds,
|
||||
Error **errp)
|
||||
static bool ppm_save(int fd, DisplaySurface *ds, Error **errp)
|
||||
{
|
||||
int width = pixman_image_get_width(ds->image);
|
||||
int height = pixman_image_get_height(ds->image);
|
||||
int fd;
|
||||
FILE *f;
|
||||
g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd));
|
||||
g_autofree char *header = NULL;
|
||||
g_autoptr(pixman_image_t) linebuf = NULL;
|
||||
int y;
|
||||
int ret;
|
||||
pixman_image_t *linebuf;
|
||||
|
||||
trace_ppm_save(filename, ds);
|
||||
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
|
||||
if (fd == -1) {
|
||||
error_setg(errp, "failed to open file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
f = fdopen(fd, "wb");
|
||||
ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
|
||||
if (ret < 0) {
|
||||
linebuf = NULL;
|
||||
goto write_err;
|
||||
trace_ppm_save(fd, ds);
|
||||
|
||||
header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255);
|
||||
if (qio_channel_write_all(QIO_CHANNEL(ioc),
|
||||
header, strlen(header), errp) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 (qio_channel_write_all(QIO_CHANNEL(ioc),
|
||||
(char *)pixman_image_get_data(linebuf),
|
||||
pixman_image_get_stride(linebuf), errp) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
void qmp_screendump(const char *filename, bool has_device, const char *device,
|
||||
@ -352,6 +345,7 @@ void qmp_screendump(const char *filename, bool has_device, const char *device,
|
||||
{
|
||||
QemuConsole *con;
|
||||
DisplaySurface *surface;
|
||||
int fd;
|
||||
|
||||
if (has_device) {
|
||||
con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
|
||||
@ -378,7 +372,16 @@ void qmp_screendump(const char *filename, bool has_device, const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
ppm_save(filename, surface, errp);
|
||||
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
|
||||
if (fd == -1) {
|
||||
error_setg(errp, "failed to open file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ppm_save(fd, surface, errp)) {
|
||||
qemu_unlink(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
|
||||
|
@ -15,7 +15,7 @@ displaysurface_create_pixman(void *display_surface) "surface=%p"
|
||||
displaysurface_free(void *display_surface) "surface=%p"
|
||||
displaychangelistener_register(void *dcl, const char *name) "%p [ %s ]"
|
||||
displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]"
|
||||
ppm_save(const char *filename, void *display_surface) "%s surface=%p"
|
||||
ppm_save(int fd, void *display_surface) "fd=%d surface=%p"
|
||||
|
||||
# gtk.c
|
||||
# gtk-gl-area.c
|
||||
|
15
util/osdep.c
15
util/osdep.c
@ -370,6 +370,21 @@ int qemu_close(int fd)
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a file from the filesystem, unless the filename is /dev/fdset/...
|
||||
*
|
||||
* Returns: On success, zero is returned. On error, -1 is returned,
|
||||
* and errno is set appropriately.
|
||||
*/
|
||||
int qemu_unlink(const char *name)
|
||||
{
|
||||
if (g_str_has_prefix(name, "/dev/fdset/")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return unlink(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* A variant of write(2) which handles partial write.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user