hardtack

Vulkan Graphics API

Vulkan is a low-overhead, cross-platform 3D graphics and compute API. My graphics projects have led me to

Meat and Potatoes

Starting a lo level graphics software project from start can be really intimidating. When I started my head was swirling with questions of compatibility, requirements, dependencies, and here to begin – even as a developer with plenty of experience with hardware and bare metal code. Here's a quick rundown of the things one needs and where to find them, beginning with the hardware and working our way up the stack of dependencies.

hardware So, you've got a GPU huh? Nice pile of silicon, bud. First of all, Vulkan is designed to make use of the common patterns and capabilities of modern GPUs. You can check the Vulkan Hardware Database to see if your GPU is supported.

drivers Let's remember that the GPU can't run Vulkan. What are you gonna do, print out the passive agressive comments from your last code review and feed them into the PCIe slot? Ultimately a driver is responsible for exposing the capabilities of the GPU to your cheeto-stained fingers. Drivers which support the Vulkan API allow the Vulkan SDK to communicate with the GPU. The good news is that if your GPU is listed in the Vulkan Hardware Database then the driver you have is probably good enough.

(interoperability) optional Because, of course, Apple has to be different[^metal-observations]. Apple devices suppor the Metal API. It is still possible to use Vulkan on Apple devices though thanks to interoperability layers like MoltenVK which translate Vulkan API calls into Metal API calls

vulkan sdk If you had only a driver you could probably make the GPU do something, even if is just letting out the magic blue smoke. Adding the Vulkan SDK in the mix means you don't have to individually ferry electrons back and forth across the PCIe bus. Okay okay, really though the software development kit is a really important part of the tech stack.

Among other things the SDK provides the source code for Vulkan functionality, headers which define the Vulkan API to your application, and a loader which specializes the functionality of the API for your particular hardware. The SDK doesn't stop there either. It also includes tools to transpile human-readable shader code into the SPIR-V bytecode that courses through the veins of the GPU as well as a comprehensive validation layer which can help you debug your code.

your application The crown jewel, the port authority, and the air traffic controller. Yes, with the Vulkan API, your application is responsible for such mundane things. But this can be a really good thing because it means that you have to know what is really happening between your application and the GPU. With great control comes great performance.

Setting Up the SDK

As discussed above the SDK reigns supreme. Honestly the short description above is scarely adequate to even introduce the SDK. At the end of the day you need to remember that the SDK is a whole collection of tools and resources. In any given situation you may need the whole shebang and in another you may only need to read the docs. In one application you might need glslc to compile a shader at build time and in another you might choose to use the run-time compilation options.

I can't, and won't, give a complete explanation of SDK setup here. Bushwacking your way through the historical system of shared libraries, path variables, and CMake package finding tools is the only way to learn. However I can give you a few pointers.

Getting Started with the Linux Tarball Vulkan SDK

Setting Up Vulkan on Raspberry Pi 5

Let's go through our checklist.

Getting Started with the Linux Tarball Vulkan SDK

# I am dong a little experiment with a fresh install of the 04.07.2024 (July 04 2024) release of Raspberry Pi OS on a Raspberry Pi 5

# update the repositories
# (written Jul 23 2024)
sudo apt update

sudo apt install -y \
cmake \
libxcb-randr0-dev \
liblz4-dev \
clang-format \
qtcreator qt5-qmake qtbase5-dev qt5-qmake qtbase5-dev-tools \

# show version of gcc / g++
gcc --version # (Debian 12.2.0-14) 12.2.0
g++ --version # (Debian 12.2.0-14) 12.2.0
tar --version # tar (GNU tar) 1.34

export VULKAN_SDK_VERSION=1.3.283.0
export VULKAN_SDK_FILENAME=vulkansdk-linux-x86_64-${VULKAN_SDK_VERSION}.tar.xz
export VULKAN_SDK_URL=https://sdk.lunarg.com/sdk/download/${VULKAN_SDK_VERSION}/linux/${VULKAN_SDK_FILENAME}

# download the SDK and extract it into its final location
mkdir ~/VulkanSDK
wget -O ~/Downloads/${VULKAN_SDK_FILENAME} ${VULKAN_SDK_URL}
tar -xf ~/Downloads/${VULKAN_SDK_FILENAME} -C ~/VulkanSDK

# build the SDK
~/VulkanSDK/${VULKAN_SDK_VERSION}/vulkansdk -j 1

# add the SDK to the path
source ~/VulkanSDK/${VULKAN_SDK_VERSION}/setup-env.sh

# This experiment seemed to work well and suggests a reduced set of steps required to get Vulkan up and running on a Raspberry Pi 5 with the latest Raspberry Pi OS.

# update and upgrade the system
sudo apt update
sudo apt upgrade

# 
sudo apt install cmake g++ libglu1-mesa-dev

# drivers and vulkan tools
sudo apt install mesa-vulkan-drivers vulkan-tools

# xz-utils to extract the tarball
sudo apt install xz-utils

# additional dependencies if you plan to build the full SDK from source
sudo apt install libglm-dev cmake libxcb-dri3-0 libxcb-present0 libpciaccess0 \
libpng-dev libxcb-keysyms1-dev libxcb-dri3-dev libx11-dev g++ gcc \
libwayland-dev libxrandr-dev libxcb-randr0-dev libxcb-ewmh-dev \
git python3 bison libx11-xcb-dev liblz4-dev libzstd-dev python3-distutils \
ocaml-core ninja-build pkg-config libxml2-dev wayland-protocols qtcreator \
qtbase5-dev qt5-qmake qtbase5-dev-tools

# download the SDK
export VULKAN_SDK_VERSION=1.3.283.0
export VULKAN_SDK_TARBALL_URL=https://sdk.lunarg.com/sdk/download/${VULKAN_SDK_VERSION}/linux/vulkansdk-linux-x86_64-${VULKAN_SDK_VERSION}.tar.xz
wget $VULKAN_SDK_TARBALL_URL

# extract the tarball into the vulkan directory
export VULKAN_SDK_DIR=~
tar -xf vulkansdk-linux-x86_64-${VULKAN_SDK_VERSION}.tar.xz -C ${VULKAN_SDK_DIR}

# add the SDK to your path
source ~/${VULKAN_SDK_DIR}/${VULKAN_SDK_VERSION}/setup-env.sh

# build the SDK using only one core to avoid running out of RAM
# (this may take overnight)
~/${VULKAN_SDK_DIR}/${VULKAN_SDK_VERSION}/vulkansdk -j 1

Sascha Willems Vulkan Examples

git clone https://github.com/SaschaWillems/Vulkan.git
cd Vulkan
mkdir build
cd build
cmake ..
make -j$(nproc)

# show the built examples
ls bin

# run an example
./bin/computecloth

Vulkan Samples

# generate the cmake project
cmake -G "Unix Makefiles" -Bbuild/linux -DCMAKE_BUILD_TYPE=Release

# build the project
cmake --build build/linux --config Release --target vulkan_samples -j$(nproc)

./build/linux/app/bin/Release/x86_64/vulkan_samples --help
./build/linux/app/bin/Release/x86_64/vulkan_samples sample hello_triangle

Vulkan with Rust

Using Vulkan with Rust is just a matter of making the right bindings to the underlying C API. There are several options available with different trade-offs in the API design.

Vulkanalia is a realtively thin wrapper around the Vulkan API which I chose because it maintains the transparency of the C API which means that I will really learn how Vulkan works. Just kidding, I chose it because it has a great tutorial.

Vulkan Tutorial (Rust)


[^metal-observations]: Vulkan and Metal (Some Observations)