Просмотр исходного кода

Added a slider to manually adjust HDR headroom on visionOS

Ideally the OS would provide a way to query the current headroom, but for now users can manually adjust it.
Sam Lantinga 9 часов назад
Родитель
Сommit
d8d5b7c6c5

+ 14 - 0
include/SDL3/SDL_hints.h

@@ -4324,6 +4324,20 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_X11_XRANDR "SDL_VIDEO_X11_XRANDR"
 
+/**
+ * A variable controlling whether the HDR headroom slider should be shown in the visionOS window settings.
+ *
+ * The variable can be set to the following values:
+ *
+ * - "0": The HDR headroom slider is not shown. (default)
+ * - "1": The HDR headroom slider is shown.
+ *
+ * This hint should be set before SDL is initialized.
+ *
+ * \since This hint is available since SDL 3.6.0.
+ */
+#define SDL_HINT_VISIONOS_HDR_HEADROOM_UI "SDL_VISIONOS_HDR_HEADROOM_UI"
+
 /**
  * A variable controlling whether touch should be enabled on the back panel of
  * the PlayStation Vita.

+ 49 - 0
src/video/uikit/SDL_CurvedContentHosting.swift

@@ -224,6 +224,7 @@ internal class SDL_CurvedContentPersistentSettings: Codable {
     var showHover: Bool?
     var isDimmed: Bool?
     var curvatureRadius: Float?
+    var headroom: Float?
 }
 
 @Observable
@@ -247,6 +248,9 @@ internal class SDL_CurvedContentSettings {
                     if let curvatureRadius = values.curvatureRadius {
                         settings.curvatureRadius = curvatureRadius
                     }
+                    if let headroom = values.headroom {
+                        settings.headroom = headroom
+                    }
                 } catch {
                     NSLog("Couldn't parse window settings: %@", error.localizedDescription)
                 }
@@ -261,6 +265,7 @@ internal class SDL_CurvedContentSettings {
         values.showHover = showHover
         values.isDimmed = isDimmed
         values.curvatureRadius = curvatureRadius
+        values.headroom = headroom
 
         do {
             let data = try JSONEncoder().encode(values)
@@ -276,6 +281,8 @@ internal class SDL_CurvedContentSettings {
     var isDimmed: Bool = false
     var dimmingReady: Bool = false
     var curvatureRadius: Float = 0.0
+    var headroom_enabled: Bool = SDL_VisionOS_ShouldShowHeadroomUI()
+    var headroom: Float = 2.0
     var sceneState: SceneState = .interactive
     var isSnapped: Bool = false
     var settingsExpanded: Bool = false
@@ -314,6 +321,16 @@ struct SDL_SettingsPanelView: View {
         }
     }
 
+    private var headroomLabel: String {
+        let formatter = NumberFormatter()
+        formatter.maximumFractionDigits = 2
+        if let label = formatter.string(for: settings.headroom) {
+            return label
+        } else {
+            return ""
+        }
+    }
+
     var body: some View {
         if settings.settingsExpanded {
             expandedPanel
@@ -333,6 +350,11 @@ struct SDL_SettingsPanelView: View {
                     Image(systemName: settings.isDimmed ? "moon.fill" : "sun.max")
                         .foregroundStyle(settings.isDimmed ? .primary : .secondary)
 
+                    if settings.headroom_enabled {
+                        Text("HDR")
+                            .font(.caption)
+                    }
+
                     Divider().frame(height: 8)
 
                     if settings.curvatureRadius == 0 {
@@ -355,6 +377,11 @@ struct SDL_SettingsPanelView: View {
                     Image(systemName: settings.isDimmed ? "moon.fill" : "sun.max")
                         .foregroundStyle(settings.isDimmed ? .primary : .secondary)
 
+                    if settings.headroom_enabled {
+                        Text("HDR")
+                            .font(.caption)
+                    }
+
                     Divider().frame(height: 8)
 
                     if settings.curvatureRadius == 0 {
@@ -415,6 +442,28 @@ struct SDL_SettingsPanelView: View {
                 Spacer()
             }
 
+            if settings.headroom_enabled {
+                // HDR slider
+                VStack(spacing: 4) {
+                    Text("HDR \(headroomLabel)")
+                        .font(.caption)
+
+                    HStack() {
+                        Image(systemName: "moon.fill")
+
+                        Slider(value: $settings.headroom, in: 1.1...4) {
+                        } currentValueLabel: {
+                            Text("\(headroomLabel)")
+                        }
+                        .onChange(of: settings.headroom) {
+                            settings.save()
+                        }
+
+                        Image(systemName: "sun.max")
+                    }
+                }
+            }
+
             // Curvature slider
             VStack(spacing: 4) {
                 Text("\(curvatureLabel)")

+ 5 - 0
src/video/uikit/SDL_CurvedContentView.swift

@@ -264,6 +264,11 @@ internal struct SDL_CurvedContentView: View {
                 }
             }
         }
+        .onChange(of: settings.headroom, initial: true) { oldHeadroom, headroom in
+            if settings.headroom_enabled {
+                SDL_VisionOS_SendHeadroom(headroom)
+            }
+        }
         .modifier(AnimatedCurveRadiusModifier(helper: helper, curveRadius: animatedScreenRadius))
         .onChange(of: sceneActivationOrObject(shouldPopulateCollisionShape ? helper.collisionShape : nil)) {
             guard let curvedUIEntity else { return }

+ 6 - 0
src/video/uikit/SDL_UIKitBridge-swift.h

@@ -32,6 +32,12 @@ void SDL_VisionOS_SendWindowSettings(NSString *settings);
 // Called from Swift scene delegates when pointer mode changes
 void SDL_VisionOS_SendPointerMode(bool enabled);
 
+// Called from Swift scene delegates when window settings are loaded
+bool SDL_VisionOS_ShouldShowHeadroomUI();
+
+// Called from Swift scene delegates when headroom changes
+void SDL_VisionOS_SendHeadroom(float headroom);
+
 // Called from Swift scene delegates when visionOS delivers a touch event
 void SDL_VisionOS_SendTouch(NSTimeInterval timestamp, SDL_FingerID fingerID, Uint32 eventType, float x, float y);
 

+ 15 - 0
src/video/uikit/SDL_UIKitBridge.m

@@ -94,6 +94,21 @@ bool SDL_VisionOS_PointerModeEnabled()
     return SDL_pointer_mode;
 }
 
+bool SDL_VisionOS_ShouldShowHeadroomUI()
+{
+    return SDL_GetHintBoolean(SDL_HINT_VISIONOS_HDR_HEADROOM_UI, false);
+}
+
+void SDL_VisionOS_SendHeadroom(float headroom)
+{
+    SDL_VideoDisplay *display = SDL_GetVideoDisplay(SDL_GetPrimaryDisplay());
+    if (display) {
+        SDL_HDROutputProperties HDR = { 1.0f, headroom };
+
+        SDL_SetDisplayHDRProperties(display, &HDR);
+    }
+}
+
 // Called from Swift scene delegates when visionOS delivers a touch event
 void SDL_VisionOS_SendTouch(NSTimeInterval timestamp, SDL_FingerID fingerID, Uint32 eventType, float x, float y)
 {