From 7d47d1652601cd56838ced9339baacda72508ada Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Sun, 5 May 2024 11:05:15 -0400 Subject: [PATCH] kmsdrm: Report the panel orientation hint property Queries the "panel orientation" property on the connector and reports it in degrees of clockwise rotation via the 'SDL.display.KMSDRM.panel_orientation' display property. This is provided by the kernel as a hint to userspace applications, and the application itself is ultimately responsible for any required coordinate transformations needed to conform to the requested orientation. --- include/SDL3/SDL_video.h | 14 ++++-- src/video/kmsdrm/SDL_kmsdrmvideo.c | 81 +++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h index 5e336a45f2..cac31574a1 100644 --- a/include/SDL3/SDL_video.h +++ b/include/SDL3/SDL_video.h @@ -409,6 +409,13 @@ extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetPrimaryDisplay(void); * enabled, this will be 1.0. This property can change dynamically when * SDL_EVENT_DISPLAY_HDR_STATE_CHANGED is sent. * + * On KMS/DRM: + * + * - `SDL_PROP_DISPLAY_KMSDRM_ORIENTATION_NUMBER`: the "panel orientation" property + * for the display in degrees of clockwise rotation. Note that this is provided + * only as a hint, and the application is responsible for any coordinate transformations + * needed to conform to the requested display orientation. + * * \param displayID the instance ID of the display to query * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. @@ -420,9 +427,10 @@ extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetPrimaryDisplay(void); */ extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetDisplayProperties(SDL_DisplayID displayID); -#define SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN "SDL.display.HDR_enabled" -#define SDL_PROP_DISPLAY_SDR_WHITE_POINT_FLOAT "SDL.display.SDR_white_point" -#define SDL_PROP_DISPLAY_HDR_HEADROOM_FLOAT "SDL.display.HDR_headroom" +#define SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN "SDL.display.HDR_enabled" +#define SDL_PROP_DISPLAY_SDR_WHITE_POINT_FLOAT "SDL.display.SDR_white_point" +#define SDL_PROP_DISPLAY_HDR_HEADROOM_FLOAT "SDL.display.HDR_headroom" +#define SDL_PROP_DISPLAY_KMSDRM_PANEL_ORIENTATION_NUMBER "SDL.display.KMSDRM.panel_orientation" /** * Get the name of a display in UTF-8 encoding. diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index db77842653..a2837b7620 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -673,6 +673,77 @@ static SDL_bool KMSDRM_CrtcGetVrr(uint32_t drm_fd, uint32_t crtc_id) return SDL_FALSE; } +static SDL_bool KMSDRM_OrientationPropId(uint32_t drm_fd, uint32_t crtc_id, uint32_t *orientation_prop_id) +{ + drmModeObjectPropertiesPtr drm_props; + + drm_props = KMSDRM_drmModeObjectGetProperties(drm_fd, + crtc_id, + DRM_MODE_OBJECT_CONNECTOR); + + if (!drm_props) { + return SDL_FALSE; + } + + *orientation_prop_id = KMSDRM_CrtcGetPropId(drm_fd, + drm_props, + "panel orientation"); + + KMSDRM_drmModeFreeObjectProperties(drm_props); + + return SDL_TRUE; +} + +static int KMSDRM_CrtcGetOrientation(uint32_t drm_fd, uint32_t crtc_id) +{ + uint32_t orientation_prop_id; + drmModeObjectPropertiesPtr props; + int i; + SDL_bool done = SDL_FALSE; + int orientation = 0; + + if (!KMSDRM_OrientationPropId(drm_fd, crtc_id, &orientation_prop_id)) { + return orientation; + } + + props = KMSDRM_drmModeObjectGetProperties(drm_fd, + crtc_id, + DRM_MODE_OBJECT_CONNECTOR); + + if (!props) { + return orientation; + } + + for (i = 0; i < props->count_props && !done; ++i) { + drmModePropertyPtr drm_prop = KMSDRM_drmModeGetProperty(drm_fd, props->props[i]); + + if (!drm_prop) { + continue; + } + + if (drm_prop->prop_id == orientation_prop_id && (drm_prop->flags & DRM_MODE_PROP_ENUM)) { + if (drm_prop->count_enums) { + /* "Normal" is the default of no rotation (0 degrees) */ + if (SDL_strcmp(drm_prop->enums[0].name, "Left Side Up") == 0) { + orientation = 90; + } else if (SDL_strcmp(drm_prop->enums[0].name, "Upside Down") == 0) { + orientation = 180; + } else if (SDL_strcmp(drm_prop->enums[0].name, "Right Side Up") == 0) { + orientation = 270; + } + } + + done = SDL_TRUE; + } + + KMSDRM_drmModeFreeProperty(drm_prop); + } + + KMSDRM_drmModeFreeObjectProperties(props); + + return orientation; +} + /* Gets a DRM connector, builds an SDL_Display with it, and adds it to the list of SDL Displays in _this->displays[] */ static void KMSDRM_AddDisplay(SDL_VideoDevice *_this, drmModeConnector *connector, drmModeRes *resources) @@ -683,6 +754,9 @@ static void KMSDRM_AddDisplay(SDL_VideoDevice *_this, drmModeConnector *connecto SDL_DisplayModeData *modedata = NULL; drmModeEncoder *encoder = NULL; drmModeCrtc *crtc = NULL; + SDL_DisplayID display_id; + SDL_PropertiesID display_properties; + int orientation; int mode_index; int i, j; int ret = 0; @@ -867,11 +941,16 @@ static void KMSDRM_AddDisplay(SDL_VideoDevice *_this, drmModeConnector *connecto display.desktop_mode.driverdata = modedata; /* Add the display to the list of SDL displays. */ - if (SDL_AddVideoDisplay(&display, SDL_FALSE) == 0) { + display_id = SDL_AddVideoDisplay(&display, SDL_FALSE); + if (!display_id) { ret = -1; goto cleanup; } + orientation = KMSDRM_CrtcGetOrientation(viddata->drm_fd, crtc->crtc_id); + display_properties = SDL_GetDisplayProperties(display_id); + SDL_SetNumberProperty(display_properties, SDL_PROP_DISPLAY_KMSDRM_PANEL_ORIENTATION_NUMBER, orientation); + cleanup: if (encoder) { KMSDRM_drmModeFreeEncoder(encoder);