carlwgeorge / rpms / qemu

Forked from rpms/qemu a year ago
Clone
cf81640
From: Christophe Fergeau <cfergeau@redhat.com>
6438461
Date: Fri, 28 Oct 2016 16:48:40 +0200
cf81640
Subject: [PATCH] qxl: Only emit QXL_INTERRUPT_CLIENT_MONITORS_CONFIG on config
cf81640
 changes
cf81640
cf81640
Currently if the client keeps sending the same monitor config to
cf81640
QEMU/spice-server, QEMU will always raise
cf81640
a QXL_INTERRUPT_CLIENT_MONITORS_CONFIG regardless of whether there was a
cf81640
change or not.
cf81640
Guest-side (with fedora 25), the kernel QXL KMS driver will also forward the
cf81640
event to user-space without checking if there were actual changes.
cf81640
Next in line are gnome-shell/mutter (on a default f25 install), which
cf81640
will try to reconfigure everything without checking if there is anything
cf81640
to do.
cf81640
Where this gets ugly is that when applying the resolution changes,
cf81640
gnome-shell/mutter will call drmModeRmFB, drmModeAddFB, and
cf81640
drmModeSetCrtc, which will cause the primary surface to be destroyed and
cf81640
recreated by the QXL KMS driver. This in turn will cause the client to
cf81640
resend a client monitors config message, which will cause QEMU to reemit
cf81640
an interrupt with an unchanged monitors configuration, ...
cf81640
This causes https://bugzilla.redhat.com/show_bug.cgi?id=1266484
cf81640
cf81640
This commit makes sure that we only emit
cf81640
QXL_INTERRUPT_CLIENT_MONITORS_CONFIG when there are actual configuration
cf81640
changes the guest should act on.
6438461
6438461
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
6438461
Message-id: 20161028144840.18326-1-cfergeau@redhat.com
6438461
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
6438461
(cherry picked from commit 6c7565028c272c4c6f2a83c3a90b044eeaf2804a)
cf81640
---
6438461
 hw/display/qxl.c | 37 ++++++++++++++++++++++++++++++++++++-
6438461
 1 file changed, 36 insertions(+), 1 deletion(-)
cf81640
cf81640
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
3d039dc
index 0e2682d28b..62d0c80dcf 100644
cf81640
--- a/hw/display/qxl.c
cf81640
+++ b/hw/display/qxl.c
6438461
@@ -992,6 +992,34 @@ static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
6438461
     return crc32(0xffffffff, p, len) ^ 0xffffffff;
6438461
 }
cf81640
 
6438461
+static bool qxl_rom_monitors_config_changed(QXLRom *rom,
6438461
+        VDAgentMonitorsConfig *monitors_config,
6438461
+        unsigned int max_outputs)
6438461
+{
6438461
+    int i;
6438461
+    unsigned int monitors_count;
6438461
+
6438461
+    monitors_count = MIN(monitors_config->num_of_monitors, max_outputs);
6438461
+
6438461
+    if (rom->client_monitors_config.count != monitors_count) {
6438461
+        return true;
cf81640
+    }
6438461
+
cf81640
+    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
cf81640
+        VDAgentMonConfig *monitor = &monitors_config->monitors[i];
cf81640
+        QXLURect *rect = &rom->client_monitors_config.heads[i];
cf81640
+        /* monitor->depth ignored */
cf81640
+        if ((rect->left != monitor->x) ||
cf81640
+            (rect->top != monitor->y)  ||
cf81640
+            (rect->right != monitor->x + monitor->width) ||
cf81640
+            (rect->bottom != monitor->y + monitor->height)) {
6438461
+            return true;
cf81640
+        }
cf81640
+    }
cf81640
+
6438461
+    return false;
6438461
+}
6438461
+
6438461
 /* called from main context only */
6438461
 static int interface_client_monitors_config(QXLInstance *sin,
6438461
                                         VDAgentMonitorsConfig *monitors_config)
6438461
@@ -1000,6 +1028,7 @@ static int interface_client_monitors_config(QXLInstance *sin,
6438461
     QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
6438461
     int i;
6438461
     unsigned max_outputs = ARRAY_SIZE(rom->client_monitors_config.heads);
6438461
+    bool config_changed = false;
6438461
 
6438461
     if (qxl->revision < 4) {
6438461
         trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,
6438461
@@ -1030,6 +1059,10 @@ static int interface_client_monitors_config(QXLInstance *sin,
6438461
     }
6438461
 #endif
6438461
 
6438461
+    config_changed = qxl_rom_monitors_config_changed(rom,
6438461
+                                                     monitors_config,
6438461
+                                                     max_outputs);
6438461
+
cf81640
     memset(&rom->client_monitors_config, 0,
cf81640
            sizeof(rom->client_monitors_config));
cf81640
     rom->client_monitors_config.count = monitors_config->num_of_monitors;
6438461
@@ -1059,7 +1092,9 @@ static int interface_client_monitors_config(QXLInstance *sin,
cf81640
     trace_qxl_interrupt_client_monitors_config(qxl->id,
cf81640
                         rom->client_monitors_config.count,
cf81640
                         rom->client_monitors_config.heads);
cf81640
-    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
cf81640
+    if (config_changed) {
cf81640
+        qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
cf81640
+    }
cf81640
     return 1;
cf81640
 }
cf81640