Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Vulkan Cookbook
Vulkan Cookbook

Vulkan Cookbook: Work through recipes to unlock the full potential of the next generation graphics API—Vulkan

eBook
€28.99 €32.99
Paperback
€41.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

Vulkan Cookbook

Instance and Devices

In this chapter, we will cover the following recipes:

  • Downloading Vulkan SDK
  • Enabling validation layers
  • Connecting with a Vulkan Loader library
  • Preparing for loading Vulkan API functions
  • Loading function exported from a Vulkan Loader library
  • Loading global-level functions
  • Checking available Instance extensions
  • Creating a Vulkan Instance
  • Loading instance-level functions
  • Enumerating available physical devices
  • Checking available device extensions
  • Getting features and properties of a physical device
  • Checking available queue families and their properties
  • Selecting the index of a queue family with the desired capabilities
  • Creating a logical device
  • Loading device-level functions
  • Getting a device queue
  • Creating a logical device with geometry shaders and graphics and compute queues
  • Destroying a logical device
  • Destroying a Vulkan Instance
  • Releasing a Vulkan Loader library

Introduction

Vulkan is a new graphics API developed by the Khronos Consortium. It is perceived as a successor to the OpenGL: it is open source and cross-platform. However, as it is possible to use Vulkan on different types of devices and operating systems, there are some differences in the basic setup code we need to create in order to use Vulkan in our application.

In this chapter, we will cover topics that are specific to using Vulkan on Microsoft Windows and Ubuntu Linux operating systems. We will learn Vulkan basics such as downloading the Software Development Kit (SDK) and setting validation layers, which enable us to debug the applications that use the Vulkan API. We will start using the Vulkan Loader library, load all the Vulkan API functions, create a Vulkan Instance, and select the device our work will be executed on.

Downloading Vulkan's SDK

To start developing applications using the Vulkan API, we need to download a SDK and use some of its resources in our application.

Vulkan's SDK can be found at https://vulkan.lunarg.com.

Getting ready

Before we can execute any application that uses the Vulkan API, we also need to install a graphics drivers that supports the Vulkan API. These can be found on a graphics hardware vendor's site.

How to do it...

On the Windows operating system family:

  1. Go to https://vulkan.lunarg.com.
  2. Scroll to the bottom of the page and choose WINDOWS operating system.
  3. Download and save the SDK installer file.
  1. Run the installer and select the destination at which you want to install the SDK. By default, it is installed to a C:\VulkanSDK\<version>\ folder.
  2. When the installation is finished, open the folder in which the Vulkan SDK was installed and then open the RunTimeInstaller sub-folder. Execute VulkanRT-<version>-Installer file. This will install the latest version of the Vulkan Loader.
  3. Once again, go to the folder in which the SDK was installed and open the Include\vulkan sub-folder. Copy the vk_platform.h and vulkan.h header files to the project folder of the application you want to develop. We will call these two files Vulkan header files.

On the Linux operating system family:

  1. Update system packages by running the following commands:
       sudo apt-get update
       sudo apt-get dist-upgrade
  1. To be able to build and execute Vulkan samples from the SDK, install additional development packages by running the following command:
       sudo apt-get install libglm-dev graphviz libxcb-dri3-0 
       libxcb-present0 libpciaccess0 cmake libpng-dev libxcb-dri3-
       dev libx11-dev
  1. Go to https://vulkan.lunarg.com.
  2. Scroll to the bottom of the page and choose LINUX operating system.
  3. Download the Linux package for the SDK and save it in the desired folder.
  4. Open Terminal and change the current directory to the folder to which the SDK package was downloaded.
  5. Change the access permissions to the downloaded file by executing the following command:
       chmod ugo+x vulkansdk-linux-x86_64-<version>.run
  1. Run the downloaded SDK package installer file with the following command:
       ./vulkansdk-linux-x86_64-<version>.run
  1. Change the current directory to the VulkanSDK/<version> folder that was created by the SDK package installer.
  1. Set up environment variables by executing the following command:
      sudo su
      VULKAN_SDK=$PWD/x86_64
      echo export PATH=$PATH:$VULKAN_SDK/bin >> /etc/environment
      echo export VK_LAYER_PATH=$VULKAN_SDK/etc/explicit_layer.d >> 
      /etc/environment
      echo $VULKAN_SDK/lib >> /etc/ld.so.conf.d/vulkan.conf
      ldconfig
  1. Change the current directory to the x86_64/include/vulkan folder.
  2. Copy vk_platform.h and vulkan.h header files to the project folder of the application you want to develop. We will call these two files Vulkan header files.
  3. Restart the computer for the changes to take effect.

How it works...

The SDK contains resources needed to create applications using the Vulkan API. Vulkan header files (the vk_platform.h and vulkan.h files) need to be included in the source code of our application so we can use the Vulkan API functions, structures, enumerations, and so on, inside the code.

The Vulkan Loader (vulkan-1.dll file on Windows, libvulkan.so.1 file on Linux systems) is a dynamic library responsible for exposing Vulkan API functions and forwarding them to the graphics driver. We connect with it in our application and load Vulkan API functions from it.

See also

The following recipes in this chapter:

  • Enabling validation layers
  • Connecting with a Vulkan Loader library
  • Releasing a Vulkan Loader library

Enabling validation layers

The Vulkan API was designed with performance in mind. One way to increase its performance is to lower state and error checking performed by the driver. This is one of the reasons Vulkan is called a "thin API" or "thin driver," it is a minimal abstraction of the hardware, which is required for the API to be portable across multiple hardware vendors and device types (high-performance desktop computers, mobile phones, and integrated and low-power embedded systems).

However, this approach makes creating applications with the Vulkan API much more difficult, compared to the traditional high-level APIs such as OpenGL. It's because very little feedback is given to developers by the driver, as it expects that programmers will correctly use the API and abide by rules defined in the Vulkan specification.

To mitigate this problem, Vulkan was also designed to be a layered API. The lowest layer, the core, is the Vulkan API itself, which communicates with the Driver, allowing us to program the Hardware (as seen in the preceding diagram). On top of it (between the Application and the Vulkan API), developers can enable additional layers, to ease the debugging process.

How to do it...

On the Windows operating system family:

  1. Go to the folder in which the SDK was installed and then open the Config sub-directory.
  2. Copy the vk_layer_settings.txt file into the directory of the executable you want to debug (into a folder of an application you want to execute).
  3. Create an environment variable named VK_INSTANCE_LAYERS:
    1. Open the command-line console (Command Prompt/cmd.exe).
    2. Type the following:
              setx VK_INSTANCE_LAYERS 
              VK_LAYER_LUNARG_standard_validation

3. Close the console.

  1. Re-open the command prompt once again.
  2. Change the current directory to the folder of the application you want to execute.
  3. Run the application; potential warnings or errors will be displayed in the standard output of the command prompt.

On the Linux operating system family:

  1. Go to the folder in which the SDK was installed and then open the Config sub-directory.
  2. Copy the vk_layer_settings.txt file into the directory of the executable you want to debug (into a folder of an application you want to execute).
  3. Create an environment variable named VK_INSTANCE_LAYERS:
    1. Open the Terminal window.
    2. Type the following:
              export
              VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_standard_validation
  1. Run the application; potential warnings or errors will be displayed in the standard output of the Terminal window.

How it works...

Vulkan validation layers contain a set of libraries which help find potential problems in created applications. Their debugging capabilities include, but are not limited to, validating parameters passed to Vulkan functions, validating texture and render target formats, tracking Vulkan objects and their lifetime and usage, and checking for potential memory leaks or dumping (displaying/printing) Vulkan API function calls. These functionalities are enabled by different validation layers, but most of them are gathered into a single layer called VK_LAYER_LUNARG_standard_validation which is enabled in this recipe. Examples of names of other layers include VK_LAYER_LUNARG_swapchain, VK_LAYER_LUNARG_object_tracker, VK_LAYER_GOOGLE_threading, or VK_LAYER_LUNARG_api_dump, among others. Multiple layers can be enabled at the same time, in a similar way as presented here in the recipe. Just assign the names of the layers you want to activate to the VK_INSTANCE_LAYERS environment variable. If you are a Windows OS user, remember to separate them with a semicolon, as in the example:

setx VK_INSTANCE_LAYERS VK_LAYER_LUNARG_api_dump;VK_LAYER_LUNARG_core_validation

If you are a Linux OS user, separate them with a colon. Here is an example:

export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump:VK_LAYER_LUNARG _core_validation

The environment variable named VK_INSTANCE_LAYERS can be also set with other OS specific ways such as, advanced operating system settings on Windows or /etc/environment on Linux.

The preceding examples enable validation layers globally, for all applications, but they can also be enabled only for our own application, in its source code during Instance creation. However, this approach requires us to recompile the whole program every time we want to enable or disable different layers. So, it is easier to enable them using the preceding recipe. This way, we also won't forget to disable them when we want to ship the final version of our application. To disable validation layers, we just have to delete VK_INSTANCE_LAYERS environment variable.

Validation layers should not be enabled in the released (shipped) version of the applications as they may drastically decrease performance.

For a full list of available validation layers, please refer to the documentation, which can be found in the Documentation sub-folder of the directory in which the Vulkan SDK was installed.

See also

The following recipes in this chapter:

  • Downloading Vulkan's SDK
  • Connecting with a Vulkan Loader library
  • Releasing a Vulkan Loader library

Connecting with a Vulkan Loader library

Support for the Vulkan API is implemented by the graphics-hardware vendor and provided through graphics drivers. Each vendor can implement it in any dynamic library they choose, and can even change it with the driver update.

That's why, along with the drivers, Vulkan Loader is also installed. We can also install it from the folder in which the SDK was installed. It allows developers to access Vulkan API entry points, through a vulkan-1.dll library on Windows OS or libvulkan.so.1 library on Linux OS, no matter what driver, from what vendor, is installed.

Vulkan Loader is responsible for transmitting Vulkan API calls to an appropriate graphics driver. On a given computer, there may be more hardware components that support Vulkan, but with Vulkan Loader, we don't need to wonder which driver we should use, or which library we should connect with to be able to use Vulkan. Developers just need to know the name of a Vulkan library: vulkan-1.dll on Windows or libvulkan.so.1 on Linux. When we want to use Vulkan in our application, we just need to connect with it in our code (load it).

On Windows OS, Vulkan Loader library is called vulkan-1.dll.
On Linux OS, Vulkan Loader library is called libvulkan.so.1.

How to do it...

On the Windows operating system family:

  1. Prepare a variable of type HMODULE named vulkan_library.
  2. Call LoadLibrary( "vulkan-1.dll" ) and store the result of this operation in a vulkan_library variable.
  3. Confirm that this operation has been successful by checking if a value of a vulkan_library variable is different than nullptr.

On the Linux operating system family:

  1. Prepare a variable of type void* named vulkan_library.
  2. Call dlopen( "libvulkan.so.1", RTLD_NOW ) and store the result of this operation in a vulkan_library variable.
  3. Confirm that this operation has been successful by checking if a value of a vulkan_library variable is different than nullptr.

How it works...

LoadLibrary() is a function available on Windows operating systems. dlopen() is a function available on Linux operating systems. They both load (open) a specified dynamic-link library into a memory space of our application. This way we can load (acquire pointers of) functions implemented and exported from a given library and use them in our application.

In the case of a function exported from a Vulkan API, in which we are, of course, most interested, we load a vulkan-1.dll library on Windows or libvulkan.so.1 library on Linux as follows:

#if defined _WIN32 
vulkan_library = LoadLibrary( "vulkan-1.dll" ); 
#elif defined __linux 
vulkan_library = dlopen( "libvulkan.so.1", RTLD_NOW ); 
#endif 

if( vulkan_library == nullptr ) { 
  std::cout << "Could not connect with a Vulkan Runtime library." << std::endl; 
  return false; 
} 
return true;

After a successful call, we can load a Vulkan-specific function for acquiring the addresses of all other Vulkan API procedures.

See also

The following recipes in this chapter:

  • Downloading Vulkan SDK
  • Enabling validation layers
  • Releasing a Vulkan Loader library

Preparing for loading Vulkan API functions

When we want to use Vulkan API in our application, we need to acquire procedures specified in the Vulkan documentation. In order to do that, we can add a dependency to the Vulkan Loader library, statically link with it in our project, and use function prototypes defined in the vulkan.h header file. The second approach is to disable the function prototypes defined in the vulkan.h header file and load function pointers dynamically in our application.

The first approach is little bit easier, but it uses functions defined directly in the Vulkan Loader library. When we perform operations on a given device, Vulkan Loader needs to redirect function calls to the proper implementation based on the handle of the device we provide as an argument. This redirection takes some time, and thus impacts performance.

The second option requires more work on the application side, but allows us to skip the preceding redirection (jump) and save some performance. It is performed by loading functions directly from the device we want to use. This way, we can also choose only the subset of Vulkan functions if we don't need them all.

In this book, the second approach is presented, as this gives developers more control over the things that are going in their applications. To dynamically load functions from a Vulkan Loader library, it is convenient to wrap the names of all Vulkan API functions into a set of simple macros and divide declarations, definitions and function loading into multiple files.

How to do it...

  1. Define the VK_NO_PROTOTYPES preprocessor definition in the project: do this in the project properties (when using development environments such as Microsoft Visual Studio or Qt Creator), or by using the #define VK_NO_PROTOTYPES preprocessor directive just before the vulkan.h file is included in the source code of our application.
  2. Create a new file, named ListOfVulkanFunctions.inl.
  3. Type the following contents into the file:
      #ifndef EXPORTED_VULKAN_FUNCTION 
      #define EXPORTED_VULKAN_FUNCTION( function ) 
      #endif 

      #undef EXPORTED_VULKAN_FUNCTION 
      // 
      #ifndef GLOBAL_LEVEL_VULKAN_FUNCTION 
      #define GLOBAL_LEVEL_VULKAN_FUNCTION( function ) 
      #endif 

      #undef GLOBAL_LEVEL_VULKAN_FUNCTION 
      // 
      #ifndef INSTANCE_LEVEL_VULKAN_FUNCTION 
      #define INSTANCE_LEVEL_VULKAN_FUNCTION( function ) 
      #endif 

      #undef INSTANCE_LEVEL_VULKAN_FUNCTION 
      // 
      #ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION 
      #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function,       extension ) 
      #endif 

      #undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION 
      // 
      #ifndef DEVICE_LEVEL_VULKAN_FUNCTION 
      #define DEVICE_LEVEL_VULKAN_FUNCTION( function ) 
      #endif 

      #undef DEVICE_LEVEL_VULKAN_FUNCTION 
      // 
      #ifndef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION 
      #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function,
      extension ) 
      #endif 
       
      #undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
  1. Create a new header file, named VulkanFunctions.h.
  2. Insert the following contents into the file:
      #include "vulkan.h" 

      namespace VulkanCookbook { 

      #define EXPORTED_VULKAN_FUNCTION( name ) extern PFN_##name name; 
      #define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name 
      name; 
      #define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name 
      name; 
      #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name,
      extension ) extern PFN_##name name; 
      #define DEVICE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name 
      name; 
      #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, 
      extension ) extern PFN_##name name; 

      #include "ListOfVulkanFunctions.inl" 

      } // namespace VulkanCookbook
  1. Create a new file with a source code named VulkanFunctions.cpp.
  2. Insert the following contents into the file:
      #include "VulkanFunctions.h" 

      namespace VulkanCookbook { 

      #define EXPORTED_VULKAN_FUNCTION( name ) PFN_##name name; 
      #define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; 
      #define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; 
      #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, 
      extension ) PFN_##name name; 
      #define DEVICE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; 
      #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, 
      extension ) PFN_##name name; 

      #include "ListOfVulkanFunctions.inl" 

      } // namespace VulkanCookbook

How it works...

The preceding set of files may seem unnecessary, or even overwhelming, at first. VulkanFunctions.h and VulkanFunctions.cpp files are used to declare and define variables in which we will store pointers to Vulkan API functions. Declarations and definitions are done through a convenient macro definition and an inclusion of a ListOfVulkanFunctions.inl file. We will update this file and add the names of many Vulkan functions, from various levels. This way, we don't need to repeat the names of functions multiple times, in multiple places, which helps us avoid making mistakes and typos. We can just write the required names of Vulkan functions only once, in the ListOfVulkanFunctions.inl file, and include it when it's needed.

How do we know the types of variables for storing pointers to Vulkan API functions? It's quite simple. The type of each function's prototype is derived directly from the function's name. When a function is named <name>, its type is PFN_<name>. For example, a function that creates an image is called vkCreateImage(), so the type of this function is PFN_vkCreateImage. That's why macros defined in the presented set of files have just one parameter for function name, from which the type can be easily derived.

Last, but not least, remember that declarations and definitions of variables, in which we will store addresses of the Vulkan functions, should be placed inside a namespace, a class, or a structure. This is because, if they are made global, this could lead to problems on some operating systems. It's better to remember about namespaces and increase the portability of our code.

Place declarations and definitions of variables containing Vulkan API function pointers inside a structure, class, or namespace.

Now that we are prepared, we can start loading Vulkan functions.

See also

The following recipes in this chapter:

  • Loading function exported from a Vulkan Loader library
  • Loading global-level functions
  • Loading instance-level functions
  • Loading device-level functions

Loading functions exported from a Vulkan Loader library

When we load (connect with) a Vulkan Loader library, we need to load its functions to be able to use the Vulkan API in our application. Unfortunately, different operating systems have different ways of acquiring the addresses of functions exported from dynamic libraries (.dll files on Windows or .so files on Linux). However, the Vulkan API strives to be portable across many operating systems. So, to allow developers to load all functions available in the API, no matter what operating system they are targeting, Vulkan introduced a function which can be used to load all other Vulkan API functions. However, this one single function can only be loaded in an OS specific way.

How to do it...

On the Windows operating system family:

  1. Create a variable of type PFN_vkGetInstanceProcAddr named vkGetInstanceProcAddr.
  2. Call GetProcAddress( vulkan_library, "vkGetInstanceProcAddr" ), cast the result of this operation onto a PFN_vkGetInstanceProcAddr type, and store it in the vkGetInstanceProcAddr variable.
  3. Confirm that this operation succeeded by checking if a value of the vkGetInstanceProcAddr variable does not equal to nullptr.

On the Linux operating system family:

  1. Create a variable of type PFN_vkGetInstanceProcAddr named vkGetInstanceProcAddr.
  2. Call dlsym( vulkan_library, "vkGetInstanceProcAddr" ), cast the result of this operation onto a PFN_vkGetInstanceProcAddr type, and store it in the vkGetInstanceProcAddr variable.
  3. Confirm that this operation succeeded by checking if a value of the vkGetInstanceProcAddr variable does not equal to nullptr.

How it works...

GetProcAddress() is a function available on Windows operating systems. dlsym() is a function available on Linux operating systems. They both acquire an address of a specified function from an already loaded dynamic-link library. The only function that must be publicly exported from all Vulkan implementations is called vkGetInstanceProcAddr(). It allows us to load any other Vulkan function in a way that is independent of the operating system we are working on.

To ease and automate the process of loading multiple Vulkan functions, and to lower the probability of making mistakes, we should wrap the processes of declaring, defining, and loading functions into a set of convenient macro definitions, as described in the Preparing for loading Vulkan API functions recipe. This way, we can keep all Vulkan API functions in just one file which contains a list of macro-wrapped names of all Vulkan functions. We can then include this single file in multiple places and get use of the C/C++ preprocessor. By redefining macros, we can declare and define the variables in which we will store function pointers, and we can also load all of them.

Here is the updated fragment of the ListOfVulkanFunctions.inl file:

#ifndef EXPORTED_VULKAN_FUNCTION 
#define EXPORTED_VULKAN_FUNCTION( function ) 
#endif 

EXPORTED_VULKAN_FUNCTION( vkGetInstanceProcAddr ) 

#undef EXPORTED_VULKAN_FUNCTION

The rest of the files (VulkanFunctions.h and VulkanFunctions.h) remain unchanged. Declarations and definitions are automatically performed with preprocessor macros. However, we still need to load functions exported from the Vulkan Loader library. The implementation of the preceding recipe may look as follows:

#if defined _WIN32 
#define LoadFunction GetProcAddress 
#elif defined __linux 
#define LoadFunction dlsym 
#endif 

#define EXPORTED_VULKAN_FUNCTION( name )                          \
name = (PFN_##name)LoadFunction( vulkan_library, #name );         \
if( name == nullptr ) {                                           \
  std::cout << "Could not load exported Vulkan function named: "  \
    #name << std::endl;                                           \
  return false;                                                   \
} 

#include "ListOfVulkanFunctions.inl" 

return true;

First we define a macro that is responsible for acquiring an address of a vkGetInstanceProcAddr() function. It gets it from the library represented by the vulkan_library variable, casts the result of this operation onto a PFN_kGetInstanceProcAddr type, and stores it in a variable named vkGetInstanceProcAddr. After that, the macro checks whether the operation succeeded, and displays the proper message on screen in the case of a failure.

All the preprocessor "magic" is done when the ListOfVulkanFunctions.inl file is included and the preceding operations are performed for each function defined in this file. In this case, it is performed for only the vkGetInstanceProcAddr() function, but the same behavior is achieved for functions from other levels.

Now, when we have a function loading function, we can acquire pointers to other Vulkan procedures in an OS-independent way.

See also

The following recipes in this chapter:

  • Connecting with a Vulkan Loader library
  • Preparing for loading Vulkan API functions
  • Loading global-level functions
  • Loading instance-level functions
  • Loading device-level functions

Loading global-level functions

We have acquired a vkGetInstanceProcAddr() function, through which we can load all other Vulkan API entry points in an OS-independent way.

Vulkan functions can be divided into three levels, which are global, instance, and device. Device-level functions are used to perform typical operations such as drawing, shader-modules creation, image creation, or data copying. Instance-level functions allow us to create logical devices. To do all this, and to load device and instance-level functions, we need to create an Instance. This operation is performed with global-level functions, which we need to load first.

How to do it...

  1. Create a variable of type PFN_vkEnumerateInstanceExtensionProperties named vkEnumerateInstanceExtensionProperties.
  2. Create a variable of type PFN_vkEnumerateInstanceLayerProperties named vkEnumerateInstanceLayerProperties.
  3. Create a variable of type PFN_vkCreateInstance named vkCreateInstance.
  4. Call vkGetInstanceProcAddr( nullptr, "vkEnumerateInstanceExtensionProperties" ), cast the result of this operation onto the PFN_vkEnumerateInstanceExtensionProperties type, and store it in a vkEnumerateInstanceExtensionProperties variable.
  5. Call vkGetInstanceProcAddr( nullptr, "vkEnumerateInstanceLayerProperties" ), cast the result of this operation onto the PFN_vkEnumerateInstanceLayerProperties type, and store it in a vkEnumerateInstanceLayerProperties variable.
  6. Call vkGetInstanceProcAddr( nullptr, "vkCreateInstance" ), cast the result of this operation onto a PFN_vkCreateInstance type, and store it in the vkCreateInstance variable.
  7. Confirm that the operation succeeded by checking whether, values of all the preceding variables are not equal to nullptr.

How it works...

In Vulkan, there are only three global-level functions: vkEnumerateInstanceExtensionProperties(), vkEnumerateInstanceLayerProperties(), and vkCreateInstance(). They are used during Instance creation to check, what instance-level extensions and layers are available and to create the Instance itself.

The process of acquiring global-level functions is similar to the loading function exported from the Vulkan Loader. That's why the most convenient way is to add the names of global-level functions to the ListOfVulkanFunctions.inl file as follows:

#ifndef GLOBAL_LEVEL_VULKAN_FUNCTION 
#define GLOBAL_LEVEL_VULKAN_FUNCTION( function ) 
#endif 

GLOBAL_LEVEL_VULKAN_FUNCTION( vkEnumerateInstanceExtensionProperties ) 
GLOBAL_LEVEL_VULKAN_FUNCTION( vkEnumerateInstanceLayerProperties ) 
GLOBAL_LEVEL_VULKAN_FUNCTION( vkCreateInstance ) 

#undef GLOBAL_LEVEL_VULKAN_FUNCTION

We don't need to change the VulkanFunctions.h and VulkanFunctions.h files, but we still need to implement the preceding recipe and load global-level functions as follows:

#define GLOBAL_LEVEL_VULKAN_FUNCTION( name )                      \
name = (PFN_##name)vkGetInstanceProcAddr( nullptr, #name );       \
if( name == nullptr ) {                                           \
  std::cout << "Could not load global-level function named: "     \
    #name << std::endl;                                           \
  return false;                                                   \
} 

#include "ListOfVulkanFunctions.inl" 

return true;

A custom GLOBAL_LEVEL_VULKAN_FUNCTION macro takes the function name and provides it to a vkGetInstanceProcAddr() function. It tries to load the given function and, in the case of a failure, returns nullptr. Any result returned by the vkGetInstanceProcAddr() function is cast onto a PFN_<name> type and stored in a proper variable.

In the case of a failure, a message is displayed so the user knows which function couldn't be loaded.

See also

The following recipes in this chapter:

  • Preparing for loading Vulkan API functions
  • Loading function exported from a Vulkan Loader library
  • Loading instance-level functions
  • Loading device-level functions

Checking available Instance extensions

Vulkan Instance gathers per application state and allows us to create a logical device on which almost all operations are performed. Before we can create an Instance object, we should think about the instance-level extensions we want to enable. An example of one of the most important instance-level extensions are swapchain related extensions, which are used to display images on screen.

Extensions in Vulkan, as opposed to OpenGL, are enabled explicitly. We can't create a Vulkan Instance and request extensions that are not supported, because the Instance creation operation will fail. That's why we need to check which extensions are supported on a given hardware platform.

How to do it...

  1. Prepare a variable of type uint32_t named extensions_count.
  2. Call vkEnumerateInstanceExtensionProperties( nullptr, &extensions_count, nullptr ). All parameters should be set to nullptr, except for the second parameter, which should point to the extensions_count variable.
  3. If a function call is successful, the total number of available instance-level extensions will be stored in the extensions_count variable.
  4. Prepare a storage for the list of extension properties. It must contain elements of type VkExtensionProperties. The best solution is to use a std::vector container. Call it available_extensions.
  5. Resize the vector to be able to hold at least the extensions_count elements.
  1. Call vkEnumerateInstanceExtensionProperties( nullptr, &extensions_count, &available_extensions[0] ). The first parameter is once again set to nullptr; the second parameter should point to the extensions_count variable; the third parameter must point to an array of at least extensions_count elements of type VkExtensionProperties. Here, in the third parameter, provide an address of the first element of the available_extensions vector.
  2. If the function returns successfully, the available_extensions vector variable will contain a list of all extensions supported on a given hardware platform.

How it works...

Code that acquires instance-level extensions can be divided into two stages. First we get the total number of available extensions as follows:

uint32_t extensions_count = 0; 
VkResult result = VK_SUCCESS; 

result = vkEnumerateInstanceExtensionProperties( nullptr, &extensions_count, nullptr ); 
if( (result != VK_SUCCESS) || 
    (extensions_count == 0) ) { 
  std::cout << "Could not get the number of Instance extensions." << std::endl; 
  return false; 
}

When called with the last parameter set to nullptr, the vkEnumerateInstanceExtensionProperties() function stores the number of available extensions in the variable pointed to in the second parameter. This way, we know how many extensions are on a given platform and how much space we need to be able to store parameters for all of them.

When we are ready to acquire extensions' properties, we can call the same function once again. This time the last parameter should point to the prepared space (an array of VkExtensionProperties elements, or a vector, in our case) in which these properties will be stored:

available_extensions.resize( extensions_count ); 
result = vkEnumerateInstanceExtensionProperties( nullptr, &extensions_count, &available_extensions[0] ); 
if( (result != VK_SUCCESS) || 
    (extensions_count == 0) ) { 
  std::cout << "Could not enumerate Instance extensions." << std::endl; 
  return false; 
} 

return true;
The pattern of calling the same function twice is common in Vulkan. There are multiple functions, which store the number of elements returned in the query when their last argument is set to nullptr. When their last element points to an appropriate variable, they return the data itself.

Now that we have the list, we can look through it and check whether the extensions we would like to enable are available on a given platform.

See also

  • The following recipes in this chapter:
    • Checking available device extensions
  • The following recipe in Chapter 2, Image Presentation:
    • Creating a Vulkan Instance with WSI extensions enabled
Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • This book explores a wide range of modern graphics programming techniques and GPU compute methods to make the best use of the Vulkan API
  • Learn techniques that can be applied to a wide range of platforms desktop, smartphones, and embedded devices
  • Get an idea on the graphics engine with multi-platform support and learn exciting imaging processing and post-processing techniques

Description

Vulkan is the next generation graphics API released by the Khronos group. It is expected to be the successor to OpenGL and OpenGL ES, which it shares some similarities with such as its cross-platform capabilities, programmed pipeline stages, or nomenclature. Vulkan is a low-level API that gives developers much more control over the hardware, but also adds new responsibilities such as explicit memory and resources management. With it, though, Vulkan is expected to be much faster. This book is your guide to understanding Vulkan through a series of recipes. We start off by teaching you how to create instances in Vulkan and choose the device on which operations will be performed. You will then explore more complex topics such as command buffers, resources and memory management, pipelines, GLSL shaders, render passes, and more. Gradually, the book moves on to teach you advanced rendering techniques, how to draw 3D scenes, and how to improve the performance of your applications. By the end of the book, you will be familiar with the latest advanced techniques implemented with the Vulkan API, which can be used on a wide range of platforms.

Who is this book for?

This book is ideal for developers who know C/C++ languages, have some basic familiarity with graphics programming, and now want to take advantage of the new Vulkan API in the process of building next generation computer graphics. Some basic familiarity of Vulkan would be useful to follow the recipes. OpenGL developers who want to take advantage of the Vulkan API will also find this book useful.

What you will learn

  • Work with Swapchain to present images on screen
  • Create, submit, and synchronize operations processed by the hardware
  • Create buffers and images, manage their memory, and upload data to them from CPU
  • Explore descriptor sets and set up an interface between application and shaders
  • Organize drawing operations into a set of render passes and subpasses
  • Prepare graphics pipelines to draw 3D scenes and compute pipelines to perform mathematical calculations
  • Implement geometry projection and tessellation, texturing, lighting, and post-processing techniques
  • Write shaders in GLSL and convert them into SPIR-V assemblies
  • Find out about and implement a collection of popular, advanced rendering techniques found in games and benchmarks

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Apr 28, 2017
Length: 700 pages
Edition : 1st
Language : English
ISBN-13 : 9781786464705
Languages :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Apr 28, 2017
Length: 700 pages
Edition : 1st
Language : English
ISBN-13 : 9781786464705
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 124.97
Vulkan Cookbook
€41.99
Learning Vulkan
€45.99
OpenGL 4 Shading Language Cookbook
€36.99
Total 124.97 Stars icon

Table of Contents

12 Chapters
Instance and Devices Chevron down icon Chevron up icon
Image Presentation Chevron down icon Chevron up icon
Command Buffers and Synchronization Chevron down icon Chevron up icon
Resources and Memory Chevron down icon Chevron up icon
Descriptor Sets Chevron down icon Chevron up icon
Render Passes and Framebuffers Chevron down icon Chevron up icon
Shaders Chevron down icon Chevron up icon
Graphics and Compute Pipelines Chevron down icon Chevron up icon
Command Recording and Drawing Chevron down icon Chevron up icon
Helper Recipes Chevron down icon Chevron up icon
Lighting Chevron down icon Chevron up icon
Advanced Rendering Techniques Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Half star icon Empty star icon Empty star icon 2.9
(19 Ratings)
5 star 31.6%
4 star 10.5%
3 star 15.8%
2 star 5.3%
1 star 36.8%
Filter icon Filter
Top Reviews

Filter reviews by




Andrew Mitchell Oct 25, 2017
Full star icon Full star icon Full star icon Full star icon Full star icon 5
[Disclaimer: I received the ebook version of this product for free] I love it, the information is presented clearly and since Vulkan is relatively new it's hard to find good resources on it, but this is definitely a good resource for anyone wanting to learn Vulkan!
Amazon Verified review Amazon
Kindle Customer Oct 02, 2017
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Full disclosure: I received a copy of this book from the author; the following review is solely my opinion.The Vulkan Cookbook does an outstanding job of walking through the Vulkan API...with so many new concepts here, the level of detail the author goes into is greatly appreciated.Each chapter's "How to Do it" section provides code samples that cohesively illustrate each new structure and function while going through the steps to create a simple Vulkan renderer.The "How it Works" section of each chapter then describes what's going on under the hood and discusses not just the code, but the concepts behind the code; these sections have helped answer many of my questions.As someone who is currently learning Vulkan, I can say that anyone leaning Vulkan should consider this book to be an indispensable resource.
Amazon Verified review Amazon
cybereality Jan 31, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
So, as of this writing, I have read all 5 books available on Amazon on the Vulkan API and I would say that Vulkan Cookbook is one of the better resources out there. The format of the book is similar to other “cookbooks” you may have seen, with each recipe essentially describing one technique in a stand-alone fashion. Meaning the steps for each one will list fundamentals, like creating a logical device and all the other prerequisites, so you can easily refer back to one chapter when it’s time to implement a particular feature. I would personally recommend reading the text from front-to-back, as I think it’s a better way to learn, but you could certainly jump around and still not miss much (assuming you already have some understanding of Vulkan). Author Pawel Lapinski does a great job of showing real code for each recipe and only shows what is actually necessary for a technique. Unlike some other books, this isn’t a dry listing of the API documentation, rather the author shows practical usage of the API with some brief explanation. For this type of text, I think this works great and I imagine it would be very helpful to refer back to when it comes time to implement into your project.Among the chapters, Lapinski covers: instances and devices, image presentation, command buffers and synchronization, resources and memory, descriptor sets, render passes and framebuffers, shaders, graphics and compute pipelines, command recording and drawing, along with some additional chapters at the end for more general graphics programming concepts like loading textures and 3d models, lighting and shadowing, and cubemapping. Each chapter itself is then broken down into smaller recipes, that could be something like “enumerating available physical devices” to “submitting a command buffer to a queue”. This is really quite a good mix of topics, and, at 700 pages, adequate coverage is given to the most commonly used parts of the Vulkan API. Having already worked through some tutorials online, and read a few other books on Vulkan, most of the topics here were things I had some familiarity toward already, but I still found the reading helpful.Due to the tactical nature of the text, I would recommend the book for more intermediate to advanced programmers. While the author does a great job of explaining the specific steps needed to do particular actions in Vulkan, it may be helpful to at least understand some of the big picture before diving in here. I might even say this is the best book on the market today for Vulkan, though I’d probably also recommend reading it after one of the others available. It may be helpful to start with a Hello World type app in Vulkan, in which case you could first follow the awesome tutorial over at vulkan-tutorial.com, or get Kenwright’s Vulkan Graphics API: in 20 Minutes, which was a little rough but still a cheap and quick way to obtain an overview of the API. For beginners, or maybe people that want to start at a more basic level, Introduction to Computer Graphics and the Vulkan API (also by Kenwright) may be a more comfortable spot to jump in at. And the other books out there were good in their own right, though some of them didn’t move past simple function/structure documentation.One thing I really wish is that someone could make a Vulkan book on the level of Frank Luna’s DirectX series. Luna is able to show many practical graphics programming techniques in one book, and in the end you’ll have a handful of pretty sweet demos to showcase. Though Kenwright attempts this, I still haven’t seen this really accomplished yet for Vulkan. While the end chapters of Vulkan Cookbook do dip into this territory with shadow mapping and post processing, it would be nice to see an entire book written like this. However, given that Vulkan is a relatively new API, it’s probably more useful to start with the basics, and hope that competent readers can port techniques from other APIs once they have a feeling for how things work.Keep in mind, Vulkan is an advanced and complex topic, and a single book won’t teach you everything you need to know. While many of the Vulkan books out today have seemed to release to mixed reviews, I feel that all of them have been helpful. Even reading the same topics explained by different authors can help with knowledge understanding and retention. And there are also some unique things in each book, so I would fully recommend reading them all if you’re really serious about getting into Vulkan. I realize there are some advanced coders that can study the documentation and hit the ground running, but I find the “guided tour” offered from books to be more conducive to learning for me personally. Your opinion my differ, but I’d have to say that you can’t really go wrong with Vulkan Cookbook by Pawel Lapinski. Recommended.
Amazon Verified review Amazon
Michael Williams May 25, 2017
Full star icon Full star icon Full star icon Full star icon Full star icon 5
There are very few sources for Vulkan even on the internet. This is the best book or any documentation really that you'll find on it. The other books are just basic documentation and grossly complex for the sake of complexity. This book actually takes you step by step with great detail
Amazon Verified review Amazon
HumanComplex May 01, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
very clear (given the subject material, vulkan is stupidly verbose). tons of practical examples.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.