Home Game Development Learning Vulkan

Learning Vulkan

By Parminder Singh
books-svg-icon Book
eBook $47.99 $32.99
Print $60.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $47.99 $32.99
Print $60.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Getting Started with the NextGen 3D Graphics API
About 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.
Publication date:
December 2016
Publisher
Packt
Pages
466
ISBN
9781786469809

 

Chapter 1.  Getting Started with the NextGen 3D Graphics API

Vulkan is a revolutionary high-performance 3D graphics and computing API for modern GPU pipeline architectures to meet the demanding requirements of the community. This API provides a brand-new approach to overcome the complexities and gaps in existing traditional APIs. Vulkan is an explicit API that promises predictable behavior and allows you to have smooth rendering frame rates without causing lags or hitches. This chapter will present an overview of the Vulkan API and its distinct features compared to its predecessor: the OpenGL API. We will take a look at Vulkan's ecosystem and understand its graphics system.

So we will cover the following topics:

  • Vulkan and its evolution

  • Vulkan versus OpenGL

  • Important jargons before we get started

  • Learning the fundamentals of Vulkan

  • Understanding the Vulkan application

  • Getting started with the Vulkan programming model

 

Vulkan and its evolution


It's almost a quarter-century since the famous OpenGL API came into existence, and it is still evolving. Internally, it is a pure state machine that contains several switches working in a binary state (on/off). These states are used to build dependency mapping in the driver to manage resources and control them in an optimal way to yield maximum performance. This state machine automates resource management implicitly, but it is not intelligent enough to capture application logic, which is the driving force behind resource management. As a result, there might be unexpected situations, such as the implementation going off, resulting in recompilation of the shaders even when the application has not requested it. In addition, the OpenGL API might be subject to other factors, such as unpredictable behavior, multithreading scalability, rendering glitches, and so on. Later in this chapter, we will compare OpenGL with the Vulkan API to understand the difference between the two.

Launched by Khronos in 2016, the Vulkan API has a revolutionary architecture that takes full advantage of modern graphics processor units to produce high-performance graphics and compute applications. If you are not aware of Khronos, it's an association of members and organizations that focus on producing open standards for royalty-free APIs. For more information, refer to https://www.khronos.org.

The original concept of Vulkan was designed and developed by AMD, based on their proprietary Mantle API. This API showcased cutting-edge capabilities through several games, thereby proving its revolutionary approach and fulfilling all the competitive demands of the industry. AMD made their Mantle API open source and donated it to Khronos. The Khronos consortium, with the help of many other hardware and software vendors, made collaborative efforts to release Vulkan.

Vulkan is not the only next-gen 3D graphics API; there are competitors, such as Microsoft's Direct-X 12 and Apple's Metal. However, Direct-X is limited to its Windows variants and Metal to Mac (OS X and iOS). Vulkan stands out in that respect. Its cross-platform nature supports almost all the available OS platforms; this list includes Windows (XP, Vista, 7, 8, and 10), Linux, Tizen, SteamOS, and Android.

 

Vulkan versus OpenGL


Here are the features/improvements in Vulkan that give it an edge over OpenGL:

  • Reduced driver overhead and CPU usage: Vulkan is designed to be closer to the underlying graphics hardware. Therefore, it provides an application programmer with direct control over computing resources on the host in order to allow the GPU to render as fast as possible. This also allows the software to directly access the graphics processor, allowing better performance.

  • Multithread scalability: Multithread scaling is really poor in OpenGL, and it is very difficult to take advantage of the threading features to better utilize the CPU. However, Vulkan is specially designed to allow end users to fully exploit its multithreading capability in a very transparent manner with no implicit global states. Jobs under different threads remain separated from the moment they are created and submitted for execution.

  • An explicit API: OpenGL is an implicit API, where resource management is the driver's responsibility. The driver takes application hints and tracks resources, which is an unnecessary overhead.

    • Vulkan is an explicit API; here, the driver is not responsible for tracking resources and their relationships. This task is assigned to the application. This clean approach is more predictable; the driver is not doing gymnastics behind the scenes to manage resources (as in OpenGL). As a result, job processing is streamlined and straightforward, resulting in optimal performance and predictable behavior.

  • Precompiled intermediate shading language: Unlike OpenGL, which requires shaders to be provided as OpenGL Shading Language (GLSL) source code, the Standard Portable Intermediate Language (SPIR-V) is a standard intermediate language used by Vulkan for parallel computing and graphics.

Note

Compilers for source languages, such as GLSL, HLSL, or LLVM, must target the SPIR-V specification and provide utilities to provide SPIR-V input. Vulkan takes this ready-to-execute binary-intermediate input and uses it at the shader stage.

  • Driver and Application layer: In OpenGL, the application layer is thinner as compared to the driver layer, as the driver's automation takes into account resource management and state tracking. Vulkan is the opposite of this. It ensures the driver is closer to the hardware with less overhead. It's an application's responsibility to manage logic, resources, and states. The following diagram shows the thickness of the driver and application code base of both the APIs:

  • Memory controls: Vulkan is capable of exposing various memory types on the system and requires the application developer to choose the appropriate memory type for the intended use of each resource. In contrast, OpenGL drivers decide on the placement of resources according to internal heuristics, which vary between vendors, and it may produce suboptimal placement or unexpected hitches if the driver moves the resource later.

  • Predictable: Vulkan is highly predictable as compared to OpenGL; it does not cause any lags or hitches while rendering. The jobs are submitted upfront as soon as they are given to the driver, whereas the OpenGL job submission process is not upfront and is at the mercy of the driver's scheduler.

  • A single API: OpenGL has separate versions for a desktop-based API (OpenGL) and embedded API (OpenGL ES). Vulkan is clean and consists of only a single API for any number of platforms. Vulkan supports mobile platforms as a first-class citizen, which is not the case in OpenGL. Usually, the OpenGL implementation first appears on desktop-based versions and is later made available to the OpenGL ES APIs.

  • Direct access to the GPU: Vulkan gives a lot of control to the application user by advertising its capabilities and hardware facilities. It exposes various types of available physical devices, memory types, command buffer queues, and extensions. This behavior ensures the software layer is much closer to the real hardware.

  • Error checking and validation: When using OpenGL, well-behaved applications pay a price when it comes to checking for errors, which they will never trigger at the time of execution. In contrast, Vulkan offers these checks and validation as an add-on service, which can be enabled and disabled as and when required. These checks are optional and can be injected into a runtime by enabling error checking and other validation layers. As a result, it causes less CPU overhead by avoiding unnecessary checks. Ideally, these error and validation layers must be turned on during the development phase for the debugging process and turned off during the release process.

  • Supports various GPU hardware: Vulkan supports mobile and desktop rasterizers as an integrated part of the implementation. It supports tile-based or deferred rasterizers for embedded platforms along with native tiling-based feed forward rasterizers.

 

Important jargons before we get started


Let's check out some of the important technical jargons used in Vulkan before we dive deep into the fundamental details. This book will cover more of these technical terms as we proceed further.

  • Physical device and device: A system may contain more than one physical Vulkan-capable hardware device. A physical device represents a unique device, whereas a device refers to a logical representation of the physical device in an application.

  • Queues: A queue represents an interface between the execution engine and the application. A physical device always contains one or more queues (graphics, compute, DMA/transfer, and so on). A queue's responsibility is to gather the jobs (command buffers) and dispatch them to the physical device for processing.

  • Memory type: Vulkan exposes various memory types. At a broader level, there are two types of memory: host and device. As we proceed through this chapter, we will cover these.

  • Command: A command is an instruction to do some act. A command can be broadly divided into action, set state, or synchronization.

    • Action commands: These can be used to draw primitives, clear a surface, copy a buffer, query/timestamp operations, and begin/end subpass operations. These commands are capable of altering framebuffer attachments, reading or writing into the memory (buffer or image), and writing query pools.

    • Set state commands: These help bind the pipelines, descriptor sets, and buffers; they also help set a dynamic state and render a pass/subpass state.

    • Synchronization commands: Synchronization helps in satisfying the requirements of two or more action commands, which may compete for resources or have some memory dependencies. This includes setting or waiting for events, inserting the pipeline barrier, and rendering pass/subpass dependencies.

  • Command buffer: A command buffer is a collection of commands; it records the commands and submits them to the queues.

In the next section, we will take an overview of Vulkan to help us understand its working model and fundamental basics. We will also understand the command syntax rules get an idea of API commands by simply looking at them.

 

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.

 

Understanding the Vulkan application


This section will provide you with an overview of the various components that contribute to, and are helpful in building a Vulkan application.

The following block diagram shows the different component blocks and respective interconnections within the system:

Driver

A Vulkan-capable system comprises a minimum of one CPU and GPU. IHV's vendor supplies the driver of a given Vulkan specification implementation for their dedicated GPU architecture. The driver acts as an interface between the application and the device itself. It provides high-level facilities to the application so it can communicate with the device. For example, it advertises the number of devices available on the system, their queues and queue capabilities, available heaps and their related properties, and so on.

Application

An application refers to a user-written program that is intended to make use of Vulkan APIs to perform graphics or compute jobs. The application starts with the initialization of the hardware and software; it detects the driver and loads all the Vulkan APIs. The presentation layer is initialized with Vulkan's Window System Integration (WSI) APIs; WSI will be helpful in rendering the drawing image on the display surface. The application creates resources and binds them to the shader stage using descriptors. The descriptor set layout helps bind the created resources to the underlying pipeline object that is created (of the graphics or compute type). Finally, command buffers are recorded and submitted to the queue for processing.

WSI

Windows System Integration is a set of extensions from Khronos for the unification of the presentation layer across different platforms, such as Linux, Windows, and Android.

SPIR-V

SPIR-V provides a precompiled binary format for specifying shaders to Vulkan. Compilers are available for various shader source languages, including variants of GLSL and HLSL, which produce SPIR-V.

LunarG SDK

The Vulkan SDK from LunarG comprises a variety of tools and resources to aid Vulkan application development. These tools and resources include the Vulkan loader, validation layers, trace and replay tools, SPIR-V tools, Vulkan runtime installer, documentation, samples, and demos, see Chapter 3, Shaking Hands with the Device to see detailed description to get started with LunarG SDK. You can read more about it at http://lunarg.com/vulkan-sdk.

 

Getting started with the Vulkan programming model


Let's discuss the Vulkan programming model in detail. Here, the end user, considering he or she is a total beginner, will be able to understand the following concepts:

  • The Vulkan programming model

  • The rendering execution model, which will be described using a pseudo step-by-step approach

  • How Vulkan works

The following diagram shows a top-down approach of the Vulkan application programming model; we will understand this process in detail and also delve into the sublevel components and their functionalities:

Hardware initialization

When a Vulkan application starts, its very first job is the initialization of the hardware. Here, the application activates the Vulkan drivers by communicating with the loader. The following diagram represents a block diagram of a Loader with its subcomponents:

Loader: A loader is a piece of code used in the application start-up to locate the Vulkan drivers in a system in a unified way across platforms. The following are the responsibilities of a loader:

  • Locating drivers: As its primary job, a loader knows where to search for drivers in the given system. It finds the correct driver and loads it.

  • Platform-independent: Initializing Vulkan is consistent across all platforms. Unlike OpenGL, where creating a context requires working with a different window system API for each environment, EGL, GLX, and WGL. Platform differences in Vulkan are expressed as extensions.

  • Injectable layers: A loader supports a layered architecture and provides the capability to inject various layers at runtime. The big improvement is that the driver need not do any of the work (or retain any of the states it would need to do the work) in determining whether the application's use of the API is valid. Therefore, it's advisable to turn on the selected injectable layers, as per application requirements, during the development stage and turn them off at the deployment stage. For example, injectable layers can offer the following:

    • Tracing the Vulkan API commands

    • Capturing rendered scenes and executing them later

    • Error and validation for debugging purposes

The Vulkan application first performs a handshake with the loader library and initializes the Vulkan implementation driver. The loader library loads Vulkan APIs dynamically. The loader also offers a mechanism that allows the automatic loading of specific layers into all Vulkan applications; this is called an Implicit-Enabled layer.

Once the loader locates the drivers and successfully links with the APIs, the application is responsible for the following:

  • Creating a Vulkan instance

  • Querying the physical device for the available queues

  • Querying extensions and storing them as function pointers, such as WSI or special feature APIs

  • Enabling an injectable layer for error checking, debugging, or the validation process

Window presentation surfaces

Once the Vulkan implementation driver is located by the loader, we are good to draw something using the Vulkan APIs. For this, we need an image to perform the drawing task and put it on the presentation window to display it:

Building a presentation image and creating windows are very platform-specific jobs. In OpenGL, windowing is intimately linked; the window system framebuffer is created along with context/device. The big difference from GL here is that context/device creation in Vulkan needn't involve the window system at all; it is managed through Window System Integration (WSI).

WSI contains a set of cross-platform windowing management extensions:

  • A unique cross-platform implementation for the majority of platforms, such as Windows, Linux, Android, and other OSes

  • A consistent API standard to easily create surfaces and display them without getting into the details

WSI supports multiple windowing systems, such as Wayland, X, and Windows, and it also manages the ownership of images via a swapchain.

WSI provides a swapchain mechanism; this allows the use of multiple images in such a way that, while the window system is displaying one image, the application can prepare the next.

The following screenshot shows the double-buffering swap image process. It contains two images named First Image and Second Image. These images are swapped between Application and Display with the help of WSI:

WSI works as an interface between Display and Application. It makes sure that both images are acquired by Display and Application in a mutually exclusive way. Therefore, when an Application works on First Image, WSI hands over Second Image to Display in order to render its contents. Once the Application finishes the painting First image, it submits it to the WSI and in return acquires Second Image to work with and vice-versa.

At this point, perform the following tasks:

  • Create a native window (like the CreateWindow method in the Windows OS)

  • Create a WSI surface attached to the window

  • Create the swapchain to present to the surface

  • Request the drawing images from the created swapchain

Resource setup

Setting up resources means storing data into memory regions. It could be any type of data, for example, vertex attributes, such as position, color, or image type/name. Certainly, the data has resided somewhere in the memory for Vulkan to access it.

Unlike OpenGL, which manages the memory behind the scenes using hints, Vulkan provides full low-level access and control of the memory. Vulkan advertises the various types of available memory on the physical device, providing the application with a fine opportunity to manage these different types of memory explicitly.

Memory heaps can be categorized into two types, based upon their performance:

  • Host local: This is a slower type of memory

  • Device local: This is a type of memory with high bandwidth; it is faster

Memory heaps can be further divided based upon their memory type configurations:

  • Device local: This type of memory is physically attached to the physical device:

    • Visible to the device

    • Not visible to the host

  • Device local, host visible: This type of memory is also physically attached to the device:

    • Visible to the device

    • Visible to the host

  • Host local, host visible: This refers to the local memory of the host, but it is slower than the local device:

    • Visible to the device

    • Visible to the host

In Vulkan, resources are explicitly taken care of by the application with exclusive control of memory management. The following is the process of resource management:

  • Resource objects: For resource setup, an application is responsible for allocating memory for resources; these resources could be either images or buffer objects.

  • Allocation and suballocations: When resource objects are created, only logical addresses are associated with them; there is no physical backing available. The application allocates physical memory and binds these logical addresses to it. As allocation is an expensive process, suballocation is an efficient way to manage the memory; it allocates a big chunk of physical memory at once and puts different resource objects into it. Suballocation is the responsibility of an application. The following diagram shows the suballocated object from the big allocated piece of physical memory:

  • Sparse memory: For very large image objects, Vulkan fully supports sparse memory with all its features. Sparse memory is a special feature that allows you to store large image resources; which are much larger than the actual memory capacity, in the memory. This technique breaks the image into tiles and loads only those tiles that fit the application logic.

  • Staging buffers: The population of the object and image buffers is done using staging, where two different memory regions are used for the physical allocation. The ideal memory placement for a resource may not be visible to the host. In this case, the application must first populate the resource in a staging buffer that is host-visible and then transfer it to the ideal location.

  • Asynchronous transfer: The data is transferred asynchronously using asynchronous commands with any of the graphics or DMA/transfer queues.

Tip

Physical memory allocation is expensive; therefore, a good practice is to allocate a large physical memory and then suballocate objects.

In contrast, OpenGL resource management does not offer granular control over the memory. There is no conception of host and device memory; the driver secretly does all of the allocation in the background. Also, these allocation and suballocation processes are not fully transparent and might change from one driver to another. This lack of consistency and hidden memory management cause unpredictable behavior. Vulkan, on the other hand, allocates the object right there in the chosen memory, making it highly predictable.

Therefore, during the resource setup stage, you need to perform the following tasks:

  1. Create a resource object.

  2. Query the appropriate memory instance and create a memory object like buffer and images.

  3. Get the memory requirements for the allocation.

  4. Allocate space and store data in it.

  5. Bind the memory with the resource object that we created.

Pipeline setup

A pipeline is a set of events that occur in a fixed sequence defined by the application logic. These events consist of the following: supplying the shaders, binding them to the resource, and managing the state:

Descriptor sets and descriptor pools

A descriptor set is an interface between resources and shaders. It is a simple structure that binds the shader to the resource information, such as images or buffers. It associates or binds a resource memory that the shader is going to use. The following are the characteristics associated with descriptor sets:

  • Frequent change: By nature, a descriptor set changes frequently; generally, it contains attributes such as material, texture, and so on.

  • Descriptor pool: Considering the nature of descriptor sets, they are allocated from a descriptor pool without introducing global synchronization

  • Multithread scalability: This allows multiple threads to update the descriptor set simultaneously

Tip

Updating or changing a descriptor set is one of the most performance-critical paths in rendering Vulkan. Therefore, the design of a descriptor set is an important aspect in achieving maximum performance. Vulkan supports logical partitioning of multiple descriptor sets at the scene (low frequency updates), model (medium frequency updates), and draw level (high frequency updates). This ensures that the high frequency update descriptor does not affect low frequency descriptor resources.

Shaders with SPIR-V

The only way to specify shaders or compute kernels in Vulkan is through SPIR-V. The following are some characteristics associated with it:

  • Multiple inputs: SPIR-V producing compilers exist for various source languages, including GLSL and HLSL. These can be used to convert a human-readable shader into a SPIR-V intermediate representation.

  • Offline compilation: Shaders/kernels are compiled offline and injected upfront.

  • glslangValidator: LunarG SDK provides the glslangValidator compiler, which can be used to create SPIR-V shaders from equivalent GLSL shaders.

  • Multiple entry points: The shader object provides multiple entry points. This is very beneficial for reducing the shipment size (and the loaded size) of the SPIR-V shaders. Variants of a shader can be packaged into a single module.

Pipeline management

A physical device contains a range of hardware settings that determine how the submitted input data of a given geometry needs to be interpreted and drawn. These settings are collectively called pipeline states. These include the rasterizer state, blend state, and depth stencil state; they also include the primitive topology type (point/line/triangle) of the submitted geometry and the shaders that will be used for rendering. There are two types of states: dynamic and static. The pipeline states are used to create the pipeline object (graphics or compute), which is a performance-critical path. Therefore, we don't want to create them again and again; we want to create them once and reuse them.

Vulkan allows you to control states using pipeline objects in conjunction with Pipeline Cache Object (PCO) and the pipeline layout:

  • Pipeline objects: Pipeline creation is expensive. It includes shader recompilation, resource binding, Render Pass, framebuffer management, and other related operations. Pipeline objects could be numbered in hundreds and thousands; therefore, each different state combination is stored as a separate pipeline object.

  • PCO: The creation of pipelines is expensive; therefore once created, a pipeline can be cached. When a new pipeline is requested, the driver can look for a closer match and create the new pipeline using the base pipeline.

Pipeline caches are opaque, and the details of their use by the driver are unspecified. The application is responsible for persisting the cache if it wishes to reuse it across runs and for providing a suitable cache at the time of pipeline creation if it wishes to reap potential benefits.

  • Pipeline layout: Pipeline layouts describe the descriptor sets that will be used with the pipeline, indicating what kind of resource is attached to each binding slot in the shader. Different pipeline objects can use the same pipeline layout.

In the pipeline management stage, this is what happens:

  • The application compiles the shader into SPIR-V form and specifies it in the pipeline shader state.

  • The descriptor helps us connect these resources to the shader itself. The application allocates the descriptor set from the descriptor pool and connects the incoming or outgoing resources to the binding slots in the shader.

  • The application creates pipeline objects, which contain the static and dynamic state configuration to control the hardware settings. The pipeline should be created from a pipeline cache pool for better performance.

Recording commands

Recording commands is the process of command buffer formation. Command buffers are allocated from the command pool memory. Command pools can also be used for multiple allocations. A command buffer is recorded by supplying commands within a given start and end scope defined by the application. The following diagram illustrates the recording of a drawing command buffer, and as you can see, it comprises many commands recorded in the top-down order responsible for object painting.

Note

Note that the commands in the command buffer may vary with the job requirement. This diagram is just an illustration that covers the most common steps performed while drawing primitives.

The major parts of drawing the are covered here:

  • Scope: The scope defines the start and end of the command buffer recording.

  • Render Pass: This defines the execution process of a job that might affect the framebuffer cache. It may comprise attachments, subpasses, and dependencies between those subpasses. The attachment refers to images on which the drawing is performed. In a subpass, an attachment-like image can be subpassed for multisampling resolve. Render Pass also controls how the framebuffer will be treated at the beginning of the pass: it will either retain the last information on it or clear it with the given color. Similarly, at the end of the Render Pass, the results are going to be either discarded or stored.

  • Pipeline: This contains the states' (static/dynamic) information represented by a pipeline object.

  • Descriptor: This binds the resource information to the pipeline.

  • Bind resource: This specifies the vertex buffer, image, or other geometry-related information.

  • Viewport: This determines the portion of the drawing surface on which the rendering of the primitives will be performed.

  • Scissor: This defines a rectangular space region beyond which nothing will be drawn.

  • Drawing: The draw command specifies geometry buffer attributes, such as the start index, total count, and so on.

Tip

The creation of a command buffer is an expensive job; it considers the most performance-critical path. It can be reused numerous times if the same work needs to happen on many frames. It can be resubmitted without needing to re-record it. Also, multiple command buffers can be produced simultaneously using multiple threads. Vulkan is specially designed to exploit multithreaded scalability. Command pools ensure there is no lock contention if used in a multithreaded environment.

The following diagram shows a scalable command buffer creation model with a multicore and multithreading approach. This model provides true parallelism with multicore processors.

Here, each thread is made to utilize a separate command buffer pool, which allocates either single or multiple command buffers, allowing no fights on resource locks.

Queue submission

Once command buffers are built, they can be submitted to a queue for processing. Vulkan exposes different types of queue to the application, such as the graphics, DMA/transfer, or compute queues. Queue selection for submission is very much dependent upon the nature of the job. For example, graphics-related tasks must be submitted to the graphics queue. Similarly, for compute operations, the compute queue will be the best choice. The submitted jobs are executed in an asynchronous fashion. Command buffers can be pushed into separate compatible queues allowing parallel execution. The application is responsible for any kind of synchronization within command buffers or between queues, even between the host and device themselves.

Queue submission performs the following jobs:

  • Acquiring the images from the swapchain on which the next frame will be drawn

  • Deploying any synchronization mechanism, such as semaphore and fence, required

  • Gathering the command buffer and submitting it to the required device queue for processing

  • Requesting the presentation of the completed painted images on the output device

 

Summary


This introductory chapter has boiled down Vulkan to a level where understanding it will be really easy for beginners. In this chapter, we learned about the evolution of Vulkan and understood the history and people behind it. Then, we distinguished this API from OpenGL and understood the reasons for its existence in the modern computing age. We also looked at simple and easy definitions of the important technical jargon associated with this API. The fundamentals of the Vulkan API provide a precise and enriched overview of its working model. We also saw the basic building blocks of the Vulkan ecosystem and got to know their roles and responsibilities with interconnections. Finally, at the end of the chapter, we understood how Vulkan works with an easy-to-understand step-by-step pseudo programming model approach.

After you finish this chapter, you will be expected to have a basic understanding of the Vulkan API and its detailed working model along with a reasonable familiarity acquaintance with its technical jargon, to take your first steps in Vulkan programming.

In the next chapter, we will start with Vulkan programming using a pseudocode approach. We will create a simple example without going into much details yet still covering important core aspects, the fundamentals of Vulkan API, and data structures to understand the complete process of graphics pipeline programming in Vulkan.

About the Author
  • Parminder Singh

    Parminder Singh is a computation graphics engineer with Blackmagic Design, Singapore. He has been working and developing graphic applications in the fields of network simulations, geo-modeling, navigation, automotive, infotainment systems, image processing, and post-production for the past decade. His research interests include GPU programming for scalable graphics and compute applications, porting, and performance optimization techniques. He is a Vulkan, Metal and OpenGL ES trainer and has also authored OpenGL ES 3.0 Cookbook, Packt. His hobbies include traveling, light cooking, and spending quality time with his baby girl. Feel free to connect Parminder at https://www.linkedin.com/in/parmindersingh18 or you can reach him at http://openglescookbook.com.

    Browse publications by this author
Latest Reviews (2 reviews total)
An average tutorial, a number of typos and a Windows only approach. I liked the on-the-fly glsl compilation bits and the emphasys on cmake.
Great book for beginners to Vulkan!
Learning Vulkan
Unlock this book and the full library FREE for 7 days
Start now