This fortnight saw a lot of Vulkan experimentation and further work towards consistent vertex buffer handling in asset loading and dynamic geometry generators.
Delving into Vulkan for a week was interesting, but very intimidating. There are an amazing number of concepts that need to be chained together to accomplish even a simple "Hello World". While I can understand the rationale it was a shock to discover that swapchains, a feature I take for granted in OpenGL, aren’t even a core API.
I had performed some previous experiments in early 2016 (or so
git tells me). It quickly became apparent that my old XSLT based header generation tool wasn’t going to cut it; I don’t know enough XSLT, and
vk.xml is clearly not designed to be parsed in a single pass. Enter
spec.py, which generates some basic Vulkan headers with a little more type safety thrown in:
[[nodiscard]] for results, noexcept ‘because C’, and enum classes because I know I’m going to pass the wrong thing somewhere.
My typical approach to wrapper objects was made complicated because of Vulkan’s insistence on requiring the parent object used for object creation be passed also to to the destruction routine. It would be easy to just throw a reference to the parent into the child object, but it’s best to aim for zero-cost where possible and also useful if our wrapper actually translates to the same bytes as the native object. Instead I rely on manual destruction (leaving the object in a state similar to post-move-construction) with assertions to catch the times I forget about it. Though in the end I did concede and add an owned wrapper which holds the aforementioned parent reference just to simplify development of
I’m pretty sure I won’t be spending more time during the work-week directly on Vulkan, but I will be gradually improving my understanding over the weekends with a view to replacing OpenGL eventually.
In the process of implementing
vk_hello I (re)implemented a bunch of GLFW boiler plate and pushed it into a new convenience library:
libcruft-glfw (predictably). There isn’t much to wrap, but it does let me care a little less about correct library teardown.
I’m not sure why I never took a great deal of notice of GLFW error handling: passing the error code via a global callback. I imagine this was done because many of the errors are deducible via the result values, but it does seem unnecessarily error prone. It made me appreciate the Vulkan approach a lot more.
A lot of the experiments I made in the Vulkan bindings required some
type_trait style trickery which necessitated some additional type transformations that standard CXX doesn’t provide. There are a few more options in my function traits class, the ability to remove noexcept, and a convenience method to chain type transforms.
The previous hard-coded preprocessor
REDUCE code was replaced with a python script; because I wasn’t willing to expand the 96 supported arguments to the ≈320 arguments required to map over the various Vulkan types. I’ve always wanted to use a build-time parameter for the arity. However the 120KiB of generated code appears to be inducing some performance problems with my IDE which means I’m reaching for
vim to edit a handful of files now. Thankfully they’re pretty self-contained, but it’s not ideal.
Now that I’ve got access to structured bindings I’m finding more edge cases in my
izip functions. This period it was with C-arrays which forced a rethink of the iterator representation. Nothing big, but it’s highlighting a lot of minor assumptions my template programming is making.
clang-5.0.0 was released, and… it impacted me surprisingly little. Everything mostly worked fine; Huzzah!
Most importantly I can now rely on more CXX17 support; structured bindings and template deduction for classes in particular. It also appears that more than one ICE triggered by some of my iterator wrappers have disappeared!
Finally… game development proper.
Mostly this followed the previous period: working towards correct display of terrain zones in
edict. This was split between introducing a few more GPU buffers to hold different types of data, and layering some more consistent allocators on top of the same. This should make the routines that operate on static model geometry, dynamic world geometry, and the GUI layers a lot more similar.
Unfortunately, no decent screenshots this week. But, with any luck I should have terrain zones acting coherently for next week. Let’s hope!