Implemented scRGB colorspace and HDR support on macOS

This commit is contained in:
Sam Lantinga
2024-02-06 05:31:43 -08:00
parent 451dc41427
commit ba074acad4
24 changed files with 10547 additions and 8010 deletions

View File

@@ -156,6 +156,11 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
selector:@selector(focusSomeWindow:)
name:NSApplicationDidBecomeActiveNotification
object:nil];
[center addObserver:self
selector:@selector(screenParametersChanged:)
name:NSApplicationDidChangeScreenParametersNotification
object:nil];
}
[center addObserver:self
@@ -178,6 +183,7 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
[center removeObserver:self name:NSWindowWillCloseNotification object:nil];
[center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil];
[center removeObserver:self name:NSApplicationDidChangeScreenParametersNotification object:nil];
[center removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
[NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
@@ -276,6 +282,11 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
}
}
- (void)screenParametersChanged:(NSNotification *)aNotification
{
Cocoa_UpdateDisplays(SDL_GetVideoDevice());
}
- (void)localeDidChange:(NSNotification *)notification
{
SDL_SendLocaleChangedEvent();

View File

@@ -34,6 +34,7 @@ struct SDL_DisplayModeData
};
extern void Cocoa_InitModes(SDL_VideoDevice *_this);
extern void Cocoa_UpdateDisplays(SDL_VideoDevice *_this);
extern int Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
extern int Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
extern int Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);

View File

@@ -83,6 +83,20 @@ static int CG_SetError(const char *prefix, CGDisplayErr result)
return SDL_SetError("%s: %s", prefix, error);
}
static NSScreen *GetNSScreenForDisplayID(CGDirectDisplayID displayID)
{
NSArray *screens = [NSScreen screens];
/* !!! FIXME: maybe track the NSScreen in SDL_DisplayData? */
for (NSScreen *screen in screens) {
const CGDirectDisplayID thisDisplay = (CGDirectDisplayID)[[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
if (thisDisplay == displayID) {
return screen;
}
}
return nil;
}
static float GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link)
{
double refreshRate = CGDisplayModeGetRefreshRate(vidmode);
@@ -261,13 +275,13 @@ static SDL_bool GetDisplayMode(SDL_VideoDevice *_this, CGDisplayModeRef vidmode,
return SDL_TRUE;
}
static const char *Cocoa_GetDisplayName(CGDirectDisplayID displayID)
static char *Cocoa_GetDisplayName(CGDirectDisplayID displayID)
{
/* This API is deprecated in 10.9 with no good replacement (as of 10.15). */
io_service_t servicePort = CGDisplayIOServicePort(displayID);
CFDictionaryRef deviceInfo = IODisplayCreateInfoDictionary(servicePort, kIODisplayOnlyPreferredName);
NSDictionary *localizedNames = [(__bridge NSDictionary *)deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
const char *displayName = NULL;
char *displayName = NULL;
if ([localizedNames count] > 0) {
displayName = SDL_strdup([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]);
@@ -276,6 +290,21 @@ static const char *Cocoa_GetDisplayName(CGDirectDisplayID displayID)
return displayName;
}
static void Cocoa_GetHDRProperties(CGDirectDisplayID displayID, SDL_HDRDisplayProperties *HDR)
{
HDR->enabled = SDL_FALSE;
HDR->SDR_whitelevel = 0.0f;
if (@available(macOS 10.15, *)) {
NSScreen *screen = GetNSScreenForDisplayID(displayID);
if (screen && screen.maximumPotentialExtendedDynamicRangeColorComponentValue > 1.0f) {
HDR->enabled = SDL_TRUE;
HDR->SDR_whitelevel = 80.0f; /* SDR content is always at scRGB 1.0 */
}
}
}
void Cocoa_InitModes(SDL_VideoDevice *_this)
{
@autoreleasepool {
@@ -337,8 +366,8 @@ void Cocoa_InitModes(SDL_VideoDevice *_this)
CVDisplayLinkCreateWithCGDisplay(displays[i], &link);
SDL_zero(display);
/* this returns a stddup'ed string */
display.name = (char *)Cocoa_GetDisplayName(displays[i]);
/* this returns a strdup'ed string */
display.name = Cocoa_GetDisplayName(displays[i]);
if (!GetDisplayMode(_this, moderef, SDL_TRUE, NULL, link, &mode)) {
CVDisplayLinkRelease(link);
CGDisplayModeRelease(moderef);
@@ -350,6 +379,8 @@ void Cocoa_InitModes(SDL_VideoDevice *_this)
CVDisplayLinkRelease(link);
CGDisplayModeRelease(moderef);
Cocoa_GetHDRProperties(displaydata->display, &display.HDR);
display.desktop_mode = mode;
display.driverdata = displaydata;
SDL_AddVideoDisplay(&display, SDL_FALSE);
@@ -360,6 +391,20 @@ void Cocoa_InitModes(SDL_VideoDevice *_this)
}
}
void Cocoa_UpdateDisplays(SDL_VideoDevice *_this)
{
SDL_HDRDisplayProperties HDR;
int i;
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = _this->displays[i];
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
Cocoa_GetHDRProperties(displaydata->display, &HDR);
SDL_SetDisplayHDRProperties(display, &HDR);
}
}
int Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
{
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
@@ -376,22 +421,10 @@ int Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SD
int Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
{
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
const CGDirectDisplayID cgdisplay = displaydata->display;
NSArray *screens = [NSScreen screens];
NSScreen *screen = nil;
NSScreen *screen = GetNSScreenForDisplayID(displaydata->display);
/* !!! FIXME: maybe track the NSScreen in SDL_DisplayData? */
for (NSScreen *i in screens) {
const CGDirectDisplayID thisDisplay = (CGDirectDisplayID)[[[i deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
if (thisDisplay == cgdisplay) {
screen = i;
break;
}
}
SDL_assert(screen != nil); /* didn't find it?! */
if (screen == nil) {
return -1;
return SDL_SetError("Couldn't get NSScreen for display");
}
{

View File

@@ -242,6 +242,15 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event)
}
display.desktop_mode = mode;
#ifndef SDL_PLATFORM_TVOS
if (@available(iOS 16.0, *)) {
if (uiscreen.potentialEDRHeadroom > 1.0f) {
display.HDR.enabled = SDL_TRUE;
display.HDR.SDR_whitelevel = 80.0f; /* SDR content is always at scRGB 1.0 */
}
}
#endif /* !SDL_PLATFORM_TVOS */
/* Allocate the display data */
#ifdef SDL_PLATFORM_VISIONOS
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] init];
@@ -273,13 +282,13 @@ int UIKit_AddDisplay(SDL_bool send_event){
mode.pixel_density = 1;
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.refresh_rate = 60;
display.natural_orientation = SDL_ORIENTATION_LANDSCAPE;
display.desktop_mode = mode;
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] init];
if (!data) {
UIKit_FreeDisplayModeData(&display.desktop_mode);
return SDL_OutOfMemory();
@@ -341,7 +350,7 @@ int UIKit_InitModes(SDL_VideoDevice *_this)
}
}
#endif
#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS)
SDL_OnApplicationDidChangeStatusBarOrientation();
#endif