How to Vulkan in 2026 Sascha Willems released an updated tutorial, "How to Vulkan in 2026," demonstrating modern Vulkan 1.3 features including dynamic rendering, buffer device address, descriptor indexing, and Synchronization2 to simplify graphics programming. The tutorial targets developers with basic C/C++ and real-time graphics knowledge, aiming to create a rasterized 3D scene with multiple illuminated and textured objects in a single file of a few hundred lines. How to Vulkan in 2026 Info Last updated 2026-07-16: Use vkQueueSubmit2 instead of vkQueueSubmit Intro This repository https://github.com/SaschaWillems/HowToVulkan and the accompanying tutorial demonstrate ways of writing a Vulkan https://vulkan.org/ graphics application in 2026. The goal is to leverage modern features to simplify Vulkan usage and, while doing so, create something more than just a basic colored triangle. Vulkan was released almost 10 years ago, and a lot has changed. Version 1.0 had to make many concessions to support a broad range of GPUs across desktop and mobile. Some of the initial concepts like render passes turned out to be not so optimal, and have been replaced by alternatives. The API matured and new areas like raytracing, video acceleration and machine learning were added. Just as important as the API is the ecosystem, which also changed a lot, giving us new options for writing shaders in languages different than GLSL and tools to help with Vulkan. And so for this tutorial we will be using Vulkan 1.3 https://docs.vulkan.org/refpages/latest/refpages/source/VK VERSION 1 3.html as a baseline. This gives us access to several features that make Vulkan easier to use while still supporting a wide range of GPUs and platforms. The ones we will be using are: Dynamic rendering https://www.khronos.org/blog/streamlining-render-passes - Greatly simplifies render pass setup, one of the most criticized Vulkan areas Buffer device address https://docs.vulkan.org/guide/latest/buffer device address.html - Lets us access buffers via pointers instead of going through descriptors Descriptor indexing https://docs.vulkan.org/refpages/latest/refpages/source/VK EXT descriptor indexing.html - Simplifies descriptor management, often referred to as "bindless" Synchronization2 https://docs.vulkan.org/guide/latest/extensions/VK KHR synchronization2.html - Improves synchronization handling, one of the hardest areas of Vulkan tl;dr: Doing Vulkan in 2026 can be very different from doing Vulkan in 2016. That's what I hope to show with this. Tip A list of devices supporting at least Vulkan 1.3 can be found here https://vulkan.gpuinfo.org/listdevices.php?apiversion=1.3 . Target audience The tutorial is focused on writing actual Vulkan code and getting things up and running as fast as possible possibly in an afternoon . It won't explain programming, software architecture, graphics concepts or how Vulkan works in detail . Instead it'll often contain links to relevant information like the Vulkan specification https://docs.vulkan.org/ . You should bring at least basic knowledge of C/C++ and real-time graphics concepts. Goal We focus on rasterization, other parts of Vulkan like compute or raytracing are not covered. At the end of this, we'll have multiple illuminated and textured 3D objects on screen that can be rotated using the mouse screenshot images/screenshot.png . The source comes in a single file with a few hundred lines of code, no abstractions, no hard-to-read modern C++ language constructs, and no object-oriented shenanigans. I believe that being able to follow source code from top to bottom without having to go through multiple layers of abstractions makes it much easier to follow. License Copyright c 2025-2026, Sascha Willems https://www.saschawillems.de . The contents of this document are licensed under the CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/ license. Source code listings and files are licensed under the MIT license. Libraries Vulkan is an explicit low-level API. Writing code for it can be very verbose. To concentrate on the interesting parts we'll be using the following libraries: SDL https://www.libsdl.org/ - Windowing and input and other features not used in this tutorial . Without a library like this we would have to write a lot of platform-specific code. Alternatives are GLFW https://www.glfw.org/ and SFML https://www.sfml-dev.org/ . SDL has the broadest platform support of these Volk https://github.com/zeux/volk - Meta-loader that simplifies loading of Vulkan functions VMA https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator - Simplifies dealing with memory allocations. Removes some of the verbosity around memory management glm https://github.com/g-truc/glm - A mathematics library with support for things like matrices and vectors tinyobjloader https://github.com/tinyobjloader/tinyobjloader - Single header loader for the obj 3D format KTX-Software https://github.com/KhronosGroup/KTX-Software - Khronos KTX GPU texture image file loader Tip None of these are required to work with Vulkan. But they make working with Vulkan easier and some of them like VMA and Volk are widely used, even in commercial applications. Programming language We'll use C++ 20, mostly for its designated initializers. They help with Vulkan's verbosity and improve code readability. Other than that we won't be using modern C++ features and also work with the C Vulkan headers instead of the C++ https://github.com/KhronosGroup/Vulkan-Hpp ones. Aside from personal preferences this is done to make this tutorial as approachable as possible, including people that use other programming languages. Shading language Vulkan consumes shaders in an intermediate format called SPIR-V https://www.khronos.org/spirv/ . This decouples the API from the actual shading language. Initially only GLSL was supported, but in 2026 there are more and better options. One of those is Slang https://github.com/shader-slang , and that's what we'll be using for this tutorial. The language itself is more modern than GLSL and offers some convenient features. Vulkan SDK While it's not required for developing Vulkan applications, the LunarG Vulkan SDK https://vulkan.lunarg.com/sdk/home provides a convenient way to install commonly used libraries and tools, some of which are used in this tutorial. It's therefore recommended to install this. When installing, be sure to select the optional GLM, Volk, SDL3 and Vulkan Memory Allocator components. Alternatively, you can download these from their respective repositories and adjust the include paths in the CMakeLists.txt file. Validation layers Vulkan was designed to minimize driver overhead. While that can result in better performance, it also removes many of the safeguards that APIs like OpenGL had and puts that responsibility into your hands. If you misuse Vulkan the driver is free to crash. So even if your app works on one GPU, it doesn't guarantee that it works on others. On the other hand, the Vulkan specification defines valid usages for all functionality. And with the validation layers https://github.com/KhronosGroup/Vulkan-ValidationLayers , an easy-to-use tool to check for that exists. Validation layers can be enabled in code, but the easier option is to enable the layers via the Vulkan Configurator GUI https://vulkan.lunarg.com/doc/view/latest/windows/vkconfig.html provided by the Vulkan SDK vulkan-sdk . Once they're enabled, any improper use of the API will be logged to the command line window of our application. Note You should always have the validation layers enabled when developing with Vulkan. This makes sure you write spec-compliant code that properly works on other systems. Graphics debugger Another indispensable tool is a graphics debugger. Similar to the CPU debugger available in IDEs like Visual Studio, these help you debug runtime issues on the GPU side of things. A commonly used cross-platform and cross-vendor graphics debugger with Vulkan support is RenderDoc https://renderdoc.org/ . While using such a debugger isn’t required for this tutorial, it’s invaluable if you want to build upon what you’ve learned and encounter issues while doing so. Development environment Our build system will be CMake https://cmake.org/ . Similar to my approach to writing code, things will be kept as simple as possible with the added benefit of being able to follow this tutorial with a wide variety of C++ compilers and IDEs. To create build files for your C++ IDE, run CMake in the source folder of the project like this: cmake -B build -G "Visual Studio 17 2022" This will write a Visual Studio 2022 solution file to the build folder. As an alternative to the command line, you can use cmake-gui https://cmake.org/cmake/help/latest/manual/cmake-gui.1.html . The generator -G depends on your IDE, you can find a list of those here https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html . Source Now that everything is properly set up we can start digging into the code. The following chapters will walk you through the main source file https://github.com/SaschaWillems/HowToVulkan/blob/main/source/main.cpp from top to bottom. Warning Some of the less interesting initialization, declaration and boilerplate code is omitted from this document. It's advised to also have the main source file open while doing this tutorial. Instance setup The first thing we need is a Vulkan instance. It connects the application to Vulkan and as such is the base for everything that follows. Setting up the instance consists of passing information about your application: VkApplicationInfo appInfo{ .sType = VK STRUCTURE TYPE APPLICATION INFO, .pApplicationName = "How to Vulkan", .apiVersion = VK API VERSION 1 3 }; Most important is the apiVersion , which tells Vulkan that we want to use Vulkan 1.3. Using a higher API version gives us more features out of the box that otherwise would have to be used via extensions. Vulkan 1.3 https://docs.vulkan.org/refpages/latest/refpages/source/VK VERSION 1 3.html is widely supported and adds a lot of features to the Vulkan core that make it easier to use. pApplicationName can be used to identify your application. Info A structure member you'll see a lot is sType . The driver needs to know what structure type it has to deal with, and with Vulkan being a C-API there is no other way than specifying it via structure member. The instance also needs to know about the extensions you want to use. As the name implies, these are used to extend the API. As instance creation and some other things are platform-specific, the instance needs to know what platform-specific extensions you want to use. For Windows e.g. you'd use VK KHR win32 surface https://docs.vulkan.org/refpages/latest/refpages/source/VK KHR win32 surface.html and VK KHR android surface https://docs.vulkan.org/refpages/latest/refpages/source/VK KHR android surface.html for Android and so on for other platforms. Note There are two extension types in Vulkan. Instance and device extensions. The former are mostly global, often platform specific extensions independent of your GPU, the latter are based on your GPU's capabilities. That would mean we'd have to write platform-specific code. But with a library like SDL we don't have to do that; instead, we ask SDL for the platform-specific instance extensions: uint32 t instanceExtensionsCount{ 0 }; char const const instanceExtensions{ SDL Vulkan GetInstanceExtensions &instanceExtensionsCount }; So no more need to worry about platform specific things. With the application info and the required extensions set up, we can create our instance: VkInstanceCreateInfo instanceCI{ .sType = VK STRUCTURE TYPE INSTANCE CREATE INFO, .pApplicationInfo = &appInfo, .enabledExtensionCount = instanceExtensionsCount, .ppEnabledExtensionNames = instanceExtensions, }; chk vkCreateInstance &instanceCI, nullptr, &instance ; This is very simple. We pass our application info and both the names and number of instance extensions that SDL gave us for the platform we're compiling for . Calling vkCreateInstance https://docs.vulkan.org/refpages/latest/refpages/source/vkCreateInstance.html creates our instance. Tip Most Vulkan functions can fail in different ways and return a VkResult https://docs.vulkan.org/refpages/latest/refpages/source/VkResult.html value. We use a small inline function called chk to check that return code and in case of an error we exit the application. In a real-world application you should do more sophisticated error handling. Device selection We now have to choose the device we want to use for rendering. Although this isn't typical, it’s possible to have several Vulkan-capable devices within a single system. For instance, if you have multiple GPUs installed or if you have both an integrated and a discrete GPU: Info When dealing with Vulkan a commonly used term is implementation. This refers to something that implements the Vulkan API. Usually it's the driver for your GPU, but it also could be a CPU based software implementation. To keep things simple we'll be using the term GPU for the rest of the tutorial. For that, we get a list of all available physical devices supporting Vulkan: uint32 t deviceCount{ 0 }; chk vkEnumeratePhysicalDevices instance, &deviceCount, nullptr ; std::vector