Skip to content

Commit

Permalink
ui/console: Pass placeholder surface to displays
Browse files Browse the repository at this point in the history
ui/console used to accept NULL as graphic console surface, but its
semantics was inconsistent among displays:
- cocoa and gtk-egl perform NULL dereference.
- egl-headless, spice and spice-egl do nothing.
- gtk releases underlying resources.
- sdl2-2d and sdl2-gl destroys the window.
- vnc shows a message, "Display output is not active."

Fortunately, only virtio-gpu and virtio-gpu-3d assign NULL so
we can study them to figure out the desired behavior. They assign
NULL *except* for the primary display when the device is realized,
reset, or its scanout is disabled. This effectively destroys
windows for the (uninitialized) secondary displays.

To implement the consistent behavior of display device
realization/reset, this change embeds it to the operation
switching the surface. When NULL was given as a new surface when
switching, ui/console will instead passes a placeholder down
to each display listeners.

sdl destroys the window for a secondary console if its surface is a
placeholder. The other displays simply shows the placeholder.

Signed-off-by: Akihiko Odaki <[email protected]>
Message-Id: <[email protected]>
Signed-off-by: Gerd Hoffmann <[email protected]>
  • Loading branch information
akihikodaki authored and kraxel committed Mar 4, 2021
1 parent b5a087b commit c821a58
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 25 deletions.
17 changes: 16 additions & 1 deletion ui/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -1675,11 +1675,26 @@ void dpy_gfx_update_full(QemuConsole *con)
void dpy_gfx_replace_surface(QemuConsole *con,
DisplaySurface *surface)
{
static const char placeholder_msg[] = "Display output is not active.";
DisplayState *s = con->ds;
DisplaySurface *old_surface = con->surface;
DisplayChangeListener *dcl;
int width;
int height;

if (!surface) {
if (old_surface) {
width = surface_width(old_surface);
height = surface_height(old_surface);
} else {
width = 640;
height = 480;
}

surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
}

assert(old_surface != surface || surface == NULL);
assert(old_surface != surface);

con->surface = surface;
QLIST_FOREACH(dcl, &s->listeners, next) {
Expand Down
4 changes: 0 additions & 4 deletions ui/gtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,10 +567,6 @@ static void gd_switch(DisplayChangeListener *dcl,
}
vc->gfx.ds = surface;

if (!surface) {
return;
}

if (surface->format == PIXMAN_x8r8g8b8) {
/*
* PIXMAN_x8r8g8b8 == CAIRO_FORMAT_RGB24
Expand Down
7 changes: 2 additions & 5 deletions ui/sdl2-2d.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,11 @@ void sdl2_2d_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
DisplaySurface *surf = qemu_console_surface(dcl->con);
DisplaySurface *surf = scon->surface;
SDL_Rect rect;
size_t surface_data_offset;
assert(!scon->opengl);

if (!surf) {
return;
}
if (!scon->texture) {
return;
}
Expand Down Expand Up @@ -75,7 +72,7 @@ void sdl2_2d_switch(DisplayChangeListener *dcl,
scon->texture = NULL;
}

if (!new_surface) {
if (is_placeholder(new_surface) && qemu_console_get_index(dcl->con)) {
sdl2_window_destroy(scon);
return;
}
Expand Down
4 changes: 2 additions & 2 deletions ui/sdl2-gl.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void sdl2_gl_switch(DisplayChangeListener *dcl,

scon->surface = new_surface;

if (!new_surface) {
if (is_placeholder(new_surface) && qemu_console_get_index(dcl->con)) {
qemu_gl_fini_shader(scon->gls);
scon->gls = NULL;
sdl2_window_destroy(scon);
Expand All @@ -112,7 +112,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
assert(scon->opengl);

graphic_hw_update(dcl->con);
if (scon->updates && scon->surface) {
if (scon->updates && scon->real_window) {
scon->updates = 0;
sdl2_gl_render_surface(scon);
}
Expand Down
6 changes: 3 additions & 3 deletions ui/spice-display.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
SimpleSpiceUpdate *update;
bool need_destroy;

if (surface && ssd->surface &&
if (ssd->surface &&
surface_width(surface) == pixman_image_get_width(ssd->surface) &&
surface_height(surface) == pixman_image_get_height(ssd->surface) &&
surface_format(surface) == pixman_image_get_format(ssd->surface)) {
Expand All @@ -410,8 +410,8 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,

/* full mode switch */
trace_qemu_spice_display_surface(ssd->qxl.id,
surface ? surface_width(surface) : 0,
surface ? surface_height(surface) : 0,
surface_width(surface),
surface_height(surface),
false);

memset(&ssd->dirty, 0, sizeof(ssd->dirty));
Expand Down
10 changes: 0 additions & 10 deletions ui/vnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -790,20 +790,10 @@ static bool vnc_check_pageflip(DisplaySurface *s1,
static void vnc_dpy_switch(DisplayChangeListener *dcl,
DisplaySurface *surface)
{
static const char placeholder_msg[] =
"Display output is not active.";
static DisplaySurface *placeholder;
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
bool pageflip = vnc_check_pageflip(vd->ds, surface);
VncState *vs;

if (surface == NULL) {
if (placeholder == NULL) {
placeholder = qemu_create_placeholder_surface(640, 480, placeholder_msg);
}
surface = placeholder;
}

vnc_abort_display_jobs(vd);
vd->ds = surface;

Expand Down

0 comments on commit c821a58

Please sign in to comment.