Blob Blame History Raw
From e4e389447c59c89d39a5a78a5f19cdfd22d7699c Mon Sep 17 00:00:00 2001
From: Adam Jackson <ajax@redhat.com>
Date: Fri, 5 Oct 2018 14:09:35 -0400
Subject: [PATCH xserver 4/4] modesetting: Use atomic instead of per-crtc walks
 where we can

drmmode_set_desired_modes (reachable from CreateScreenResources,
EnterVT, etc.) currently works by doing ->set_mode_major on each CRTC.
This is silly, as atomic lets us configure every CRTC at once. It's also
fragile, because we're not trying very hard to ensure the intermediate
states are valid.

This patch introduces drmmode_set_mode_atomic, which blasts the entire
RANDR state into the kernel in an... atomic... fashion. We change
drmmode_set_desired_modes and drmmode_xf86crtc_resize to use this
instead of walking each CRTC. We also change drmmode_crtc_set_mode to
use this, so that client RANDR requests (operating CRTC-at-a-time, since
RANDR doesn't have atomic changes yet) use the same code paths.

Signed-off-by: Adam Jackson <ajax@redhat.com>
---
 .../drivers/modesetting/drmmode_display.c     | 179 +++++++++++-------
 1 file changed, 109 insertions(+), 70 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 7924aa396..020678155 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -772,6 +772,96 @@ drmmode_target_output(ScrnInfoPtr scrn, xf86CrtcPtr crtc)
 
     return NULL;
 }
+
+static int
+drmmode_set_mode_atomic(ScrnInfoPtr scrn, modesettingPtr ms, Bool test_only)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    drmModeAtomicReq *req = drmModeAtomicAlloc();
+    uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+    int i, j, ret = 0;
+
+    if (!req)
+        return 1;
+
+    for (i = 0; i < xf86_config->num_crtc; i++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[i];
+        drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+        Bool active = crtc->enabled;
+        uint32_t fb_id;
+        int x, y;
+        drmModeModeInfo kmode;
+
+        if (active) {
+            drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->desiredMode);
+            ret |= drm_mode_ensure_blob(crtc, kmode);
+
+            /* XXX this probably doesn't belong here */
+            if (!crtc->mode.HDisplay && crtc->desiredMode.HDisplay)
+                memcpy(&crtc->mode, &crtc->desiredMode, sizeof(crtc->mode));
+        }
+
+        ret |= !drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y);
+        ret |= crtc_add_prop(req, drmmode_crtc,
+                             DRMMODE_CRTC_ACTIVE, active);
+        ret |= crtc_add_prop(req, drmmode_crtc,
+                             DRMMODE_CRTC_MODE_ID,
+                             active ? drmmode_crtc->current_mode->blob_id : 0);
+        ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
+    }
+
+    for (i = 0; i < xf86_config->num_output; i++) {
+        xf86OutputPtr output = xf86_config->output[i];
+        drmmode_output_private_ptr drmmode_output = output->driver_private;
+        drmmode_crtc_private_ptr drm_crtc =
+            output->crtc ? output->crtc->driver_private : NULL;
+
+        if (drmmode_output->output_id == -1)
+            continue;
+
+        ret |= connector_add_prop(req, drmmode_output,
+                                  DRMMODE_CONNECTOR_CRTC_ID,
+                                  drm_crtc ? drm_crtc->mode_crtc->crtc_id : 0);
+    }
+
+    if (test_only)
+        flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+
+    if (ret == 0)
+        ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
+
+    if (ret == 0 && !test_only) {
+        for (i = 0; i < xf86_config->num_crtc; i++) {
+            xf86CrtcPtr crtc = xf86_config->crtc[i];
+            for (j = 0; i < xf86_config->num_output; i++) {
+                xf86OutputPtr output = xf86_config->output[j];
+                drmmode_output_private_ptr drmmode_output =
+                    output->driver_private;
+
+                if (output->crtc == crtc)
+                    drmmode_output->current_crtc = crtc;
+                else if (drmmode_output->current_crtc == crtc)
+                    drmmode_output->current_crtc = NULL;
+            }
+        }
+    }
+
+    if (ret == 0 && test_only) {
+        for (i = 0; i < xf86_config->num_crtc; i++) {
+            xf86CrtcPtr crtc = xf86_config->crtc[i];
+            crtc->mode = crtc->desiredMode;
+            crtc->rotation = crtc->desiredRotation;
+            crtc->x = crtc->desiredX;
+            crtc->y = crtc->desiredY;
+            if (!xf86CrtcRotate(crtc))
+                ret = 1;
+        }
+    }
+
+    drmModeAtomicFree(req);
+    return ret;
+}
+
 static int
 drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
 {
@@ -786,73 +876,12 @@ drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
     int x, y;
     int i, ret = 0;
 
+    if (ms->atomic_modeset)
+        return drmmode_set_mode_atomic(crtc->scrn, ms, test_only);
+
     if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
         return 1;
 
-    if (ms->atomic_modeset) {
-        drmModeAtomicReq *req = drmModeAtomicAlloc();
-        Bool active;
-        uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
-
-        if (!req)
-            return 1;
-
-        ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
-        ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
-
-        /* Orphaned CRTCs need to be disabled right now in atomic mode */
-        for (i = 0; i < xf86_config->num_crtc; i++) {
-            xf86CrtcPtr other_crtc = xf86_config->crtc[i];
-            drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private;
-            int lost_outputs = 0;
-            int remaining_outputs = 0;
-            int j;
-
-            if (other_crtc == crtc)
-                continue;
-
-            for (j = 0; j < xf86_config->num_output; j++) {
-                xf86OutputPtr output = xf86_config->output[j];
-                drmmode_output_private_ptr drmmode_output = output->driver_private;
-
-                if (drmmode_output->current_crtc == other_crtc) {
-                    if (output->crtc == crtc)
-                        lost_outputs++;
-                    else
-                        remaining_outputs++;
-                }
-            }
-
-            if (lost_outputs > 0 && remaining_outputs == 0) {
-                ret |= crtc_add_prop(req, other_drmmode_crtc,
-                                     DRMMODE_CRTC_ACTIVE, 0);
-                ret |= crtc_add_prop(req, other_drmmode_crtc,
-                                     DRMMODE_CRTC_MODE_ID, 0);
-            }
-        }
-
-        if (test_only)
-            flags |= DRM_MODE_ATOMIC_TEST_ONLY;
-
-        if (ret == 0)
-            ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
-
-        if (ret == 0 && !test_only) {
-            for (i = 0; i < xf86_config->num_output; i++) {
-                xf86OutputPtr output = xf86_config->output[i];
-                drmmode_output_private_ptr drmmode_output = output->driver_private;
-
-                if (output->crtc == crtc)
-                    drmmode_output->current_crtc = crtc;
-                else if (drmmode_output->current_crtc == crtc)
-                    drmmode_output->current_crtc = NULL;
-            }
-        }
-
-        drmModeAtomicFree(req);
-        return ret;
-    }
-
     output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
     if (!output_ids)
         return -1;
@@ -3199,14 +3228,19 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
     if (!drmmode_glamor_handle_new_screen_pixmap(drmmode))
         goto fail;
 
-    for (i = 0; i < xf86_config->num_crtc; i++) {
-        xf86CrtcPtr crtc = xf86_config->crtc[i];
+    if (ms->atomic_modeset) {
+        if (drmmode_set_mode_atomic(scrn, ms, FALSE))
+            goto fail;
+    } else {
+        for (i = 0; i < xf86_config->num_crtc; i++) {
+            xf86CrtcPtr crtc = xf86_config->crtc[i];
 
-        if (!crtc->enabled)
-            continue;
+            if (!crtc->enabled)
+                continue;
 
-        drmmode_set_mode_major(crtc, &crtc->mode,
-                               crtc->rotation, crtc->x, crtc->y);
+            drmmode_set_mode_major(crtc, &crtc->mode,
+                                   crtc->rotation, crtc->x, crtc->y);
+        }
     }
 
     if (old_fb_id) {
@@ -3457,8 +3491,13 @@ Bool
 drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw)
 {
     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+    modesettingPtr ms = modesettingPTR(pScrn);
     int c;
 
+    /* drmmode_set_mode_atomic returns 0 on success, we return TRUE */
+    if (ms->atomic_modeset)
+        return !drmmode_set_mode_atomic(pScrn, ms, /* test_only = */ !set_hw);
+
     for (c = 0; c < config->num_crtc; c++) {
         xf86CrtcPtr crtc = config->crtc[c];
         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-- 
2.20.1