Book Image

Learning Vulkan

By : Parminder Singh
Book Image

Learning Vulkan

By: Parminder Singh

Overview of this book

Vulkan, the next generation graphics and compute API, is the latest offering by Khronos. This API is the successor of OpenGL and unlike OpenGL, it offers great flexibility and high performance capabilities to control modern GPU devices. With this book, you'll get great insights into the workings of Vulkan and how you can make stunning graphics run with minimum hardware requirements. We begin with a brief introduction to the Vulkan system and show you its distinct features with the successor to the OpenGL API. First, you will see how to establish a connection with hardware devices to query the available queues, memory types, and capabilities offered. Vulkan is verbose, so before diving deep into programing, you’ll get to grips with debugging techniques so even first-timers can overcome error traps using Vulkan’s layer and extension features. You’ll get a grip on command buffers and acquire the knowledge to record various operation commands into command buffer and submit it to a proper queue for GPU processing. We’ll take a detailed look at memory management and demonstrate the use of buffer and image resources to create drawing textures and image views for the presentation engine and vertex buffers to store geometry information. You'll get a brief overview of SPIR-V, the new way to manage shaders, and you'll define the drawing operations as a single unit of work in the Render pass with the help of attachments and subpasses. You'll also create frame buffers and build a solid graphics pipeline, as well as making use of the synchronizing mechanism to manage GPU and CPU hand-shaking. By the end, you’ll know everything you need to know to get your hands dirty with the coolest Graphics API on the block.
Table of Contents (18 chapters)
Learning Vulkan
Credits
About the Author
Acknowledgments
About the Reviewer
www.PacktPub.com
Preface

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:

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 vk Free* 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.