From patchwork Fri Jun 10 09:20:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 12877451 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id ED2F5C433EF for ; Fri, 10 Jun 2022 11:05:02 +0000 (UTC) Received: from localhost ([::1]:42718 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nzcRp-0006rK-EL for qemu-devel@archiver.kernel.org; Fri, 10 Jun 2022 07:05:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:49868) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nzapy-0000BP-N5 for qemu-devel@nongnu.org; Fri, 10 Jun 2022 05:21:50 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:55229) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nzapv-0001qF-ER for qemu-devel@nongnu.org; Fri, 10 Jun 2022 05:21:50 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1654852905; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ebiRccH2awWxGwAppvEzoFJ/M1x++CURc9+zFzjg06Y=; b=Tg3pgGK+yzR4n3AgVD3t94NHF1h1EnLDBiRXAb9GjAxdVz0CvzVyQjCQzv7bduAJRvRUoS c0zLzYYnX90WmPufmBGYJ/9H7+k1pon2sJg/Le4067gJ0WM2gWgx602x5muJmi8wb6rIl9 peQ3AH4XmS7FImIcv/jWYGzDQhw56Co= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-654-_2Xh9ZlrMw-WSYMohO052Q-1; Fri, 10 Jun 2022 05:21:42 -0400 X-MC-Unique: _2Xh9ZlrMw-WSYMohO052Q-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2981A811E75; Fri, 10 Jun 2022 09:21:42 +0000 (UTC) Received: from sirius.home.kraxel.org (unknown [10.39.192.40]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9F36440466A9; Fri, 10 Jun 2022 09:21:41 +0000 (UTC) Received: by sirius.home.kraxel.org (Postfix, from userid 1000) id 9273F1800916; Fri, 10 Jun 2022 11:20:45 +0200 (CEST) From: Gerd Hoffmann To: qemu-devel@nongnu.org Cc: "Canokeys.org" , "Michael S. Tsirkin" , Stefano Stabellini , Anthony Perard , Paul Durrant , Akihiko Odaki , Peter Maydell , "Hongren (Zenithal) Zheng" , xen-devel@lists.xenproject.org, Alex Williamson , Gerd Hoffmann , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= Subject: [PULL 16/17] ui: Deliver refresh rate via QemuUIInfo Date: Fri, 10 Jun 2022 11:20:42 +0200 Message-Id: <20220610092043.1874654-17-kraxel@redhat.com> In-Reply-To: <20220610092043.1874654-1-kraxel@redhat.com> References: <20220610092043.1874654-1-kraxel@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kraxel@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Akihiko Odaki 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 Message-Id: <20220226115516.59830-3-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 2 +- include/ui/gtk.h | 2 +- hw/display/xenfb.c | 14 +++++++++++--- ui/console.c | 6 ------ ui/gtk-egl.c | 4 ++-- ui/gtk-gl-area.c | 3 +-- ui/gtk.c | 45 +++++++++++++++++++++++++------------------- 7 files changed, 42 insertions(+), 34 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 642d6f5248cf..b64d82436097 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -139,6 +139,7 @@ typedef struct QemuUIInfo { int yoff; uint32_t width; uint32_t height; + uint32_t refresh_rate; } QemuUIInfo; /* cursor data format is 32bit RGBA */ @@ -431,7 +432,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); void (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info); void (*gl_block)(void *opaque, bool block); } GraphicHwOps; diff --git a/include/ui/gtk.h b/include/ui/gtk.h index 101b147d1b98..ae0f53740d19 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -155,7 +155,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); void gd_hw_gl_flushed(void *vc); /* ui/gtk-egl.c */ diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index cea10fe3c780..50857cd97a0b 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/ui/console.c b/ui/console.c index 36c80cd1de85..9331b85203a0 100644 --- a/ui/console.c +++ b/ui/console.c @@ -160,7 +160,6 @@ static void gui_update(void *opaque) uint64_t dcl_interval; DisplayState *ds = opaque; DisplayChangeListener *dcl; - QemuConsole *con; ds->refreshing = true; dpy_refresh(ds); @@ -175,11 +174,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 e3bd4bc27431..b5bffbab2522 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -140,8 +140,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-gl-area.c b/ui/gtk-gl-area.c index 2e0129c28cd4..682638a197d2 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -121,8 +121,7 @@ void gd_gl_area_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.gls) { if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { diff --git a/ui/gtk.c b/ui/gtk.c index c57c36749e0e..2a791dd2aa04 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -710,11 +710,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, true); +} + +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, true); @@ -738,33 +747,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) @@ -801,8 +809,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); @@ -1691,7 +1698,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; }