Learning the fundamentals of Vulkan

This section will cover the basics of Vulkan. Here we will discuss the following:

  • Vulkan's execution model
  • Vulkan's queue
  • The object model
  • Object life-time and command syntax
  • Error checking and validation

Vulkan's execution model

A Vulkan-capable system is able to query the system and expose the number of physical devices available on it. Each of the physical devices advertises one or more queues. These queues are categorized into different families, where each family has very specific functionalities. For example, these functionalities could include graphics, compute, data transfer, and sparse memory management. Each member of the queue family may contain one or more similar queues, making them compatible with each other. For example, a given implementation may support data transfer and graphics operations on the same queue.

Vulkan allows you to explicitly manage memory control via the application. It exposes the various types of heap available on the device, where each heap belongs to a different memory region. Vulkan's execution model is fairly simple and straightforward. Here, command buffers are submitted into queues, which are then consumed by the physical device in order to be processed.

A Vulkan application is responsible for controlling a set of Vulkan-capable devices by recording a number of commands into command buffers and submitting them into a queue. This queue is read by the driver that executes the jobs upfront in the submitted order. The command buffer construction is expensive; therefore, once constructed, it can be cached and submitted to the queue for execution as many times as required. Further, several command buffers can be built simultaneously in parallel using multiple threads in an application.

The following diagram shows a simplified pictorial representation of the execution model:

Vulkan's execution model

In this, the application records two command buffers containing several commands. These commands are then given to one or more queues depending upon the job nature. The queues submit these command buffer jobs to the device for processing. Finally, the device processes the results and either displays them on the output display or returns them to the application for further processing.

In Vulkan, the application is responsible for the following:

  • Producing all the necessary prerequisites for the successful execution of commands:
    • This may include preparing resources, precompiling a shader, and attaching the resources to the shader; specifying the render states; building a pipeline; and drawing calls

  • Memory management
  • Synchronization
    • Between the host and device
    • Between the different queues available on the device

  • Hazard management

Vulkan's queues

Queues are the medium in Vulkan through which command buffers are fed into the device. The command buffers record one or more commands and submit them to the required queue. The device may expose multiple queues; therefore, it is the application's responsibility to submit the command buffer to the correct queue.

The command buffers can be submitted to the following:

  • Single queue:
    • The order of the submission of the command buffer and execution or playback are maintained
    • Command buffers are executed in a serial fashion

  • Multiple queues:
    • Allows the execution of the command buffer in parallel in two or more queues.
    • The order of the submission and execution of command buffers are not guaranteed unless specified explicitly. It is the application's responsibility to synchronize this; in its absence, the execution may be completely out of order with respect.

Vulkan provides various synchronization primitives to allow you to have relative control of the work execution within a single queue or across queues. These are as follows:

  • Semaphore: This synchronizes work across multiple queues or a coarse-grained command buffer submission in a single queue.
  • Events: Events controls fine-grained synchronization and are applied on a single queue, allowing us to synchronize work within a single command buffer or sequence of command buffers submitted to a single queue. The host can also participate in event-based synchronization.
  • Fences: These allow synchronization between the host and device.
  • Pipeline barriers: A pipeline barrier is an inserted instruction that ensures that commands prior to it must be executed before commands specified after it in the command buffer.

The object model

At the application level, all the entities, including devices, queues, command buffers, framebuffers, pipelines, and so on, are called Vulkan objects. Internally, at the API level, these Vulkan objects are recognized with handles. These handles can be of two types: dispatchable and non-dispatchable.

  • A dispatchable handle: This is a pointer that refers to an opaque-shaped entity inside. Opaque types do not allow you to have direct access to the structure's field. The fields can only be accessed using API routines. Each dispatchable handle has an associated dispatchable type that is used to pass as a parameter in the API command. Here's an example of this:

VkInstance

VkCommandBuffer

VkPhysicalDevice

VkDevice

VkQueue

  • Non-dispatchable handles: These are 64-bit integer-type handles that may contain the object information itself, rather than a pointer to the structure. Here's an example of this:

VkSemaphore

VkFence

VkQueryPool

VkBufferView

VkDeviceMemory

VkBuffer

VkImage

VkPipeline

VkShaderModule

VkSampler

VkRenderPass

VkDescriptorPool

VkDescriptorSetLayout

VkFramebuffer

VkPipelineCache

VkCommandPool

VkDescriptorSet

VkEvent

VkPipelineLayout

VkImageView

Object lifetime and command syntax

In Vulkan, objects are created and destroyed explicitly as per application logic, and it is the responsibility of an application to manage this.

Objects in Vulkan are created using Create and destroyed using the Destroy command:

  • Create syntax: Objects are created using the vkCreate* command; this accepts a Vk*CreateInfo structure as a parameter input
  • Destroy syntax: The objects produced using the Create command are destroyed using vkDestroy*

Objects created as part of the existing object pool or heap are created using the Allocate command and released from the pool or heap with Free.

  • Allocate syntax: Objects that are created as part of an object pool use vkAllocate* along with Vk*AllocateInfo as an argument input.
  • Freeing syntax: Objects are released back to the pool or memory using the vkFree* command.

Any given implementation information can be easily accessed using the vkGet* command. The API implementation of the form vkCmd* is used to record commands in the command buffer.

Error checking and validation

Vulkan is specially designed to offer maximum performance by keeping error checks and validations optional. At runtime, the error checks and validations are really minimal, making the building of a command buffer and submission highly efficient. These optional capabilities can be enabled using Vulkan's layered architecture, which allows the dynamic injection of various layers (debugging and validation) into the running system.

..................Content has been hidden....................

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