[RFC/POC PATCH vd_agent 16/16] vdagent: Use output_id from VDAgentMonitorsConfigV2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When output_id is set in any VDAgentMonConfigV2 struct of the
VDAgentMonitorsConfigV2 message, it means the monitor is streamed from
the guest by the streaming agent. In that case, we only regard the
monitor configs with output_id set as relevant, as those are surely
configured for X11, but there may be others which aren't.

If no output_id is set in the message, there is no streaming and the
behaviour should be unchanged (i.e. all configs are applied and the id
is the index in the array of the incoming message).
---
 src/vdagent/x11-randr.c | 142 ++++++++++++++++++++++++++++------------
 1 file changed, 101 insertions(+), 41 deletions(-)

diff --git a/src/vdagent/x11-randr.c b/src/vdagent/x11-randr.c
index 39d3f1e..40a899c 100644
--- a/src/vdagent/x11-randr.c
+++ b/src/vdagent/x11-randr.c
@@ -737,7 +737,7 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
                                     int fallback)
 {
     int primary_w, primary_h;
-    int i, real_num_of_monitors = 0;
+    int i;
     VDAgentMonitorsConfigV2 *curr = NULL;
 
     if (!x11->has_xrandr)
@@ -752,43 +752,99 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
         dump_monitors_config(x11, mon_config, "from guest");
     }
 
+    int have_output_ids = 0;
     for (i = 0; i < mon_config->num_of_monitors; i++) {
-        if (monitor_enabled(&mon_config->monitors[i]))
-            real_num_of_monitors = i + 1;
+        if (mon_config->monitors[i].output_id) {
+            have_output_ids = 1;
+            break;
+        }
     }
-    mon_config->num_of_monitors = real_num_of_monitors;
+
+    // a boolean mask of present monitor configs for given ID (index in the array)
+    uint8_t presence_mask[MONITOR_SIZE_COUNT] = { 0 };
+
+    // Filter the incoming monitor configs according to the output_id field.
+    //
+    // If output_id was set (i.e. > 0) in any monitor config (have_output_ids =
+    // 1), it means the streaming agent is streaming and we only want to
+    // configure the monitors that have the output_id set, as those should be
+    // the only ones displaying X11. So we filter out anything that has
+    // output_id == 0. At the same time, also decrement the output_id by 1, as
+    // xrandr indices are 0-based, but incoming output IDs are 1-based (0
+    // meaning output ID is unset).
+    //
+    // If no monitor config has output_id set, we are not streaming with the
+    // streaming agent and we assume all monitors in the config are configured
+    // for X11. In that case, we copy them all and set their output_id to their
+    // index in the monitors_config list, so that we can use the output_id
+    // uniformly in the rest of the function.
+    VDAgentMonitorsConfigV2 *filtered_mc =
+        (VDAgentMonitorsConfigV2 *) g_malloc(sizeof(VDAgentMonitorsConfigV2) +
+        mon_config->num_of_monitors * sizeof(VDAgentMonConfigV2));
+    filtered_mc->num_of_monitors = 0;
+    filtered_mc->flags = mon_config->flags;
 
     update_randr_res(x11, 0);
-    if (mon_config->num_of_monitors > x11->randr.res->noutput) {
-        syslog(LOG_WARNING,
-               "warning unexpected client request: #mon %d > driver output %d",
-               mon_config->num_of_monitors, x11->randr.res->noutput);
-        mon_config->num_of_monitors = x11->randr.res->noutput;
+
+    for (i = 0; i < mon_config->num_of_monitors; i++) {
+        if ((have_output_ids && mon_config->monitors[i].output_id) || !have_output_ids) {
+            uint32_t new_output_id;
+            if (have_output_ids) {
+                // output_id comes in a sequence starting from 1, xrandr expects 0-based
+                new_output_id = mon_config->monitors[i].output_id - 1;
+            } else {
+                // if output_ids aren't set, use the array index as output_id
+                new_output_id = filtered_mc->num_of_monitors;
+            }
+
+            if (new_output_id >= x11->randr.res->noutput) {
+                syslog(LOG_WARNING, "Received monitor config ID %d > driver max output nr %d, skipping",
+                       new_output_id, x11->randr.res->noutput - 1);
+                continue;
+            }
+
+            if (new_output_id >= MONITOR_SIZE_COUNT) {
+                syslog(LOG_WARNING, "Received monitor config ID %d > monitor count limit %d, skipping",
+                       new_output_id, MONITOR_SIZE_COUNT - 1);
+                continue;
+            }
+
+            VDAgentMonConfigV2 *new_mc = &filtered_mc->monitors[filtered_mc->num_of_monitors];
+            new_mc->output_id = new_output_id;
+            new_mc->height = mon_config->monitors[i].height;
+            new_mc->width = mon_config->monitors[i].width;
+            new_mc->depth = mon_config->monitors[i].depth;
+            new_mc->x = mon_config->monitors[i].x;
+            new_mc->y = mon_config->monitors[i].y;
+
+
+            presence_mask[new_output_id] = 1;
+
+            filtered_mc->num_of_monitors++;
+        }
     }
 
-    if (mon_config->num_of_monitors > MONITOR_SIZE_COUNT) {
-        syslog(LOG_WARNING, "warning: client send %d monitors, capping at %d",
-               mon_config->num_of_monitors, MONITOR_SIZE_COUNT);
-        mon_config->num_of_monitors = MONITOR_SIZE_COUNT;
+    if (x11->debug) {
+        dump_monitors_config(x11, filtered_mc, "filtered");
     }
 
-    zero_base_monitors(x11, mon_config, &primary_w, &primary_h);
+    zero_base_monitors(x11, filtered_mc, &primary_w, &primary_h);
 
     constrain_to_screen(x11, &primary_w, &primary_h);
 
     if (x11->debug) {
-        dump_monitors_config(x11, mon_config, "after zeroing");
+        dump_monitors_config(x11, filtered_mc, "after zeroing");
     }
 
     curr = get_current_mon_config(x11);
     if (!curr)
         goto exit;
-    if (same_monitor_configs(mon_config, curr) &&
+    if (same_monitor_configs(filtered_mc, curr) &&
            x11->width[0] == primary_w && x11->height[0] == primary_h) {
         goto exit;
     }
 
-    if (same_monitor_configs(mon_config, x11->randr.failed_conf)) {
+    if (same_monitor_configs(filtered_mc, x11->randr.failed_conf)) {
         syslog(LOG_WARNING, "Ignoring previous failed client monitor config");
         goto exit;
     }
@@ -797,16 +853,20 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
     g_unlink(config);
     g_free(config);
 
-    for (i = mon_config->num_of_monitors; i < x11->randr.res->noutput; i++)
-        xrandr_disable_output(x11, i);
-
-    /* First, disable disabled CRTCs... */
-    for (i = 0; i < mon_config->num_of_monitors; ++i) {
-        if (!monitor_enabled(&mon_config->monitors[i])) {
+    // disable all outputs which we don't have a config for
+    for (i = 0; i < MIN(sizeof(presence_mask), x11->randr.res->noutput); i++) {
+        if (!presence_mask[i]) {
             xrandr_disable_output(x11, i);
         }
     }
 
+    // disable outputs that are disabled in the monitor configs
+    for (i = 0; i < filtered_mc->num_of_monitors; ++i) {
+        if (!monitor_enabled(&filtered_mc->monitors[i])) {
+            xrandr_disable_output(x11, filtered_mc->monitors[i].output_id);
+        }
+    }
+
     /* ... and disable the ones that would be bigger than
      * the new RandR screen once it is resized. If they are enabled the
      * XRRSetScreenSize call will fail with BadMatch. They will be
@@ -824,9 +884,10 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
         if ((x + width > primary_w) || (y + height > primary_h)) {
             if (x11->debug)
                 syslog(LOG_DEBUG, "Disabling monitor %d: %dx%d+%d+%d > (%d,%d)",
-                       i, width, height, x, y, primary_w, primary_h);
+                       filtered_mc->monitors[i].output_id,
+                       width, height, x, y, primary_w, primary_h);
 
-            xrandr_disable_output(x11, i);
+            xrandr_disable_output(x11, curr->monitors[i].output_id);
         }
     }
 
@@ -852,10 +913,10 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
                    fullscreen it will keep sending the failing config. */
                 free(x11->randr.failed_conf);
                 x11->randr.failed_conf =
-                    malloc(config_size(mon_config->num_of_monitors));
+                    malloc(config_size(filtered_mc->num_of_monitors));
                 if (x11->randr.failed_conf)
-                    memcpy(x11->randr.failed_conf, mon_config,
-                           config_size(mon_config->num_of_monitors));
+                    memcpy(x11->randr.failed_conf, filtered_mc,
+                           config_size(filtered_mc->num_of_monitors));
                 return;
             }
         }
@@ -863,34 +924,33 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
 
     /* Finally, we set the new resolutions on RandR CRTCs now that the
      * RandR screen is big enough to hold these.  */
-    for (i = 0; i < mon_config->num_of_monitors; ++i) {
+    for (i = 0; i < filtered_mc->num_of_monitors; ++i) {
         int width, height;
         int x, y;
 
-        if (!monitor_enabled(&mon_config->monitors[i])) {
+        if (!monitor_enabled(&filtered_mc->monitors[i])) {
             continue;
         }
         /* Try to create the requested resolution */
-        width = mon_config->monitors[i].width;
-        height = mon_config->monitors[i].height;
-        x = mon_config->monitors[i].x;
-        y = mon_config->monitors[i].y;
+        width = filtered_mc->monitors[i].width;
+        height = filtered_mc->monitors[i].height;
+        x = filtered_mc->monitors[i].x;
+        y = filtered_mc->monitors[i].y;
 
         if (x11->debug) {
             syslog(LOG_DEBUG, "Setting resolution for monitor %d: %dx%d+%d+%d)",
-                   i, width, height, x, y);
+                   filtered_mc->monitors[i].output_id, width, height, x, y);
         }
 
-        if (!xrandr_add_and_set(x11, i, x, y, width, height) &&
-                enabled_monitors(mon_config) == 1) {
-            set_screen_to_best_size(x11, width, height,
-                                    &primary_w, &primary_h);
+        if (!xrandr_add_and_set(x11, filtered_mc->monitors[i].output_id, x, y, width, height) &&
+            enabled_monitors(filtered_mc) == 1)
+        {
+            set_screen_to_best_size(x11, width, height, &primary_w, &primary_h);
             break;
         }
     }
 
-    update_randr_res(x11,
-        x11->randr.num_monitors != enabled_monitors(mon_config));
+    update_randr_res(x11, x11->randr.num_monitors != enabled_monitors(filtered_mc));
     x11->width[0] = primary_w;
     x11->height[0] = primary_h;
 
-- 
2.17.1

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/spice-devel




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]