Skip to content

Hidden SDL_Window* used as shared GL context fails on Emscripten #12678

Open
@vittorioromeo

Description

@vittorioromeo

I have ran into another issue while implementing an SDL3 backend for my fork of SFML.

The design of the library involves the creation of a shared GL context at the beginning of main that allows resources such as textures and shaders to be reused by multiple GL contexts.

With a bespoke per-platform implementation of OpenGL contexts, this approach works well on every platform. Notably, I create a dummy context in this way for Emscripten + OpenGL ES:

EGLNativeWindowType dummyWindow{};
m_surface = eglCreateWindowSurface(m_display, m_config, *static_cast<EGLNativeWindowType*>(windowPtr), nullptr);
constexpr EGLint contextAttribs[]{EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE};
eglCreateContext(m_display, m_config, toShared, contextAttribs);

I'm in the process of removing all of these bespoke per-platform implementations with a single portable SDL3-based GL context implementation. Because every SDL3 OpenGL context requires to be associated with a window, I am using a hidden window to create my shared context:

sharedCtxWindow = SDL_CreateWindow("", 1, 1, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN);

This works great on every platform, but fails catastrophically on Emscripten. The hidden window is created successfully, but upon attempting to create the second window, an error like this one is produced in the browser:

Uncaught ErrnoError: File exists
    ErrnoError http://localhost:6931/x.js:2007
    mknod http://localhost:6931/x.js:2554
    mkdir http://localhost:6931/x.js:2600
    165439 http://localhost:6931/x.js:860
    runMainThreadEmAsm http://localhost:6931/x.js:4098
    _emscripten_asm_const_int_sync_on_main_thread http://localhost:6931/x.js:4100
    createExportWrapper http://localhost:6931/x.js:677
    callMain http://localhost:6931/x.js:9436
    doRun http://localhost:6931/x.js:9489
    run http://localhost:6931/x.js:9498
[x.js:2007:11](http://localhost:6931/x.js)

Unfortunately, it would be very difficult for me to change the design of the library, which revolves around the idea of a shared context installed at the beginning of main. At this point I am considering not using SDL3 to create OpenGL contexts and keeping the bespoke implementations, which is a bit of a pain...

I have created a MVCE here:

#include <SDL3/SDL.h>
#include <SDL3/SDL_timer.h>

#include <iostream>

int main()
{
    if (!SDL_Init(SDL_INIT_VIDEO))
    {
        std::cerr << "SDL_Init Error: " << SDL_GetError() << '\n';
        return 1;
    }

    auto sharedCtxWindow = SDL_CreateWindow("", 1, 1, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN);
    if (sharedCtxWindow == nullptr)
    {
        std::cerr << "Failed to create shared context hidden window:" << SDL_GetError() << '\n';
        return 1;
    }

    auto sharedCtx = SDL_GL_CreateContext(sharedCtxWindow);
    if (sharedCtx == nullptr)
    {
        std::cerr << "Failed to create shared GL context:" << SDL_GetError() << '\n';
        return 1;
    }

    auto window = SDL_CreateWindow("Example", 640, 480, SDL_WINDOW_OPENGL);
    if (window == nullptr)
    {
        std::cerr << "Failed to create window:" << SDL_GetError() << '\n';
        return 1;
    }

    auto windowCtx = SDL_GL_CreateContext(window);
    if (windowCtx == nullptr)
    {
        std::cerr << "Failed to create window GL context:" << SDL_GetError() << '\n';
        return 1;
    }

    if (!SDL_GL_MakeCurrent(sharedCtxWindow, sharedCtx))
    {
        std::cerr << "Failed to activate shared GL context: " << SDL_GetError() << '\n';
        return 1;
    }

    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);

    if (!SDL_GL_MakeCurrent(window, windowCtx))
    {
        std::cerr << "Failed to activate window GL context: " << SDL_GetError() << '\n';
        return 1;
    }

    SDL_Event event;

    while (true)
    {
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_EVENT_QUIT)
            {
                return 0;
            }
        }

        SDL_GL_SwapWindow(window);
        SDL_Delay(10);
    }
}

To compile and run:

em++ sdlbug.cpp --use-port=sdl3 -o x.html
emrun ./x.html

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions