Instance
Any API that lets developers interact with a complex system must strike a balance between flexibility and ease of use. Vulkan goes unusually far on the flexibility side of this tradeoff by providing you with many tuning knobs at every stage of an execution process that most other GPU APIs largely hide from you. It therefore requires you to acquire an unusually good understanding of the complex process through which a GPU-based program gets things done.
In the first part of this course, we will make this complexity tractable by introducing it piece-wise, in the context of a trivial GPU program that merely squares an array of floating-point numbers. In the second part of the course, you will then see that once these basic concepts of Vulkan are understood, they easily scale them up to the complexity of a full Gray-Scott reaction.
As a first step, this chapter will cover how you can load the Vulkan library from Rust, set up a Vulkan instance in a way that eases later debugging, and enumerate available Vulkan devices.
Introducing vulkano
The first step that we must take before we can use Vulkan in Rust code, is to link your program to a Vulkan binding. This is a Rust crate that handles the hard work of linking to the Vulkan C library and exposing a Rust layer on top of it so that your Rust code may interact with it.
In this course, we will use the vulkano
crate for this
purpose. This crate builds on top of the auto-generated
ash
crate, which closely matches the Vulkan
C API with only minor Rust-specific API tweaks, by supplementing it with two
layers of abstraction:
- A low-level layer that re-exposes Vulkan types and functions in a manner that is more in line with Rust programmer expectations. For example, C-style free functions that operate on their first pointer parameter are replaced with Rust-style structs with methods.
- A high-level layer that automates away some common operations (like sub-allocation of GPU memory allocations into smaller chunks) and makes as many operations as possible safe (no possibility for undefined behavior).
Crucially, this layering is fine-grained (done individually for each Vulkan object type) and transparent (any high-level object lets you access the lower-level object below it). As a result, if you ever encounter a situation where the high-level layer has made design choices that are not right for your use case, you are always able to drop down to a lower-level layer and do things your own way.
This means that anything you can do with raw Vulkan API calls, you can also do
with vulkano
. But vulkano
will usually give you an alternate way to do
things that is easier, fast/flexible enough for most purposes, and requires a
lot less unsafe Rust code that must be carefully audited for memory/thread/type
safety. For many applications, this is a better tradeoff than using ash
directly.
The vulkano
dependency has already been added to this course’s example code,
but for reference, this is how you would add it:
# You do not need to type in this command, it has already been done for you
cargo add --no-default-features --features=macros vulkano
This adds the vulkano
dependency in a manner that disables the x11
feature
that enables X11 support. This feature is not needed for this course, where we
are not rendering images to X11 windows. And it won’t work in this course’s
Linux containers, which do not contain a complete X11 stack as this would
unnecessarily increase download size.
We do, however, keep the macros
features on, because we will need it in order
to use the vulkano-shaders
crate later on. We’ll discuss what this crate
does and why we need it in a future chapter.
Loading the library
Now that we have the vulkano
binding available, we can use it to load the
Vulkan library. In principle, you could customize this loading process to e.g.
switch between different Vulkan libraries, but in practice this is rarely needed
because as we will see later Vulkan provides several tools to customize the
behavior of the library.
Hence, for the purpose of this course, we will stick with the default
vulkano
library-loading method, which is appropriate for almost every Vulkan
application:
use std::error::Error;
use vulkano::library::VulkanLibrary;
// Simplify error handling with type-erased errors
type Result<T> = std::result::Result<T, Box<dyn Error>>;
fn main() -> Result<()> {
// Load the Vulkan library
let library = VulkanLibrary::new()?;
// ...
Ok(())
}
Like all system operations, loading the library can fail if e.g. no Vulkan implementation is installed on the host system, and we need to handle that.
Here, we choose to do it the easy way by converting the associated error type
into a type-erased Box<dyn Error>
type that can hold all error types, and
bubbling this error out of the main()
function using the ?
error propagation
operator. The Rust runtime will then take care of displaying the error message
and aborting the program with a nonzero exit code. This basic error handling
strategy is good enough for the simple utilities that we will be building
throughout this course.
Once errors are handled, we may query the resulting VulkanLibrary
object.
For example, we can…
- Check which revision of the Vulkan specification is supported. This versioning allows the Vulkan specification to evolve by telling us which newer features can be used by our application.
- Check which Vulkan extensions are supported. Extensions allow Vulkan to support features that do not make sense on every single system supported by the API, such as the ability to display visuals in X11 and Wayland windows on Linux.
- Check which Vulkan layers are available. Layers are stackable plugins that customize
the behavior of your Vulkan library without replacing it. For example,
the popular
VK_LAYER_KHRONOS_validation
layer adds error checking to all Vulkan functions, allowing you to check your application’s debug builds without slowing down its release builds.
Once we have learned what we need to know, we can then proceed with the next setup step, which is to set up a Vulkan API instance.
Setting up an instance
An Vulkan Instance
is configured from a VulkanLibrary
by specifying a
few things about our application, including which optional Vulkan library
features we want to use.
For reasons that will soon become clear, we must set up an Instance
before
we can do anything else with the Vulkan API, including enumerating available
devices.
While the basic process is easy, we will take a few detours along the way to set up some optional Vulkan features that will make our debugging experience nicer later on.
vulkano
configuration primer
For most configuration work, vulkano
uses a recuring API design pattern that
is based on configuration structs, where most fields have a default value.
When combined with Rust’s functional struct update syntax, this API design allows you to elegantly specify only the parameters that you care about. Here is an example:
use vulkano::instance::{InstanceCreateInfo, InstanceCreateFlags};
let instance_info = InstanceCreateInfo {
flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,
..InstanceCreateInfo::application_from_cargo_toml()
};
The above instance configuration struct expresses the following intent:
- We let the Vulkan implementation expose devices that do not fully conform with the Vulkan specification, but only a slightly less featureful “portability subset” thereof. This is needed for some exotic Vulkan implementations like MoltenVk, which layers on top of macOS’ Metal API to work around Apple’s lack of Vulkan support.
- We let
vulkano
infer the application name and version from our Cargo project’s metadata, so that we do not need to specify the same information in two different places. - For all other fields of the
InstanceCreateInfo
struct, we use the default instance configuration, which is to provide no extra information about our app to the Vulkan implementation and to enable no optional features.
Most optional Vulkan instance features are about interfacing with your operating system’s display features for rendering visuals on screen and are not useful for the kind of headless computations that we are going to study in this course. However, there are two optional Vulkan debugging features that we strongly advise enabling on every platform that supports them:
- If the
VK_LAYER_KHRONOS_validation
layer is available, then it is a good idea to enable it in your debug builds. This enables debugging features falling in the following categories, at a runtime performance cost:- Error checking for Vulkan entry points, whose invalid usage normally results
in instant Undefined Behavior.
vulkano
’s high level layer is already meant to prevent or report such incorrect usage, but unfortunately it is not immune to the occasional bug or limitation. It is thus good to have some defense-in-depth against UB in your debug builds before you try to report a GPU driver bug that later turns out to be avulkano
bug. - “Best practices” linting which detects suspicious API usage that is not illegal per the spec but may e.g. cause performance issues. This is basically a code linter executing at run-time with full knowledge of the application state.
- Ability to use
printf()
in GPU code in order to easily investigate its state when it behaves unexpectedly, aka “Debug Printf”.
- Error checking for Vulkan entry points, whose invalid usage normally results
in instant Undefined Behavior.
- The
VK_EXT_debug_utils
extension lets you send diagnostic messages from the Vulkan implementation to your favorite log output (stderr
,syslog
…). I would advise enabling it for both debug and release builds, on all systems that support it.- In addition to being heavily used by the aforementioned validation layer, these messages often provide invaluable context when you are trying to diagnose why an application refuses to run as expected on someone else’s computer.
Indeed, these two debugging features are so important that vulkano
provides
dedicated tooling for enabling and configuring them. Let’s look into that.
Validation layer
As mentioned above, the Vulkan validation layer has some runtime overhead and
partially duplicates the functionality of vulkano
’s safe API. Therefore, it is
normally only enabled in in debug builds.
We can check if the program is built in debug mode using the
cfg!(debug_assertions)
expression. When that is the case, we will want to
check if the VK_LAYER_KHRONOS_validation
layer is available, and if so add it
to the set of layers that we enable for our instance:
// Set up a blank instance configuration.
//
// For what we are going to do here, an imperative style will be more effective
// than the functional style shown above, which is otherwise preferred.
let mut instance_info = InstanceCreateInfo::application_from_cargo_toml();
// In debug builds...
if cfg!(debug_assertions)
// ...if the validation layer is available...
&& library.layer_properties()?
.any(|layer| layer.name() == "VK_LAYER_KHRONOS_validation")
{
// ...then enable it...
instance_info
.enabled_layers
.push("VK_LAYER_KHRONOS_validation".into());
// TODO: ...and configure it
}
// TODO: Proceed with rest of instance configuration
Back in the Vulkan 1.0 days, simply enabling the layer like this would have been enough. But as the TODO above suggests, the validation layer have since acquired optional features which are not enabled by default, largely because of their performance impact.
Because we only enable the validation layer in debug builds, where runtime
performance is not a big concern, we can enable as many of those as we like by
pushing the appropriate
flags
into the
enabled_validation_features
member of our InstanceCreateInfo
struct. The only limitation that we must
respect in doing so is that GPU-assisted validation (which provides extended
error checking) is incompatible with use of printf()
in GPU code. For the
purpose of this course, we will priorize GPU-assisted validation over GPU
printf()
.
The availability of these fine-grained settings is signaled by support of the
VK_EXT_validation_features
layer extension.1 We can detect this extension and enable it along with
almost every feature except for GPU printf()
using the following code:
use vulkano::instance::debug::ValidationFeatureEnable;
if library
.supported_layer_extensions("VK_LAYER_KHRONOS_validation")?
.ext_validation_features
{
instance_info.enabled_extensions.ext_validation_features = true;
instance_info.enabled_validation_features.extend([
ValidationFeatureEnable::GpuAssisted,
ValidationFeatureEnable::GpuAssistedReserveBindingSlot,
ValidationFeatureEnable::BestPractices,
ValidationFeatureEnable::SynchronizationValidation,
]);
}
And if we put it all together, we get the following validation layer setup routine:
/// Enable Vulkan validation layer in debug builds
fn enable_debug_validation(
library: &VulkanLibrary,
instance_info: &mut InstanceCreateInfo,
) -> Result<()> {
// In debug builds...
if cfg!(debug_assertions)
// ...if the validation layer is available...
&& library.layer_properties()?
.any(|layer| layer.name() == "VK_LAYER_KHRONOS_validation")
{
// ...then enable it...
instance_info
.enabled_layers
.push("VK_LAYER_KHRONOS_validation".into());
// ...along with most available optional features
if library
.supported_layer_extensions("VK_LAYER_KHRONOS_validation")?
.ext_validation_features
{
instance_info.enabled_extensions.ext_validation_features = true;
instance_info.enabled_validation_features.extend([
ValidationFeatureEnable::GpuAssisted,
ValidationFeatureEnable::GpuAssistedReserveBindingSlot,
ValidationFeatureEnable::BestPractices,
ValidationFeatureEnable::SynchronizationValidation,
]);
}
}
Ok(())
}
To conclude this section, it should be mentioned that the Vulkan validation
layer is not featured in the default Vulkan setup of most Linux distributions,
and must often be installed separately. For example, on Ubuntu, the
vulkan-validationlayers
separate package must be installed first. This is one
reason why you should never force-enable validation layers in production Vulkan
binaries.
Logging configuration
Now that validation layer has been taken care of, let us turn our attention to the other optional Vulkan debugging feature that we highlighted as worth enabling whenever possible, namely logging of messages from the Vulkan implementation.
Vulkan logging is configured using the
DebugUtilsMessengerCreateInfo
struct. There are three main things that we must specify here:
- What message severities
we want to handle.
- As in most logging systems, a simple
ERROR
/WARNING
/INFO
/VERBOSE
classification is used. But in Vulkan, enabling a certain severity does not implicitly enable higher severities, so you can e.g. handleERROR
andVERBOSE
messages using different strategies without handlingWARNING
andINFO
messages at all. - In typical Vulkan implementations,
ERROR
andWARNING
messages should be an exceptional event, whereasINFO
andVERBOSE
messages can be sent at an unpleasantly high frequency. However anERROR
/WARNING
message is often only understandable given the context of previousINFO
/VERBOSE
messages. It is therefore a good idea to printERROR
andWARNING
messages by default, but provide an easy way to printINFO
/VERBOSE
messages too when needed.
- As in most logging systems, a simple
- What message
types we want to handle.
- Most Vulkan implementation messages will fall in the
GENERAL
category, but the validation layer may send messages in theVALIDATION
andPERFORMANCE
category too. As you may guess, the latter messages types report application correctness and runtime performance issues respectively.
- Most Vulkan implementation messages will fall in the
- What we want to
do
when a message matches the above criteria.
- Building such a
DebugUtilsMessengerCallback
isunsafe
becausevulkano
cannot check that your messaging callback, which is triggered by Vulkan API calls, does not make any Vulkan API calls itself. Doing so is forbidden for hopefully obvious reasons.2 - Because we are building simple programs here, where the complexity of a
production-grade logging system like
syslog
is unnecessary, we will simply forward these messages tostderr
. For our first Vulkan program, aneprintln!()
call will suffice. - Vulkan actually uses a form of structured logging, where the logging callback does not receive just a message string, but also a bunch of associated metadata about the context in which the message was emitted. In the interest of simplicity, our callback will only print out a subset of this metadata, which should be enough for our purposes.
- Building such a
As mentioned above, we should expose the message severity tradeoff to the user.
We can do this using a simple clap
CLI interface.
Here we will leverage clap
’s Args
feature, which lets us modularize our CLI
arguments into several independent structs. This will later allow us to build
multiple clap
-based programs that share some common command-line arguments.
Along the way, we will also expose the ability discussed in the beginning of
this chapter to probe devices which are not fully Vulkan-compliant.
use clap::Args;
/// Vulkan instance configuration
#[derive(Debug, Args)]
pub struct InstanceOptions {
/// Increase Vulkan log verbosity. Can be specified multiple times.
#[arg(short, long, action = clap::ArgAction::Count)]
pub verbose: u8,
}
Once we have that, we can set up some basic Vulkan logging configuration…
use vulkano::instance::debug::{
DebugUtilsMessageSeverity, DebugUtilsMessageType,
DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo
};
/// Generate a Vulkan logging configuration
fn logger_info(options: &InstanceOptions) -> DebugUtilsMessengerCreateInfo {
// Select accepted message severities
type S = DebugUtilsMessageSeverity;
let mut message_severity = S::ERROR | S::WARNING;
if options.verbose >= 1 {
message_severity |= S::INFO;
}
if options.verbose >= 2 {
message_severity |= S::VERBOSE;
}
// Accept all message types
type T = DebugUtilsMessageType;
let message_type = T::GENERAL | T::VALIDATION | T::PERFORMANCE;
// Define the callback that turns messages to logs on stderr
// SAFETY: The logging callback makes no Vulkan API call
let user_callback = unsafe {
DebugUtilsMessengerCallback::new(|severity, ty, data| {
// Format message identifiers, if any
let id_name = data
.message_id_name
.map(|id_name| format!(" {id_name}"))
.unwrap_or_default();
let id_number = (data.message_id_number != 0)
.then(|| format!(" #{}", data.message_id_number))
.unwrap_or_default();
// Put most information into a single stderr output
eprintln!("[{severity:?} {ty:?}{id_name}{id_number}] {}", data.message);
})
};
// Put it all together
DebugUtilsMessengerCreateInfo {
message_severity,
message_type,
..DebugUtilsMessengerCreateInfo::user_callback(user_callback)
}
}
Instance and logger creation
Now that we have a logger configuration, we are almost ready to enable logging. There are just two remaining concerns to take care of:
- Logging uses the optional Vulkan
VK_EXT_debug_utils
extension that may not always be available. We must check for its presence and enable it if available. - For mysterious reasons, Vulkan allows programs to use different logging
configurations at the time where an
Instance
is being set up and afterwards. This means that we will need to set up logging twice, once at the time where we create anInstance
and another time after that.
After instance creation, logging is taken care of by a separate
DebugUtilsMessenger
object, which follows the usual RAII design: as long as it is alive, messages
are logged, and once it is dropped, logging stop. If you want logging to happen
for an application’s entire lifetime (which you usually do), the easiest way to
avoid dropping this object too early is to bundle it with your other long-lived
Vulkan objects in a long-lived “context” struct.
We will now demonstrate this pattern with a struct that combines a Vulkan instance with optional logging. Its constructor sets up all aforementioned features, including logging if available:
use std::sync::Arc;
use vulkano::instance::{
debug::DebugUtilsMessenger, Instance, InstanceCreateFlags
};
/// Vulkan instance, with associated logging if available
pub struct LoggingInstance {
pub instance: Arc<Instance>,
pub messenger: Option<DebugUtilsMessenger>,
}
//
impl LoggingInstance {
/// Set up a `LoggingInstance`
pub fn new(library: Arc<VulkanLibrary>, options: &InstanceOptions) -> Result<Self> {
// Prepare some basic instance configuration from Cargo metadata, and
// enable portability subset device for macOS/MoltenVk compatibility
let mut instance_info = InstanceCreateInfo {
flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,
..InstanceCreateInfo::application_from_cargo_toml()
};
// Enable validation layers in debug builds
enable_debug_validation(&library, &mut instance_info)?;
// Set up logging to stderr if the Vulkan implementation supports it
let mut log_info = None;
if library.supported_extensions().ext_debug_utils {
instance_info.enabled_extensions.ext_debug_utils = true;
let config = logger_info(options);
instance_info.debug_utils_messengers.push(config.clone());
log_info = Some(config);
}
// Set up instance, logging creation-time messages
let instance = Instance::new(library, instance_info)?;
// Keep logging after instance creation
let instance2 = instance.clone();
let messenger = log_info
.map(move |config| DebugUtilsMessenger::new(instance2, config))
.transpose()?;
Ok(LoggingInstance {
instance,
messenger,
})
}
}
…and once we have that, we can query this instance to enumerate available devices on the system, for the purpose of picking (at least) one that we will eventually run computations on. This will be the topic of the next exercise, and the next chapter after that.
Exercise
Introducing info
The exercises/
codebase that you have been provided with contains a set of
executable programs (in src/bin
), that share some code via a common utility
library (at the root of src/
). Most of the code introduced in this chapter is
located in the instance
module of this utility library.
The info
executable, whose source code lies in src/bin/info.rs
, lets you
query some properties of your system’s Vulkan setup. You can think of it as a
simplified version of the classic vulkaninfo
utility from the Linux
vulkan-tools
package, with a less overwhelming default configuration.
You can run this executable using the following Cargo command…
cargo run --bin info
…and if your Vulkan implementation is recent enough, you may notice that the validation layer is already doing its job by displaying some warnings:
Click here for example output
[WARNING VALIDATION VALIDATION-SETTINGS #2132353751] vkCreateInstance(): Both GPU Assisted Validation and Normal Core Check Validation are enabled, this is not recommend as it will be very slow. Once all errors in Core Check are solved, please disable, then only use GPU-AV for best performance.
[WARNING VALIDATION BestPractices-specialuse-extension #1734198062] vkCreateInstance(): Attempting to enable extension VK_EXT_debug_utils, but this extension is intended to support use by applications when debugging and it is strongly recommended that it be otherwise avoided.
[WARNING VALIDATION BestPractices-deprecated-extension #-628989766] vkCreateInstance(): Attempting to enable deprecated extension VK_EXT_validation_features, but this extension has been deprecated by VK_EXT_layer_settings.
[WARNING VALIDATION BestPractices-specialuse-extension #1734198062] vkCreateInstance(): Attempting to enable extension VK_EXT_validation_features, but this extension is intended to support use by applications when debugging and it is strongly recommended that it be otherwise avoided.
Vulkan instance ready:
- Max API version: 1.3.281
- Physical devices:
[WARNING VALIDATION WARNING-GPU-Assisted-Validation #615892639] vkGetPhysicalDeviceProperties2(): Internal Warning: Setting VkPhysicalDeviceVulkan12Properties::maxUpdateAfterBindDescriptorsInAllPools to 32
[WARNING VALIDATION WARNING-GPU-Assisted-Validation #615892639] vkGetPhysicalDeviceProperties2(): Internal Warning: Setting VkPhysicalDeviceVulkan12Properties::maxUpdateAfterBindDescriptorsInAllPools to 32
0. AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
* Device type: DiscreteGpu
1. llvmpipe (LLVM 20.1.6, 256 bits)
* Device type: Cpu
Thankfully, these warnings are mostly inconsequential:
- The
VALIDATION-SETTINGS
warning complains that we are using an unnecessarily exhaustive validation configuration, which can have a strong averse effect on runtime performance. It suggests running the program multiple times with less extensive validation. This is cumbersome, though, which is why in this course we just let debug builds be slow. - The
BestPractices-specialuse-extension
warnings complain about our use of debugging-focused extensions. But we do it on purpose to make debugging easier. - The
BestPractices-deprecated-extension
warning complains about a genuine issue (we are using an old extension to configure the validation layer), however we can’t easily fix this issue right now (vulkano
does not support the new configuration mechanism yet). - The
WARNING-GPU-Assisted-Validation
warnings complain about an internal implementation detail of GPU-assisted validation that we have no control on. It suggests a possible bug in GPU-assisted validation that should be reported at some point.
Other operating modes
By running a release build of the program instead, we see that the warnings go away, highlighting the fact that validation layers are only enabled in debug builds:
cargo run --release --bin info
Click here for example output
Vulkan instance ready:
- Max API version: 1.3.281
- Physical devices:
0. AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
* Device type: DiscreteGpu
1. llvmpipe (LLVM 20.1.6, 256 bits)
* Device type: Cpu
…however, if you increase the Vulkan log verbosity by specifying the -v
command-line option to the output binary (which goes after a --
to separate it
from Cargo options), you will see that Vulkan logging remains enabled even in
release builds, as we would expect.
cargo run --release --bin info -- -v
Click here for example output
[INFO GENERAL Loader Message] No valid vk_loader_settings.json file found, no loader settings will be active
[INFO GENERAL Loader Message] Searching for implicit layer manifest files
[INFO GENERAL Loader Message] In following locations:
[INFO GENERAL Loader Message] /home/hadrien/.config/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /home/hadrien/.config/kdedefaults/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /etc/xdg/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /etc/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /home/hadrien/.local/share/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /home/hadrien/.local/share/flatpak/exports/share/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /var/lib/flatpak/exports/share/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /usr/local/share/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] /usr/share/vulkan/implicit_layer.d
[INFO GENERAL Loader Message] Found the following files:
[INFO GENERAL Loader Message] /etc/vulkan/implicit_layer.d/renderdoc_capture.json
[INFO GENERAL Loader Message] /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json
[INFO GENERAL Loader Message] /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
[INFO GENERAL Loader Message] Found manifest file /etc/vulkan/implicit_layer.d/renderdoc_capture.json (file version 1.1.2)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json (file version 1.0.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json (file version 1.0.0)
[INFO GENERAL Loader Message] Searching for explicit layer manifest files
[INFO GENERAL Loader Message] In following locations:
[INFO GENERAL Loader Message] /home/hadrien/.config/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /home/hadrien/.config/kdedefaults/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /etc/xdg/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /etc/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /home/hadrien/.local/share/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /home/hadrien/.local/share/flatpak/exports/share/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /var/lib/flatpak/exports/share/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /usr/local/share/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d
[INFO GENERAL Loader Message] Found the following files:
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_api_dump.json
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_monitor.json
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_screenshot.json
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_INTEL_nullhw.json
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_MESA_overlay.json
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_MESA_screenshot.json
[INFO GENERAL Loader Message] /usr/share/vulkan/explicit_layer.d/VkLayer_MESA_vram_report_limit.json
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_api_dump.json (file version 1.2.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_monitor.json (file version 1.0.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_screenshot.json (file version 1.2.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json (file version 1.2.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_INTEL_nullhw.json (file version 1.0.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_MESA_overlay.json (file version 1.0.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_MESA_screenshot.json (file version 1.0.0)
[INFO GENERAL Loader Message] Found manifest file /usr/share/vulkan/explicit_layer.d/VkLayer_MESA_vram_report_limit.json (file version 1.0.0)
[INFO GENERAL Loader Message] Searching for driver manifest files
[INFO GENERAL Loader Message] In following locations:
[INFO GENERAL Loader Message] /home/hadrien/.config/vulkan/icd.d
[INFO GENERAL Loader Message] /home/hadrien/.config/kdedefaults/vulkan/icd.d
[INFO GENERAL Loader Message] /etc/xdg/vulkan/icd.d
[INFO GENERAL Loader Message] /etc/vulkan/icd.d
[INFO GENERAL Loader Message] /home/hadrien/.local/share/vulkan/icd.d
[INFO GENERAL Loader Message] /home/hadrien/.local/share/flatpak/exports/share/vulkan/icd.d
[INFO GENERAL Loader Message] /var/lib/flatpak/exports/share/vulkan/icd.d
[INFO GENERAL Loader Message] /usr/local/share/vulkan/icd.d
[INFO GENERAL Loader Message] /usr/share/vulkan/icd.d
[INFO GENERAL Loader Message] Found the following files:
[INFO GENERAL Loader Message] /usr/share/vulkan/icd.d/radeon_icd.x86_64.json
[INFO GENERAL Loader Message] /usr/share/vulkan/icd.d/lvp_icd.x86_64.json
[INFO GENERAL Loader Message] Found ICD manifest file /usr/share/vulkan/icd.d/radeon_icd.x86_64.json, version 1.0.0
[INFO GENERAL Loader Message] Found ICD manifest file /usr/share/vulkan/icd.d/lvp_icd.x86_64.json, version 1.0.0
[INFO GENERAL Loader Message] Insert instance layer "VK_LAYER_MESA_device_select" (libVkLayer_MESA_device_select.so)
[INFO GENERAL Loader Message] vkCreateInstance layer callstack setup to:
[INFO GENERAL Loader Message] <Application>
[INFO GENERAL Loader Message] ||
[INFO GENERAL Loader Message] <Loader>
[INFO GENERAL Loader Message] ||
[INFO GENERAL Loader Message] VK_LAYER_MESA_device_select
[INFO GENERAL Loader Message] Type: Implicit
[INFO GENERAL Loader Message] Enabled By: Implicit Layer
[INFO GENERAL Loader Message] Disable Env Var: NODEVICE_SELECT
[INFO GENERAL Loader Message] Manifest: /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
[INFO GENERAL Loader Message] Library: libVkLayer_MESA_device_select.so
[INFO GENERAL Loader Message] ||
[INFO GENERAL Loader Message] <Drivers>
Vulkan instance ready:
- Max API version: 1.3.281
- Physical devices:
[INFO GENERAL Loader Message] linux_read_sorted_physical_devices:
[INFO GENERAL Loader Message] Original order:
[INFO GENERAL Loader Message] [0] llvmpipe (LLVM 20.1.6, 256 bits)
[INFO GENERAL Loader Message] [1] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] Sorted order:
[INFO GENERAL Loader Message] [0] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] [1] llvmpipe (LLVM 20.1.6, 256 bits)
[INFO GENERAL Loader Message] linux_read_sorted_physical_devices:
[INFO GENERAL Loader Message] Original order:
[INFO GENERAL Loader Message] [0] llvmpipe (LLVM 20.1.6, 256 bits)
[INFO GENERAL Loader Message] [1] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] Sorted order:
[INFO GENERAL Loader Message] [0] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] [1] llvmpipe (LLVM 20.1.6, 256 bits)
[INFO GENERAL Loader Message] linux_read_sorted_physical_devices:
[INFO GENERAL Loader Message] Original order:
[INFO GENERAL Loader Message] [0] llvmpipe (LLVM 20.1.6, 256 bits)
[INFO GENERAL Loader Message] [1] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] Sorted order:
[INFO GENERAL Loader Message] [0] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] [1] llvmpipe (LLVM 20.1.6, 256 bits)
[INFO GENERAL Loader Message] linux_read_sorted_physical_devices:
[INFO GENERAL Loader Message] Original order:
[INFO GENERAL Loader Message] [0] llvmpipe (LLVM 20.1.6, 256 bits)
[INFO GENERAL Loader Message] [1] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] Sorted order:
[INFO GENERAL Loader Message] [0] AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
[INFO GENERAL Loader Message] [1] llvmpipe (LLVM 20.1.6, 256 bits)
0. AMD Radeon Pro WX 3200 Series (RADV POLARIS12)
* Device type: DiscreteGpu
1. llvmpipe (LLVM 20.1.6, 256 bits)
* Device type: Cpu
Hands-on
You can query the full list of available command-line flags using the standard
--help
command option, which goes after --
like other non-Cargo options.
Please play around with the various available CLI options and try to use this
utility to answer the following questions:
- Is your computer’s GPU correctly detected, or do you only see a
llvmpipe
CPU emulation device (or worse, no device at all) ?- Please report absence of a GPU device to the teacher, with a bit of luck we may find the right system configuration tweak to get it to work.
- What optional instance extensions and layers does your Vulkan implementation support?
- How much device-local memory do your GPUs have ?
- What Vulkan extensions do your GPUs support ?
- (Linux-specific) Can you tell where on disk the shared libraries featuring Vulkan drivers (known as Installable Client Drivers or ICDs in Khronos API jargon) are stored ?
Once your thirst for system configuration knowledge is quenched, you may then study the source code of this program. Which is admittedly not the prettiest as it priorizes beginner readability over maximal maintainability in more than one place…
Overall, this program demonstrates how various system properties can be queried
using the VulkanLibrary
and Instance
APIs. But not all available
properties are exposed because the Vulkan specification is huge and we are only
going to cover a subset of it in this course. However, if any property in the
documentation linked above gets you curious, do not hesitate to adjust the code
of the info
program so that it gets printed as well!
-
…which has recently been deprecated and scheduled for replacement by
VK_EXT_layer_settings
, but alasvulkano
does not support this new layer configuration mechanism yet. ↩ -
The Vulkan messaging API allows for synchronous implementations. In such implementations, when a Vulkan API call emits a message, it is interrupted midway through its internal processing while the message is being processed. This means that the Vulkan API implementation may be in an inconsistent state (e.g. some thread-local mutex may be locked). If our message processing callback then proceeds to make another Vulkan API call, this new API call will observe that inconsistent implementation state, which can result in an arbitrarily bad outcome (e.g. a thread deadlock in the above example). Furthermore, the new Vulkan API call could later emit more messages, potentially resulting in infinite recursion. ↩