libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
9.64k stars 1.79k forks source link

SDL_GL_CreateContext failing on MacOS Monterey #5912

Closed ooshlablu closed 2 years ago

ooshlablu commented 2 years ago

The Performous project (https://github.com/performous/performous) has been running into an issue with SDL_GL_CreateContext specifically on MacOS Monterey systems (any version). We are able to reproduce the issue with both local builds and releases produced via github actions: (https://nightly.link/performous/performous/workflows/build_and_release/master/Performous-latest.dmg.zip). Previous versions of MacOS work fine.

We are unable to diagnose the issue and are looking for advice from the community, specifically if others have seen this issue, or if there has been a fundamental shift in using SDL on Monterey that we may have missed.

Attached is an image of the exception and the output that was caught.

Screen Shot 2022-07-11 at 10 00 40 AM

Lord-Kamina commented 2 years ago

Here's the function that created the window:

Window::Window() : screen(nullptr, &SDL_DestroyWindow), glContext(nullptr, &SDL_GL_DeleteContext) {
    std::atexit(SDL_Quit);
    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK))
        throw std::runtime_error(std::string("SDL_Init failed: ") + SDL_GetError());
    SDL_JoystickEventState(SDL_ENABLE);
    { // Setup GL attributes for context creation
        SDL_SetHintWithPriority("SDL_HINT_VIDEO_HIGHDPI_DISABLED", "0", SDL_HINT_DEFAULT);
        GLattrSetter attr_r(SDL_GL_RED_SIZE, 8);
        GLattrSetter attr_g(SDL_GL_GREEN_SIZE, 8);
        GLattrSetter attr_b(SDL_GL_BLUE_SIZE, 8);
        GLattrSetter attr_a(SDL_GL_ALPHA_SIZE, 8);
        GLattrSetter attr_buf(SDL_GL_BUFFER_SIZE, 32);
        GLattrSetter attr_d(SDL_GL_DEPTH_SIZE, 24);
        GLattrSetter attr_db(SDL_GL_DOUBLEBUFFER, 1);
        GLattrSetter attr_glmaj(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        GLattrSetter attr_glmin(SDL_GL_CONTEXT_MINOR_VERSION, 3);
        GLattrSetter attr_glprof(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
        Uint32 flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
        if (config["graphic/highdpi"].b()) { flags |= SDL_WINDOW_ALLOW_HIGHDPI; }
        else { SDL_SetHintWithPriority("SDL_HINT_VIDEO_HIGHDPI_DISABLED", "1", SDL_HINT_OVERRIDE); }
        int width = config["graphic/window_width"].i();
        int height = config["graphic/window_height"].i();
        int windowPosX = config["graphic/window_pos_x"].i();
        int windowPosY = config["graphic/window_pos_y"].i();
        int displayCount = SDL_GetNumVideoDisplays();
        if (displayCount <= 0) {
            throw std::runtime_error(std::string("video/error: SDL_GetNumVideoDisplays failed: ") + SDL_GetError());
        }
        SDL_Rect totalSize;
        if (displayCount > 1) {
            totalSize.x = 0;
            totalSize.y = 0;
            totalSize.w = 0;
            totalSize.h = 0;
            int displayNum = 0;
            SDL_Rect displaySize;
            SDL_Rect prevTotal;
            while (displayNum < displayCount) {
                if (SDL_GetDisplayBounds(displayNum, &displaySize) != 0) {
                    throw std::runtime_error(std::string("video/error: SDL_GetDisplayBounds failed: ") + SDL_GetError());
                }
                prevTotal.x = totalSize.x;
                prevTotal.y = totalSize.y;
                prevTotal.w = totalSize.w;
                prevTotal.h = totalSize.h;
                SDL_UnionRect(&prevTotal, &displaySize, &totalSize);
                ++displayNum;
            }
        }
        else {
            if (SDL_GetDisplayBounds(0, &totalSize) != 0) {
                throw std::runtime_error(std::string("video/error: SDL_GetDisplayBounds failed: ") + SDL_GetError());
            }
        }
        SDL_Point winOrigin {windowPosX, windowPosY};
        if (SDL_PointInRect(&winOrigin, &totalSize) == SDL_FALSE) {
            if (winOrigin.x < totalSize.x) { winOrigin.x = totalSize.x; }
            else if (winOrigin.x > totalSize.w) { winOrigin.x = (totalSize.w - width); }
            if (winOrigin.y < totalSize.y) { winOrigin.y = totalSize.y; }
            else if (winOrigin.y > totalSize.h) { winOrigin.y = (totalSize.h - height); }
            std::clog << "video/info: Saved window position outside of current display set-up; resetting to " << winOrigin.x << "," << winOrigin.y << std::endl;
        }
        SDL_Point winEnd {(winOrigin.x + width), (winOrigin.y + height)};
        if (SDL_PointInRect(&winEnd, &totalSize) == SDL_FALSE) {
            if (winEnd.x > totalSize.w) {
            width = totalSize.w;
            winOrigin.x = (totalSize.w - width);
            }
            if (winEnd.y > totalSize.h) {
            height = totalSize.h;
            winOrigin.y = (totalSize.y - height);
            }
            std::clog << "video/info: Saved window size outside of current display set-up; resetting to " << width << "x" << height << std::endl;
        }

        if (winOrigin.x == 0)
        {
            winOrigin.x = SDL_WINDOWPOS_UNDEFINED;
        }
        if (winOrigin.y == 0)
        {
            winOrigin.y = SDL_WINDOWPOS_UNDEFINED;
        }

        std::clog << "video/info: Create window dimensions: " << width << "x" << height << " on screen position: " << winOrigin.x << "x" << winOrigin.y << std::endl;
        screen.reset(SDL_CreateWindow(PACKAGE " " VERSION, winOrigin.x, winOrigin.y, width, height, flags));
        if (!screen) throw std::runtime_error(std::string("SDL_CreateWindow failed: ") + SDL_GetError());
        glContext.reset(SDL_GL_CreateContext(screen.get()));
        if (glContext == nullptr) throw std::runtime_error(std::string("SDL_GL_CreateContext failed with error: ") + SDL_GetError());
        if (epoxy_gl_version() < 33) throw std::runtime_error("Performous needs at least OpenGL 3.3+ Core profile to run.");
        glutil::GLErrorChecker error("Initializing buffers");
        {
            initBuffers();
        }
    }
    SDL_SetWindowMinimumSize(screen.get(), 640, 360);
    SDL_GetWindowPosition(screen.get(), &m_windowX, &m_windowY);
    // Dump some OpenGL info
    std::clog << "video/info: GL_VENDOR:     " << glGetString(GL_VENDOR) << std::endl;
    std::clog << "video/info: GL_VERSION:    " << glGetString(GL_VERSION) << std::endl;
    std::clog << "video/info: GL_RENDERER:   " << glGetString(GL_RENDERER) << std::endl;
    // Extensions would need more complex outputting, otherwise they will break clog.
    //std::clog << "video/info: GL_EXTENSIONS: " << glGetString(GL_EXTENSIONS) << std::endl;
    createShaders();
    resize();
    SDL_ShowWindow(screen.get());
}
icculus commented 2 years ago

Tried this on Monterey 12.5 with the Performous-latest.dmg.zip build and it worked correctly.

Has this changed in the last two weeks in some way?

I'm on an M1 Mac Mini, so this build would be using the x86-64 Rosetta emulator for me, if that makes a difference.

a-hurst commented 2 years ago

I'm still running Monterey 12.4 on my M1 MBP and SDL_GL_CreateContext works perfectly fine with PySDL2 using the official ARM-native libSDL macOS binaries (both 2.0.22 and the 2.23.1 pre-release), so I don't think a recent macOS change or architecture issue is the problem here.

Screen Shot 2022-07-27 at 11 35 28 AM

Maybe it's something to do with how the OpenGL context is being requested/set up? With OpenGL being deprecated on modern macOS there are a few weirdnesses you run into with the Metal compatibility layer.

icculus commented 2 years ago

@ooshlablu Is there a specific machine this triggers on? A specific MacBook, iMac, whatever?

ooshlablu commented 2 years ago

I was able to trigger it on a 2015 and 2017 mac book pro when I opened the issue. I am no longer able to trigger it with our most recent builds... There were a few things merged over the past couple of weeks, but I don't think anything that was purposefully targeted at resolving this issue.

icculus commented 2 years ago

Ok, for now I'm going to close this, but please comment here if it pops back up and I'll reopen for further investigation!