75 lines
3.2 KiB
Diff
75 lines
3.2 KiB
Diff
|
From: Christophe Fergeau <cfergeau@redhat.com>
|
||
|
Date: Fri, 14 Oct 2016 14:22:36 +0200
|
||
|
Subject: [PATCH] qxl: Only emit QXL_INTERRUPT_CLIENT_MONITORS_CONFIG on config
|
||
|
changes
|
||
|
|
||
|
Currently if the client keeps sending the same monitor config to
|
||
|
QEMU/spice-server, QEMU will always raise
|
||
|
a QXL_INTERRUPT_CLIENT_MONITORS_CONFIG regardless of whether there was a
|
||
|
change or not.
|
||
|
Guest-side (with fedora 25), the kernel QXL KMS driver will also forward the
|
||
|
event to user-space without checking if there were actual changes.
|
||
|
Next in line are gnome-shell/mutter (on a default f25 install), which
|
||
|
will try to reconfigure everything without checking if there is anything
|
||
|
to do.
|
||
|
Where this gets ugly is that when applying the resolution changes,
|
||
|
gnome-shell/mutter will call drmModeRmFB, drmModeAddFB, and
|
||
|
drmModeSetCrtc, which will cause the primary surface to be destroyed and
|
||
|
recreated by the QXL KMS driver. This in turn will cause the client to
|
||
|
resend a client monitors config message, which will cause QEMU to reemit
|
||
|
an interrupt with an unchanged monitors configuration, ...
|
||
|
This causes https://bugzilla.redhat.com/show_bug.cgi?id=1266484
|
||
|
|
||
|
This commit makes sure that we only emit
|
||
|
QXL_INTERRUPT_CLIENT_MONITORS_CONFIG when there are actual configuration
|
||
|
changes the guest should act on.
|
||
|
---
|
||
|
hw/display/qxl.c | 20 +++++++++++++++++++-
|
||
|
1 file changed, 19 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
|
||
|
index 0e2682d..56759f8 100644
|
||
|
--- a/hw/display/qxl.c
|
||
|
+++ b/hw/display/qxl.c
|
||
|
@@ -1000,6 +1000,7 @@ static int interface_client_monitors_config(QXLInstance *sin,
|
||
|
QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
|
||
|
int i;
|
||
|
unsigned max_outputs = ARRAY_SIZE(rom->client_monitors_config.heads);
|
||
|
+ bool config_changed = false;
|
||
|
|
||
|
if (qxl->revision < 4) {
|
||
|
trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,
|
||
|
@@ -1030,6 +1031,21 @@ static int interface_client_monitors_config(QXLInstance *sin,
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
+ if (rom->client_monitors_config.count != MIN(monitors_config->num_of_monitors, max_outputs)) {
|
||
|
+ config_changed = true;
|
||
|
+ }
|
||
|
+ for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
|
||
|
+ VDAgentMonConfig *monitor = &monitors_config->monitors[i];
|
||
|
+ QXLURect *rect = &rom->client_monitors_config.heads[i];
|
||
|
+ /* monitor->depth ignored */
|
||
|
+ if ((rect->left != monitor->x) ||
|
||
|
+ (rect->top != monitor->y) ||
|
||
|
+ (rect->right != monitor->x + monitor->width) ||
|
||
|
+ (rect->bottom != monitor->y + monitor->height)) {
|
||
|
+ config_changed = true;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
memset(&rom->client_monitors_config, 0,
|
||
|
sizeof(rom->client_monitors_config));
|
||
|
rom->client_monitors_config.count = monitors_config->num_of_monitors;
|
||
|
@@ -1059,7 +1075,9 @@ static int interface_client_monitors_config(QXLInstance *sin,
|
||
|
trace_qxl_interrupt_client_monitors_config(qxl->id,
|
||
|
rom->client_monitors_config.count,
|
||
|
rom->client_monitors_config.heads);
|
||
|
- qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
|
||
|
+ if (config_changed) {
|
||
|
+ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
|
||
|
+ }
|
||
|
return 1;
|
||
|
}
|
||
|
|