瀏覽代碼

kmsdrm: Support sorting displays via the priority hint

Use the connector name for displays and sort them according to priority, if the hint is set.
Frank Praznik 10 月之前
父節點
當前提交
0faf9dc4a4
共有 3 個文件被更改,包括 65 次插入2 次删除
  1. 3 2
      include/SDL3/SDL_hints.h
  2. 2 0
      src/video/kmsdrm/SDL_kmsdrmsym.h
  3. 60 0
      src/video/kmsdrm/SDL_kmsdrmvideo.c

+ 3 - 2
include/SDL3/SDL_hints.h

@@ -3149,13 +3149,14 @@ extern "C" {
  * prioritized in the list of displays, as exposed by calling
  * SDL_GetDisplays(), with the first listed becoming the primary display. The
  * naming convention can vary depending on the environment, but it is usually
- * a connector name (e.g. 'DP-1', 'DP-2', 'HDMI-1', etc...).
+ * a connector name (e.g. 'DP-1', 'DP-2', 'HDMI-A-1',etc...).
  *
- * On X11 and Wayland desktops, the connector names associated with displays
+ * On Wayland and X11 desktops, the connector names associated with displays
  * can typically be found by using the `xrandr` utility.
  *
  * This hint is currently supported on the following drivers:
  *
+ * - KMSDRM (kmsdrm)
  * - Wayland (wayland)
  *
  * This hint should be set before SDL is initialized.

+ 2 - 0
src/video/kmsdrm/SDL_kmsdrmsym.h

@@ -63,6 +63,8 @@ SDL_KMSDRM_SYM_OPT(int,drmModeAddFB2WithModifiers,(int fd, uint32_t width,
                          const uint32_t pitches[4], const uint32_t offsets[4],
                          const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags))
 
+SDL_KMSDRM_SYM_OPT(const char *,drmModeGetConnectorTypeName,(uint32_t connector_type))
+
 SDL_KMSDRM_SYM(int,drmModeRmFB,(int fd, uint32_t bufferId))
 SDL_KMSDRM_SYM(drmModeFBPtr,drmModeGetFB,(int fd, uint32_t buf))
 SDL_KMSDRM_SYM(drmModeCrtcPtr,drmModeGetCrtc,(int fd, uint32_t crtcId))

+ 60 - 0
src/video/kmsdrm/SDL_kmsdrmvideo.c

@@ -799,8 +799,10 @@ static void KMSDRM_AddDisplay(SDL_VideoDevice *_this, drmModeConnector *connecto
     SDL_DisplayModeData *modedata = NULL;
     drmModeEncoder *encoder = NULL;
     drmModeCrtc *crtc = NULL;
+    const char *connector_type = NULL;
     SDL_DisplayID display_id;
     SDL_PropertiesID display_properties;
+    char name_fmt[64];
     int orientation;
     int mode_index;
     int i, j;
@@ -963,6 +965,15 @@ static void KMSDRM_AddDisplay(SDL_VideoDevice *_this, drmModeConnector *connecto
         KMSDRM_CrtcSetVrr(viddata->drm_fd, crtc->crtc_id, true);
     }
 
+    // Set the name by the connector type, if possible
+    if (KMSDRM_drmModeGetConnectorTypeName) {
+        connector_type = KMSDRM_drmModeGetConnectorTypeName(connector->connector_type);
+        if (connector_type == NULL) {
+            connector_type = "Unknown";
+        }
+        SDL_snprintf(name_fmt, sizeof(name_fmt), "%s-%u", connector_type, connector->connector_type_id);
+    }
+
     /*****************************************/
     // Part 2: setup the SDL_Display itself.
     /*****************************************/
@@ -984,6 +995,9 @@ static void KMSDRM_AddDisplay(SDL_VideoDevice *_this, drmModeConnector *connecto
     CalculateRefreshRate(&dispdata->mode, &display.desktop_mode.refresh_rate_numerator, &display.desktop_mode.refresh_rate_denominator);
     display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
     display.desktop_mode.internal = modedata;
+    if (connector_type) {
+        display.name = name_fmt;
+    }
 
     // Add the display to the list of SDL displays.
     display_id = SDL_AddVideoDisplay(&display, false);
@@ -1016,6 +1030,49 @@ cleanup:
     }
 } // NOLINT(clang-analyzer-unix.Malloc): If no error `dispdata` is saved in the display
 
+static void KMSDRM_SortDisplays(SDL_VideoDevice *_this)
+{
+    const char *name_hint = SDL_GetHint(SDL_HINT_VIDEO_DISPLAY_PRIORITY);
+
+    if (name_hint) {
+        char *saveptr;
+        char *str = SDL_strdup(name_hint);
+        SDL_VideoDisplay **sorted_list = SDL_malloc(sizeof(SDL_VideoDisplay *) * _this->num_displays);
+
+        if (str && sorted_list) {
+            int sorted_index = 0;
+
+            // Sort the requested displays to the front of the list.
+            const char *token = SDL_strtok_r(str, ",", &saveptr);
+            while (token) {
+                for (int i = 0; i < _this->num_displays; ++i) {
+                    SDL_VideoDisplay *d = _this->displays[i];
+                    if (d && SDL_strcmp(token, d->name) == 0) {
+                        sorted_list[sorted_index++] = d;
+                        _this->displays[i] = NULL;
+                        break;
+                    }
+                }
+
+                token = SDL_strtok_r(NULL, ",", &saveptr);
+            }
+
+            // Append the remaining displays to the end of the list.
+            for (int i = 0; i < _this->num_displays; ++i) {
+                if (_this->displays[i]) {
+                    sorted_list[sorted_index++] = _this->displays[i];
+                }
+            }
+
+            // Copy the sorted list back to the display list.
+            SDL_memcpy(_this->displays, sorted_list, sizeof(SDL_VideoDisplay *) * _this->num_displays);
+        }
+
+        SDL_free(str);
+        SDL_free(sorted_list);
+    }
+}
+
 /* Initializes the list of SDL displays: we build a new display for each
    connecter connector we find.
    This is to be called early, in VideoInit(), because it gets us
@@ -1078,6 +1135,9 @@ static bool KMSDRM_InitDisplays(SDL_VideoDevice *_this)
         goto cleanup;
     }
 
+    // Sort the displays, if necessary
+    KMSDRM_SortDisplays(_this);
+
     // Determine if video hardware supports async pageflips.
     if (KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_ASYNC_PAGE_FLIP, &async_pageflip) != 0) {
         SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not determine async page flip capability.");