Initialization
Creating an instance
Before you can start utilizing the Vulkan API, the first thing to do is to create
an instance. An instance specifies the mapping between vulkano and the local Vulkan library.
As of vulkano version 0.31.0
, the library needs to be explicitly specified by passing a
VulkanLibrary
to the Instance
constructor.
For starters, our program will be very simple, so, for now, creating an instance won't need any additional parameters, so we can create it with default configurations:
#![allow(unused)] fn main() { use vulkano::VulkanLibrary; use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}; let library = VulkanLibrary::new().expect("no local Vulkan library/DLL"); let instance = Instance::new( library, InstanceCreateInfo { flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, ..Default::default() }, ) .expect("failed to create instance"); }
Like many other functions in vulkano, creating an instance returns a Result
. If Vulkan is not
available on the system, this result will contain an error. For the sake of this example we call
expect
on the Result
, which prints a message to stderr and terminates the application if it
contains an error. In a real game or application you should handle that situation in a nicer way,
for example by opening a dialog box with an explanation. This is out of scope of this book.
The InstanceCreateFlags::ENUMERATE_PORTABILITY
flag is set to support devices, such as those on
MacOS and iOS systems, that do not fully conform to the Vulkan Specification. For more details, consult the
instance documentation.
Before going further you can try your code by running:
cargo run
Enumerating physical devices
The machine you run your program on may have multiple devices that support Vulkan. Before we can ask a video card to perform some operations, we have to enumerate all the physical devices that support Vulkan and choose which one we are going to use for this operation.
In reality a physical device can be a dedicated graphics card, but also an integrated graphics processor or a software implementation. It can be basically anything that allows running Vulkan operations.
As of the writing of this book, it is not yet possible to use multiple devices simultaneously in an efficient way (eg. SLI/Crossfire). You can use multiple devices simultaneously in the same program, but there is not much point in doing so because you cannot share anything between them. Consequently the best thing to do in practice is to choose one physical device which is going to run everything:
#![allow(unused)] fn main() { let physical_device = instance .enumerate_physical_devices() .expect("could not enumerate devices") .next() .expect("no devices available"); }
The enumerate_physical_devices
function returns a Result
of an iterator to the list of
available physical devices. We call next
on it to return the first device, if any. Note that the
first device is not necessarily the best device. In a real program you probably want to leave the
choice to the user (later we will see a better implementation of this).
Keep in mind that the list of physical devices can be empty. This happens if Vulkan is installed on the system, but none of the physical devices of the machine are capable of supporting Vulkan. In a real-world application you are encouraged to handle this situation properly as well.
Next: Device creation