Hi everyone, first time poster here.
I’m making a cross-platform game engine of sorts with multiple rendering backends. A rendering backend is loaded dynamically at runtime, the engine itself has no idea what API it is using (i.e., it could be OpenGL, D3D, Vulkan, Metal, CUDA, etc).
I currently have two options for window management:
1, Create the SDL_Window in the engine core, and pass a pointer to a rendering backend when it is initialized. This is my preferred option as it would allow me to handle window resizing, fullscreen toggling, etc, in one place.
2, Let each rendering backend themselves handle the window management. This would ensure compatibility with each rendering API, but would likely lead to a lot of duplicated code. It would also mean that the output window would switch if the rendering backend is replaced with another one during runtime.
The reason I’m unsure about this choice is because of the SDL_WINDOW_OPENGL flag (https://wiki.libsdl.org/SDL_WindowFlags). From what I can find it makes it possible to create a OpenGL context for a given window, so the flag is necessary for an OpenGL based rendering backend. My question is then if specifying this flag locks you in to using only OpenGL? Or you can you specify SDL_WINDOW_OPENGL and then render using D3D, Metal or Vulkan instead?
TL;DR: If you specify SDL_WINDOW_OPENGL, can you still render using D3D, Metal or Vulkan?
Thanks in advance for any answers!
TL;DR: If you specify SDL_WINDOW_OPENGL, can you still render using D3D,
Metal or Vulkan?
no idea about that part, sorry…
However, I recently thought about the problem of where to create the
window etc when (re)introducing pluggable renderers into Yamagi Quake II
My solution was a function in the renderer that is called before the
window is created and that returns flags for SDL_CreateWindow().
So for OpenGL renderers it returns SDL_WINDOW_OPENGL, for other
renderers (that don’t currently exist in YQ2, we only have an old GL1
and a new GL3 renderer) it’d just return 0.
The returned flags are or-ed with whatever other flags I want to pass to
SDL_CreateWindow() (like SDL_WINDOW_FULLSCREEN or
SDL_WINDOW_FULLSCREEN_DESKTOP) and then used when creating the window.
After the Window has been created, I call an InitContext(window)
function in the renderer that will create the OpenGL context (and would
do something else or maybe nothing or I don’t know for other backends).
So most of the Window handling code is implemented only once in the
engine, and only the backend-specific parts are implemented in the
renderer (in our case there is some slight code duplication due to both
renderers using OpenGL).
If you wanna take a look, the relevant code can be found here:
Hey, thanks for the answer! That approach would definitely solve one of the problems (i.e. the one regarding code duplication).
One thing I hope to support is to hot-swap renderers (using different APIs) during runtime and output to the same window. This is of course not something you would want to ship in a real game, but I’d like it for development and debugging purposes. In other words, I’d like to create the window before I’ve initialized any renderer. And I’d like to be able to destroy the renderer and initialize another one without destroying the window. So I’m going to wait a bit more and see if someone knows the answer to my original question.
If it turns out option 1 is impossible I might go for your approach though.
Probably, but you shouldn’t risk it. On many platforms, we use this flag to do a bunch of tapdancing to get an OpenGL-compatible visual for the window, which may or may not interfere with other APIs.
@Daniel_Gibson’s advice here is good, I just want to add that (in 2.0.6) if you want a Vulkan renderer, you should use the new SDL_WINDOW_VULKAN flag to SDL_CreateWindow, and the new APIs that will help you set up a surface.
Direct3D and Metal can be used with an SDL window, if you use SDL_GetWindowWMInfo() to get the native window handle from an SDL_Window and then do the setup yourself, without any SDL_WINDOW_OPENGL or _VULKAN flag.
I suspected (but hoped it wouldn’t) be something like that. Probably not going to risk it then.
Anyway, huge thanks to both you and @Daniel_Gibson for the help!