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.
This commit is contained in:
Frank Praznik 2024-10-18 11:25:10 -04:00
parent a6e5ab437f
commit 0faf9dc4a4
3 changed files with 65 additions and 2 deletions

View File

@ -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.

View File

@ -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))

View File

@ -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.");