WIP ‐ Vulkan - bryanedds/Nu GitHub Wiki

The Four Horsemen

Vulkan rendering incorporates four foundational components, here tentatively titled the Four Horsemen:

Memory Management

This horseman has been subdued by the Vulkan Memory Alligator. Device memory allocation can be completely automated and consequently ignored during the initial pass. For the optimization phase, VMA enables controlled device memory management via custom memory pools, so that Nu's VRAM can be cut at its joints.

Command System

All of the actual live rendering work is controlled by commands. The infrastructure for processing these commands is responsible for all of the synchronization, which presents both the major danger of (platform specific) error and the major challenge of optimization. During the initial pass, the commands will presumably execute serially, resulting in negligible complexity. During the optimization phase, they will be parallelized, which may or may not produce enough complexity to warrant abstraction.

Graphics Pipelines

All of the information needed to tell Vulkan what to draw and how to draw it is hardcoded into static data structures called graphics pipelines. This information includes not only the shaders, but entire multi-pass rendering sequences like deferred rendering. The process of porting Nu's existing rendering architecture will consist of translating it into pipelines. There will be at least three pipelines, one each for 2D, 3D and IMGUI.

Presentation System

Once the pipelines' output is merged into the final image, presentation is the process of sending it to the screen. These consecutive images are placed in a queue called the swap chain, where they await delivery to an object called the surface, which represents the screen or window via SDL. How the swap chain is set up determines correct synchronization with Nu's framerate, vsync and latency. It is crucial to get this right, but should be simple enough to get out of the way pretty quickly. There should be at least three swap chain images (i.e. places in queue) to prevent delays in writing to the swap chain (Sellers, p. 144, but cf https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain#page_Creating-the-swap-chain).

Custom Validation

TODO: Learn as we go on this, but let's see what we might be able to anticipate.

.Net Binding

Nu's interface to Vulkan is the Vortice.Vulkan binding. It is adequately low-level while providing appropriate and very helpful optional abstractions, including selective Vulkan function overloads and most importantly string handling. It also provides invisible cross-platform loading. It is of minimal size and complexity and therefore hackable.

Vortice.Vulkan is partly based on vk, which is no longer actively maintained. There is also another, more direct, descendent of vk currently under maintenance: Vulkan.Net. It is a beautiful wrapper, but lacks the helpful abstractions.

Standard

  • Common practice and convention for interacting with Vulkan must be adhered to as much as possible. Any deviation may lead to unpredictable results due to inadequate implementation by vendors.

  • The claims of validation error messages about user code should be taken seriously and literally. They are very good at revealing deceptive false premises.

  • Vortice.Vulkan's one shortcoming is that it inappropriately uses the Vulkan prefix "vk/Vk" in non-Vulkan functions and types, which is misleading. For clarity, these must be marked "// not vulkan function" (or equivalent). Regular use types like VkUtf8String are excepted.

  • If Vortice.Vulkan fails to allow any particular compliance with the spec, this must be noted in a comment. The exception to this is Vortice.Vulkan's internalization of the sType struct member.

Vulkan functions

  • All Vulkan functions must be looked up in the spec upon first use.

  • Vortice.Vulkan often provides a choice between managed pointers (byref) and unmanaged pointers. For the sake of simplicity, the former should be preferred. No comment required.

  • Otherwise, the most conservative overload of Vulkan functions should be the default. i.e. the arguments should normally match the spec.

  • Higher-level overloads of Vulkan functions can be used if there is a compelling reason to do so. Use of higher-level overloads and the reason for said use must be explained in a comment.

Vulkan Structs

  • All Vulkan structs must be looked up in the spec upon first use.

  • When constructing informational Vulkan structs, only the bare minimal relevant members should be filled out, ordered according to the spec.

Vulkan Boolean

  • Vortice.Vulkan does not enable spec compliant boolean usage. Normal boolean values should be used to provide required type via implicit conversion.

Pointers

  • Use of pointer handling helpers from Vortice.Vulkan should be avoided.

  • All pointer handling should be done through Native.fs.

  • All arrays and strings must be pinned in memory before unmanaged pointers to them are passed to Vulkan structs or functions.

  • Abstractions must always be used wherever possible for handling unmanaged pointers to strings and arrays.

  • Abstractions for handling unmanaged pointers must be assigned with the "use" keyword.

General Notes

References