qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/2] edid: Make refresh rate configurable
@ 2021-03-03 15:29 Akihiko Odaki
  2021-03-03 15:29 ` [PATCH v2 2/2] virtio-gpu: Respect UI refresh rate for EDID Akihiko Odaki
  0 siblings, 1 reply; 4+ messages in thread
From: Akihiko Odaki @ 2021-03-03 15:29 UTC (permalink / raw)
  Cc: Stefano Stabellini, Michael S . Tsirkin, Paul Durrant,
	qemu Developers, Gerd Hoffmann, Akihiko Odaki, Anthony Perard,
	xen-devel

Signed-off-by: Akihiko Odaki <akihiko.odaki@gmail.com>
---
 hw/display/edid-generate.c |  9 +++++----
 include/hw/display/edid.h  | 12 +++++++-----
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c
index 1665b7cbb29..b0ce583d436 100644
--- a/hw/display/edid-generate.c
+++ b/hw/display/edid-generate.c
@@ -203,7 +203,7 @@ static void edid_desc_dummy(uint8_t *desc)
     edid_desc_type(desc, 0x10);
 }
 
-static void edid_desc_timing(uint8_t *desc,
+static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate,
                              uint32_t xres, uint32_t yres,
                              uint32_t xmm, uint32_t ymm)
 {
@@ -216,9 +216,9 @@ static void edid_desc_timing(uint8_t *desc,
     uint32_t ysync  = yres *  5 / 1000;
     uint32_t yblank = yres * 35 / 1000;
 
-    uint32_t clock  = 75 * (xres + xblank) * (yres + yblank);
+    uint64_t clock  = (uint64_t)refresh_rate * (xres + xblank) * (yres + yblank);
 
-    stl_le_p(desc, clock / 10000);
+    stl_le_p(desc, clock / 10000000);
 
     desc[2] = xres   & 0xff;
     desc[3] = xblank & 0xff;
@@ -303,6 +303,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
     uint8_t *xtra3 = NULL;
     uint8_t *dta = NULL;
     uint32_t width_mm, height_mm;
+    uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000;
     uint32_t dpi = 100; /* if no width_mm/height_mm */
 
     /* =============== set defaults  =============== */
@@ -400,7 +401,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
 
     /* =============== descriptor blocks =============== */
 
-    edid_desc_timing(edid + desc, info->prefx, info->prefy,
+    edid_desc_timing(edid + desc, refresh_rate, info->prefx, info->prefy,
                      width_mm, height_mm);
     desc += 18;
 
diff --git a/include/hw/display/edid.h b/include/hw/display/edid.h
index 1f8fc9b3750..520f8ec2027 100644
--- a/include/hw/display/edid.h
+++ b/include/hw/display/edid.h
@@ -11,6 +11,7 @@ typedef struct qemu_edid_info {
     uint32_t    prefy;
     uint32_t    maxx;
     uint32_t    maxy;
+    uint32_t    refresh_rate;
 } qemu_edid_info;
 
 void qemu_edid_generate(uint8_t *edid, size_t size,
@@ -21,10 +22,11 @@ void qemu_edid_region_io(MemoryRegion *region, Object *owner,
 
 uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res);
 
-#define DEFINE_EDID_PROPERTIES(_state, _edid_info)              \
-    DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0),    \
-    DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0),    \
-    DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0),     \
-    DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0)
+#define DEFINE_EDID_PROPERTIES(_state, _edid_info)                         \
+    DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0),               \
+    DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0),               \
+    DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0),                \
+    DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0),                \
+    DEFINE_PROP_UINT32("refresh_rate", _state, _edid_info.refresh_rate, 0)
 
 #endif /* EDID_H */
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] virtio-gpu: Respect UI refresh rate for EDID
  2021-03-03 15:29 [PATCH v2 1/2] edid: Make refresh rate configurable Akihiko Odaki
@ 2021-03-03 15:29 ` Akihiko Odaki
  2021-03-10 13:29   ` Gerd Hoffmann
  0 siblings, 1 reply; 4+ messages in thread
From: Akihiko Odaki @ 2021-03-03 15:29 UTC (permalink / raw)
  Cc: Stefano Stabellini, Michael S . Tsirkin, Paul Durrant,
	qemu Developers, Gerd Hoffmann, Akihiko Odaki, Anthony Perard,
	xen-devel

This change adds a new member, refresh_rate to QemuUIInfo in
include/ui/console.h. It represents the refresh rate of the
physical display backend, and it is more appropriate than
GUI update interval as the refresh rate which the emulated device
reports:
- sdl may set GUI update interval shorter than the refresh rate
  of the physical display to respond to user-generated events.
- sdl and vnc aggressively changes GUI update interval, but
  a guests is typically not designed to respond to frequent
  refresh rate changes, or frequent "display mode" changes in
  general. The frequency of refresh rate changes of the physical
  display backend matches better to the guest's expectation.

QemuUIInfo also has other members representing "display mode",
which makes it suitable for refresh rate representation. It has
a throttling of update notifications, and prevents frequent changes
of the display mode.

Signed-off-by: Akihiko Odaki <akihiko.odaki@gmail.com>
---
 hw/display/virtio-gpu-base.c   |  1 +
 hw/display/virtio-gpu.c        |  1 +
 hw/display/xenfb.c             | 14 ++++++++---
 include/hw/virtio/virtio-gpu.h |  1 +
 include/ui/console.h           |  2 +-
 include/ui/gtk.h               |  2 +-
 ui/console.c                   |  6 -----
 ui/gtk-egl.c                   |  4 +--
 ui/gtk.c                       | 45 ++++++++++++++++++++--------------
 9 files changed, 44 insertions(+), 32 deletions(-)

diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 4a57350917c..86ed208d031 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -80,6 +80,7 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
 
     g->req_state[idx].x = info->xoff;
     g->req_state[idx].y = info->yoff;
+    g->req_state[idx].refresh_rate = info->refresh_rate;
     g->req_state[idx].width = info->width;
     g->req_state[idx].height = info->height;
     g->req_state[idx].width_mm = info->width_mm;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 2e4a9822b6a..eee22b18e8a 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -216,6 +216,7 @@ virtio_gpu_generate_edid(VirtIOGPU *g, int scanout,
         .height_mm = b->req_state[scanout].height_mm,
         .prefx = b->req_state[scanout].width,
         .prefy = b->req_state[scanout].height,
+        .refresh_rate = b->req_state[scanout].refresh_rate,
     };
 
     edid->size = cpu_to_le32(sizeof(edid->edid));
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 838260b6ad1..a53341ef673 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -777,16 +777,24 @@ static void xenfb_update(void *opaque)
     xenfb->up_fullscreen = 0;
 }
 
-static void xenfb_update_interval(void *opaque, uint64_t interval)
+static void xenfb_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
 {
     struct XenFB *xenfb = opaque;
+    uint32_t refresh_rate;
 
     if (xenfb->feature_update) {
 #ifdef XENFB_TYPE_REFRESH_PERIOD
         if (xenfb_queue_full(xenfb)) {
             return;
         }
-        xenfb_send_refresh_period(xenfb, interval);
+
+        refresh_rate = info->refresh_rate;
+        if (!refresh_rate) {
+            refresh_rate = 75;
+        }
+
+        /* T = 1 / f = 1 [s*Hz] / f = 1000*1000 [ms*mHz] / f */
+        xenfb_send_refresh_period(xenfb, 1000 * 1000 / refresh_rate);
 #endif
     }
 }
@@ -983,5 +991,5 @@ struct XenDevOps xen_framebuffer_ops = {
 static const GraphicHwOps xenfb_ops = {
     .invalidate  = xenfb_invalidate,
     .gfx_update  = xenfb_update,
-    .update_interval = xenfb_update_interval,
+    .ui_info     = xenfb_ui_info,
 };
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index fae149235c5..876c4a51a67 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -64,6 +64,7 @@ struct virtio_gpu_scanout {
 struct virtio_gpu_requested_state {
     uint16_t width_mm, height_mm;
     uint32_t width, height;
+    uint32_t refresh_rate;
     int x, y;
 };
 
diff --git a/include/ui/console.h b/include/ui/console.h
index d30e972d0b5..6c4eb4df718 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -127,6 +127,7 @@ typedef struct QemuUIInfo {
     int       yoff;
     uint32_t  width;
     uint32_t  height;
+    uint32_t  refresh_rate;
 } QemuUIInfo;
 
 /* cursor data format is 32bit RGBA */
@@ -384,7 +385,6 @@ typedef struct GraphicHwOps {
     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);
     void (*gl_block)(void *opaque, bool block);
     void (*gl_flushed)(void *opaque);
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 3c1cd98db8b..1fde553c0f0 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -87,7 +87,7 @@ extern bool gtk_use_gl_area;
 
 /* ui/gtk.c */
 void gd_update_windowsize(VirtualConsole *vc);
-int gd_monitor_update_interval(GtkWidget *widget);
+void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget);
 
 /* ui/gtk-egl.c */
 void gd_egl_init(VirtualConsole *vc);
diff --git a/ui/console.c b/ui/console.c
index c5d11bc7017..3f5a0c113e2 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -203,7 +203,6 @@ static void gui_update(void *opaque)
     uint64_t dcl_interval;
     DisplayState *ds = opaque;
     DisplayChangeListener *dcl;
-    QemuConsole *con;
 
     ds->refreshing = true;
     dpy_refresh(ds);
@@ -218,11 +217,6 @@ static void gui_update(void *opaque)
     }
     if (ds->update_interval != interval) {
         ds->update_interval = interval;
-        QTAILQ_FOREACH(con, &consoles, next) {
-            if (con->hw_ops->update_interval) {
-                con->hw_ops->update_interval(con->hw, interval);
-            }
-        }
         trace_console_refresh(interval);
     }
     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 588e7b1bb19..1a32888e08b 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -116,8 +116,8 @@ void gd_egl_refresh(DisplayChangeListener *dcl)
 {
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
 
-    vc->gfx.dcl.update_interval = gd_monitor_update_interval(
-            vc->window ? vc->window : vc->gfx.drawing_area);
+    gd_update_monitor_refresh_rate(
+            vc, vc->window ? vc->window : vc->gfx.drawing_area);
 
     if (!vc->gfx.esurface) {
         gd_egl_init(vc);
diff --git a/ui/gtk.c b/ui/gtk.c
index 79dc2401203..c3e20806877 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -726,11 +726,20 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
     return TRUE;
 }
 
-static void gd_set_ui_info(VirtualConsole *vc, gint width, gint height)
+static void gd_set_ui_refresh_rate(VirtualConsole *vc, int refresh_rate)
 {
     QemuUIInfo info;
 
-    memset(&info, 0, sizeof(info));
+    info = *dpy_get_ui_info(vc->gfx.dcl.con);
+    info.refresh_rate = refresh_rate;
+    dpy_set_ui_info(vc->gfx.dcl.con, &info);
+}
+
+static void gd_set_ui_size(VirtualConsole *vc, gint width, gint height)
+{
+    QemuUIInfo info;
+
+    info = *dpy_get_ui_info(vc->gfx.dcl.con);
     info.width = width;
     info.height = height;
     dpy_set_ui_info(vc->gfx.dcl.con, &info);
@@ -754,33 +763,32 @@ static void gd_resize_event(GtkGLArea *area,
 {
     VirtualConsole *vc = (void *)opaque;
 
-    gd_set_ui_info(vc, width, height);
+    gd_set_ui_size(vc, width, height);
 }
 
 #endif
 
-/*
- * If available, return the update interval of the monitor in ms,
- * else return 0 (the default update interval).
- */
-int gd_monitor_update_interval(GtkWidget *widget)
+void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget)
 {
 #ifdef GDK_VERSION_3_22
     GdkWindow *win = gtk_widget_get_window(widget);
+    int refresh_rate;
 
     if (win) {
         GdkDisplay *dpy = gtk_widget_get_display(widget);
         GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
-        int refresh_rate = gdk_monitor_get_refresh_rate(monitor); /* [mHz] */
-
-        if (refresh_rate) {
-            /* T = 1 / f = 1 [s*Hz] / f = 1000*1000 [ms*mHz] / f */
-            return MIN(1000 * 1000 / refresh_rate,
-                       GUI_REFRESH_INTERVAL_DEFAULT);
-        }
+        refresh_rate = gdk_monitor_get_refresh_rate(monitor); /* [mHz] */
+    } else {
+        refresh_rate = 0;
     }
+
+    gd_set_ui_refresh_rate(vc, refresh_rate);
+
+    /* T = 1 / f = 1 [s*Hz] / f = 1000*1000 [ms*mHz] / f */
+    vc->gfx.dcl.update_interval = refresh_rate ?
+        MIN(1000 * 1000 / refresh_rate, GUI_REFRESH_INTERVAL_DEFAULT) :
+        GUI_REFRESH_INTERVAL_DEFAULT;
 #endif
-    return 0;
 }
 
 static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
@@ -810,8 +818,7 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
         return FALSE;
     }
 
-    vc->gfx.dcl.update_interval =
-        gd_monitor_update_interval(vc->window ? vc->window : s->window);
+    gd_update_monitor_refresh_rate(vc, vc->window ? vc->window : s->window);
 
     fbw = surface_width(vc->gfx.ds);
     fbh = surface_height(vc->gfx.ds);
@@ -1655,7 +1662,7 @@ static gboolean gd_configure(GtkWidget *widget,
 {
     VirtualConsole *vc = opaque;
 
-    gd_set_ui_info(vc, cfg->width, cfg->height);
+    gd_set_ui_size(vc, cfg->width, cfg->height);
     return FALSE;
 }
 
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] virtio-gpu: Respect UI refresh rate for EDID
  2021-03-03 15:29 ` [PATCH v2 2/2] virtio-gpu: Respect UI refresh rate for EDID Akihiko Odaki
@ 2021-03-10 13:29   ` Gerd Hoffmann
  2021-03-10 16:08     ` Akihiko Odaki
  0 siblings, 1 reply; 4+ messages in thread
From: Gerd Hoffmann @ 2021-03-10 13:29 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: Stefano Stabellini, Paul Durrant, Michael S . Tsirkin,
	qemu Developers, Anthony Perard, xen-devel

  Hi,

> -static void xenfb_update_interval(void *opaque, uint64_t interval)
> +static void xenfb_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)

> -    .update_interval = xenfb_update_interval,
> +    .ui_info     = xenfb_ui_info,

Hmm, I suspect xenfb really wants the actual refresh rate, even in case
vnc/sdl change it dynamically.  Anthony?  Stefano?

I guess we should just leave the update_interval callback as-is, for
those who want know, and use ui_info->refresh_rate for the virtual edid
refresh rate (which may not match the actual update interval in case of
dynamic changes).  Adding a comment explaining the difference to
console.h is a good idea too.

Otherwise looks good to me overall.  Splitting the ui/gtk update to a
separate patch is probably a good idea.

take care,
  Gerd



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] virtio-gpu: Respect UI refresh rate for EDID
  2021-03-10 13:29   ` Gerd Hoffmann
@ 2021-03-10 16:08     ` Akihiko Odaki
  0 siblings, 0 replies; 4+ messages in thread
From: Akihiko Odaki @ 2021-03-10 16:08 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Stefano Stabellini, Paul Durrant, Michael S . Tsirkin,
	qemu Developers, Anthony Perard, xen-devel

2021年3月10日(水) 22:29 Gerd Hoffmann <kraxel@redhat.com>:
>
>   Hi,
>
> > -static void xenfb_update_interval(void *opaque, uint64_t interval)
> > +static void xenfb_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
>
> > -    .update_interval = xenfb_update_interval,
> > +    .ui_info     = xenfb_ui_info,
>
> Hmm, I suspect xenfb really wants the actual refresh rate, even in case
> vnc/sdl change it dynamically.  Anthony?  Stefano?
>
> I guess we should just leave the update_interval callback as-is, for
> those who want know, and use ui_info->refresh_rate for the virtual edid
> refresh rate (which may not match the actual update interval in case of
> dynamic changes).  Adding a comment explaining the difference to
> console.h is a good idea too.

sdl shortens update_interval to respond to user inputs, but it has
nothing to do with frame buffer. Using ui_info->refresh_rate will
eliminate worthless frame updates even for xenfb in such cases.

xenfb has a behavior similar to virtio-gpu. Instead of generating
interrupts, they just tell the refresh rate to the guest and expect
the guest to provide a frame buffer by itself. I think the dynamic
display mode change is also problematic for xenfb if the guest driver
uses the information (although the Linux driver does not use it at
least.) It is possible to have both of the refresh rate member in
QemuUIInfo and update_interval, but I don't see a difference
justifying that.

Anyway, I'd also like to hear opinions from Xen developers.

>
> Otherwise looks good to me overall.  Splitting the ui/gtk update to a
> separate patch is probably a good idea.
>

I'll do so when submitting the next version.

Regards,
Akihiko Odaki


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-03-10 16:38 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-03 15:29 [PATCH v2 1/2] edid: Make refresh rate configurable Akihiko Odaki
2021-03-03 15:29 ` [PATCH v2 2/2] virtio-gpu: Respect UI refresh rate for EDID Akihiko Odaki
2021-03-10 13:29   ` Gerd Hoffmann
2021-03-10 16:08     ` Akihiko Odaki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).