Skip to content

Commit ade6cfd

Browse files
committed
Consolidate Apple display-info helpers (refresh rate + output size)
Six copies across cocoa_gl_ctx.m, cocoa_vk_ctx.m, and metal.m collapse to two shared helpers in cocoa_common.m. Each driver keeps a named vtable entry (forwarding thunk) because the three entry points are reached through different paths that bypass each other — dispserv-first, ctx-direct from vulkan.c, and poke-direct from video_thread_wrapper.c. dispserv_apple fills its two previously-NULL slots against the same helpers. Incidentally fixes unguarded @available sites on pre-iOS-10 (masked by Metal/MoltenVK deployment minimums) and the unconditional nativeBounds call (iOS 8+) that would throw on iOS 6/7. macOS 10.5 now returns a real refresh rate instead of a hardcoded 60.
1 parent 095fe0f commit ade6cfd

6 files changed

Lines changed: 234 additions & 153 deletions

File tree

gfx/display_servers/dispserv_apple.m

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,13 @@
4242
#else
4343
#import <ApplicationServices/ApplicationServices.h>
4444
#endif
45-
/* The CGDisplayModeRef family (CGDisplayCopyAllDisplayModes,
45+
/* RARCH_HAS_CGDISPLAYMODE_API is defined in cocoa_common.h. The
46+
* CGDisplayModeRef family (CGDisplayCopyAllDisplayModes,
4647
* CGDisplayModeGetWidth, CGDisplaySetDisplayMode, ...) arrived in
4748
* 10.6 Snow Leopard. The 10.5 SDK only offers the older
4849
* CGDisplayAvailableModes / CFDictionaryRef path, which is a
4950
* different enough API that we just stub the resolution list on
5051
* pre-10.6 targets rather than port to both. */
51-
#if defined(MAC_OS_X_VERSION_10_6) && \
52-
(!defined(MAC_OS_X_VERSION_MIN_REQUIRED) || \
53-
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
54-
#define RARCH_HAS_CGDISPLAYMODE_API 1
55-
#endif
5652
#endif
5753

5854
#ifdef OSX
@@ -578,6 +574,21 @@ static void apple_display_server_destroy(void *data)
578574
free(apple);
579575
}
580576

577+
/* Thin wrappers around cocoa_common.m helpers to match the
578+
* video_display_server_t signatures (which take a leading void*).
579+
* Shared implementation lives in cocoa_common.m so the poke /
580+
* gfx_ctx_driver_t vtables can reach it too - see cocoa_common.h. */
581+
static float apple_display_server_get_refresh_rate(void *data)
582+
{
583+
return cocoa_get_refresh_rate();
584+
}
585+
586+
static void apple_display_server_get_video_output_size(void *data,
587+
unsigned *width, unsigned *height, char *desc, size_t desc_len)
588+
{
589+
cocoa_get_video_output_size(width, height, desc, desc_len);
590+
}
591+
581592
const video_display_server_t dispserv_apple = {
582593
apple_display_server_init,
583594
apple_display_server_destroy,
@@ -608,8 +619,8 @@ static void apple_display_server_destroy(void *data)
608619
NULL, /* set_screen_orientation */
609620
NULL, /* get_screen_orientation */
610621
#endif
611-
NULL, /* get_refresh_rate */
612-
NULL, /* get_video_output_size */
622+
apple_display_server_get_refresh_rate,
623+
apple_display_server_get_video_output_size,
613624
NULL, /* get_video_output_prev */
614625
NULL, /* get_video_output_next */
615626
cocoa_get_metrics,

gfx/drivers/metal.m

Lines changed: 9 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5306,26 +5306,10 @@ static void metal_set_video_mode(void *data,
53065306

53075307
static float metal_get_refresh_rate(void *data)
53085308
{
5309-
#ifdef OSX
5310-
CGDirectDisplayID mainDisplayID = CGMainDisplayID();
5311-
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(mainDisplayID);
5312-
double currentRate = CGDisplayModeGetRefreshRate(currentMode);
5313-
CFRelease(currentMode);
5314-
return currentRate;
5315-
#else
5316-
CADisplayLink *displayLink = [CocoaView get].displayLink;
5317-
if (displayLink)
5318-
{
5319-
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 || __TV_OS_VERSION_MAX_ALLOWED >= 150000
5320-
if (@available(iOS 15.0, tvOS 15.0, *))
5321-
return displayLink.preferredFrameRateRange.preferred;
5322-
#endif
5323-
return displayLink.preferredFramesPerSecond;
5324-
}
5325-
if (@available(iOS 10.3, tvOS 10.2, *))
5326-
return [UIScreen mainScreen].maximumFramesPerSecond;
5327-
return 60.0f;
5328-
#endif
5309+
/* Body consolidated into cocoa_common.m. Kept as a named
5310+
* poke entry because video_driver_get_refresh_rate falls back
5311+
* to poke->get_refresh_rate when dispserv returns 0. */
5312+
return cocoa_get_refresh_rate();
53295313
}
53305314

53315315
static void metal_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling)
@@ -5412,38 +5396,11 @@ static uint32_t metal_get_flags(void *data)
54125396
static void metal_get_video_output_size(void *data,
54135397
unsigned *width, unsigned *height, char *desc, size_t desc_len)
54145398
{
5415-
#if TARGET_OS_IPHONE
5416-
/* iOS/tvOS: Return physical screen resolution, not window size */
5417-
UIScreen *screen = [UIScreen mainScreen];
5418-
CGRect nativeBounds = screen.nativeBounds;
5419-
*width = (unsigned)nativeBounds.size.width;
5420-
*height = (unsigned)nativeBounds.size.height;
5421-
5422-
if (desc && desc_len > 0)
5423-
{
5424-
float scale = cocoa_screen_get_native_scale();
5425-
if (scale >= 3.0f)
5426-
strlcpy(desc, "Super Retina", desc_len);
5427-
else if (scale >= 2.0f)
5428-
strlcpy(desc, "Retina", desc_len);
5429-
else
5430-
strlcpy(desc, "Standard", desc_len);
5431-
}
5432-
#else
5433-
/* macOS: Return display resolution */
5434-
CGDirectDisplayID display = CGMainDisplayID();
5435-
*width = (unsigned)CGDisplayPixelsWide(display);
5436-
*height = (unsigned)CGDisplayPixelsHigh(display);
5437-
5438-
if (desc && desc_len > 0)
5439-
{
5440-
float scale = cocoa_screen_get_backing_scale_factor();
5441-
if (scale >= 2.0f)
5442-
strlcpy(desc, "Retina", desc_len);
5443-
else
5444-
strlcpy(desc, "Standard", desc_len);
5445-
}
5446-
#endif
5399+
/* Body consolidated into cocoa_common.m. Kept as a named
5400+
* poke entry because video_thread_wrapper.c's
5401+
* thread_get_video_output_size calls poke->get_video_output_size
5402+
* directly, bypassing dispserv_apple. */
5403+
cocoa_get_video_output_size(width, height, desc, desc_len);
54475404
}
54485405

54495406
/* HDR poke interface setters.

gfx/drivers_context/cocoa_gl_ctx.m

Lines changed: 10 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -259,26 +259,11 @@ static void cocoa_gl_gfx_ctx_get_video_size(void *data,
259259

260260
static float cocoa_gl_gfx_ctx_get_refresh_rate(void *data)
261261
{
262-
#ifdef OSX
263-
#ifdef MAC_OS_X_VERSION_10_6
264-
/* CGDisplayModeRef and CGDisplayCopyDisplayMode are 10.6+.
265-
* On the 10.5 Leopard SDK only the older CFDictionaryRef-based
266-
* CGDisplayCurrentMode API exists; not worth wiring up for a
267-
* refresh-rate readout, so fall back to 60. */
268-
CGDirectDisplayID mainDisplayID = CGMainDisplayID();
269-
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(mainDisplayID);
270-
float currentRate = CGDisplayModeGetRefreshRate(currentMode);
271-
CFRelease(currentMode);
272-
return currentRate;
273-
#else
274-
return 60.0f;
275-
#endif
276-
#else
277-
if (@available(iOS 10.3, tvOS 10.2, *))
278-
return [UIScreen mainScreen].maximumFramesPerSecond;
279-
else
280-
return 60;
281-
#endif
262+
/* Body consolidated into cocoa_common.m. Kept as a named
263+
* vtable entry because vulkan.c-style code paths reach the
264+
* ctx driver directly via video_context_driver_get_refresh_rate,
265+
* bypassing dispserv_apple's own hook. */
266+
return cocoa_get_refresh_rate();
282267
}
283268

284269
static gfx_ctx_proc_t cocoa_gl_gfx_ctx_get_proc_address(const char *symbol_name)
@@ -719,38 +704,11 @@ static bool cocoa_gl_gfx_ctx_set_resize(void *data, unsigned width, unsigned hei
719704
static void cocoa_gl_gfx_ctx_get_video_output_size(void *data,
720705
unsigned *width, unsigned *height, char *desc, size_t desc_len)
721706
{
722-
#if TARGET_OS_IPHONE
723-
/* iOS/tvOS: Return physical screen resolution, not window size */
724-
UIScreen *screen = [UIScreen mainScreen];
725-
CGRect nativeBounds = screen.nativeBounds;
726-
*width = (unsigned)nativeBounds.size.width;
727-
*height = (unsigned)nativeBounds.size.height;
728-
729-
if (desc && desc_len > 0)
730-
{
731-
float scale = cocoa_screen_get_native_scale();
732-
if (scale >= 3.0f)
733-
strlcpy(desc, "Super Retina", desc_len);
734-
else if (scale >= 2.0f)
735-
strlcpy(desc, "Retina", desc_len);
736-
else
737-
strlcpy(desc, "Standard", desc_len);
738-
}
739-
#else
740-
/* macOS: Return display resolution */
741-
CGDirectDisplayID display = CGMainDisplayID();
742-
*width = (unsigned)CGDisplayPixelsWide(display);
743-
*height = (unsigned)CGDisplayPixelsHigh(display);
744-
745-
if (desc && desc_len > 0)
746-
{
747-
float scale = cocoa_screen_get_backing_scale_factor();
748-
if (scale >= 2.0f)
749-
strlcpy(desc, "Retina", desc_len);
750-
else
751-
strlcpy(desc, "Standard", desc_len);
752-
}
753-
#endif
707+
/* Body consolidated into cocoa_common.m. Kept as a named
708+
* vtable entry because video_thread_wrapper.c's
709+
* thread_get_video_output_size calls the poke / ctx hook
710+
* directly, bypassing dispserv_apple. */
711+
cocoa_get_video_output_size(width, height, desc, desc_len);
754712
}
755713

756714
const gfx_ctx_driver_t gfx_ctx_cocoagl = {

gfx/drivers_context/cocoa_vk_ctx.m

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,11 @@ static void cocoa_vk_gfx_ctx_get_video_size(void *data,
140140

141141
static float cocoa_vk_gfx_ctx_get_refresh_rate(void *data)
142142
{
143-
#ifdef OSX
144-
CGDirectDisplayID mainDisplayID = CGMainDisplayID();
145-
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(mainDisplayID);
146-
float currentRate = CGDisplayModeGetRefreshRate(currentMode);
147-
CFRelease(currentMode);
148-
return currentRate;
149-
#else
150-
return [UIScreen mainScreen].maximumFramesPerSecond;
151-
#endif
143+
/* Body consolidated into cocoa_common.m. Kept as a named
144+
* vtable entry because vulkan_get_refresh_rate() reaches the
145+
* ctx driver directly via video_context_driver_get_refresh_rate,
146+
* bypassing dispserv_apple's own hook. */
147+
return cocoa_get_refresh_rate();
152148
}
153149

154150
static gfx_ctx_proc_t cocoa_vk_gfx_ctx_get_proc_address(const char *symbol_name)
@@ -353,38 +349,11 @@ static bool cocoa_vk_gfx_ctx_set_resize(void *data, unsigned width, unsigned hei
353349
static void cocoa_vk_gfx_ctx_get_video_output_size(void *data,
354350
unsigned *width, unsigned *height, char *desc, size_t desc_len)
355351
{
356-
#if TARGET_OS_IPHONE
357-
/* iOS/tvOS: Return physical screen resolution, not window size */
358-
UIScreen *screen = [UIScreen mainScreen];
359-
CGRect nativeBounds = screen.nativeBounds;
360-
*width = (unsigned)nativeBounds.size.width;
361-
*height = (unsigned)nativeBounds.size.height;
362-
363-
if (desc && desc_len > 0)
364-
{
365-
float scale = cocoa_screen_get_native_scale();
366-
if (scale >= 3.0f)
367-
strlcpy(desc, "Super Retina", desc_len);
368-
else if (scale >= 2.0f)
369-
strlcpy(desc, "Retina", desc_len);
370-
else
371-
strlcpy(desc, "Standard", desc_len);
372-
}
373-
#else
374-
/* macOS: Return display resolution */
375-
CGDirectDisplayID display = CGMainDisplayID();
376-
*width = (unsigned)CGDisplayPixelsWide(display);
377-
*height = (unsigned)CGDisplayPixelsHigh(display);
378-
379-
if (desc && desc_len > 0)
380-
{
381-
float scale = cocoa_screen_get_backing_scale_factor();
382-
if (scale >= 2.0f)
383-
strlcpy(desc, "Retina", desc_len);
384-
else
385-
strlcpy(desc, "Standard", desc_len);
386-
}
387-
#endif
352+
/* Body consolidated into cocoa_common.m. Kept as a named
353+
* vtable entry because video_thread_wrapper.c's
354+
* thread_get_video_output_size calls the poke / ctx hook
355+
* directly, bypassing dispserv_apple. */
356+
cocoa_get_video_output_size(width, height, desc, desc_len);
388357
}
389358

390359
const gfx_ctx_driver_t gfx_ctx_cocoavk = {

ui/drivers/cocoa/cocoa_common.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@
2929
#include <AppKit/AppKit.h>
3030
#endif
3131

32+
/* The CGDisplayModeRef family (CGDisplayCopyDisplayMode,
33+
* CGDisplayCopyAllDisplayModes, CGDisplayModeGetRefreshRate, ...)
34+
* arrived in 10.6 Snow Leopard. The 10.5 Leopard SDK only offers
35+
* the older CGDisplayCurrentMode + CFDictionaryRef path. Sites that
36+
* use either API (cocoa_common.m's cocoa_get_refresh_rate and
37+
* dispserv_apple.m's resolution-switching code) branch on this
38+
* macro. Defined here so every translation unit sees the same
39+
* answer. */
40+
#if defined(OSX) && defined(MAC_OS_X_VERSION_10_6) && \
41+
(!defined(MAC_OS_X_VERSION_MIN_REQUIRED) || \
42+
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
43+
#define RARCH_HAS_CGDISPLAYMODE_API 1
44+
#endif
45+
3246
/* RetroArchPlaylistManager.m/.h uses Obj-C nullability macros
3347
* (NS_ASSUME_NONNULL_BEGIN/END, nullable, _Nonnull) and
3448
* lightweight generics (NSArray<...>) - all Xcode 7+ (2015)
@@ -157,6 +171,25 @@ bool cocoa_get_metrics(
157171
void *data, enum display_metric_types type,
158172
float *value);
159173

174+
/* Shared display-info helpers.
175+
*
176+
* Three vtables call these via thin wrappers, because different
177+
* call sites reach them through different paths:
178+
* - video_driver_get_refresh_rate / _get_video_output_size go
179+
* through dispserv first, poke second.
180+
* - video_context_driver_get_refresh_rate (used by vulkan.c's
181+
* vulkan_get_refresh_rate) goes straight to the gfx_ctx_driver_t
182+
* vtable, bypassing dispserv.
183+
* - video_thread_wrapper.c's thread_get_video_output_size calls
184+
* poke->get_video_output_size directly, bypassing dispserv.
185+
*
186+
* Each vtable therefore keeps a registered function; the bodies all
187+
* funnel here so there is only one implementation per platform. */
188+
float cocoa_get_refresh_rate(void);
189+
190+
void cocoa_get_video_output_size(unsigned *width, unsigned *height,
191+
char *desc, size_t desc_len);
192+
160193
#endif
161194

162195
void cocoa_file_load_with_detect_core(const char *filename);

0 commit comments

Comments
 (0)