segfault at vkResetFences
That's the error message that's greeted me for the last few weeks. There was a segfault, which is a portmanteau of segmentation fault - a program has tried to access a segment of memory that it shouldn't have. Usually your debugger can take you to the line where the segfault happens and you'll see what you did wrong - Are you accessing an array element that doesn't exist? Did you forget to initialize something? Segfaults are annoying, but usually they can be squashed in development.
Except for now.
The debugger gave me a location where the error was happening - deep within the Vulkan loader. It said that the error happened in the function vkResetFences, but I didn't call that from anywhere within Nova. Something strange was happening.
I tried a lot of things to learn more about this error. I tried compiling the Vulkan loader myself, tried compiling Nova with Visual Studio, tried commenting out large swaths of code until the error went away so isolate the offending line - many hours were spent cursing at my compiler. I learned a few interesting things, such as that the Vulkan loader doesn't support being compiled with MinGW, and that Nova doesn't like being compiled with Visual Studio, and that the error wasn't necessarily happening in the function vkResetFences, but since I had a release build of the Vulkan loader then gdb wasn't reporting the offending stack frame accurately. This was all rather interesting and would probably be useful, but was not useful now.
I cast a wide net online, reaching out for any help I could get. Some people suggested I was smashing my stack, but that didn't seem likely - stack smashing seems to be super rare and difficult to actually do. I looked into debugging a Vulkan application, and realized that I had never gotten a Vulkan debug callback working.
I'm using vulkan.hpp, a C++ wrapper around Vulkan. It's a thin wrapper around the Vulkan API - sometimes too thin. Vulkan debug callbacks, in which you give Vulkan a callback to call when it has something to say about how badly you're misusing the API, is a Vulkan extension, and it isn't loaded very well by vulkan.hpp. Google gave some example code to load the debug callback extension, I gave Vulkan a callback to print errors, and... the callback printed out many errors. Whoops.
In OpenGL, I never had to clean up objects when my program shut down - that was all handled by the API. In Vulkan, however, you do have to clean up after yourself. This information had slipped by me. I went through all my code and added the statements to destroy things I wasn't using, and Nova stopped crashing. When you use the API correctly, your program won't break. Who knew?
...but now it's time for OpenGL
I spent four months working on converting Nova to Vulkan. I got probably 2/3 of the way there, but I kept running into more and more problems. The tale above is just one of them: turns out learning a new graphics API all at once is pretty challenging. I took a step back and decided that I couldn't justify spending another four months getting Vulkan Nova working, not with Bedrock shaders right around the corner and not with all the features Optifine keeps adding. If I had any hope of being competitive, I needed to get a working renderer together as soon as possible... and I already had a working renderer, one that used OpenGL.
The first task was bringing in all the improvements made in the conversion to Vulkan. I made a number of tweaks to the build scripts and wrote a loader for Bedrock materials, and those changes had to be brought in.
Data-Driven Render Passes
During the time I spent working on Vulkan, I came across an article titled Render Graphs and Vulkan: A Deep Dive. The article talked about a data-driven renderer that gives a great deal of flexibility with regards to how a renderer processes a scene, and I realized that it was exactly what I wanted. The author of that article had solved a number of problems I was struggling with, so why not use their solutions?
I decided to upgrade Bedrock's material system to use render passes while bringing in the Bedrock material file loader. The render passes would form the backbone of Nova's data processing algorithms, so I definitely wanted to have that system in place as early as possible.
Bugfixes and Improvements
We haven't only been developing new tech, however. Coler706 has been working on bugfixes and improvements to the existing tech. He discovered that the place I had initially hooked into Minecraft for chunk updates wasn't very good, and found a better place so that Nova was able to handle the removal of block and loaded chunks from the player outward, like in vanilla. He's also been expanding the set of GUI screens that Nova can handle, paying special attention to the in-game GUI. The work he's doing has fixed many issues that I would have taken much longer to get to, so I very much appreciate his help.
Thi brings us to today. We have a strong modern OpenGL base to work off of. We're moving ahead strong with implementing the render pass system, constantly improving the data format to be more expressive and easier to use. We're fixing bugs and making improvements that are highly visible to the end user. Nova development in 2018 is moving along very well!