console: save current scanout details
Add a new DisplayScanout structure to save the current scanout details. This allows to attach later UI backends and set the scanout. Introduce displaychangelistener_display_console() helper function to handle the dpy_gfx_switch/gl_scanout() & dpy_gfx_update() calls. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
f6ef71bded
commit
ebced09185
@ -108,6 +108,17 @@ struct QemuConsoleClass {
|
|||||||
#define QEMU_ALLOCATED_FLAG 0x01
|
#define QEMU_ALLOCATED_FLAG 0x01
|
||||||
#define QEMU_PLACEHOLDER_FLAG 0x02
|
#define QEMU_PLACEHOLDER_FLAG 0x02
|
||||||
|
|
||||||
|
typedef struct ScanoutTexture {
|
||||||
|
uint32_t backing_id;
|
||||||
|
bool backing_y_0_top;
|
||||||
|
uint32_t backing_width;
|
||||||
|
uint32_t backing_height;
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
} ScanoutTexture;
|
||||||
|
|
||||||
typedef struct DisplaySurface {
|
typedef struct DisplaySurface {
|
||||||
pixman_format_code_t format;
|
pixman_format_code_t format;
|
||||||
pixman_image_t *image;
|
pixman_image_t *image;
|
||||||
@ -178,6 +189,22 @@ typedef struct QemuDmaBuf {
|
|||||||
bool draw_submitted;
|
bool draw_submitted;
|
||||||
} QemuDmaBuf;
|
} QemuDmaBuf;
|
||||||
|
|
||||||
|
enum display_scanout {
|
||||||
|
SCANOUT_NONE,
|
||||||
|
SCANOUT_SURFACE,
|
||||||
|
SCANOUT_TEXTURE,
|
||||||
|
SCANOUT_DMABUF,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DisplayScanout {
|
||||||
|
enum display_scanout kind;
|
||||||
|
union {
|
||||||
|
/* DisplaySurface *surface; is kept in QemuConsole */
|
||||||
|
ScanoutTexture texture;
|
||||||
|
QemuDmaBuf *dmabuf;
|
||||||
|
};
|
||||||
|
} DisplayScanout;
|
||||||
|
|
||||||
typedef struct DisplayState DisplayState;
|
typedef struct DisplayState DisplayState;
|
||||||
typedef struct DisplayGLCtx DisplayGLCtx;
|
typedef struct DisplayGLCtx DisplayGLCtx;
|
||||||
|
|
||||||
|
165
ui/console.c
165
ui/console.c
@ -77,6 +77,7 @@ struct QemuConsole {
|
|||||||
console_type_t console_type;
|
console_type_t console_type;
|
||||||
DisplayState *ds;
|
DisplayState *ds;
|
||||||
DisplaySurface *surface;
|
DisplaySurface *surface;
|
||||||
|
DisplayScanout scanout;
|
||||||
int dcls;
|
int dcls;
|
||||||
DisplayGLCtx *gl;
|
DisplayGLCtx *gl;
|
||||||
int gl_block;
|
int gl_block;
|
||||||
@ -146,6 +147,7 @@ static void dpy_refresh(DisplayState *s);
|
|||||||
static DisplayState *get_alloc_displaystate(void);
|
static DisplayState *get_alloc_displaystate(void);
|
||||||
static void text_console_update_cursor_timer(void);
|
static void text_console_update_cursor_timer(void);
|
||||||
static void text_console_update_cursor(void *opaque);
|
static void text_console_update_cursor(void *opaque);
|
||||||
|
static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
|
||||||
|
|
||||||
static void gui_update(void *opaque)
|
static void gui_update(void *opaque)
|
||||||
{
|
{
|
||||||
@ -481,6 +483,8 @@ static void text_console_resize(QemuConsole *s)
|
|||||||
TextCell *cells, *c, *c1;
|
TextCell *cells, *c, *c1;
|
||||||
int w1, x, y, last_width;
|
int w1, x, y, last_width;
|
||||||
|
|
||||||
|
assert(s->scanout.kind == SCANOUT_SURFACE);
|
||||||
|
|
||||||
last_width = s->width;
|
last_width = s->width;
|
||||||
s->width = surface_width(s->surface) / FONT_WIDTH;
|
s->width = surface_width(s->surface) / FONT_WIDTH;
|
||||||
s->height = surface_height(s->surface) / FONT_HEIGHT;
|
s->height = surface_height(s->surface) / FONT_HEIGHT;
|
||||||
@ -1052,6 +1056,48 @@ static void console_putchar(QemuConsole *s, int ch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void displaychangelistener_display_console(DisplayChangeListener *dcl,
|
||||||
|
QemuConsole *con)
|
||||||
|
{
|
||||||
|
static const char nodev[] =
|
||||||
|
"This VM has no graphic display device.";
|
||||||
|
static DisplaySurface *dummy;
|
||||||
|
|
||||||
|
if (!con) {
|
||||||
|
if (!dcl->ops->dpy_gfx_switch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!dummy) {
|
||||||
|
dummy = qemu_create_placeholder_surface(640, 480, nodev);
|
||||||
|
}
|
||||||
|
dcl->ops->dpy_gfx_switch(dcl, dummy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con->scanout.kind == SCANOUT_DMABUF &&
|
||||||
|
displaychangelistener_has_dmabuf(dcl)) {
|
||||||
|
dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf);
|
||||||
|
} else if (con->scanout.kind == SCANOUT_TEXTURE &&
|
||||||
|
dcl->ops->dpy_gl_scanout_texture) {
|
||||||
|
dcl->ops->dpy_gl_scanout_texture(dcl,
|
||||||
|
con->scanout.texture.backing_id,
|
||||||
|
con->scanout.texture.backing_y_0_top,
|
||||||
|
con->scanout.texture.backing_width,
|
||||||
|
con->scanout.texture.backing_height,
|
||||||
|
con->scanout.texture.x,
|
||||||
|
con->scanout.texture.y,
|
||||||
|
con->scanout.texture.width,
|
||||||
|
con->scanout.texture.height);
|
||||||
|
} else if (con->scanout.kind == SCANOUT_SURFACE &&
|
||||||
|
dcl->ops->dpy_gfx_switch) {
|
||||||
|
dcl->ops->dpy_gfx_switch(dcl, con->surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
dcl->ops->dpy_gfx_update(dcl, 0, 0,
|
||||||
|
qemu_console_get_width(con, 0),
|
||||||
|
qemu_console_get_height(con, 0));
|
||||||
|
}
|
||||||
|
|
||||||
void console_select(unsigned int index)
|
void console_select(unsigned int index)
|
||||||
{
|
{
|
||||||
DisplayChangeListener *dcl;
|
DisplayChangeListener *dcl;
|
||||||
@ -1068,13 +1114,7 @@ void console_select(unsigned int index)
|
|||||||
if (dcl->con != NULL) {
|
if (dcl->con != NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (dcl->ops->dpy_gfx_switch) {
|
displaychangelistener_display_console(dcl, s);
|
||||||
dcl->ops->dpy_gfx_switch(dcl, s->surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (s->surface) {
|
|
||||||
dpy_gfx_update(s, 0, 0, surface_width(s->surface),
|
|
||||||
surface_height(s->surface));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ds->have_text) {
|
if (ds->have_text) {
|
||||||
@ -1480,9 +1520,6 @@ static bool dpy_gl_compatible_with(QemuConsole *con, DisplayChangeListener *dcl)
|
|||||||
|
|
||||||
void register_displaychangelistener(DisplayChangeListener *dcl)
|
void register_displaychangelistener(DisplayChangeListener *dcl)
|
||||||
{
|
{
|
||||||
static const char nodev[] =
|
|
||||||
"This VM has no graphic display device.";
|
|
||||||
static DisplaySurface *dummy;
|
|
||||||
QemuConsole *con;
|
QemuConsole *con;
|
||||||
|
|
||||||
assert(!dcl->ds);
|
assert(!dcl->ds);
|
||||||
@ -1507,16 +1544,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
|
|||||||
} else {
|
} else {
|
||||||
con = active_console;
|
con = active_console;
|
||||||
}
|
}
|
||||||
if (dcl->ops->dpy_gfx_switch) {
|
displaychangelistener_display_console(dcl, con);
|
||||||
if (con) {
|
|
||||||
dcl->ops->dpy_gfx_switch(dcl, con->surface);
|
|
||||||
} else {
|
|
||||||
if (!dummy) {
|
|
||||||
dummy = qemu_create_placeholder_surface(640, 480, nodev);
|
|
||||||
}
|
|
||||||
dcl->ops->dpy_gfx_switch(dcl, dummy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
text_console_update_cursor(NULL);
|
text_console_update_cursor(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1597,13 +1625,9 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
|
|||||||
{
|
{
|
||||||
DisplayState *s = con->ds;
|
DisplayState *s = con->ds;
|
||||||
DisplayChangeListener *dcl;
|
DisplayChangeListener *dcl;
|
||||||
int width = w;
|
int width = qemu_console_get_width(con, x + w);
|
||||||
int height = h;
|
int height = qemu_console_get_height(con, y + h);
|
||||||
|
|
||||||
if (con->surface) {
|
|
||||||
width = surface_width(con->surface);
|
|
||||||
height = surface_height(con->surface);
|
|
||||||
}
|
|
||||||
x = MAX(x, 0);
|
x = MAX(x, 0);
|
||||||
y = MAX(y, 0);
|
y = MAX(y, 0);
|
||||||
x = MIN(x, width);
|
x = MIN(x, width);
|
||||||
@ -1626,12 +1650,10 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
|
|||||||
|
|
||||||
void dpy_gfx_update_full(QemuConsole *con)
|
void dpy_gfx_update_full(QemuConsole *con)
|
||||||
{
|
{
|
||||||
if (!con->surface) {
|
int w = qemu_console_get_width(con, 0);
|
||||||
return;
|
int h = qemu_console_get_height(con, 0);
|
||||||
}
|
|
||||||
dpy_gfx_update(con, 0, 0,
|
dpy_gfx_update(con, 0, 0, w, h);
|
||||||
surface_width(con->surface),
|
|
||||||
surface_height(con->surface));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dpy_gfx_replace_surface(QemuConsole *con,
|
void dpy_gfx_replace_surface(QemuConsole *con,
|
||||||
@ -1658,6 +1680,7 @@ void dpy_gfx_replace_surface(QemuConsole *con,
|
|||||||
|
|
||||||
assert(old_surface != surface);
|
assert(old_surface != surface);
|
||||||
|
|
||||||
|
con->scanout.kind = SCANOUT_SURFACE;
|
||||||
con->surface = surface;
|
con->surface = surface;
|
||||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||||
if (con != (dcl->con ? dcl->con : active_console)) {
|
if (con != (dcl->con ? dcl->con : active_console)) {
|
||||||
@ -1833,6 +1856,9 @@ void dpy_gl_scanout_disable(QemuConsole *con)
|
|||||||
DisplayState *s = con->ds;
|
DisplayState *s = con->ds;
|
||||||
DisplayChangeListener *dcl;
|
DisplayChangeListener *dcl;
|
||||||
|
|
||||||
|
if (con->scanout.kind != SCANOUT_SURFACE) {
|
||||||
|
con->scanout.kind = SCANOUT_NONE;
|
||||||
|
}
|
||||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||||
dcl->ops->dpy_gl_scanout_disable(dcl);
|
dcl->ops->dpy_gl_scanout_disable(dcl);
|
||||||
}
|
}
|
||||||
@ -1849,6 +1875,11 @@ void dpy_gl_scanout_texture(QemuConsole *con,
|
|||||||
DisplayState *s = con->ds;
|
DisplayState *s = con->ds;
|
||||||
DisplayChangeListener *dcl;
|
DisplayChangeListener *dcl;
|
||||||
|
|
||||||
|
con->scanout.kind = SCANOUT_TEXTURE;
|
||||||
|
con->scanout.texture = (ScanoutTexture) {
|
||||||
|
backing_id, backing_y_0_top, backing_width, backing_height,
|
||||||
|
x, y, width, height
|
||||||
|
};
|
||||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||||
dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
|
dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
|
||||||
backing_y_0_top,
|
backing_y_0_top,
|
||||||
@ -1863,6 +1894,8 @@ void dpy_gl_scanout_dmabuf(QemuConsole *con,
|
|||||||
DisplayState *s = con->ds;
|
DisplayState *s = con->ds;
|
||||||
DisplayChangeListener *dcl;
|
DisplayChangeListener *dcl;
|
||||||
|
|
||||||
|
con->scanout.kind = SCANOUT_DMABUF;
|
||||||
|
con->scanout.dmabuf = dmabuf;
|
||||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||||
dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
|
dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
|
||||||
}
|
}
|
||||||
@ -1989,10 +2022,8 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
|
|||||||
s = qemu_console_lookup_unused();
|
s = qemu_console_lookup_unused();
|
||||||
if (s) {
|
if (s) {
|
||||||
trace_console_gfx_reuse(s->index);
|
trace_console_gfx_reuse(s->index);
|
||||||
if (s->surface) {
|
width = qemu_console_get_width(s, 0);
|
||||||
width = surface_width(s->surface);
|
height = qemu_console_get_height(s, 0);
|
||||||
height = surface_height(s->surface);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
trace_console_gfx_new();
|
trace_console_gfx_new();
|
||||||
s = new_console(ds, GRAPHIC_CONSOLE, head);
|
s = new_console(ds, GRAPHIC_CONSOLE, head);
|
||||||
@ -2021,13 +2052,8 @@ void graphic_console_close(QemuConsole *con)
|
|||||||
static const char unplugged[] =
|
static const char unplugged[] =
|
||||||
"Guest display has been unplugged";
|
"Guest display has been unplugged";
|
||||||
DisplaySurface *surface;
|
DisplaySurface *surface;
|
||||||
int width = 640;
|
int width = qemu_console_get_width(con, 640);
|
||||||
int height = 480;
|
int height = qemu_console_get_height(con, 480);
|
||||||
|
|
||||||
if (con->surface) {
|
|
||||||
width = surface_width(con->surface);
|
|
||||||
height = surface_height(con->surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_console_gfx_close(con->index);
|
trace_console_gfx_close(con->index);
|
||||||
object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
|
object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
|
||||||
@ -2179,7 +2205,19 @@ int qemu_console_get_width(QemuConsole *con, int fallback)
|
|||||||
if (con == NULL) {
|
if (con == NULL) {
|
||||||
con = active_console;
|
con = active_console;
|
||||||
}
|
}
|
||||||
return con ? surface_width(con->surface) : fallback;
|
if (con == NULL) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
switch (con->scanout.kind) {
|
||||||
|
case SCANOUT_DMABUF:
|
||||||
|
return con->scanout.dmabuf->width;
|
||||||
|
case SCANOUT_TEXTURE:
|
||||||
|
return con->scanout.texture.width;
|
||||||
|
case SCANOUT_SURFACE:
|
||||||
|
return surface_width(con->surface);
|
||||||
|
default:
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int qemu_console_get_height(QemuConsole *con, int fallback)
|
int qemu_console_get_height(QemuConsole *con, int fallback)
|
||||||
@ -2187,7 +2225,19 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
|
|||||||
if (con == NULL) {
|
if (con == NULL) {
|
||||||
con = active_console;
|
con = active_console;
|
||||||
}
|
}
|
||||||
return con ? surface_height(con->surface) : fallback;
|
if (con == NULL) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
switch (con->scanout.kind) {
|
||||||
|
case SCANOUT_DMABUF:
|
||||||
|
return con->scanout.dmabuf->height;
|
||||||
|
case SCANOUT_TEXTURE:
|
||||||
|
return con->scanout.texture.height;
|
||||||
|
case SCANOUT_SURFACE:
|
||||||
|
return surface_height(con->surface);
|
||||||
|
default:
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vc_chr_accept_input(Chardev *chr)
|
static void vc_chr_accept_input(Chardev *chr)
|
||||||
@ -2253,12 +2303,13 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
|
|||||||
s->total_height = DEFAULT_BACKSCROLL;
|
s->total_height = DEFAULT_BACKSCROLL;
|
||||||
s->x = 0;
|
s->x = 0;
|
||||||
s->y = 0;
|
s->y = 0;
|
||||||
if (!s->surface) {
|
if (s->scanout.kind != SCANOUT_SURFACE) {
|
||||||
if (active_console && active_console->surface) {
|
if (active_console && active_console->scanout.kind == SCANOUT_SURFACE) {
|
||||||
g_width = surface_width(active_console->surface);
|
g_width = qemu_console_get_width(active_console, g_width);
|
||||||
g_height = surface_height(active_console->surface);
|
g_height = qemu_console_get_height(active_console, g_height);
|
||||||
}
|
}
|
||||||
s->surface = qemu_create_displaysurface(g_width, g_height);
|
s->surface = qemu_create_displaysurface(g_width, g_height);
|
||||||
|
s->scanout.kind = SCANOUT_SURFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->hw_ops = &text_console_ops;
|
s->hw_ops = &text_console_ops;
|
||||||
@ -2317,6 +2368,7 @@ static void vc_chr_open(Chardev *chr,
|
|||||||
s = new_console(NULL, TEXT_CONSOLE, 0);
|
s = new_console(NULL, TEXT_CONSOLE, 0);
|
||||||
} else {
|
} else {
|
||||||
s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
|
s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
|
||||||
|
s->scanout.kind = SCANOUT_SURFACE;
|
||||||
s->surface = qemu_create_displaysurface(width, height);
|
s->surface = qemu_create_displaysurface(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2340,13 +2392,13 @@ static void vc_chr_open(Chardev *chr,
|
|||||||
|
|
||||||
void qemu_console_resize(QemuConsole *s, int width, int height)
|
void qemu_console_resize(QemuConsole *s, int width, int height)
|
||||||
{
|
{
|
||||||
DisplaySurface *surface;
|
DisplaySurface *surface = qemu_console_surface(s);
|
||||||
|
|
||||||
assert(s->console_type == GRAPHIC_CONSOLE);
|
assert(s->console_type == GRAPHIC_CONSOLE);
|
||||||
|
|
||||||
if (s->surface && (s->surface->flags & QEMU_ALLOCATED_FLAG) &&
|
if (surface && (surface->flags & QEMU_ALLOCATED_FLAG) &&
|
||||||
pixman_image_get_width(s->surface->image) == width &&
|
pixman_image_get_width(surface->image) == width &&
|
||||||
pixman_image_get_height(s->surface->image) == height) {
|
pixman_image_get_height(surface->image) == height) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2356,7 +2408,12 @@ void qemu_console_resize(QemuConsole *s, int width, int height)
|
|||||||
|
|
||||||
DisplaySurface *qemu_console_surface(QemuConsole *console)
|
DisplaySurface *qemu_console_surface(QemuConsole *console)
|
||||||
{
|
{
|
||||||
return console->surface;
|
switch (console->scanout.kind) {
|
||||||
|
case SCANOUT_SURFACE:
|
||||||
|
return console->surface;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PixelFormat qemu_default_pixelformat(int bpp)
|
PixelFormat qemu_default_pixelformat(int bpp)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user