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