diff mbox series

[1/3] ui/gtk: skip drawing guest scanout when associated VC is invisible

Message ID 20240130234840.53122-2-dongwon.kim@intel.com (mailing list archive)
State New, archived
Headers show
Series ui/gtk: introducing vc->visible | expand

Commit Message

Kim, Dongwon Jan. 30, 2024, 11:48 p.m. UTC
From: Dongwon Kim <dongwon.kim@intel.com>

A new flag "visible" is added to show visibility status of the gfx console.
The flag is set to 'true' when the VC is visible but set to 'false' when
it is hidden or closed. When the VC is invisible, drawing guest frames
should be skipped as it will never be completed and it would potentially
lock up the guest display especially when blob scanout is used.

Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>

Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
---
 include/ui/gtk.h |  1 +
 ui/gtk-egl.c     |  8 ++++++++
 ui/gtk-gl-area.c |  8 ++++++++
 ui/gtk.c         | 10 +++++++++-
 4 files changed, 26 insertions(+), 1 deletion(-)

Comments

Marc-André Lureau Jan. 31, 2024, 7:08 a.m. UTC | #1
Hi Dongwon

On Wed, Jan 31, 2024 at 3:50 AM <dongwon.kim@intel.com> wrote:
>
> From: Dongwon Kim <dongwon.kim@intel.com>
>
> A new flag "visible" is added to show visibility status of the gfx console.
> The flag is set to 'true' when the VC is visible but set to 'false' when
> it is hidden or closed. When the VC is invisible, drawing guest frames
> should be skipped as it will never be completed and it would potentially
> lock up the guest display especially when blob scanout is used.

Can't it skip drawing when the widget is not visible instead?
https://docs.gtk.org/gtk3/method.Widget.is_visible.html

>
> Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
>
> Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
> ---
>  include/ui/gtk.h |  1 +
>  ui/gtk-egl.c     |  8 ++++++++
>  ui/gtk-gl-area.c |  8 ++++++++
>  ui/gtk.c         | 10 +++++++++-
>  4 files changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/include/ui/gtk.h b/include/ui/gtk.h
> index aa3d637029..2de38e5724 100644
> --- a/include/ui/gtk.h
> +++ b/include/ui/gtk.h
> @@ -57,6 +57,7 @@ typedef struct VirtualGfxConsole {
>      bool y0_top;
>      bool scanout_mode;
>      bool has_dmabuf;
> +    bool visible;
>  #endif
>  } VirtualGfxConsole;
>
> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
> index 3af5ac5bcf..993c283191 100644
> --- a/ui/gtk-egl.c
> +++ b/ui/gtk-egl.c
> @@ -265,6 +265,10 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
>  #ifdef CONFIG_GBM
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
>                     vc->gfx.esurface, vc->gfx.ectx);
>
> @@ -363,6 +367,10 @@ void gd_egl_flush(DisplayChangeListener *dcl,
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>      GtkWidget *area = vc->gfx.drawing_area;
>
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
>          graphic_hw_gl_block(vc->gfx.dcl.con, true);
>          vc->gfx.guest_fb.dmabuf->draw_submitted = true;
> diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
> index 52dcac161e..04e07bd7ee 100644
> --- a/ui/gtk-gl-area.c
> +++ b/ui/gtk-gl-area.c
> @@ -285,6 +285,10 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
>  {
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
>          graphic_hw_gl_block(vc->gfx.dcl.con, true);
>          vc->gfx.guest_fb.dmabuf->draw_submitted = true;
> @@ -299,6 +303,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
>  #ifdef CONFIG_GBM
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
>      egl_dmabuf_import_texture(dmabuf);
>      if (!dmabuf->texture) {
> diff --git a/ui/gtk.c b/ui/gtk.c
> index 810d7fc796..02eb667d8a 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -1312,15 +1312,20 @@ static void gd_menu_quit(GtkMenuItem *item, void *opaque)
>  static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
>  {
>      GtkDisplayState *s = opaque;
> -    VirtualConsole *vc = gd_vc_find_by_menu(s);
> +    VirtualConsole *vc;
>      GtkNotebook *nb = GTK_NOTEBOOK(s->notebook);
>      gint page;
>
> +    vc = gd_vc_find_current(s);
> +    vc->gfx.visible = false;
> +
> +    vc = gd_vc_find_by_menu(s);
>      gtk_release_modifiers(s);
>      if (vc) {
>          page = gtk_notebook_page_num(nb, vc->tab_item);
>          gtk_notebook_set_current_page(nb, page);
>          gtk_widget_grab_focus(vc->focus);
> +        vc->gfx.visible = true;
>      }
>  }
>
> @@ -1350,6 +1355,7 @@ static gboolean gd_tab_window_close(GtkWidget *widget, GdkEvent *event,
>      VirtualConsole *vc = opaque;
>      GtkDisplayState *s = vc->s;
>
> +    vc->gfx.visible = false;
>      gtk_widget_set_sensitive(vc->menu_item, true);
>      gd_widget_reparent(vc->window, s->notebook, vc->tab_item);
>      gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook),
> @@ -1423,6 +1429,7 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque)
>          gd_update_geometry_hints(vc);
>          gd_update_caption(s);
>      }
> +    vc->gfx.visible = true;
>  }
>
>  static void gd_menu_show_menubar(GtkMenuItem *item, void *opaque)
> @@ -2471,6 +2478,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
>  #ifdef CONFIG_GTK_CLIPBOARD
>      gd_clipboard_init(s);
>  #endif /* CONFIG_GTK_CLIPBOARD */
> +    vc->gfx.visible = true;
>  }
>
>  static void early_gtk_display_init(DisplayOptions *opts)
> --
> 2.34.1
>
>
Kim, Dongwon Jan. 31, 2024, 6:56 p.m. UTC | #2
Hi Marc-André,

> https://docs.gtk.org/gtk3/method.Widget.is_visible.html

This is what we had tried first but it didn't seem to work for the case of window minimization.
I see the visible flag for the GTK widget didn't seem to be toggled for some reason. And when
closing window, vc->window widget is destroyed so it is not possible to check the flag using
this GTK function. Having extra flag bound to VC was most intuitive for the logic I wanted to
implement.

Thanks!!
DW

> Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when associated
> VC is invisible
> 
> Hi Dongwon
> 
> On Wed, Jan 31, 2024 at 3:50 AM <dongwon.kim@intel.com> wrote:
> >
> > From: Dongwon Kim <dongwon.kim@intel.com>
> >
> > A new flag "visible" is added to show visibility status of the gfx console.
> > The flag is set to 'true' when the VC is visible but set to 'false'
> > when it is hidden or closed. When the VC is invisible, drawing guest
> > frames should be skipped as it will never be completed and it would
> > potentially lock up the guest display especially when blob scanout is used.
> 
> Can't it skip drawing when the widget is not visible instead?
> https://docs.gtk.org/gtk3/method.Widget.is_visible.html
> 
> >
> > Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
> >
> > Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
> > ---
> >  include/ui/gtk.h |  1 +
> >  ui/gtk-egl.c     |  8 ++++++++
> >  ui/gtk-gl-area.c |  8 ++++++++
> >  ui/gtk.c         | 10 +++++++++-
> >  4 files changed, 26 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/ui/gtk.h b/include/ui/gtk.h index
> > aa3d637029..2de38e5724 100644
> > --- a/include/ui/gtk.h
> > +++ b/include/ui/gtk.h
> > @@ -57,6 +57,7 @@ typedef struct VirtualGfxConsole {
> >      bool y0_top;
> >      bool scanout_mode;
> >      bool has_dmabuf;
> > +    bool visible;
> >  #endif
> >  } VirtualGfxConsole;
> >
> > diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 3af5ac5bcf..993c283191
> > 100644
> > --- a/ui/gtk-egl.c
> > +++ b/ui/gtk-egl.c
> > @@ -265,6 +265,10 @@ void
> gd_egl_scanout_dmabuf(DisplayChangeListener
> > *dcl,  #ifdef CONFIG_GBM
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> >                     vc->gfx.esurface, vc->gfx.ectx);
> >
> > @@ -363,6 +367,10 @@ void gd_egl_flush(DisplayChangeListener *dcl,
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >      GtkWidget *area = vc->gfx.drawing_area;
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> >draw_submitted) {
> >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; diff --git
> > a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 52dcac161e..04e07bd7ee
> > 100644
> > --- a/ui/gtk-gl-area.c
> > +++ b/ui/gtk-gl-area.c
> > @@ -285,6 +285,10 @@ void
> > gd_gl_area_scanout_flush(DisplayChangeListener *dcl,  {
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> >draw_submitted) {
> >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; @@ -299,6
> > +303,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
> > #ifdef CONFIG_GBM
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> >      egl_dmabuf_import_texture(dmabuf);
> >      if (!dmabuf->texture) {
> > diff --git a/ui/gtk.c b/ui/gtk.c
> > index 810d7fc796..02eb667d8a 100644
> > --- a/ui/gtk.c
> > +++ b/ui/gtk.c
> > @@ -1312,15 +1312,20 @@ static void gd_menu_quit(GtkMenuItem *item,
> > void *opaque)  static void gd_menu_switch_vc(GtkMenuItem *item, void
> > *opaque)  {
> >      GtkDisplayState *s = opaque;
> > -    VirtualConsole *vc = gd_vc_find_by_menu(s);
> > +    VirtualConsole *vc;
> >      GtkNotebook *nb = GTK_NOTEBOOK(s->notebook);
> >      gint page;
> >
> > +    vc = gd_vc_find_current(s);
> > +    vc->gfx.visible = false;
> > +
> > +    vc = gd_vc_find_by_menu(s);
> >      gtk_release_modifiers(s);
> >      if (vc) {
> >          page = gtk_notebook_page_num(nb, vc->tab_item);
> >          gtk_notebook_set_current_page(nb, page);
> >          gtk_widget_grab_focus(vc->focus);
> > +        vc->gfx.visible = true;
> >      }
> >  }
> >
> > @@ -1350,6 +1355,7 @@ static gboolean gd_tab_window_close(GtkWidget
> *widget, GdkEvent *event,
> >      VirtualConsole *vc = opaque;
> >      GtkDisplayState *s = vc->s;
> >
> > +    vc->gfx.visible = false;
> >      gtk_widget_set_sensitive(vc->menu_item, true);
> >      gd_widget_reparent(vc->window, s->notebook, vc->tab_item);
> >      gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook),
> > @@ -1423,6 +1429,7 @@ static void gd_menu_untabify(GtkMenuItem *item,
> void *opaque)
> >          gd_update_geometry_hints(vc);
> >          gd_update_caption(s);
> >      }
> > +    vc->gfx.visible = true;
> >  }
> >
> >  static void gd_menu_show_menubar(GtkMenuItem *item, void *opaque)
> @@
> > -2471,6 +2478,7 @@ static void gtk_display_init(DisplayState *ds,
> > DisplayOptions *opts)  #ifdef CONFIG_GTK_CLIPBOARD
> >      gd_clipboard_init(s);
> >  #endif /* CONFIG_GTK_CLIPBOARD */
> > +    vc->gfx.visible = true;
> >  }
> >
> >  static void early_gtk_display_init(DisplayOptions *opts)
> > --
> > 2.34.1
> >
> >
> 
> 
> --
> Marc-André Lureau
Marc-André Lureau Feb. 1, 2024, 6:42 a.m. UTC | #3
Hi

On Wed, Jan 31, 2024 at 10:56 PM Kim, Dongwon <dongwon.kim@intel.com> wrote:
>
> Hi Marc-André,
>
> > https://docs.gtk.org/gtk3/method.Widget.is_visible.html
>
> This is what we had tried first but it didn't seem to work for the case of window minimization.
> I see the visible flag for the GTK widget didn't seem to be toggled for some reason. And when

Right, because minimize != visible. You can still get window preview
with alt-tab and other compositor drawings.

Iow, it should keep rendering even when minimized.

> closing window, vc->window widget is destroyed so it is not possible to check the flag using
> this GTK function. Having extra flag bound to VC was most intuitive for the logic I wanted to
> implement.
>
> Thanks!!
> DW
>
> > Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when associated
> > VC is invisible
> >
> > Hi Dongwon
> >
> > On Wed, Jan 31, 2024 at 3:50 AM <dongwon.kim@intel.com> wrote:
> > >
> > > From: Dongwon Kim <dongwon.kim@intel.com>
> > >
> > > A new flag "visible" is added to show visibility status of the gfx console.
> > > The flag is set to 'true' when the VC is visible but set to 'false'
> > > when it is hidden or closed. When the VC is invisible, drawing guest
> > > frames should be skipped as it will never be completed and it would
> > > potentially lock up the guest display especially when blob scanout is used.
> >
> > Can't it skip drawing when the widget is not visible instead?
> > https://docs.gtk.org/gtk3/method.Widget.is_visible.html
> >
> > >
> > > Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
> > >
> > > Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
> > > ---
> > >  include/ui/gtk.h |  1 +
> > >  ui/gtk-egl.c     |  8 ++++++++
> > >  ui/gtk-gl-area.c |  8 ++++++++
> > >  ui/gtk.c         | 10 +++++++++-
> > >  4 files changed, 26 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/include/ui/gtk.h b/include/ui/gtk.h index
> > > aa3d637029..2de38e5724 100644
> > > --- a/include/ui/gtk.h
> > > +++ b/include/ui/gtk.h
> > > @@ -57,6 +57,7 @@ typedef struct VirtualGfxConsole {
> > >      bool y0_top;
> > >      bool scanout_mode;
> > >      bool has_dmabuf;
> > > +    bool visible;
> > >  #endif
> > >  } VirtualGfxConsole;
> > >
> > > diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 3af5ac5bcf..993c283191
> > > 100644
> > > --- a/ui/gtk-egl.c
> > > +++ b/ui/gtk-egl.c
> > > @@ -265,6 +265,10 @@ void
> > gd_egl_scanout_dmabuf(DisplayChangeListener
> > > *dcl,  #ifdef CONFIG_GBM
> > >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> > >
> > > +    if (!vc->gfx.visible) {
> > > +        return;
> > > +    }
> > > +
> > >      eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> > >                     vc->gfx.esurface, vc->gfx.ectx);
> > >
> > > @@ -363,6 +367,10 @@ void gd_egl_flush(DisplayChangeListener *dcl,
> > >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> > >      GtkWidget *area = vc->gfx.drawing_area;
> > >
> > > +    if (!vc->gfx.visible) {
> > > +        return;
> > > +    }
> > > +
> > >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> > >draw_submitted) {
> > >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> > >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; diff --git
> > > a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 52dcac161e..04e07bd7ee
> > > 100644
> > > --- a/ui/gtk-gl-area.c
> > > +++ b/ui/gtk-gl-area.c
> > > @@ -285,6 +285,10 @@ void
> > > gd_gl_area_scanout_flush(DisplayChangeListener *dcl,  {
> > >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> > >
> > > +    if (!vc->gfx.visible) {
> > > +        return;
> > > +    }
> > > +
> > >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> > >draw_submitted) {
> > >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> > >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; @@ -299,6
> > > +303,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
> > > #ifdef CONFIG_GBM
> > >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> > >
> > > +    if (!vc->gfx.visible) {
> > > +        return;
> > > +    }
> > > +
> > >      gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> > >      egl_dmabuf_import_texture(dmabuf);
> > >      if (!dmabuf->texture) {
> > > diff --git a/ui/gtk.c b/ui/gtk.c
> > > index 810d7fc796..02eb667d8a 100644
> > > --- a/ui/gtk.c
> > > +++ b/ui/gtk.c
> > > @@ -1312,15 +1312,20 @@ static void gd_menu_quit(GtkMenuItem *item,
> > > void *opaque)  static void gd_menu_switch_vc(GtkMenuItem *item, void
> > > *opaque)  {
> > >      GtkDisplayState *s = opaque;
> > > -    VirtualConsole *vc = gd_vc_find_by_menu(s);
> > > +    VirtualConsole *vc;
> > >      GtkNotebook *nb = GTK_NOTEBOOK(s->notebook);
> > >      gint page;
> > >
> > > +    vc = gd_vc_find_current(s);
> > > +    vc->gfx.visible = false;
> > > +
> > > +    vc = gd_vc_find_by_menu(s);
> > >      gtk_release_modifiers(s);
> > >      if (vc) {
> > >          page = gtk_notebook_page_num(nb, vc->tab_item);
> > >          gtk_notebook_set_current_page(nb, page);
> > >          gtk_widget_grab_focus(vc->focus);
> > > +        vc->gfx.visible = true;
> > >      }
> > >  }
> > >
> > > @@ -1350,6 +1355,7 @@ static gboolean gd_tab_window_close(GtkWidget
> > *widget, GdkEvent *event,
> > >      VirtualConsole *vc = opaque;
> > >      GtkDisplayState *s = vc->s;
> > >
> > > +    vc->gfx.visible = false;
> > >      gtk_widget_set_sensitive(vc->menu_item, true);
> > >      gd_widget_reparent(vc->window, s->notebook, vc->tab_item);
> > >      gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook),
> > > @@ -1423,6 +1429,7 @@ static void gd_menu_untabify(GtkMenuItem *item,
> > void *opaque)
> > >          gd_update_geometry_hints(vc);
> > >          gd_update_caption(s);
> > >      }
> > > +    vc->gfx.visible = true;
> > >  }
> > >
> > >  static void gd_menu_show_menubar(GtkMenuItem *item, void *opaque)
> > @@
> > > -2471,6 +2478,7 @@ static void gtk_display_init(DisplayState *ds,
> > > DisplayOptions *opts)  #ifdef CONFIG_GTK_CLIPBOARD
> > >      gd_clipboard_init(s);
> > >  #endif /* CONFIG_GTK_CLIPBOARD */
> > > +    vc->gfx.visible = true;
> > >  }
> > >
> > >  static void early_gtk_display_init(DisplayOptions *opts)
> > > --
> > > 2.34.1
> > >
> > >
> >
> >
> > --
> > Marc-André Lureau
Kim, Dongwon Feb. 1, 2024, 6:48 p.m. UTC | #4
Hi Marc-André,

Thanks for your feedback. Yes, you are right, rendering doesn't stop on Ubuntu system
as it has preview even after the window is minimized. But this is not always the case.
Some simple windows managers don't have this preview (thumbnail)
feature and this visible flag is not toggled. And the rendering stops right away there when
the window is minimized.

Detaching then closing the window which makes it go back to tabs does not
make the flag reset, too. To us, having this extra flag for VC is one simple and intuitive
way to handle such situations (including upcoming guest display hot plug in patches)

Thanks!

> Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when associated
> VC is invisible
> 
> Hi
> 
> On Wed, Jan 31, 2024 at 10:56 PM Kim, Dongwon <dongwon.kim@intel.com>
> wrote:
> >
> > Hi Marc-André,
> >
> > > https://docs.gtk.org/gtk3/method.Widget.is_visible.html
> >
> > This is what we had tried first but it didn't seem to work for the case of
> window minimization.
> > I see the visible flag for the GTK widget didn't seem to be toggled
> > for some reason. And when
> 
> Right, because minimize != visible. You can still get window preview with alt-
> tab and other compositor drawings.
> 
> Iow, it should keep rendering even when minimized.
> 
> > closing window, vc->window widget is destroyed so it is not possible
> > to check the flag using this GTK function. Having extra flag bound to
> > VC was most intuitive for the logic I wanted to implement.
> >
> > Thanks!!
> > DW
> >
> > > Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when
> > > associated VC is invisible
> > >
> > > Hi Dongwon
> > >
> > > On Wed, Jan 31, 2024 at 3:50 AM <dongwon.kim@intel.com> wrote:
> > > >
> > > > From: Dongwon Kim <dongwon.kim@intel.com>
> > > >
> > > > A new flag "visible" is added to show visibility status of the gfx console.
> > > > The flag is set to 'true' when the VC is visible but set to 'false'
> > > > when it is hidden or closed. When the VC is invisible, drawing
> > > > guest frames should be skipped as it will never be completed and
> > > > it would potentially lock up the guest display especially when blob
> scanout is used.
> > >
> > > Can't it skip drawing when the widget is not visible instead?
> > > https://docs.gtk.org/gtk3/method.Widget.is_visible.html
> > >
> > > >
> > > > Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> > > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > > Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
> > > >
> > > > Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
> > > > ---
> > > >  include/ui/gtk.h |  1 +
> > > >  ui/gtk-egl.c     |  8 ++++++++
> > > >  ui/gtk-gl-area.c |  8 ++++++++
> > > >  ui/gtk.c         | 10 +++++++++-
> > > >  4 files changed, 26 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/include/ui/gtk.h b/include/ui/gtk.h index
> > > > aa3d637029..2de38e5724 100644
> > > > --- a/include/ui/gtk.h
> > > > +++ b/include/ui/gtk.h
> > > > @@ -57,6 +57,7 @@ typedef struct VirtualGfxConsole {
> > > >      bool y0_top;
> > > >      bool scanout_mode;
> > > >      bool has_dmabuf;
> > > > +    bool visible;
> > > >  #endif
> > > >  } VirtualGfxConsole;
> > > >
> > > > diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index
> > > > 3af5ac5bcf..993c283191
> > > > 100644
> > > > --- a/ui/gtk-egl.c
> > > > +++ b/ui/gtk-egl.c
> > > > @@ -265,6 +265,10 @@ void
> > > gd_egl_scanout_dmabuf(DisplayChangeListener
> > > > *dcl,  #ifdef CONFIG_GBM
> > > >      VirtualConsole *vc = container_of(dcl, VirtualConsole,
> > > > gfx.dcl);
> > > >
> > > > +    if (!vc->gfx.visible) {
> > > > +        return;
> > > > +    }
> > > > +
> > > >      eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> > > >                     vc->gfx.esurface, vc->gfx.ectx);
> > > >
> > > > @@ -363,6 +367,10 @@ void gd_egl_flush(DisplayChangeListener *dcl,
> > > >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> > > >      GtkWidget *area = vc->gfx.drawing_area;
> > > >
> > > > +    if (!vc->gfx.visible) {
> > > > +        return;
> > > > +    }
> > > > +
> > > >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> > > >draw_submitted) {
> > > >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> > > >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; diff
> > > >--git  a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index
> > > >52dcac161e..04e07bd7ee
> > > > 100644
> > > > --- a/ui/gtk-gl-area.c
> > > > +++ b/ui/gtk-gl-area.c
> > > > @@ -285,6 +285,10 @@ void
> > > > gd_gl_area_scanout_flush(DisplayChangeListener *dcl,  {
> > > >      VirtualConsole *vc = container_of(dcl, VirtualConsole,
> > > > gfx.dcl);
> > > >
> > > > +    if (!vc->gfx.visible) {
> > > > +        return;
> > > > +    }
> > > > +
> > > >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> > > >draw_submitted) {
> > > >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> > > >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; @@ -299,6
> > > > +303,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener
> > > > +*dcl,
> > > > #ifdef CONFIG_GBM
> > > >      VirtualConsole *vc = container_of(dcl, VirtualConsole,
> > > > gfx.dcl);
> > > >
> > > > +    if (!vc->gfx.visible) {
> > > > +        return;
> > > > +    }
> > > > +
> > > >      gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> > > >      egl_dmabuf_import_texture(dmabuf);
> > > >      if (!dmabuf->texture) {
> > > > diff --git a/ui/gtk.c b/ui/gtk.c
> > > > index 810d7fc796..02eb667d8a 100644
> > > > --- a/ui/gtk.c
> > > > +++ b/ui/gtk.c
> > > > @@ -1312,15 +1312,20 @@ static void gd_menu_quit(GtkMenuItem
> > > > *item, void *opaque)  static void gd_menu_switch_vc(GtkMenuItem
> > > > *item, void
> > > > *opaque)  {
> > > >      GtkDisplayState *s = opaque;
> > > > -    VirtualConsole *vc = gd_vc_find_by_menu(s);
> > > > +    VirtualConsole *vc;
> > > >      GtkNotebook *nb = GTK_NOTEBOOK(s->notebook);
> > > >      gint page;
> > > >
> > > > +    vc = gd_vc_find_current(s);
> > > > +    vc->gfx.visible = false;
> > > > +
> > > > +    vc = gd_vc_find_by_menu(s);
> > > >      gtk_release_modifiers(s);
> > > >      if (vc) {
> > > >          page = gtk_notebook_page_num(nb, vc->tab_item);
> > > >          gtk_notebook_set_current_page(nb, page);
> > > >          gtk_widget_grab_focus(vc->focus);
> > > > +        vc->gfx.visible = true;
> > > >      }
> > > >  }
> > > >
> > > > @@ -1350,6 +1355,7 @@ static gboolean
> > > > gd_tab_window_close(GtkWidget
> > > *widget, GdkEvent *event,
> > > >      VirtualConsole *vc = opaque;
> > > >      GtkDisplayState *s = vc->s;
> > > >
> > > > +    vc->gfx.visible = false;
> > > >      gtk_widget_set_sensitive(vc->menu_item, true);
> > > >      gd_widget_reparent(vc->window, s->notebook, vc->tab_item);
> > > >      gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook),
> > > > @@ -1423,6 +1429,7 @@ static void gd_menu_untabify(GtkMenuItem
> > > > *item,
> > > void *opaque)
> > > >          gd_update_geometry_hints(vc);
> > > >          gd_update_caption(s);
> > > >      }
> > > > +    vc->gfx.visible = true;
> > > >  }
> > > >
> > > >  static void gd_menu_show_menubar(GtkMenuItem *item, void *opaque)
> > > @@
> > > > -2471,6 +2478,7 @@ static void gtk_display_init(DisplayState *ds,
> > > > DisplayOptions *opts)  #ifdef CONFIG_GTK_CLIPBOARD
> > > >      gd_clipboard_init(s);
> > > >  #endif /* CONFIG_GTK_CLIPBOARD */
> > > > +    vc->gfx.visible = true;
> > > >  }
> > > >
> > > >  static void early_gtk_display_init(DisplayOptions *opts)
> > > > --
> > > > 2.34.1
> > > >
> > > >
> > >
> > >
> > > --
> > > Marc-André Lureau
> 
> 
> 
> --
> Marc-André Lureau
Daniel P. Berrangé March 7, 2024, 9:40 a.m. UTC | #5
On Tue, Jan 30, 2024 at 03:48:38PM -0800, dongwon.kim@intel.com wrote:
> From: Dongwon Kim <dongwon.kim@intel.com>
> 
> A new flag "visible" is added to show visibility status of the gfx console.
> The flag is set to 'true' when the VC is visible but set to 'false' when
> it is hidden or closed. When the VC is invisible, drawing guest frames
> should be skipped as it will never be completed and it would potentially
> lock up the guest display especially when blob scanout is used.
> 
> Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
> 
> Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
> ---
>  include/ui/gtk.h |  1 +
>  ui/gtk-egl.c     |  8 ++++++++
>  ui/gtk-gl-area.c |  8 ++++++++
>  ui/gtk.c         | 10 +++++++++-
>  4 files changed, 26 insertions(+), 1 deletion(-)
> 
> diff --git a/include/ui/gtk.h b/include/ui/gtk.h
> index aa3d637029..2de38e5724 100644
> --- a/include/ui/gtk.h
> +++ b/include/ui/gtk.h
> @@ -57,6 +57,7 @@ typedef struct VirtualGfxConsole {
>      bool y0_top;
>      bool scanout_mode;
>      bool has_dmabuf;
> +    bool visible;
>  #endif
>  } VirtualGfxConsole;
>  
> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
> index 3af5ac5bcf..993c283191 100644
> --- a/ui/gtk-egl.c
> +++ b/ui/gtk-egl.c
> @@ -265,6 +265,10 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
>  #ifdef CONFIG_GBM
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>  
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
>                     vc->gfx.esurface, vc->gfx.ectx);
>  
> @@ -363,6 +367,10 @@ void gd_egl_flush(DisplayChangeListener *dcl,
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>      GtkWidget *area = vc->gfx.drawing_area;
>  
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
>          graphic_hw_gl_block(vc->gfx.dcl.con, true);
>          vc->gfx.guest_fb.dmabuf->draw_submitted = true;
> diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
> index 52dcac161e..04e07bd7ee 100644
> --- a/ui/gtk-gl-area.c
> +++ b/ui/gtk-gl-area.c
> @@ -285,6 +285,10 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
>  {
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>  
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
>          graphic_hw_gl_block(vc->gfx.dcl.con, true);
>          vc->gfx.guest_fb.dmabuf->draw_submitted = true;
> @@ -299,6 +303,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
>  #ifdef CONFIG_GBM
>      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
>  
> +    if (!vc->gfx.visible) {
> +        return;
> +    }
> +
>      gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
>      egl_dmabuf_import_texture(dmabuf);
>      if (!dmabuf->texture) {

If we skip processing these requests, what happens when the
QEMU windows is then re-displayed. Won't it now be missing
updates to various regions of the guest display ?

>
With regards,
Daniel
Daniel P. Berrangé March 7, 2024, 9:46 a.m. UTC | #6
On Thu, Feb 01, 2024 at 06:48:58PM +0000, Kim, Dongwon wrote:
> Hi Marc-André,
> 
> Thanks for your feedback. Yes, you are right, rendering doesn't stop on Ubuntu system
> as it has preview even after the window is minimized. But this is not always the case.
> Some simple windows managers don't have this preview (thumbnail)
> feature and this visible flag is not toggled. And the rendering stops right away there
> when the window is minimized.

This makes me pretty uncomfortable. This is proposing changing QEMU
behaviour to workaround a problem whose behaviour varies based on
what 3rd party software QEMU is running on

What you say "window managers" are you referring to a traditional
X11 based host display only, or does the problem also exist on
modern Wayland host display ?

If the problem is confined to X11, that would steer towards saying
we shouldn't try to workaround it given that X11 is very much
obsolete at this point.

With regards,
Daniel
Kim, Dongwon March 7, 2024, 5:34 p.m. UTC | #7
Hi Daniel,

> -----Original Message-----
> From: Daniel P. Berrangé <berrange@redhat.com>
> Sent: Thursday, March 7, 2024 1:41 AM
> To: Kim, Dongwon <dongwon.kim@intel.com>
> Cc: qemu-devel@nongnu.org
> Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when associated
> VC is invisible
> 
> On Tue, Jan 30, 2024 at 03:48:38PM -0800, dongwon.kim@intel.com wrote:
> > From: Dongwon Kim <dongwon.kim@intel.com>
> >
> > A new flag "visible" is added to show visibility status of the gfx console.
> > The flag is set to 'true' when the VC is visible but set to 'false'
> > when it is hidden or closed. When the VC is invisible, drawing guest
> > frames should be skipped as it will never be completed and it would
> > potentially lock up the guest display especially when blob scanout is used.
> >
> > Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Cc: Vivek Kasireddy <vivek.kasireddy@intel.com>
> >
> > Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
> > ---
> >  include/ui/gtk.h |  1 +
> >  ui/gtk-egl.c     |  8 ++++++++
> >  ui/gtk-gl-area.c |  8 ++++++++
> >  ui/gtk.c         | 10 +++++++++-
> >  4 files changed, 26 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/ui/gtk.h b/include/ui/gtk.h index
> > aa3d637029..2de38e5724 100644
> > --- a/include/ui/gtk.h
> > +++ b/include/ui/gtk.h
> > @@ -57,6 +57,7 @@ typedef struct VirtualGfxConsole {
> >      bool y0_top;
> >      bool scanout_mode;
> >      bool has_dmabuf;
> > +    bool visible;
> >  #endif
> >  } VirtualGfxConsole;
> >
> > diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 3af5ac5bcf..993c283191
> > 100644
> > --- a/ui/gtk-egl.c
> > +++ b/ui/gtk-egl.c
> > @@ -265,6 +265,10 @@ void
> gd_egl_scanout_dmabuf(DisplayChangeListener
> > *dcl,  #ifdef CONFIG_GBM
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> >                     vc->gfx.esurface, vc->gfx.ectx);
> >
> > @@ -363,6 +367,10 @@ void gd_egl_flush(DisplayChangeListener *dcl,
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >      GtkWidget *area = vc->gfx.drawing_area;
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> >draw_submitted) {
> >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; diff --git
> > a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 52dcac161e..04e07bd7ee
> > 100644
> > --- a/ui/gtk-gl-area.c
> > +++ b/ui/gtk-gl-area.c
> > @@ -285,6 +285,10 @@ void
> > gd_gl_area_scanout_flush(DisplayChangeListener *dcl,  {
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf-
> >draw_submitted) {
> >          graphic_hw_gl_block(vc->gfx.dcl.con, true);
> >          vc->gfx.guest_fb.dmabuf->draw_submitted = true; @@ -299,6
> > +303,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
> > #ifdef CONFIG_GBM
> >      VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> >
> > +    if (!vc->gfx.visible) {
> > +        return;
> > +    }
> > +
> >      gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> >      egl_dmabuf_import_texture(dmabuf);
> >      if (!dmabuf->texture) {
> 
> If we skip processing these requests, what happens when the QEMU windows is
> then re-displayed. Won't it now be missing updates to various regions of the
> guest display ?
 
[Kim, Dongwon]  Scanout blob is continuously submitted by the guest even when the vc->visible is false. So it will just display the current guest frame right away when the window is redisplayed again.

> 
> >
> With regards,
> Daniel
> --
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Kim, Dongwon March 7, 2024, 5:53 p.m. UTC | #8
Hi Daniel,

> -----Original Message-----
> From: Daniel P. Berrangé <berrange@redhat.com>
> Sent: Thursday, March 7, 2024 1:46 AM
> To: Kim, Dongwon <dongwon.kim@intel.com>
> Cc: Marc-André Lureau <marcandre.lureau@gmail.com>; qemu-
> devel@nongnu.org
> Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when associated
> VC is invisible
> 
> On Thu, Feb 01, 2024 at 06:48:58PM +0000, Kim, Dongwon wrote:
> > Hi Marc-André,
> >
> > Thanks for your feedback. Yes, you are right, rendering doesn't stop
> > on Ubuntu system as it has preview even after the window is minimized. But
> this is not always the case.
> > Some simple windows managers don't have this preview (thumbnail)
> > feature and this visible flag is not toggled. And the rendering stops
> > right away there when the window is minimized.
> 
> This makes me pretty uncomfortable. This is proposing changing QEMU
> behaviour to workaround a problem whose behaviour varies based on what 3rd
> party software QEMU is running on
> 
> What you say "window managers" are you referring to a traditional
> X11 based host display only, or does the problem also exist on modern
> Wayland host display ?

[Kim, Dongwon]  I didn't mean anything about the compositor/display server itself. And I am not sure about the general behavior of Wayland compositors but the point here is the rendering while the app is being iconized (minimized) is not always the case. For example, ICE-WM on Yocto Linux doesn't have any preview for the iconized or minimized applications, which means all drawing activities on the minimized app are paused. This is the problem in case blob scanout is used with virtio-gpu on the guest because the guest won't receive the response for the frame submission until the frame is fully rendered on the host. This is causing timeout and further issue on the display pipeline in virtio-gpu driver in the guest.

> 
> If the problem is confined to X11, that would steer towards saying we shouldn't
> try to workaround it given that X11 is very much obsolete at this point.

[Kim, Dongwon]  I think I should try Wayland too but I guess it depends on the compositor and the shell design. Of course I need to test but what if it works ok on the Ubuntu running with wayland backend but not with Weston?

> 
> With regards,
> Daniel
> --
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Daniel P. Berrangé March 7, 2024, 6:01 p.m. UTC | #9
On Thu, Mar 07, 2024 at 05:53:24PM +0000, Kim, Dongwon wrote:
> Hi Daniel,
> 
> > -----Original Message-----
> > From: Daniel P. Berrangé <berrange@redhat.com>
> > Sent: Thursday, March 7, 2024 1:46 AM
> > To: Kim, Dongwon <dongwon.kim@intel.com>
> > Cc: Marc-André Lureau <marcandre.lureau@gmail.com>; qemu-
> > devel@nongnu.org
> > Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when associated
> > VC is invisible
> > 
> > On Thu, Feb 01, 2024 at 06:48:58PM +0000, Kim, Dongwon wrote:
> > > Hi Marc-André,
> > >
> > > Thanks for your feedback. Yes, you are right, rendering doesn't stop
> > > on Ubuntu system as it has preview even after the window is minimized. But
> > this is not always the case.
> > > Some simple windows managers don't have this preview (thumbnail)
> > > feature and this visible flag is not toggled. And the rendering stops
> > > right away there when the window is minimized.
> > 
> > This makes me pretty uncomfortable. This is proposing changing QEMU
> > behaviour to workaround a problem whose behaviour varies based on what 3rd
> > party software QEMU is running on
> > 
> > What you say "window managers" are you referring to a traditional
> > X11 based host display only, or does the problem also exist on modern
> > Wayland host display ?
> 
> [Kim, Dongwon]  I didn't mean anything about the compositor/display
> server itself. And I am not sure about the general behavior of Wayland
> compositors but the point here is the rendering while the app is being
> iconized (minimized) is not always the case. For example, ICE-WM on
> Yocto Linux doesn't have any preview for the iconized or minimized
> applications, which means all drawing activities on the minimized
> app are paused. This is the problem in case blob scanout is used
> with virtio-gpu on the guest because the guest won't receive the
> response for the frame submission until the frame is fully rendered
> on the host. This is causing timeout and further issue on the display
> pipeline in virtio-gpu driver in the guest.

I guess I'm wondering why we should consider this a bug in QEMU
rather than a bug in either the toolkit or host rendering stack ?

Lets say there was no guest OS here, just a regular host app
issuing drawing requests that were equivalent to the workload
the guest is issuing.  If that applications' execution got
blocked because its drawing requests are not getting processed
when iconified, I'd be inclined to call it a bug.

Or are we perhaps handling drawing in the wrong way in QEMU ?

If the problem is with drawing to a iconified windows, is
there an intermediate target buffer we should be drawing
to, instead of directly to the window. There must be some
supported way to have drawing requests fully processed in
the background indepent of having a visible window, surely ?

With regards,
Daniel
Kim, Dongwon March 7, 2024, 7:50 p.m. UTC | #10
Hi Daniel,

> -----Original Message-----
> From: Daniel P. Berrangé <berrange@redhat.com>
> Sent: Thursday, March 7, 2024 10:01 AM
> To: Kim, Dongwon <dongwon.kim@intel.com>
> Cc: Marc-André Lureau <marcandre.lureau@gmail.com>; qemu-
> devel@nongnu.org
> Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when associated
> VC is invisible
> 
> On Thu, Mar 07, 2024 at 05:53:24PM +0000, Kim, Dongwon wrote:
> > Hi Daniel,
> >
> > > -----Original Message-----
> > > From: Daniel P. Berrangé <berrange@redhat.com>
> > > Sent: Thursday, March 7, 2024 1:46 AM
> > > To: Kim, Dongwon <dongwon.kim@intel.com>
> > > Cc: Marc-André Lureau <marcandre.lureau@gmail.com>; qemu-
> > > devel@nongnu.org
> > > Subject: Re: [PATCH 1/3] ui/gtk: skip drawing guest scanout when
> > > associated VC is invisible
> > >
> > > On Thu, Feb 01, 2024 at 06:48:58PM +0000, Kim, Dongwon wrote:
> > > > Hi Marc-André,
> > > >
> > > > Thanks for your feedback. Yes, you are right, rendering doesn't
> > > > stop on Ubuntu system as it has preview even after the window is
> > > > minimized. But
> > > this is not always the case.
> > > > Some simple windows managers don't have this preview (thumbnail)
> > > > feature and this visible flag is not toggled. And the rendering
> > > > stops right away there when the window is minimized.
> > >
> > > This makes me pretty uncomfortable. This is proposing changing QEMU
> > > behaviour to workaround a problem whose behaviour varies based on
> > > what 3rd party software QEMU is running on
> > >
> > > What you say "window managers" are you referring to a traditional
> > > X11 based host display only, or does the problem also exist on
> > > modern Wayland host display ?
> >
> > [Kim, Dongwon]  I didn't mean anything about the compositor/display
> > server itself. And I am not sure about the general behavior of Wayland
> > compositors but the point here is the rendering while the app is being
> > iconized (minimized) is not always the case. For example, ICE-WM on
> > Yocto Linux doesn't have any preview for the iconized or minimized
> > applications, which means all drawing activities on the minimized app
> > are paused. This is the problem in case blob scanout is used with
> > virtio-gpu on the guest because the guest won't receive the response
> > for the frame submission until the frame is fully rendered on the
> > host. This is causing timeout and further issue on the display
> > pipeline in virtio-gpu driver in the guest.
> 
> I guess I'm wondering why we should consider this a bug in QEMU rather than
> a bug in either the toolkit or host rendering stack ?
> 
> Lets say there was no guest OS here, just a regular host app issuing drawing
> requests that were equivalent to the workload the guest is issuing.  If that
> applications' execution got blocked because its drawing requests are not
> getting processed when iconified, I'd be inclined to call it a bug.
> 
> Or are we perhaps handling drawing in the wrong way in QEMU ?
[Kim, Dongwon] Hmm.. Yeah that is a good point.. If non-rendering workload is blocked in the same way, that would be a problem. 
> 
> If the problem is with drawing to a iconified windows, is there an intermediate
> target buffer we should be drawing to, instead of directly to the window. There
> must be some supported way to have drawing requests fully processed in the
> background indepent of having a visible window, surely ?
[Kim, Dongwon]  I will check what other options that don't look like WAs are available.

> 
> With regards,
> Daniel
> --
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
diff mbox series

Patch

diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index aa3d637029..2de38e5724 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -57,6 +57,7 @@  typedef struct VirtualGfxConsole {
     bool y0_top;
     bool scanout_mode;
     bool has_dmabuf;
+    bool visible;
 #endif
 } VirtualGfxConsole;
 
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 3af5ac5bcf..993c283191 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -265,6 +265,10 @@  void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
 #ifdef CONFIG_GBM
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 
+    if (!vc->gfx.visible) {
+        return;
+    }
+
     eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
                    vc->gfx.esurface, vc->gfx.ectx);
 
@@ -363,6 +367,10 @@  void gd_egl_flush(DisplayChangeListener *dcl,
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
     GtkWidget *area = vc->gfx.drawing_area;
 
+    if (!vc->gfx.visible) {
+        return;
+    }
+
     if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
         graphic_hw_gl_block(vc->gfx.dcl.con, true);
         vc->gfx.guest_fb.dmabuf->draw_submitted = true;
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index 52dcac161e..04e07bd7ee 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -285,6 +285,10 @@  void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
 {
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 
+    if (!vc->gfx.visible) {
+        return;
+    }
+
     if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
         graphic_hw_gl_block(vc->gfx.dcl.con, true);
         vc->gfx.guest_fb.dmabuf->draw_submitted = true;
@@ -299,6 +303,10 @@  void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
 #ifdef CONFIG_GBM
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 
+    if (!vc->gfx.visible) {
+        return;
+    }
+
     gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
     egl_dmabuf_import_texture(dmabuf);
     if (!dmabuf->texture) {
diff --git a/ui/gtk.c b/ui/gtk.c
index 810d7fc796..02eb667d8a 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1312,15 +1312,20 @@  static void gd_menu_quit(GtkMenuItem *item, void *opaque)
 static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
-    VirtualConsole *vc = gd_vc_find_by_menu(s);
+    VirtualConsole *vc;
     GtkNotebook *nb = GTK_NOTEBOOK(s->notebook);
     gint page;
 
+    vc = gd_vc_find_current(s);
+    vc->gfx.visible = false;
+
+    vc = gd_vc_find_by_menu(s);
     gtk_release_modifiers(s);
     if (vc) {
         page = gtk_notebook_page_num(nb, vc->tab_item);
         gtk_notebook_set_current_page(nb, page);
         gtk_widget_grab_focus(vc->focus);
+        vc->gfx.visible = true;
     }
 }
 
@@ -1350,6 +1355,7 @@  static gboolean gd_tab_window_close(GtkWidget *widget, GdkEvent *event,
     VirtualConsole *vc = opaque;
     GtkDisplayState *s = vc->s;
 
+    vc->gfx.visible = false;
     gtk_widget_set_sensitive(vc->menu_item, true);
     gd_widget_reparent(vc->window, s->notebook, vc->tab_item);
     gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook),
@@ -1423,6 +1429,7 @@  static void gd_menu_untabify(GtkMenuItem *item, void *opaque)
         gd_update_geometry_hints(vc);
         gd_update_caption(s);
     }
+    vc->gfx.visible = true;
 }
 
 static void gd_menu_show_menubar(GtkMenuItem *item, void *opaque)
@@ -2471,6 +2478,7 @@  static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
 #ifdef CONFIG_GTK_CLIPBOARD
     gd_clipboard_init(s);
 #endif /* CONFIG_GTK_CLIPBOARD */
+    vc->gfx.visible = true;
 }
 
 static void early_gtk_display_init(DisplayOptions *opts)