Skip to content

Commit

Permalink
Fixed bug 2696 - Mac: fix display mode refresh rate calculation
Browse files Browse the repository at this point in the history
Alex Szpakowski

SDL's Cocoa backend uses the CGDisplayMode API to get refresh rate information about a display mode, but CGDisplayModeGetRefreshRate will return 0 on most non-CRT monitors.

The only way I know of to get correct refresh rate information in OS X is via the CoreVideo DisplayLink API.
I have attached a patch which tries to use the CVDisplayLinkGetNominalOutputVideoRefreshPeriod function if CGDisplayModeGetRefreshRate fails, which fixes display mode refresh rate information on the monitors I tested.

The CVDisplayLink API requires linking with the CoreVideo framework, and the patch updates the various build files to do so.
  • Loading branch information
slouken committed Aug 23, 2014
1 parent a79ed6c commit 059579e
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 5 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Expand Up @@ -970,6 +970,7 @@ elseif(APPLE)
set_source_files_properties(${EXTRA_SOURCES} PROPERTIES LANGUAGE C)
set(HAVE_SDL_FILE TRUE)
set(SDL_FRAMEWORK_COCOA 1)
set(SDL_FRAMEWORK_COREVIDEO 1)
else()
message_error("SDL_FILE must be enabled to build on MacOS X")
endif()
Expand Down Expand Up @@ -1029,6 +1030,10 @@ elseif(APPLE)
endif()

# Actually load the frameworks at the end so we don't duplicate include.
if(SDL_FRAMEWORK_COREVIDEO)
find_library(COREVIDEO CoreVideo)
list(APPEND EXTRA_LIBS ${COREVIDEO})
endif()
if(SDL_FRAMEWORK_COCOA)
find_library(COCOA_LIBRARY Cocoa)
list(APPEND EXTRA_LIBS ${COCOA_LIBRARY})
Expand Down
8 changes: 8 additions & 0 deletions Xcode/SDL/SDL.xcodeproj/project.pbxproj
Expand Up @@ -810,6 +810,9 @@
DB31407217554B71006C0E22 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 007317C10858E15000B2BC32 /* Carbon.framework */; };
DB31408B17554D37006C0E22 /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CFA89C106B4BA100758660 /* ForceFeedback.framework */; };
DB31408D17554D3C006C0E22 /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CFA89C106B4BA100758660 /* ForceFeedback.framework */; };
FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; };
FA73671E19A54140004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; };
FA73671F19A54144004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -1109,13 +1112,15 @@
F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; };
F5A2EF3A00C6A3C201000001 /* README-macosx.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = "README-macosx.txt"; path = "../../README-macosx.txt"; sourceTree = SOURCE_ROOT; };
F5F81AD400D706B101000001 /* Readme SDL Developer.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = "Readme SDL Developer.txt"; path = "pkg-support/Readme SDL Developer.txt"; sourceTree = SOURCE_ROOT; };
FA73671C19A540EF004122E4 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = /System/Library/Frameworks/CoreVideo.framework; sourceTree = "<absolute>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
BECDF6680761BA81005FE872 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */,
007317A20858DECD00B2BC32 /* AudioToolbox.framework in Frameworks */,
007317A30858DECD00B2BC32 /* AudioUnit.framework in Frameworks */,
007317A40858DECD00B2BC32 /* Cocoa.framework in Frameworks */,
Expand All @@ -1131,6 +1136,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FA73671E19A54140004122E4 /* CoreVideo.framework in Frameworks */,
007317A90858DECD00B2BC32 /* AudioToolbox.framework in Frameworks */,
007317AA0858DECD00B2BC32 /* AudioUnit.framework in Frameworks */,
007317AB0858DECD00B2BC32 /* Cocoa.framework in Frameworks */,
Expand All @@ -1145,6 +1151,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FA73671F19A54144004122E4 /* CoreVideo.framework in Frameworks */,
DB31406C17554B71006C0E22 /* AudioToolbox.framework in Frameworks */,
DB31406D17554B71006C0E22 /* AudioUnit.framework in Frameworks */,
DB31406E17554B71006C0E22 /* Cocoa.framework in Frameworks */,
Expand Down Expand Up @@ -1738,6 +1745,7 @@
BEC562FE0761C0E800A33029 /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
FA73671C19A540EF004122E4 /* CoreVideo.framework */,
00D0D08310675DD9004B05EF /* CoreFoundation.framework */,
007317C10858E15000B2BC32 /* Carbon.framework */,
0073179B0858DECD00B2BC32 /* AudioToolbox.framework */,
Expand Down
92 changes: 92 additions & 0 deletions Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions configure
Expand Up @@ -23338,6 +23338,7 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h
# The Mac OS X platform requires special setup.
EXTRA_CFLAGS="$EXTRA_CFLAGS -fpascal-strings"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lobjc"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreVideo"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Cocoa"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit"
Expand Down
1 change: 1 addition & 0 deletions configure.in
Expand Up @@ -3215,6 +3215,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
# The Mac OS X platform requires special setup.
EXTRA_CFLAGS="$EXTRA_CFLAGS -fpascal-strings"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lobjc"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreVideo"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Cocoa"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit"
Expand Down
1 change: 1 addition & 0 deletions premake/README-macosx.txt
Expand Up @@ -17,6 +17,7 @@ tests on that platform.

The Mac OS X projects currently have reliance on the following dependencies:

-CoreVideo.framework
-AudioToolbox.framework
-AudioUnit.framework
-Cocoa.framework
Expand Down
1 change: 1 addition & 0 deletions premake/projects/SDL2.lua
Expand Up @@ -213,6 +213,7 @@ SDL_project "SDL2"
}
SDL_links
{
"CoreVideo.framework",
"AudioToolbox.framework",
"AudioUnit.framework",
"Cocoa.framework",
Expand Down
40 changes: 35 additions & 5 deletions src/video/cocoa/SDL_cocoamodes.m
Expand Up @@ -27,6 +27,10 @@
/* We need this for IODisplayCreateInfoDictionary and kIODisplayOnlyPreferredName */
#include <IOKit/graphics/IOGraphicsLib.h>

/* We need this for CVDisplayLinkGetNominalOutputVideoRefreshPeriod */
#include <CoreVideo/CVBase.h>
#include <CoreVideo/CVDisplayLink.h>

/* we need this for ShowMenuBar() and HideMenuBar(). */
#include <Carbon/Carbon.h>

Expand Down Expand Up @@ -114,7 +118,7 @@
}

static SDL_bool
GetDisplayMode(_THIS, const void *moderef, SDL_DisplayMode *mode)
GetDisplayMode(_THIS, const void *moderef, CVDisplayLinkRef link, SDL_DisplayMode *mode)
{
SDL_DisplayModeData *data;
long width = 0;
Expand All @@ -133,14 +137,17 @@
CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode);
width = (long) CGDisplayModeGetWidth(vidmode);
height = (long) CGDisplayModeGetHeight(vidmode);
refreshRate = (long) CGDisplayModeGetRefreshRate(vidmode);
refreshRate = (long) (CGDisplayModeGetRefreshRate(vidmode) + 0.5);

if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels),
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
bpp = 32;
} else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels),
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
bpp = 16;
} else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels),
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
bpp = 30;
} else {
bpp = 0; /* ignore 8-bit and such for now. */
}
Expand All @@ -151,6 +158,7 @@
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
if (!IS_SNOW_LEOPARD_OR_LATER()) {
CFNumberRef number;
double refresh;
CFDictionaryRef vidmode = (CFDictionaryRef) moderef;
number = CFDictionaryGetValue(vidmode, kCGDisplayWidth);
CFNumberGetValue(number, kCFNumberLongType, &width);
Expand All @@ -159,15 +167,27 @@
number = CFDictionaryGetValue(vidmode, kCGDisplayBitsPerPixel);
CFNumberGetValue(number, kCFNumberLongType, &bpp);
number = CFDictionaryGetValue(vidmode, kCGDisplayRefreshRate);
CFNumberGetValue(number, kCFNumberLongType, &refreshRate);
CFNumberGetValue(number, kCFNumberDoubleType, &refresh);
refreshRate = (long) (refresh + 0.5);
}
#endif

/* CGDisplayModeGetRefreshRate returns 0 for many non-CRT displays. */
if (refreshRate == 0 && link != NULL) {
CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
if ((time.flags & kCVTimeIsIndefinite) == 0 && time.timeValue != 0) {
refreshRate = (long) ((time.timeScale / (double) time.timeValue) + 0.5);
}
}

mode->format = SDL_PIXELFORMAT_UNKNOWN;
switch (bpp) {
case 16:
mode->format = SDL_PIXELFORMAT_ARGB1555;
break;
case 30:
mode->format = SDL_PIXELFORMAT_ARGB2101010;
break;
case 32:
mode->format = SDL_PIXELFORMAT_ARGB8888;
break;
Expand Down Expand Up @@ -241,6 +261,7 @@
SDL_DisplayData *displaydata;
SDL_DisplayMode mode;
const void *moderef = NULL;
CVDisplayLinkRef link = NULL;

if (pass == 0) {
if (!CGDisplayIsMain(displays[i])) {
Expand Down Expand Up @@ -277,16 +298,21 @@
}
displaydata->display = displays[i];

CVDisplayLinkCreateWithCGDisplay(displays[i], &link);

SDL_zero(display);
/* this returns a stddup'ed string */
display.name = (char *)Cocoa_GetDisplayName(displays[i]);
if (!GetDisplayMode (_this, moderef, &mode)) {
if (!GetDisplayMode(_this, moderef, link, &mode)) {
CVDisplayLinkRelease(link);
Cocoa_ReleaseDisplayMode(_this, moderef);
SDL_free(display.name);
SDL_free(displaydata);
continue;
}

CVDisplayLinkRelease(link);

display.desktop_mode = mode;
display.current_mode = mode;
display.driverdata = displaydata;
Expand Down Expand Up @@ -328,20 +354,24 @@
#endif

if (modes) {
CVDisplayLinkRef link = NULL;
const CFIndex count = CFArrayGetCount(modes);
CFIndex i;

CVDisplayLinkCreateWithCGDisplay(data->display, &link);

for (i = 0; i < count; i++) {
const void *moderef = CFArrayGetValueAtIndex(modes, i);
SDL_DisplayMode mode;
if (GetDisplayMode(_this, moderef, &mode)) {
if (GetDisplayMode(_this, moderef, link, &mode)) {
if (IS_SNOW_LEOPARD_OR_LATER()) {
CGDisplayModeRetain((CGDisplayModeRef) moderef);
}
SDL_AddDisplayMode(display, &mode);
}
}

CVDisplayLinkRelease(link);
Cocoa_ReleaseDisplayModeList(_this, modes);
}
}
Expand Down

0 comments on commit 059579e

Please sign in to comment.