Browse Source

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.
Frank Praznik 11 months ago
parent
commit
7d47d16526
2 changed files with 91 additions and 4 deletions
  1. 11 3
      include/SDL3/SDL_video.h
  2. 80 1
      src/video/kmsdrm/SDL_kmsdrmvideo.c

+ 11 - 3
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.

+ 80 - 1
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);