Engine Update: Vulkan Enters the Chat

by Debbie Liknes 4 min read
C++ Game Engine Architecture Chai Update

OpenGL is dead. Long live Vulkan.

A Tale as Old as Time

About 6 months ago, before the winter holidays, I told myself I was going to take a break from engine development. Just for the holidays. When it comes to side projects, I made the fatal mistake of forgetting how much momentum matters.

But we’re so back, baby.

Does This Refactoring Make My Asset Management Look Fat?

About 2 months ago, I looked through my codebase with fresh eyes and saw…lets say room for improvement. I had an open PR that I never merged, and a handful of…ahem…frustrated comments about how much I hated debugging shadow mapping. I’m really proud of the effort I put into the OpenGL Renderer. I hadn’t really used OpenGL much before, and its been valuable to learn the differences. I’m more familiar with Vulkan, but its hard to get right. Using a less rigid graphics api allowed me to make progress on other layers without constructing a whole universe of GPU resource management architecture. But… My intention was to write a graphics api agnostic seam between the Renderer (a plugin) and the engine (obviously not a plugin). And what I realized was I let what my plugin was doing dictate the interface between them. Not good. Not only that, but in the past, Vulkan has bit me because of the resource management. That needed thought, and it wasn’t represented in my current codebase.

I always like to think that refactoring means I’ve learned something. And I intend to prove it this time. A Senior engineer I work with once told me that good refactoring means reducing lines of code. And in my engine, the code required to spin up an application was extremely verbose. That has been reduced by almost half, to show the same scene.

Areas I targeted for improvement:

  • Asset Management: This is the main redo. I had previously put a lot of work into my asset system. Unfortunately, looking at it now, I realized I made the interfaces too generic, and as a result, the system for material instances was overly confusing. I decided that fully generic asset loaders had to go, and there needed to be well defined interfaces for asset vs. resource management. Assets are CPU data. Resources are GPU data. Dont get it twisted.
  • Logging: I was using print out statements to tell me when something was wrong. It’s high time I wrap a logging library
  • Better project structure: Don’t underestimate this one. I had an extremely bloated core library and not much separation, and folders that were named nonsensically. This is bad for a couple reasons. 1. It’s a HUGE library to link to, and you might get a bunch of stuff you don’t really need. And 2. I can’t freaking find anything, and it would take me forever to decide where something belongs that wouldn’t break a dependency. So, this time I’ve taken better care to separate interfaces and types into different projects.

Things That Don’t Exist Anymore In This Update

In an ideal world, I would reimplement every feature I had in the last version. Reality is not so.

  • The OpenGL renderer As the tagline implies, it’s dead. Deleted. Perhaps some day I will remake it, but probably not. There are more interesting graphics APIs to write plugins for, which is where I would prefer to put my efforts.
  • Material instances This is a temporary setback. I have plans to reimplement them, but I wanted to make damn sure I wasnt blurring any lines in my asset and resource managment. The material instances will be back soon. Better than ever.
  • Cascaded shadow mapping This was the aforementioned open PR. It mostly worked, mostly just needed cleanup, but since I knew I was abandoning the OpenGL renderer anyway, I ended up just closing it. CSM will be back.

Things That Miraculously (mostly) Survived

  • Plugins The plugins got a tiny facelift, but it was mostly cosmetic. The guts remain the same.
  • Scene Layer I did a genuinely good job on this. The component system is basically unchanged
  • Math Library The math library got some cleanup and restructure. But the functions are the same. This time, with more unit tests.

Conclusion

I want to keep this post quick and digestible, I just wanted to get a quick update out because I merged the Vulkan Renderer last night. Expect a few more lengthy posts detailing this refactor and architecture decisions. It’s a holiday this weekend (Father’s day) but I promise I won’t take another 6 months off.