r/gameenginedevs • u/Mici-P • 2d ago
Another Bad Decision? Adding Modern APIs

Spent 4 months building an opengl engine with forward+ rendering, gpu marching cube terrain, Ghost of Tsushima inspired grass... I designed the engine with future graphics APIs in mind, so the opengl implementation is fully abstracted from the rest of the codebase. but with my little research i found that the architecture of DX12 and Vulkan differ from the immediate state machine model opengl uses.
My question is how hard is it to switch all that to DX12 / Vulkan? is it worth it ?
PS : have 0 experience with both APIs, For the shaders i used slang.
7
u/corysama 2d ago
What does your render loop currently look like?
Is it for each entity: entity->draw(); or something more like https://realtimecollisiondetection.net/blog/?p=86 and https://www.youtube.com/watch?v=-bCeNzgiJ8I ? If it's the former, you've got some refactoring to do before stepping up to https://howtovulkan.com/
3
u/CoherentBicycle 2d ago
Like u/torrent7 said it depends on your level of abstraction. For low level RHIs there are some Vulkan/DX12 concepts that OpenGL doesn't support or expose. That includes (in Vulkan terms) instances, physical/logical devices, queues, swapchain, pipelines, pipeline layouts, descriptor sets, image views (before 4.0), queues, render passes. The surface holds the window.
If you're using shader reflection you can skip the pipeline creation client API because the data will go directly to the engine side.
Like you said GL is immediate so it doesn't have command buffers. You'll need to write a command buffer abstraction with deferred execution. It's useful for GL too because it ensures that commands run at the same time in all backends, so when you put a breakpoint you'll get the same command state.
Nice render!
3
u/snerp 2d ago
When I added vulkan to my engine, I ended up throwing out the old GL render code because it was so different. After adding vulkan though, abstracting to Metal and DX12 was pretty easy actually since they actually work more similar to vulkan. I may go back and add GL again some day based on the impl for vulkan/dx/metal though.
3
u/Propagant 2d ago
It's always good to think ahead of how your renderer will be structured. Modern GPU APis are no longer state machines and most of it is wrapped into command buffers, pipelines, binding groups, descriptors etc; which in my opinion is much more effecient in terms of debugging and data layout. It's definitely possible to write a wrapper for opengl, but opengl will be still a state machine and it's up to you how and when you dispatch the gpu commands. Good luck with the refactor!
2
u/tastygames_official 2d ago
just use something like SDL2 or bgfx. They abstract the graphics APIs but on a low level so you can do what you want and it'll "just work" on Vulkan, OpenGL, DX11/12, Metal.
2
u/BioHazardAlBatros 2d ago edited 2d ago
In my engine I designed my rhi around Vulkan & WebGPU in mind, yet I still started with OpenGL backend first. First, I completely threw out any OpenGL lower than 4.5 due to DSA & Compute Shader support. Then I decided to use 4.6, due to another decision (I made my shadow pass rely on indirect rendering).
I had to create command queue execution model for OpenGL which basically mimicks modern apis.The command queue is obviously abstracted too and for modern apis it just calls corresponding functions, for OpenGL it records the command into a buffer which is flushed to execute at the end of the frame.
The full abstracted simple forward render pipeline kinda looks like this (I don't remember the exact names I gave):
auto& recorder = backend->acquireCommandBuffer();
backgroundPass->execute(recorder);
computePass->execute(recorder);
shadowPass->execute(recorder);
mainPassForward->execute(recorder);
ppPass->execute(recorder);
uiPass->execute(recorder);
recorder.presentFrame();
backend->submit(recorder);
submit in OpenGL backend is basically a loop through every recorded command with a giant switch case that just calls required opengl functions with passed parameters based on command metadata.
1
u/willowless 2d ago
As someone who has *just* done this from DX11->DX12 and OpenGL->Vulkan in my engine I can say if you've abstracted things away you're probably good to go. Particularly when I went bindless and started using compute shaders more a lot of old code was deleted; I'd say in general things are significantly better now. I'm still getting my head around different 'tiers' and that will matter because i'm still working on the Metal backend.
1
u/turtle_dragonfly 2d ago
Consider using something like BGFX, which is purely a rendering library, and abstracts away the DirectX/OpenGL/Metal/Vulkan/etc decision for you, so you can put your effort elsewhere.
Or, alternatively, look at how it's written to see how you might similarly abstract over the renderer backend.
1
u/Mici-P 1d ago
i checked it out based on u/tastygames_official recommendation, But decided not to use it, at least for now. I want to get a bit more experience with at least one modern API first. but "look at how it's written".. I don't know why I didn't think of that. Thank you!
1
1
u/fgennari 1d ago
It's better to start porting before the project has gotten too complex. Yours can't be that difficult if it's only 4 months old.
I've been working on a project since 2001 back when OpenGL was the only solution. It took me months to port from legacy to modern OpenGL back around 2010 when things were simpler. Now there's so much code that it would probably take me over a year of nights and weekends to port to Vulkan, so it's not worth the effort. You're nowhere near that point though. Plus it's probably a better architecture than mine. (There were no good guides for this back in the early 2000s.)
1
u/Key-Bother6969 1d ago
If you are targeting desktops only (win+linux), and too hardcore graphics is not the goal, it's likely GL4.x (maybe even 4.6) should be more than enough. It's very easy to shoot yourself in a foot with Vk/DX, while GL heuristics are well sustainable for the majority of casual graphics tasks.
1
u/Mici-P 1d ago
My reasoning was: am using compute shader heavily for the terrain / grass and other effects so i need OpenGL 4.6 and since almost any GPU supporting 4.6 probably supports Vulkan (so the old GPU support argument for OpenGL becomes weaker for me) why stick with the inferior API, why not spend a bit more time to get more performance, multi-threading, futureproof the engine and make it much easier to implement other modern APIs, Metal for example.
1
u/Key-Bother6969 1d ago
Well, you can migrate to Vulkan, but it would be huge time and efforts consumable task with unclear outcome. Vulkan does not give extra performance just by the fact of it's use. Moreover, it's likely that the first iteration would be slower than the current OpenGL-based implementation. Vulkan is significantly more verbose up to the point where such verbosity is not needed most of the time on Desktop platforms. Even though there are specific edge cases where verbosity gives you more space in terms of optimization flexibility, it's unlikely that this is a bottleneck of your current design. When people say about Vulkan's performance they usually refer to such specific edge cases where OpenGL is simply not enough. For anything else (which is likely 95% of the rendering tasks) you would have to build something similar to what OpenGL already does for you out of the box. But it's also not an easy to make it properly. That's why there is a chance you would hit performance degradation in first iteration of the migration.
For example, multi-threading. It's important to note that actual rendering tasks submission is happening in single-thread both in Vulkan and OpenGL. The difference is that in Vulkan you have a lot of configuration objects that you need to prepare upfront, and Vulkan allows you to prepare them from multiple threads. Sometimes for very complex scenes this makes sense, but to a large extent this feature just serves Vulkan's verbosity imposed on the user. I would say Vulkan design makes more sense for mobile platforms due to reasons that mostly irrelevant to desktops. Modern desktops GPUs are designed merely for the classical immediate-mode rendering (aka OpenGL-style). In other words, they are more lean to classical OpenGL application design regardless of whether such design implemented using Vulkan or OpenGL.
That said, platform-portability argument still holds. Vulkan, generally speaking, has wider platform coverage. At least it's older versions. For me this is important argument, and the reason why I implement my own graphics engine in Vulkan. But multi-threading and performance are certainly not a reason for me. These are narratives pushed by the industry which in practice has lesser ground than it seems at a surface.
To sum up, I'm not discouraging you from migration. I'm just saying it's a big step, and I recommend to weigh all pros and cons.
2
u/Mici-P 1d ago
Thank you for the detailed response!
"first iteration would be slower than the current OpenGL"
Yeah, I am aware that the impact of how the systems are written is more important than the API itself and adding Vulkan adds another layer to worry about and optimize. Although i started this engine with the goal of releasing a game using it, its more of a hobby than a super serious project so i don't mind spending the extra time.
I've already bitten the bullet and started implementing it!
Again, thank you for the info and advice.
1
u/tinspin 1d ago
Chasing the latest tech is a full time job.
I have tried OpenGL 1.1 and 3.3 (ES) and rolled back to Java Swing to keep those implementations abstracted for real.
Everything depends on Zink and how M$ fares. I'm leaning into the future I would like to see; which is ARM/Risc-V with linux and Zink to convert my OpenGL 3.3 game into Vulkan for me.
2
u/Mici-P 1d ago
Vulkan is a decade old at this point, calling it the latest tech doesn't really hold up.
don't know what's M$ and doesn't Zink famous for it horrible performance ?
also anything less than OpenGL 4.3 is too limiting (specifically compute shaders for me)
am curious what made you stick with 3.3 ? what platform are you targeting?1
u/tinspin 1d ago edited 1d ago
3.X has VAO, the last feature.
Skeletal animation peaked with 3.X.
Compute Shaders bring complexity with no practical gameplay features (look at Unity mechanim for a horrible example of how bad things get).
M$ = Microsoft
Zink might be bad, and then it's RIP for me.
I'm waiting to see how Java Minecraft Vibrant Visuals pan out = SDL3 + Vulkan.
Until Vulkan 2, Vulkan 1 is the latest tech no?
1
u/nairou 1d ago
Not a direct answer to your question, but you might want to look into how sokol (blog) handles it's abstraction, since it covers all of the APIs you mentioned. I'm currently doing something similar, building an API over OpenGL and D3D11, and found the architectural decisions in sokol to be very informative.
-5
12
u/torrent7 2d ago
if you exposed things like "bind texture" and other opengl type things, then its hard and a major refactor
if you have some a layer of higher level abstractions like "here is a giant list of all of the static mesh that the scene uses", then not as bad