Abandoning Vulkan

posted in Moonlight coffee
Published April 07, 2023
Advertisement

About the author, or why you should care about what I do or do not do with the Vulkan API

I am a professional programmer, but I do not develop games for a living. In the past, I have brought you the fine small3d game development library, open source titles like Gloom, Avoid the Bug and Frog Remixed (the latter two are now archived and offline). More recently I have used the aforementioned small3d game development library to release the fine masterpiece Islet Hell across Windows, Linux, MacOS, Android and iOS.

What is this small3d game development library?

I wanted my titles to be cross-platform and open source ever since I started out with 3D game development (as a hobby). I had heard about “writing games not engines”, a popular concept at the time (you can read more about that here) and I started out trying to make a game involving a bug, chasing a goat. Given my modest 3D modeling skills the bug ended up looking like a crow but, in any case somehow I got it done while learning OpenGL.

Avoid the Bug game

While working on this Avoid the Bug title, I could not help but notice that 3D game development without a game engine is a lot of work. There is so much time that needs to be spent writing the code that loads models, renders them on the screen and animates them that it would not be very efficient to be doing it again and again every time one codes a new title. I think that it is for that reason that a lot of developers tend to use an engine like Unity or Unreal these days. Wanting to do things almost from scratch (I say almost because I still use libraries like glfw or libpng) was getting out of fashion. But since I went down that road I decided to extract an engine from that first game I made so that I would not need to code everything again when I would produce my next game. This is how small3d came to be and, as a matter of fact, if you read the above mentioned article your will find that that was pretty much the idea it was supporting too. I was calling small3d an “engine” in the beginning, but it is really just a library that I have been maintaining and extending ever since while using it to make my games.

Where does Vulkan fit into all of this?

To cut a long story short, soon after small3d was launched and I was happily working on my open source game projects, I came across the news about Vulkan in 2016. It sounded great. I learned that it was a brand new API, forged in the industry, low level and “clean”, here to save us from the hot mess that OpenGL had become.

To be perfectly honest, I was not thrilled with the news that there was more to learn about cross platform 3D development APIs beyond OpenGL, with which I had only recently managed to familiarise myself. But the way Vulkan was presented was quite compelling. It was the future of Android, it allowed multi-threaded programming, known developers were praising its many qualities. Also it was a bit of a challenge. “Forget about the hand-holding OpenGL has gotten you used to”, they said. With Vulkan you would have to totally control the GPU. Vulkan would make you a grown-up. And just in case anyone had any doubts about how soon we should get our hands dirty with it, companies were asserting that “your device is ready”. Presumably they were already supporting it since before we even knew it existed. I am exaggerating but that was the feeling I was getting.

Granted, Khronos and anybody who was somebody in the open 3D API standards universe were reassuring about OpenGL. We were told that OpenGL would be around for a long time, if not forever. But there was always a sign that we should not remain too comfortable with it. Apple deprecated it (in favour not of Vulkan but Metal, but Vulkan comes with MoltenVK, which translates its commands to Metal, allowing it to run on MacOS and iOS). Google Stadia (don’t laugh) was going to have Vulkan center stage (pun intended). A bunch of companies were laying out plans to migrate to Vulkan “soon”. Interviews about the woes of OpenGL would just not stop. There was also a testimonial somewhere about driver developers having to code around known game bugs from the driver side because game developers just could not learn to use OpenGL properly.

At the same time, I could not help but notice that a lot of fellow hobbyist developers were not too eager to learn Vulkan. It seemed like too much work and some were even accusing it of being unrealistically cumbersome to the programmer. Nonetheless, given the fact that my game library is quite limited in features and because one of my priorities is to ensure that it runs on as many different hardware platforms as possible, I decided to get into it. I worked through the Vulkan Tutorial, I wrote a C helper library for Vulkan to facilitate plugging it into small3d and I implemented all my existing graphics features that were already developed in OpenGL, also in Vulkan.

Things went pretty much ok over the next couple of years. I was maintaining my OpenGL renderer and my Vulkan renderer in parallel, making sure that they are at feature parity. It was easy to switch a game build from OpenGL to Vulkan and vice versa without any changes in the code. I always did have a feeling that maybe I was doing a bit too much work but I thought it was worth it. OpenGL would keep my titles running on older devices and Vulkan would be great for newer ones and would ensure that my games run everywhere in the future, if OpenGL stops being supported someday. I was noticing that Vulkan would just not get tamed though and that was not because of its complexity with regard to OpenGL. Time and time again, some GPU would freeze and would require a trivial change in the code to sidestep the issue, or the image rendered on some screen would be corrupted and, once again, a change of the code from one way of doing things into another one, both correct, would allow me to move on. I found this a bit contradictory. Vulkan was supposed to give us responsibility for our GPU programming, thus making it easy for vendors to avoid driver bugs and quirks.

What went wrong?

A big realisation came in the summer of 2022. It was at that time that I actually released a game, not as open source on GitHub, but as a commercial title on Steam, the Apple App Store and Google Play. Don’t be dazzled by the “commercial title” characterisation. It is still just a little hobby game, for which I am charging a modest amount, just to get an experience of actually selling something.

No matter how unambitious I am about my game development career, I am quite interested in doing the few things I actually do reasonably well. So, I hate the thought of somebody paying 1 euro or dollar for a game only to have it crash on their computer or phone. So I have tried, as much as possible, to ensure that Islet Hell, the game I have released, would run properly on as many devices I could get my hands on. I have provided free copies to friends and strangers and I have also collected old phones and laptops to install and test the game myself. The experience was devastating as far as Vulkan is concerned. I started out only providing an OpenGL version for the PC for Windows and Linux because I had seen more than enough desktop machines missing a Vulkan driver. But for MacOS, iOS and Android I provided only Vulkan binaries, encouraged by the support for the API I had witnessed on my own devices and by how well MoltenVK (the Vulkan to Metal translation layer) worked at home. I assumed that if I made my title available only for Androids running the version of the operating system that is supposed to support Vulkan, all would be fine.

The glitches I witnessed on many machines I tested the game on made me seriously reconsider. I have to say that the first system to go was the Android. I do not want to name specific vendors in this text, but the support for Vulkan in many cases, even if “officially” certified, is abysmal, to the point of shaders crashing just because I have put an extra variable somewhere or because I have not used a data type that the driver likes (even though it is correct according to the documentation). There was even one feature (skeletal animation) which I was just not able to code in GLSL for Vulkan. Granted, my game is not actually using it, but I still had to deactivate it in the small3d library because just by being available it would make the driver crash. The situation with Apple devices was marginally better. MoltenVK is quite decent. But I still got a sticky issue with all graphics disappearing from the screen sometimes that I just could not resolve.

Even though I am not providing many technical details in this article, I can assure you that I have tried very hard to get to the bottom of all of these problems that I am mentioning. I have managed to resolve some and for others I have found evidence that they actually are unresolved issues of the implementation of Vulkan on some devices. I am not blaming anyone for this, I understand that Khronos is trying to do a good job formulating the standard and that the vendors will get it right at some point. But it is just not something I feel I can trust right now. If you would like to check whether or not I know what I am doing, please feel free to review the last commit in small3d’s source code that actually supports Vulkan.

Also please feel free to contact me, or add a comment here below if you would like specific examples of the issues I am mentioning above and I will provide them. I would consider a swarm of more capable developers coming here and proving me wrong on every point a happy outcome that will make me reconsider my position.

In any case, all of the above mentioned problems would just magically disappear, every time I replaced the Vulkan renderer with OpenGL (or OpenGL ES on mobile). The OpenGL(ES) renderer was super easy to get right and it just would not crash under any circumstance, not even on Apple where it is supposedly deprecated. So my commercial title ended up running on OpenGL everywhere by the time it got to be stable (or on OpenGL ES in the case of mobile).

The Finishing Blow

Despite all these troubles, I did not even think of removing Vulkan from small3d a few months ago. I thought it was still a good investment in the future. However, lately I have seen some announcements about the newly released VK_EXT_shader_object extension for Vulkan. It was followed by Vulkan heavyweights expressing their opinion that programming with pipelines was not good (yes, pipelines, that thing I have spent hours and hours learning how to program). On top of that there are some comments, again from developers much more important than myself, that we need a new Vulkan version to clean up the mess that has accumulated in the API so far, and that for what was a “new clean API” a few years ago. There is also an announcement about an effort to improve the documentation.

All of this kind of makes me think that what we have here is not at all a new future-proof API that we just need to get used to before we can get on with efficiently coding more robust applications. We have an API just like the others, with its pros and cons, and issues that need resolving.

Considering the time I have been spending on trying to maintain the Vulkan renderer in parallel with the OpenGL one, and the complexity managing the two has added to my codebase, I have decided that the best thing to do for now is to just stop supporting Vulkan.

I would like to make it clear that I am not saying that Vulkan is a bad API. Neither that it does not have a future. A hobbyist graphics / game developer like me could not even pretend to be able to make such a statement with any credibility. I have seen what teams of professionals have done with Vulkan, in Red Dead Redemption II for example. I am just saying that it is not something that can be used for my purposes. small3d is supposed to let C++ enthusiasts code games in the language they love, using a minimalist support infrastructure that allows those games to run anywhere. The problem is that, with Vulkan, the games will just not do that (run everywhere). A lot of old or low budget devices do not have implementations that are good enough yet. And with the new effort to reorganise the API, I predict that it will be very long before devices like these will get any reasonable amount of stability.

I could keep Vulkan around indefinitely but I would rather use the time that would have taken to do other things. For example I could focus on writing another game, or work on improving my lighting (I am only using Gouraud shading for the time being), and that without having to implement or test everything I do on two APIs, one of which is guaranteed to fail on many pieces of hardware. And since it does fail, that means that even if I keep the Vulkan renderer functional only in some testing environments, I cannot use it in production for the foreseeable future. To quote a character from an 80s movie that I still remember, “a weapon unused is a useless weapon”.

2 likes 6 comments

Comments

Josh Klint

Yes, rendering pipelines suck. You end up just putting all your settings into a sortable container and then using an STL map to retrieve them each time they are used, something the driver could easily do. Technically it makes the driver faster, but it's just shifting that load onto your application.

Thank god they remove render passes or I would not have been able to finish my engine.

April 26, 2023 12:09 PM
dimi309

@Josh Klint Agreed. The drawback I am discussing is the time it will take for all these radical improvements to be supported on older (if ever) or low-budget devices.

April 26, 2023 01:36 PM
Geri

This is how i see:

OpenGL is crappy, but its STILL magnitudes better than anything else, including vulkan, metal, directx whatever version.

Why? Because when opengl was designed, the main focus was to give a super easy to use, opensource, platform independent, flexible, extension based, coherent procedural library to the people. Pretty much everything that was released in the last 25 years supports at least an early version of it. This means that an opengl based game engine can support wide variety of hardware and platforms easily even within the same code.

It succesfully outlived every other api. DirectX gets fully rewritten once in a while, support for old versions get removed/deleted after a while. glide, cif, s3d, and other apis died off quickly. OpenGL is a backwards and forward compatible workhorse, which doesnt needs special fuel, just some hay and straw.

The first radical attempts arised when they tried to break the api into two (classic opengl init VS core profiles) for fake and shoddy reasons. Luckily they were not able to do it, and the normal opengl supports the newest features through the extension system. When these lobbysts realized they will not be able to push their ways into the api, they decided to create a new modern, threaded, resource-flow based api for themself, called vulkan, quite similar in conception to directx 12. Which is totally fine by me, as i will never lay my hands on vulkan or dx12 ever.

OpenGL is bugous for sure, the game will have different bugs and behave differently on every platforms and every generations of video cards. But what is the solution? DirectX12? It not even works on most of the machines at the end users yet, barely anything has even made for it despite its a 7+ year old api. Vulkan? That isnt supported widely either. DirectX9? Thankyou but thats super limited and slow, so then i'd still have to do some version of opengl for phones and linux. Software rendering? Yes, thats what i was went in instead, and now really i am the one who controls what happens in the rendering.

The thing is, if someone goes with vulkan or directx, he still have to do an opengl path as a failsafe method. And then its better to just do opengl only. Yeah, its 30% slower than the modern apis, maybe there will be no driver for it and the computer will emulate a super old version of it, maybe some function the vendor implemented is buggy, and reflection of the character's swrod will be a bit garbled, maybe the fps will fell with a driver from 200 to 30 with a random driver for unexplainable reasons. But in exchange, it will work, and allow you to write the code once and deploy it to dozens of platforms for all era, and the game will run. Which is the most important, especially if you want to get buyers, donations, ad revenue, whatever. And no other api can do this right now.

April 26, 2023 10:39 PM
dimi309

@Geri Thanks for this very good, detailed overview of the 3D API landscape! There is a lot of information here that I was not aware of, but in any case, I have reached the same conclusions as you, at least for the kind of projects that I am developing at the moment.

April 27, 2023 12:54 PM
jdtec01

Good read and mimics my own experience (although I didn't get as far as you have by actually releasing things).

Did you consider something like SDL GPU, bgfx or one of the other ‘bring your own game engine’ renderer APIs? You get the benefit of being able to go use OpenGL, Metal, Vulkan or DirectX with the same abstraction code.

September 17, 2024 08:09 AM
dimi309

@jdtec01 Thank you!

Libraries like bgfx are great, but for my projects so far I have tried keeping external dependencies to a minimum, so I have opted for coding against the graphics API directly. In that sense, I have found that one can still write games that pretty much run everywhere using OpenGL 3.3 and OpenGL ES 2.0. It's a good choice if graphics-wise you do not mind not using the latest and greatest. 🙂

September 17, 2024 10:42 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement