From af0ec13fc325110edc85d4241422558e31f36d70 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 28 Jan 2023 17:09:24 -0400 Subject: [PATCH] iOS: fix display modes to have accurate pixel sizes and screen scales. --- src/video/uikit/SDL_uikitmodes.m | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/video/uikit/SDL_uikitmodes.m b/src/video/uikit/SDL_uikitmodes.m index 60b555511..896b747f1 100644 --- a/src/video/uikit/SDL_uikitmodes.m +++ b/src/video/uikit/SDL_uikitmodes.m @@ -271,7 +271,7 @@ static int UIKit_AddSingleDisplayMode(SDL_VideoDisplay *display, int w, int h, mode.pixel_w = w; mode.pixel_h = h; - mode.display_scale = uiscreen.scale; + mode.display_scale = uiscreen.nativeScale; mode.refresh_rate = UIKit_GetDisplayModeRefreshRate(uiscreen); mode.format = SDL_PIXELFORMAT_ABGR8888; @@ -300,10 +300,32 @@ static int UIKit_AddDisplayMode(SDL_VideoDisplay *display, int w, int h, return 0; } +static CGSize GetUIScreenModePixelSize(UIScreen *uiscreen, UIScreenMode *mode) +{ + /* For devices such as iPhone 6/7/8 Plus, the UIScreenMode reported by iOS + * isn't the physical pixels of the display, but rather the point size times + * the scale. For example, on iOS 12.2 on iPhone 8 Plus the physical pixel + * resolution is 1080x1920, the size reported by mode.size is 1242x2208, + * the size in points is 414x736, the scale property is 3.0, and the + * nativeScale property is ~2.6087 (ie 1920.0 / 736.0). So we need a bit of + * math to convert from retina pixels (point size multiplied by scale) to + * real pixels. + * Note that the iOS Simulator doesn't have this behavior for those devices. + * https://github.com/libsdl-org/SDL/issues/3220 + */ + CGSize size = mode.size; + CGFloat scale = uiscreen.nativeScale / uiscreen.scale; + + size.width = SDL_round(size.width * scale); + size.height = SDL_round(size.height * scale); + + return size; +} + int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event) { UIScreenMode *uiscreenmode = uiscreen.currentMode; - CGSize size = uiscreenmode.size; + CGSize size = GetUIScreenModePixelSize(uiscreen, uiscreenmode); SDL_VideoDisplay display; SDL_DisplayMode mode; @@ -406,8 +428,9 @@ void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay *display) #endif for (UIScreenMode *uimode in availableModes) { - int w = uimode.size.width; - int h = uimode.size.height; + CGSize size = GetUIScreenModePixelSize(data.uiscreen, uimode); + int w = size.width; + int h = size.height; /* Make sure the width/height are oriented correctly */ if (isLandscape != (w > h)) {