Vulkan offers another key difference to OpenGL with respect to memory allocation. When it comes to managing memory allocations as well as assigning it to individual resources, the OpenGL driver does most of the work for the developer. This allows applications to be developed, tested and deployed very quickly. In Vulkan however, the programmer takes responsibility meaning that many operations that OpenGL orchestrates heuristically can be orchestrated based on an absolute knowledge of the resource lifecycle.
Software developers use custom memory management for various reasons:
In previous blog posts we already hinted at some of the systems that Vulkan provides for memory management, which consider these factors.
We focus on image and buffer memory in this post as it is the central concept to using the Vulkan API effectively.
Memory HierarchyMemory is a precious resource, and it can involve several indirect costs by the operating systems. For example some operating systems have a linear cost over the number of allocations for each submission to a Vulkan Queue. Another scenario is that the operating system also handles the paging state of allocations depending on other proceses, we therefore encourage not using too many allocations and organizing them “wisely”.
Staging BuffersWhen memory cannot be mapped to the host or requires format conversions such as packing texels for image memory, a copy of the data from a temporary buffer into the final resource may be required. This process is referred to as ‘staging’ and is common practice for DirectX users already. In OpenGL, the driver implicity managed the temporary copy and potentially batched copying to the device for you. In Vulkan (and with ARB_buffer_storage in OpenGL as well), the use of persistent mapped buffers can achieve similar results.
On devices with dedicated device memory, it is most likely that all resources that are used for many frames are filled through staging buffers. When updating image data we recommend the use of staging buffers, rather than staging images for our hardware. For a small data buffer, updates via the CommandBuffer provide an alternative approach by inlining the data directly.
Alignment and AliasingThe fact that we can manually bind resources to actual memory addresses, gives rise to the following points:
While OpenGL does allow a bit of aliasing for buffers, by just allocating a big buffer and using offsets, Vulkan allows the same for all resources now. One of the simpler use-cases for this capability is overlapping many different-sized framebuffer images into the same memory allocation when the application knows only one size is active in the frame. Some developers use this type of varying resolution rendering to guarantee constant frame-rates. More complex cases could be re-use memory within the same frame for different purposes and achieve an overall lower upper memory bound. A warning from our driver developers is that this feature can put you quickly in the danger zone, where there will be dragons. Memory contents are not defined when aliasing between resources of different types, and care must be taken to (re-)initialize memory contents every time memory is used with a new object.
A far safer scenario is just re-using memory allocations of pre-allocated chunks. Every time a new resource is required we check if we have available chunks from which we can sub-allocate, or whether we should create a new chunk. Memory can be recycled after a few frames when the GPU is not accessing it anymore.
Buffer Offset UsageFor Buffer memory we recommend making use of the offset mechanism the API provides. Just like in OpenGL, Vulkan allows to binding a range of a buffer. The benefit is that we avoid CPU memory costs for lots of tiny buffers, as well as cache misses by using just the same buffer object and varying the offset.
This optimization applies to all buffers, but in the previous blog post on shader resource binding it was mentioned that the offsets are particularly good for uniform buffers.
SummarySub-allocation is considered to be a first class approach when working in Vulkan. There are certainly cases where one doesn’t need to use it (e.g. very large 3D volume textures). However, the fact that Vulkan provides us with this flexible and granular approach to memory management, means that with careful consideration to the requirements of our application, one can craft improved memory management schemes.
When this level of performance control is less important than maintainability, OpenGL will continue to deliver. Vulkan on the other hand will find its place where highly dynamic scenes containing many elements require this type of orchestration to achieve peak performance across platforms.
Authors: Chris Hebert and Christoph Kubisch (special thanks to Daniel Koch)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3