SFML: [MacOS] Empty std::vector returned from getFullscreenModes(), causing segfault

Subject of the issue

This issue is described in the forums, here: https://en.sfml-dev.org/forums/index.php?topic=28601.0

I am not the OP of that thread, but I (and others) are seeing the same issue. Essentially, on MacOS (latest versions), a call to getFullScreenModes() (https://github.com/SFML/SFML/blob/2.6.x/src/SFML/Window/OSX/VideoModeImpl.cpp#L40) returns an empty vector of video modes. This is because each candidate is rejected by the continue at line 65, owing to all of them being larger than the reported desktop width/height.

Adding some debug output at that point shows the following modes are all rejected:

mode.size.x = 3840, desktop.size.x = 3420, mode.size.y = 2400, desktop.size.y = 2224
mode.size.x = 4096, desktop.size.x = 3420, mode.size.y = 2560, desktop.size.y = 2224
mode.size.x = 4096, desktop.size.x = 3420, mode.size.y = 2664, desktop.size.y = 2224
mode.size.x = 5120, desktop.size.x = 3420, mode.size.y = 3200, desktop.size.y = 2224
mode.size.x = 5120, desktop.size.x = 3420, mode.size.y = 3328, desktop.size.y = 2224
(Empty std::vector of modes returned)

This appears to be related to the question about whether Apple’s CGDisplayModeGetWidth() function returns its value in points or pixels.

Your environment

  • OS: MacOS 13.1 “Ventura”
  • Version of SFML: I’ve tried 3.0 and 2.5.x branches
  • Apple clang version 14.0.0 (clang-1400.0.29.202)
  • Special compiler flags used: just the usual -std=c++17 -g -Wall -Wextra -Werror -Wpedantic

Steps to reproduce

This is using SFML 3.0 but a similar program for 2.5.x exhibits the same behaviour. Note, this issue is on MacOS only.

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>

#include <iostream>
#include <vector>

int main()
{
    std::vector<sf::VideoMode> modes = sf::VideoMode::getFullscreenModes();
    if (modes.empty())
    {
        std::cout << "Empty set of modes returned\n";
    }
    else
    {
        for (std::size_t i = 0; i < modes.size(); ++i)
        {
            sf::VideoMode mode = modes[i];
            std::cout << "Mode #" << i << ": " << mode.size.x << "x" << mode.size.y << " - " << mode.bitsPerPixel
                      << " bpp" << std::endl;
        }
    }

    sf::RenderWindow win(sf::VideoMode(sf::Vector2u{800, 600}), "Test", sf::Style::Fullscreen);
    return 0;
}

Expected behavior

We should not see a segfault, but SFML is assuming it will always have a valid mode as a default (after it states “The requested video mode is not available, switching to a valid mode”) - but getFullscreenModes() is returning an empty vector, so it segfaults.

Actual behavior

Segfault owing to the empty vector.

Do please let me know if anything needs clarification.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 15 (8 by maintainers)

Most upvoted comments

I’ve read and re-read both this thread and the original forum thread a few times, while trying to find any solution or workaround for my project. I’ve also switched between SFML 2.5 and 3, as well as Mac M1 and non-M1 macs.

Here are some summaries/thoughts that occur to me so far. Some of this is deduction on my part, so please correct anything here that seems wrong!

  • A possible workaround, it sounds like, is to neuter one or two lines of code from SFML. From the forum thread:
    • Removing this continue allows the apparently-too-large-and-thus-invalid modes through, resulting in a non-empty vector being returned. This allows SFML to continue without crashing, though it still then resorts to a backup mode instead of whatever the user selects from that list.
    • This line seems to be responsible for the too-large resolutions above. Disabling this line seems to also work around the problem, at least insofar as making sure the returned vector is non-empty and that its values are valid. It’s not clear whether this actually works as far as giving the user the resolution he selects from the vector. Maybe someone could test this?
  • In the forum someone mentions this StackOverflow thread regarding CGDisplayModeGetWidth/Height’s inconsistent behavior and documentation. At first glance, it seems very likely to be related to this issue, if not a direct cause. But then if you read the full conversation in the thread, it’s implied that the OP of that question was just mistaken about his testing setup so… I don’t really know what to make of this - could be something, could be nothing.

And this might be unrelated but…

  • I was running into an issue that smells very related to this, on SFML 2.5 and non-M1 macs (wasn’t able to test at all with M1 macs until I upgraded to SFML 3.0). In these cases, the game would open in fullscreen mode, but SFML would end up “confused” about what the resolution was. It seemed to be that Mac never changed from its native resolution, but SFML thought it had. The result is that the game would render in a limited-size portion of the full screen, the size of the portion corresponding to the user’s chosen resolution. So if you tried a 1920x resolution on a Mac that had a ~3300x resolution, your full screen would be “captured” by the app but the game itself would still be rendered very small.
    • In these cases, I’ve tried but failed to find a way to simply detect what the actual resolution of the game is after the window is up, hoping that at the very least I could get the real situation and deal with it in code. So far I have not found a way to do that.