Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken visual output in full screen mode with OS X 10.15 #3418

Closed
SDLBugzilla opened this issue Feb 11, 2021 · 0 comments
Closed

Broken visual output in full screen mode with OS X 10.15 #3418

SDLBugzilla opened this issue Feb 11, 2021 · 0 comments

Comments

@SDLBugzilla
Copy link
Collaborator

This bug report was migrated from our old Bugzilla tracker.

These attachments are available in the static archive:

Reported in version: 2.0.10
Reported for operating system, platform: macOS 10.15, x86

Comments on the original bug report:

On 2019-10-11 16:22:15 +0000, wrote:

In our SDL based Metal application we observe that the visual output in fullscreen mode is erroneously scaled/displaced in some resolutions. This only happens with OS X 10.15 and only with Retina displays. Changing the display settings in the System Preferences has a strong effect, we haven't observed the problem when using the leftmost setting (the most scaled one), but any of the other settings has a chance to reveal the problem. This strongly indicates an issue with respect to the scaling factors between the points and pixels coordinate system or maybe a change in behavior in OS X 10.15. We also observe that small resolutions seem to be more affected than high resolutions.

We also tested with the testdraw2 sample and observed that it also shows problems, although we observed black screen instead of scaling/displacing effects in the fail case. We also observe a similar dependency on the display settings. We suggest to use the testdraw2 sample to investigate the problem on a Mac with OS X 10.15.

On 2019-10-12 09:02:41 +0000, Hasi50 wrote:

Looks like I have found a simliar or same Issue at:

widelands/widelands#3542

e.g. check this image https://user-images.githubusercontent.com/16598373/66640573-7dc65c00-ec19-11e9-90ec-02f39fc3f02e.png

please point me to some OpenGL Example, I may compile and creat a screenshot.

Meanwhile I will compile SDL 2.0.10 (via Macports) with Debuginfo.

On 2019-10-12 13:43:50 +0000, Hasi50 wrote:

Mhh, the Issue should be somwehere in
Cocoa_GL_CreateContext in SDL_cocoaopengl.m

(nice Mix of C++ and objective C :-)

But I dont see any obvious flaw by now

On 2019-10-12 13:56:28 +0000, Alex Szpakowski wrote:

Is this the same as / a duplicate of bug # 4810 ?

On 2019-10-12 14:15:18 +0000, Hasi50 wrote:

(In reply to Alex Szpakowski from comment # 3)

Is this the same as / a duplicate of bug # 4810 ?

I see the scaling Issue in my Case (opengl in Widelands).
The rest of the Window is just black.

But they could be related. I currently try to find out
What may have changed from the Apple Documentaiton.

On 2019-10-12 14:24:42 +0000, Alex Szpakowski wrote:

(In reply to Hasi50 from comment # 4)

(In reply to Alex Szpakowski from comment # 3)

Is this the same as / a duplicate of bug # 4810 ?

I see the scaling Issue in my Case (opengl in Widelands).
The rest of the Window is just black.

Yes, that's the same issue I'm describing. The window is additionally supposed to have a black frame at the very start, but instead it's white or dark grey (depending on if the user has Dark Mode enabled on the system or not), because the code to draw the initial black frame isn't working. After that first black frame, the color of the window's contents depends on the app.

On 2019-10-14 00:40:10 +0000, Alex Szpakowski wrote:

I believe I've fixed the OpenGL scaling issues with https://hg.libsdl.org/SDL/rev/46b094f7d20e , but the Metal scaling issues will need further investigation.

On 2019-10-14 06:47:54 +0000, Hasi50 wrote:

Thanks Alex Szpakowski,
Your patch fixed my wideland Issue!

I will continue with my Widelands / github bug to get this as patch
to Macports. (Homebrew as not affected?).

Good Luck hunting the metal aspects of this bug.

On 2019-10-17 13:24:29 +0000, wrote:

OP here: it is not clear from the thread so far whether anyone has actually reproduced fullscreen issues with Metal based applications as we did. Our game was rejected during App Store review because they encountered a black screen instead of the correct visuals. While we have strong evidence that the culprit may be buried somewhere in SDL due to our experiences with the SDL samples it would be reassuring if we knew that the problem was reproduced by SDL developers so that the chances to resolve the problem soon are instact. Thank you.

On 2019-10-17 14:46:22 +0000, Alex Szpakowski wrote:

I have reproduced an issue - on my Macbook Pro with 10.15, entering exclusive-fullscreen, exiting fullscreen, and re-entering exclusive-fullscreen will push the content of the window up slightly, with a black bar at the bottom (regardless of whether Metal or OpenGL is used). I have not reproduced any issue related to a completely black screen, or content being scaled.

I'm working on a fix for that problem - I believe the bug is inside macOS itself (in its fullscreen modes), my fix uses different CGDisplayModeRef objects which don't have that issue on my computer.

I'll need to be a bit careful with the fix to avoid introducing the same problem that this revert commit was made to work around, though: https://hg.libsdl.org/SDL/rev/7dc3cec9ac85

On 2019-10-23 08:45:13 +0000, wrote:

OP here again: we would like to provide some more information regarding the issue reported in the original post. We observe the fullscreen issue both with Metal- and OpenGL-based applications therefore we believe that the fix explained in comment 6 fixes a different problem. We have applied the commit to one of our own OpenGL based applications and the fullscreen issues still persisted.

We did some more testing with the testdraw2 sample and observed similar behavior when using OpenGL or Metal. We used the sample with the following parameters:
--renderer opengl | metal
--geometry wxh
--fullscreen
We tested with a Mac Mini running OS X 10.15 attached to a 4K monitor, the desktop running a 4k display mode. With our setup we observe that the sample either displays correct content or nothing at all (black screen). In our case we observed:

  • correct display with --geometry 1600x900 or higher
  • black screen with --geometry 1600x900 or lower under the condition that the scaling setting in the display preferences was set to rightmost or second-rightmost setting before running the test
  • correct display with --geometry 1600x900 or lower under the condition that the scaling setting in the display preferences was set to one of the three left-most settings before running the test

We would like to ask you to try to reproduce this behavior. We would be interested to know whether this behavior is linked to the observations described in comment 9.

We think that the dependency on the scaling setting observed both in our game and in testdraw2 should already give a significant hint to the nature of the problem and we would appreciate hearing your thoughts about how such a dependency could be explained.

On 2019-10-24 23:22:44 +0000, Alex Szpakowski wrote:

Here's the change I made which fixes the issues I've observed, let me know if it fixes things on your system: https://hg.libsdl.org/SDL/rev/d62dcbe19211

On 2019-10-25 15:06:39 +0000, wrote:

I downloaded the most recent SDL2 from github and rebuilt the library. Now fullscreen mode is nonfunctional here, tested on two different Macs, one with 10.15 and one with 10.14. On both systems I see the error message

Unable to find mode dict in array

It turns out that the error is caused by CGDisplaySetDisplayMode() in Cocoa_SetDisplayMode(). The error code is -1000.

Further investigation revealed that fullscreen mode starts working again if I remove the new key (kCGDisplayShowDuplicateLowResolutionModes) from the dictionary. In that case I observe that only very few modes make it through the new filter in GetDisplayMode().

When the kCGDisplayShowDuplicateLowResolutionModes key is present I see a huge list of modes entering GetDisplayMode() and still a large amount of them get through the filter, including many duplicates. On the other hand the maximal mode did not make it through even once.

Is there a way to print complete information about each mode so that we could maybe find out which mode properties make trouble?

On 2019-10-25 16:56:11 +0000, Alex Szpakowski wrote:

(In reply to sjordan from comment # 12)

I downloaded the most recent SDL2 from github and rebuilt the library. Now
fullscreen mode is nonfunctional here, tested on two different Macs, one
with 10.15 and one with 10.14. On both systems I see the error message

Unable to find mode dict in array

It turns out that the error is caused by CGDisplaySetDisplayMode() in
Cocoa_SetDisplayMode(). The error code is -1000.

Can you post some minimal code (or steps via testdraw2 or similar) which reproduce that problem for you, as well as the monitor setups you're using? Have you only reproduced the issue on third party monitors, or does it happen on Macs that have a built-in display as well? What sort of retina settings do the affected monitors have?

Is there a way to print complete information about each mode so that we
could maybe find out which mode properties make trouble?

"--info modes" passed into one of the test programs prints out what SDL's higher level APIs know about the display modes. For the lower level details that are actually causing issues, you would have to add prints inside the GetDisplayMode function in src/video/cocoa/SDL_cocoamodes.m.

On 2019-10-25 17:10:32 +0000, Alex Szpakowski wrote:

(In reply to Alex Szpakowski from comment # 13)

"--info modes" passed into one of the test programs prints out what SDL's
higher level APIs know about the display modes. For the lower level details
that are actually causing issues, you would have to add prints inside the
GetDisplayMode function in src/video/cocoa/SDL_cocoamodes.m.

One thing that might be interesting to print out is the bitfield returned by CGDisplayModeGetIOFlags, for each Cocoa display mode.

On 2019-10-26 00:14:42 +0000, Alex Szpakowski wrote:

I tested with my Retina laptop connected to a second non-Retina display, and I can reproduce the issue on both displays now. If I disconnect the second display it works fine.

I've done some investigation. It seems like while kCGDisplayShowDuplicateLowResolutionModes populates the list returned by CGDisplayCopyAllDisplayModes with highdpi modes which work when fullscreen is repeatedly entered, it also adds duplicates of those modes which have a different pixel format and don't work with CGDisplaySetDisplayMode.

Unfortunately Apple does not seem to have any public API to determine whether those display modes are actually valid. CGDisplayModeCopyPixelEncoding can't even be used to detect it - the same pixel format is returned for both, even though if I NSLog the CGDisplayModeRef, it shows a different pixel format in its internal (non-public) data structure.

What I'll probably end up doing is add those duplicates to a list associated with each SDL display mode, which SetDisplayMode will iterate over and try one after the other. It's not a great solution but the alternatives seem worse.

I also discovered some modes that SDL should be ignoring because their IO flags indicate they aren't valid in other ways), code for that should be much easier to add because Apple actually provides APIs to detect that, unlike this other issue.

On 2019-10-26 18:32:30 +0000, Alex Szpakowski wrote:

https://hg.libsdl.org/SDL/rev/35ed58402582 does what I described above, and fixes the issues introduced with the previous commit.

Unfortunately, extremely low res (800x600 lowdpi, etc) display modes still show a black screen with the cursor. I believe this is a bug in macOS (even if the "fix" is for Apple to mark those modes as not supported), and I don't think it's likely SDL will be able to work around the bug itself.

In general exclusive-fullscreen mode switching causes various problems across most operating systems, and it's not very user friendly either (especially on macOS, where you can't even switch programs without exiting exclusive fullscreen, if you only have one monitor). If Apple QA are running into their black screen bug because they switch to a low res display mode when testing your app, it's probably a better idea overall to avoid using exclusive fullscreen instead (or at least extremely low res display modes).

On 2019-10-29 16:56:34 +0000, wrote:

I can confirm that the second fix fixes the first fix, but both fixes combined don't fix the original problems observed in our game in in the testdraw2 sample.

We did some investigations into a different direction which I would like to share. As mentioned previously the scaling setting in the preferences play an important role for our problem and they also hint towards an issue with point/pixel scaling factors.

We found an interesting correlation between our fail case and the behavior of [nsWindow.screen backingScaleFactor]. It turns out that whenever we encounter the fail case the scale factor is zero when we print it quickly after calling SDL_CreateWindow. After some time the value changes to a non-zero value. In the success case the scaling factor is nonzero 'immediately'. Note that we don't use that factor. We also find that the window backingScaleFactor does not show the strange behavior even in the fail case.

We have also attempted to find out whether any event triggers the transition from zero to non-zero. We found the transition happening when we call SDL_PollEvent. We can even force this to happen by explicitly adding a SDL_PollEvent at an early stage, but it will only happen if a certain amount of time elapsed, so we need to add some sleep before the call to trigger the transition at an earlier stage. All that seems to imply that the transition happens async and that SDL_PollEvent merely causes the system to update its internal state at that time.

We have also verified that the scaling setting in the preferences does NOT directly correlate to the scaling factor behavior. We find that a particular scaling setting can lead to a fail case for one resolution and a success case for another resolution. This shows that the scaling setting alone does not determine whether the problem will appear or not.

We have also verified on another Mac with 10.14 that the scaling factor is always non-zero and we always have the success case.

I have no idea how to interpret this initial-zero behavior and haven't found any usable information on the screen backing scale factor. It seems as 10.15 does some stuff more async than before and maybe the problem could be caused by unfortunate timings. I would be very interested to hear your opinion about that.

On 2019-10-30 13:12:02 +0000, wrote:

Finally we found the cause of all our problems: it's the origin hack in Cocoa_SetWindowFullscreen:

    /* Hack to fix origin on Mac OS X 10.4 */
    NSRect screenRect = [[nswindow screen] frame];
    if (screenRect.size.height >= 1.0f) {
        rect.origin.y += (screenRect.size.height - rect.size.height);
    }

If we comment this one out our game and testdraw2 do behave correctly.

It turns out that if a window is not fully contained in the screen, it's screen property becomes zero and therefore we saw a zero when printing the backing scale factor (although it's not clear why it became nonzero later).

We suggest to add a runtime check which skips this code for 10.15 (or possibly earlier if you happen to know that the hack is not needed for certain older versions).

On 2019-10-30 14:05:12 +0000, Alex Szpakowski wrote:

Thanks for the investigation! I'll have to do some tests to see what impact removing that hack might have (and maybe I'll need to replace it with something else, if removing it causes other problems on 10.15+) - I probably won't get to it in the next few days, but if your workaround is working for you I don't see a problem with using it locally in the meantime.

On 2019-10-30 14:32:40 +0000, wrote:

We just realized that skipping the hack is probably not the correct way of resolving the problem. We suspect that maybe the hack compares values with mismatching coordinate systems, but we need to dig a bit more into it. What was the original situation which necessitated adding that code? What is the precise meaning of the if statement? The comparison screenRect.size.height >= 1.0f looks a bit odd assuming height should be in points or pixels.

On 2019-10-30 17:55:25 +0000, wrote:

More info: consider the line

NSRect screenRect = [[nswindow screen] frame];

in Cocoa_SetWindowFullscreen. We found that this rect has the dimensions of the desktop
on our OS X 10.15 setup. This is true both for the success case and the fail case. It seems as the success case is actually a fail case in disguise.

On the other Mac with OS X 10.14 the same rect has the dimension of the newly created screen. This is what I would expect, because at that time the window has already been created successfully and there should be a newly created screen associated to the window.

What are the cases in which the whole origin conversion code for the fullscreen case is supposed to have a non-trivial result?

On 2019-10-31 09:00:22 +0000, wrote:

Today we found that if we print the dimensions of [nswindow screen] later, then we find them to be correct. So the conclusion seems to be that OS X 10.15 does indeed do the window/screen setup more async than before and that the origin correction code uses the [nswindow screen] at a time where the window/screen setup isn't finalized yet.

On 2019-11-08 21:47:03 +0000, Ozkan Sezer wrote:

This issue we hit in quakespasm (https://sf.net/p/quakespasm/) which is
an OpenGL game: On Catalina, the entire viewport is moved down by half
the screen, but only when running fullscreen, windowed mode is Ok. The
length by which the viewport is moved depends on resolution: It's half
the screen when running at desktop resolution, becomes less when running
at smaller resolutions. This was seen on an iMac with a Retina display,
with SDL-2.0 built from latest hg. (Surprisingly, the SDL1.2 builds were
reported to be fine.)

On 2020-02-07 12:16:36 +0000, Stijn Volckaert wrote:

We are seeing this same issue in the upcoming Unreal Tournament (99) client for Mac. We're using SDL 2.0.10 and OpenGL. We tested on two macOS 10.15 systems. One was a mid2012 MBP (screen resolution 1440x900). No issues here. The other was a mid2013 iMac (screen resolution 2560x1440). This one only renders the top of our GL viewport if we set the game resolution to 1024x768. The rest of the screen is black. If we set the game resolution to 2560x1440, everything works fine. Switching to windowed mode also fixes the problem. Setting NSHighResolutionCapable to true or false in the plist file has no effect.

On 2020-02-07 12:46:19 +0000, wrote:

Seeing that other projects are affected by the same problem, I would like to comment that the workaround described in Comment 18 works for us, we have released our game with the workaround enabled and haven't observed any problems so far.

To be more precise, the workaround is to do the following replacement in SDL_cocoawindow.m:

    /* Hack to fix origin on Mac OS X 10.4 */
    NSRect screenRect = [[nswindow screen] frame];
    if (screenRect.size.height >= 1.0f) {
        rect.origin.y += (screenRect.size.height - rect.size.height);
    }

replace with

NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
if ((version.majorVersion == 10) && (version.minorVersion < 15)) {

    /* Hack to fix origin on Mac OS X 10.4 */
    NSRect screenRect = [[nswindow screen] frame];
    if (screenRect.size.height >= 1.0f) {
        rect.origin.y += (screenRect.size.height - rect.size.height);
    }
}

Note that this workaround only works with OSX 10.10 and higher. Alternatively you can also just delete the code, but that requires additional testing on pre 10.15 systems.

On 2020-02-11 18:22:21 +0000, Sam Lantinga wrote:

Okay, I pushed the workaround for 2.0.12 release. Alex, can you keep investigating to find the root cause? I'd like to remove the hacks if we figure out what's happening here.
https://hg.libsdl.org/SDL/rev/25c5f567de44

On 2020-02-11 18:37:41 +0000, Sam Lantinga wrote:

I tried to make the version detection safe prior to 10.10 here:
https://hg.libsdl.org/SDL/rev/a6d3d330dedc

Please let me know whether this is the right way to do it!

On 2020-03-14 08:29:02 +0000, Joshua Root wrote:

(In reply to Sam Lantinga from comment # 27)

I tried to make the version detection safe prior to 10.10 here:
https://hg.libsdl.org/SDL/rev/a6d3d330dedc

Please let me know whether this is the right way to do it!

Unfortunately that doesn't work when using an SDK older than 10.10 (since the NSOperatingSystemVersion type is not defined). The fix is simply to also check the SDK version; would you like me to open a new bug or just attach a patch here?

On 2020-03-15 00:46:40 +0000, Sam Lantinga wrote:

SDL doesn't officially support SDK older than 10.10, but you're welcome to attach a patch here.

Thanks!

On 2020-03-15 01:13:24 +0000, Joshua Root wrote:

Created attachment 4256
typedef NSOperatingSystemVersion for older SDKs

OK, here you go. Seems to build fine back to 10.7 SDK with this change.

On 2020-03-23 18:43:37 +0000, Sam Lantinga wrote:

Patch added, thanks!
https://hg.libsdl.org/SDL/rev/83df8de77e12

On 2020-10-06 16:02:26 +0000, Ozkan Sezer wrote:

(In reply to Sam Lantinga from comment # 27)

I tried to make the version detection safe prior to 10.10 here:
https://hg.libsdl.org/SDL/rev/a6d3d330dedc

Please let me know whether this is the right way to do it!

See bug # 5306.

On 2020-10-09 01:01:15 +0000, Ozkan Sezer wrote:

(In reply to Ozkan Sezer from comment # 32)

See bug # 5306.

Applied https://hg.libsdl.org/SDL/rev/dc437e72435f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant