619821
From de84e9659aa6b91bd1a7c4fb30fde859882b9201 Mon Sep 17 00:00:00 2001
619821
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
619821
Date: Thu, 5 Jan 2017 23:58:10 +0100
619821
Subject: [PATCH 4/4] qxl: Only emit QXL_INTERRUPT_CLIENT_MONITORS_CONFIG on
619821
 config changes
619821
MIME-Version: 1.0
619821
Content-Type: text/plain; charset=UTF-8
619821
Content-Transfer-Encoding: 8bit
619821
619821
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
619821
Message-id: <20170105235810.27189-1-marcandre.lureau@redhat.com>
619821
Patchwork-id: 73185
619821
O-Subject: [RHEL-7.4 qemu-kvm PATCH] qxl: Only emit QXL_INTERRUPT_CLIENT_MONITORS_CONFIG on config changes
619821
Bugzilla: 1342489
619821
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
619821
RH-Acked-by: Christophe Fergeau <cfergeau@redhat.com>
619821
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
619821
619821
From: Christophe Fergeau <cfergeau@redhat.com>
619821
619821
Currently if the client keeps sending the same monitor config to
619821
QEMU/spice-server, QEMU will always raise
619821
a QXL_INTERRUPT_CLIENT_MONITORS_CONFIG regardless of whether there was a
619821
change or not.
619821
Guest-side (with fedora 25), the kernel QXL KMS driver will also forward the
619821
event to user-space without checking if there were actual changes.
619821
Next in line are gnome-shell/mutter (on a default f25 install), which
619821
will try to reconfigure everything without checking if there is anything
619821
to do.
619821
Where this gets ugly is that when applying the resolution changes,
619821
gnome-shell/mutter will call drmModeRmFB, drmModeAddFB, and
619821
drmModeSetCrtc, which will cause the primary surface to be destroyed and
619821
recreated by the QXL KMS driver. This in turn will cause the client to
619821
resend a client monitors config message, which will cause QEMU to reemit
619821
an interrupt with an unchanged monitors configuration, ...
619821
This causes https://bugzilla.redhat.com/show_bug.cgi?id=1266484
619821
619821
This commit makes sure that we only emit
619821
QXL_INTERRUPT_CLIENT_MONITORS_CONFIG when there are actual configuration
619821
changes the guest should act on.
619821
619821
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
619821
Message-id: 20161028144840.18326-1-cfergeau@redhat.com
619821
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
619821
619821
(cherry picked from commit 6c7565028c272c4c6f2a83c3a90b044eeaf2804a)
619821
619821
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
619821
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
619821
---
619821
 hw/display/qxl.c | 37 ++++++++++++++++++++++++++++++++++++-
619821
 1 file changed, 36 insertions(+), 1 deletion(-)
619821
619821
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
619821
index f762439..c76c237 100644
619821
--- a/hw/display/qxl.c
619821
+++ b/hw/display/qxl.c
619821
@@ -989,6 +989,34 @@ static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
619821
     return crc32(0xffffffff, p, len) ^ 0xffffffff;
619821
 }
619821
 
619821
+static bool qxl_rom_monitors_config_changed(QXLRom *rom,
619821
+        VDAgentMonitorsConfig *monitors_config,
619821
+        unsigned int max_outputs)
619821
+{
619821
+    int i;
619821
+    unsigned int monitors_count;
619821
+
619821
+    monitors_count = MIN(monitors_config->num_of_monitors, max_outputs);
619821
+
619821
+    if (rom->client_monitors_config.count != monitors_count) {
619821
+        return true;
619821
+    }
619821
+
619821
+    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
619821
+        VDAgentMonConfig *monitor = &monitors_config->monitors[i];
619821
+        QXLURect *rect = &rom->client_monitors_config.heads[i];
619821
+        /* monitor->depth ignored */
619821
+        if ((rect->left != monitor->x) ||
619821
+            (rect->top != monitor->y)  ||
619821
+            (rect->right != monitor->x + monitor->width) ||
619821
+            (rect->bottom != monitor->y + monitor->height)) {
619821
+            return true;
619821
+        }
619821
+    }
619821
+
619821
+    return false;
619821
+}
619821
+
619821
 /* called from main context only */
619821
 static int interface_client_monitors_config(QXLInstance *sin,
619821
                                         VDAgentMonitorsConfig *monitors_config)
619821
@@ -997,6 +1025,7 @@ static int interface_client_monitors_config(QXLInstance *sin,
619821
     QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
619821
     int i;
619821
     unsigned max_outputs = ARRAY_SIZE(rom->client_monitors_config.heads);
619821
+    bool config_changed = false;
619821
 
619821
     if (qxl->revision < 4) {
619821
         trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,
619821
@@ -1027,6 +1056,10 @@ static int interface_client_monitors_config(QXLInstance *sin,
619821
     }
619821
 #endif
619821
 
619821
+    config_changed = qxl_rom_monitors_config_changed(rom,
619821
+                                                     monitors_config,
619821
+                                                     max_outputs);
619821
+
619821
     memset(&rom->client_monitors_config, 0,
619821
            sizeof(rom->client_monitors_config));
619821
     rom->client_monitors_config.count = monitors_config->num_of_monitors;
619821
@@ -1056,7 +1089,9 @@ static int interface_client_monitors_config(QXLInstance *sin,
619821
     trace_qxl_interrupt_client_monitors_config(qxl->id,
619821
                         rom->client_monitors_config.count,
619821
                         rom->client_monitors_config.heads);
619821
-    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
619821
+    if (config_changed) {
619821
+        qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
619821
+    }
619821
     return 1;
619821
 }
619821
 
619821
-- 
619821
1.8.3.1
619821