Chapter 5. Command Buffer and Memory Management in Vulkan

A command buffer is a collection of commands, and it is submitted to an appropriate hardware queue for GPU processing. The driver then fetches the command buffers and validates and compiles them before the real GPU processing starts.

This chapter will shed light on command buffer concepts. We will learn about command pool creation, allocation/deallocation of command buffers, and recording commands. We will implement the command buffers and use them in the next chapter to drive a swapchain. A swapchain abstracts the mechanism to interface with platform surfaces and provides an array of images that can be used to perform rendering. Once rendering is done, the image is presented to the native windowing system.

In the second half of the chapter, we will understand memory management in Vulkan. We will discuss the concepts of host and device memory. We will look into memory allocators to manage host memory allocations. At the end of this chapter, we will delve into device memory and learn the methods to allocate/deallocate and use it through mapping.

This chapter will cover the following topics on command buffers and memory allocation:

  • Getting started with command buffers
  • Understanding the command pool and command buffer APIs
  • Recording command buffers
  • Implementing the command buffer wrapper class
  • Managing memory in Vulkan

Getting started with command buffers

As the name suggests, a command buffer is a buffer or collection of commands in a single unit. A command buffer records various Vulkan API commands that an application is expected to execute. Command buffers once baked can be reused again and again. They record the commands in the sequence that is specified by the application. These commands are meant for carrying out different type jobs; this includes binding vertex buffer, pipeline binding, recording Render Pass commands, setting viewport and scissor, specifying drawing commands,  controlling copy operations on image and buffer contents, and more.

There are two types of command buffers: primary and secondary command buffers:

  • Primary command buffers: These are the owners of the secondary command buffers and responsible for executing them; they are directly submitted to the queues
  • Secondary command buffers: These are executed through primary command buffers and cannot be directly submitted to queues

The number of command buffers in an application can vary from a few hundred to thousands. The Vulkan API is designed to offer maximum performance; therefore, the command buffers are allocated from the command pools in order to amortize the cost (when used in a multithreaded environment--refer to the Explicit synchronization section in this chapter) of resource creation across multiple command buffers. A command buffer cannot be created directly; instead, it is allocated from the command pool:

Getting started with command buffers

Command buffers are persistent; they are created once and can be reused continuously. Further, if a command buffer is no longer useful, it can be renewed with a simple reset command and made ready for another recording. This is an efficient way as compared to destroying and then creating a new buffer for the same purpose.

Explicit synchronization

When multiple command buffers are created in a multithreaded environment, then it's advisable to separate the synchronization domains by introducing separate command pools for each thread. This makes the cost of command buffer allocations efficient since the application does not need explicit synchronization in a different thread.

However, it is the application's responsibility to manage the synchronization between the command buffers that are shared across multiple threads.

Explicit synchronization

In contrast, OpenGL is an implicit synchronization model. In OpenGL, a lot of things are done automatically, which comes at the cost of a lot of resource tracking, cache flushing, and dependency chain construction. All of this is done behind the curtains, which indeed is an overhead of the CPU. Vulkan is fairly simple in this context; the explicit synchronization guarantees that there is no hidden mechanism nor an element of surprise.

An application is better aware of its resources, and hence, their usage and dependencies. A driver is less likely to pinpoint the dependencies with accuracy. As a result, the OpenGL implementation ends up with unexpected shader recompilations, cache flushes, and so on. Vulkan's explicit synchronization makes it free from these limitations, thereby making the hardware more productive.

Another differentiation is the submission of the command buffers in OpenGL: command buffers are pushed behind the scenes and are not in control of the application. An application that submits the commands has no guarantee when those jobs will be executed. This is because OpenGL executes command buffers in batches. It waits for the commands to build the batch and then it dispatches them together. On the other hand, Vulkan gives explicit control to the command buffer to allow the processing up front by submitting it to the desired queue.

Types of command in command buffers

A command buffer consists of one or more commands. These commands can be categorized into three types:

  • Action: This command performs operations such as draw, dispatch, clear, copy, query/timestamp operations, and begin/end a subpass
  • State management: This includes descriptor sets, bind pipelines, and buffers, and it is used to set the dynamic state, push constants, and the Render Pass/subpass state
  • Synchronization: These commands are used for synchronization: pipeline barriers, set events, wait events, and Render Pass/subpass dependencies

Command buffers and queues

Command buffers are submitted to a hardware queue where they are processed asynchronously. Submission to queues can be made efficient by batching command buffers and executing them once. Vulkan has a deferred command model where a collection of draw calls in the command buffer and submissions are done separately and considered two different operations. This is helpful from an application perspective. This is because it will have prior knowledge of a large portion of the scene and this can be used as an opportunity to add appropriate optimizations to the submission, which would've been difficult to achieve in OpenGL.

Vulkan provides a logical view of the hardware queue, where each logical view is tightly connected to a hardware queue. A single Vulkan hardware queue can be represented by multiple logical queues, where each queue is being created based on the queue properties. For example, the presentation of rendered swapchain images may require the command buffer to submit them to a graphics queue, which is capable of presentation as well

The order of execution

Command buffers can be submitted to either a single queue or multiple queues:

  • Single queue submission: Multiple command buffers submitted to a single queue may be executed or overlapped. In single queue submission, a command buffer must obey the order of the execution of operations as per the command order and the API order specification. This book only covers the submission commands used for vkQueueSubmit; it does not cover sparse memory binding command buffers (through vkQueueBindSparse).
  • Multiple queue submission: The command buffers submitted to multiple queues may be executed in any order unless explicit ordering constraints are applied through the synchronization mechanism via semaphores and fences.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.79.20