BogdanB
BogdanB

Reputation: 1

bgfx init hangs without errors (MacOS)

I am trying to make a "Hello Quad" with bgfx and sdl2. I was able to open a window with sdl no problem, but when I tried adding simple bgfx starter my program hangs with no errors. Here is the full code:

#include <iostream>
#include <fstream>
#include <vector>
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>

#include <bx/math.h>

template <typename T>
void print(T t)
{
    std::cout << t << std::endl;
}

template <typename T, typename... Args>
void print(T t, Args... args)
{
    std::cout << t << " ";
    print(args...);
}

int main(int argc, char *argv[])
{
    print("program start");

    // Initialize SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    print("sdl inited");

    // Create a window
    SDL_Window *window = SDL_CreateWindow("bgfx with SDL2", 100, 100, 800, 600, SDL_WINDOW_SHOWN);
    if (window == nullptr)
    {
        std::cerr << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
        SDL_Quit();
        return 1;
    }

    print("window created");

    // Get the window's native handle
    SDL_SysWMinfo wmi;
    SDL_VERSION(&wmi.version);
    if (!SDL_GetWindowWMInfo(window, &wmi))
    {
        std::cerr << "Could not get window information! SDL_Error: " << SDL_GetError() << std::endl;
        SDL_DestroyWindow(window);
        SDL_Quit();
        return 1;
    }

    print("got window native handle");

    // Set up the bgfx platform data with the native window handle
    bgfx::PlatformData pd;
#if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
    pd.nwh = (void *)(uintptr_t)wmi.info.x11.window;
#elif BX_PLATFORM_OSX
    pd.nwh = wmi.info.cocoa.window;
#elif BX_PLATFORM_WINDOWS
    pd.nwh = wmi.info.win.window;
#endif

    print("connected bgfx and sdl");

    pd.ndt = nullptr;
    pd.context = nullptr;
    pd.backBuffer = nullptr;
    pd.backBufferDS = nullptr;

    print("prepared pd");

    bgfx::setPlatformData(pd);

    print("set pd");

    // Initialize bgfx
    bgfx::Init init;

    print("created bgfx init object");

    init.debug = BGFX_DEBUG_TEXT;
    init.type = bgfx::RendererType::Count; // Automatically choose the renderer
    init.resolution.width = 800;
    init.resolution.height = 600;
    init.resolution.reset = BGFX_RESET_VSYNC;

    print("set init object props");

    if (!bgfx::init(init))
    {
        std::cerr << "Failed to initialize bgfx!" << std::endl;
        SDL_DestroyWindow(window);
        SDL_Quit();
        return 1;
    }

    print("bgfx inited");

...
// main loop

    return 0;
}

The last debug statement that was printed to console is "set init object props"... Not the error message in case of failure or the next debug message in case of success. So I compiled the project (including sdl and bgfx) in debug mode and ran it with lldb and here is what I got:

program start
sdl inited
window created
got window native handle
connected bgfx and sdl
prepared pd
set pd
created bgfx init object
set init object props
2024-08-19 12:58:15.890213-0700 HelloQuad[35299:1439942] /Users/.../libs/bgfx.cmake/bgfx/src/bgfx.cpp (3417): BGFX bgfx platform data like window handle or backbuffer is not set, creating headless device.
2024-08-19 12:58:15.890234-0700 HelloQuad[35299:1439942] /Users/.../libs/bgfx.cmake/bgfx/src/bgfx.cpp (3449): BGFX Init...
2024-08-19 12:58:15.890248-0700 HelloQuad[35299:1439942] /Users/.../libs/bgfx.cmake/bgfx/src/bgfx.cpp (3456): BGFX Version 1.108.7238 (commit: 8065659e90a2673dd2ac4b12f193604a631833e3)
2024-08-19 12:58:15.891525-0700 HelloQuad[35299:1439942] /Users/.../libs/bgfx.cmake/bgfx/src/bgfx.cpp (1833): BGFX Creating rendering thread.
2024-08-19 12:58:15.891593-0700 HelloQuad[35299:1439942] /Users/.../libs/bgfx.cmake/bgfx/src/bgfx.cpp (1842): BGFX Running in multi-threaded mode
2024-08-19 12:58:15.891618-0700 HelloQuad[35299:1440041] /Users/.../libs/bgfx.cmake/bgfx/src/bgfx_p.h (2926): BGFX render thread start
2024-08-19 12:58:15.892255-0700 HelloQuad[35299:1440041] /Users/.../libs/bgfx.cmake/bgfx/src/renderer_mtl.mm (379): BGFX Init.

and that's it... it hangs. And when I pause execution during the hang:

Process 35299 stopped
* thread #1, name = 'bgfx - renderer backend thread', queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x000000018b26d7f0 libsystem_kernel.dylib`semaphore_wait_trap + 8
libsystem_kernel.dylib`semaphore_wait_trap:
->  0x18b26d7f0 <+8>: ret    

libsystem_kernel.dylib`semaphore_wait_signal_trap:
    0x18b26d7f4 <+0>: mov    x16, #-0x25
    0x18b26d7f8 <+4>: svc    #0x80
    0x18b26d7fc <+8>: ret    
Target 0: (HelloQuad) stopped.

I also found this from 10 years ago: https://github.com/bkaradzic/bgfx/issues/501, which says to add this directive: "BGFX_CONFIG_MULTITHREADED=0" So I tried it but it did not work - interestingly, the bgfx debug messages still said the same thing: "Running in multi-threaded mode", "render thread start", so I am not sure if that's because a 10 year old directive just might not do what it used to or am I messing up the compilation/linking (it was a bit complicated because I used the CMake not GENie version), but, since the code compiles and links perfectly fine, and I was able to open an sdl window just fine I ruled out that option.

I don't really know how to continue debugging this...

Upvotes: 0

Views: 121

Answers (1)

ichordev
ichordev

Reputation: 23

First thing's first, you should set the bgfx::PlatformData inside of the bgfx::Init struct, not separately. Since you are not setting init.platformData, when you call bgfx::init bgfx's platform data will be overridden with the (unset) value of init.platformData.

Second of all, the way you are setting nwh will not work for macOS. Instead, you need to call a few SDL functions on your SDL_Window pointer to get the pointer you're after:

nwh = SDL_Metal_GetLayer(SDL_Metal_CreateView(window));

On Linux/BSD you need to set ndt (native display type), and your code also assumed that the platform type would always correspond to a single window manager; however for Linux/BSD a user could be using X11 or Wayland, so I have changed it to a switch-case statement based on wmi.subsystem:

    bgfx::Init init;
    
    switch(wmi.subsystem){
        #if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
            case SDL_SYSWM_X11:
                init.platformData.nwh = (void*)(uintptr_t)wmi.info.x11.window;
                init.platformData.ndt = wmi.info.x11.display;
                break;
            case SDL_SYSWM_WAYLAND:
                init.platformData.nwh = wmi.info.wl.surface;
                init.platformData.ndt = wmi.info.wl.display;
                init.platformData.type = NativeWindowHandleType::Wayland;
                break;
        #elif BX_PLATFORM_OSX
            case SDL_SYSWM_COCOA:
                SDL_MetalView view = SDL_Metal_CreateView(window);
                init.platformData.nwh = SDL_Metal_GetLayer(view);
                break;
        #elif BX_PLATFORM_WINDOWS
            case SDL_SYSWM_WINDOWS:
                init.platformData.nwh = wmi.info.win.window;
                break;
        #endif
        default:
            print("Your windowing subsystem is not supported on this platform!");
            quit();
    }
    
    init.debug = BGFX_DEBUG_TEXT;
    init.type = bgfx::RendererType::Count;
    init.resolution.width = 800;
    init.resolution.height = 600;
    init.resolution.reset = BGFX_RESET_VSYNC;
    
    bgfx::init(init);

Please note that even though the above code has a case for Wayland on Linux/BSD, it will never normally execute because SDL2 will always default to starting with X11 even when the user's window manager is Wayland. To remedy this, on Linux/BSD you should always attempt to initialise SDL with the "wayland" video driver first:

SDL_Init(0);
#if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
    bool wayland = SDL_VideoInit("wayland") == 0;
    if(!wayland) SDL_VideoInit(nullptr);
#else
    SDL_VideoInit(nullptr);
#endif

(Any error-handling has been omitted for brevity)

Upvotes: 2

Related Questions