libsdl-org / sdl12-compat

An SDL-1.2 compatibility layer that uses SDL 2.0 behind the scenes.
Other
197 stars 40 forks source link

SDL12COMPAT_GetWindow() handle is GL `un-renderable` on macOS #225

Closed kjliew closed 2 years ago

kjliew commented 2 years ago

SDL12COMPAT_GetWindow() returns SDL_Window handle which is GL un-renderable in SDL2 plugin on macOS.

A simple testcase is attached. The same code works fine on Windows 11 and Linux with an RGB triangle on blue background. On macOS only a window with black screen. testcase.zip

icculus commented 2 years ago
    if (argc == 2 && !strcmp(argv[1], "--darwin-fix"))
        flags = SDL_OPENGL;

In SDL 1.2 and SDL2, creating a usable GL context expects the window to be created with SDL_OPENGL (SDL_WINDOW_OPENGL in SDL2). I'm actually surprised this works on Windows and Linux without that flag.

In sdl12-compat, without SDL_OPENGL, this is probably setting up Direct3D on Windows and Metal on macOS when it makes a 2D renderer for the 1.2 screen surface.

kjliew commented 2 years ago

So, you actually read the code ... ๐Ÿ˜œand figured out the workaround for macOS.

In sdl12-compat, without SDL_OPENGL, this is probably setting up Direct3D on Windows and Metal on macOS when it makes a 2D renderer for the 1.2 screen surface.

You're right, but this is dealt with in the SDL2 domain by explicitly forcing an OpenGL renderer then destroying it. SDL2 then takes care of GL context on the window. In some cases, SDL2 may destroy the window and respawn it. After all sdl12-compat is SDL2 behind the scene.

    SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
    render = SDL_CreateRenderer(window, -1, 0);

In pure SDL2->SDL2 scenario, this works wonderfully so long as OpenGL is supported. Now it may sound like an undocumented SDL2 trick to obtain GL render capabilities. This trick is quite useful in plugin to avoid touching upper level codes to add SDL_WINDOW_OPENGL to the flag during window creation. The same trick works for SDL1.2->SDL2 through SDL_CreateWindowFrom() foreign window conversion as there is no other way to specify window creation flags.

The --darwin-fix has another caveats other than requiring SDL_OPENGL flag, it needs to register a callback in SDL2 domain for SDL_SwapBuffers(). Linux and Windows enjoys the cleaner approach once the codes landed in SDL2 without any caveats. For cross-platform library, it would be awesome to have the consistency for the same codes to work without too many platform-specific meddling.

Perhaps this could be an issue with SDL2 instead. I hope you find the testcase useful to showcase the inconsistency across Windows, Linux and macOS. If this is unfixable, then at least the behaviors as demo in the testcase would persist for future SDL2 and sdl12-compat development. Feel free to adopt the testcase to guard against any changes in SDL2 and sdl12-compat that would break it.

icculus commented 2 years ago

Okay, I spent some time poking around, and the best I can come up with (with my limited knowledge of Cocoa, mind you) is that either SDL breaks something when trying to move an existing window from a Metal view to an OpenGL context, or macOS itself has a bug because this isn't something that anyone has likely tried to do. It could be either!

BUT: here's my suggestion, which I think is the most reasonable solution:

Force the renderer to OpenGL before you call SDL_SetVideoMode:

SDL_putenv("SDL_RENDER_DRIVER=opengl");

This will do nothing on normal SDL 1.2 (as this affects SDL2's renderer api), and on sdl12-compat, it'll make the initial window OpenGL compatible on all platforms without creating a Direct3D/Metal/whatever context. If you use SDL_OPENGL, this will be ignored, since we won't create an SDL_Renderer, but if you need SDL_SetVideoMode to give you something that you can draw pixels to like a normal 1.2 SDL_Surface but also let you make OpenGL calls, this will do it, and it's considered legal for SDL2 to request the current GL context of an SDL_Renderer and make OpenGL calls in addition to (or instead of) any SDL 2D rendering, which means this can meet the plugin's needs.

So this should work: it removes the need to destroy/recreate an SDL_Renderer or GL context in the plugin, avoids needing the SDL_OPENGL flag explicitly, and gets the test case you posted working on my Mac.

Does this work for you?

kjliew commented 2 years ago

Cool, thanks! Yes, I think this will work. ๐Ÿ‘ I consider myself a noob on Cocoa/NSWindow, almost all the debug/trace took place on Windows/Linux. Hence, I depend on cross-platform libraries to be consistent in behaviors.

this is dealt with in the SDL2 domain by explicitly forcing an OpenGL renderer then destroying it. SDL2 then takes care of GL context on the window. In some cases, SDL2 may destroy the window and respawn it.

Somehow, this trick is broken with sdl12-compat and only on macOS. Luckily it works for SDL2->SDL2 and remains consistent across Linux, Windows and macOS. Hope you guys will adopt the testcase to keep the trick alive.

Thanks again!