Rust-Vulkano: Vulkano is a Rust wrapper around the Vulkan graphics API.

Vulkano Docs Build Status Gitter chat

See also

Vulkano is a Rust wrapper around the Vulkan graphics API. It follows the Rust philosophy, which is that as long as you don't use unsafe code you shouldn't be able to trigger any undefined behavior. In the case of Vulkan, this means that non-unsafe code should always conform to valid API usage.

What does vulkano do?

  • Provides a low-levelish API around Vulkan. It doesn't hide what it does, but provides some comfort types.
  • Plans to prevent all invalid API usages, even the most obscure ones. The purpose of vulkano is not to simply let you draw a teapot, but to cover all possible usages of Vulkan and detect all the possible problems in order to write robust programs. Invalid API usage is prevented thanks to both compile-time checks and runtime checks.
  • Can handle synchronization on the GPU side for you (unless you choose do that yourself), as this aspect of Vulkan is both annoying to handle and error-prone. Dependencies between submissions are automatically detected, and semaphores are managed automatically. The behavior of the library can be customized thanks to unsafe trait implementations.
  • Tries to be convenient to use. Nobody is going to use a library that requires you to browse the documentation for hours for every single operation.

Note that in general vulkano does not require you to install the official Vulkan SDK. This is not something specific to vulkano (you don't need the SDK to write programs that use Vulkan, even without vulkano), but many people are unaware of that and install the SDK thinking that it is required. However, macOS and iOS platforms do require a little more Vulkan setup since it is not natively supported. See below for more details.

Development status

Vulkano is still in heavy development and doesn't yet meet its goals of being very robust. However the general structure of the library is most likely definitive, and all future breaking changes will likely be straight-forward to fix in user code.


To get started you are encouraged to use the following resources:

  • The guide on - Starts with trivial compute examples (~50 lines of code) then works up to rendering triangles and mandelbrots.
  • The vulkano-examples repository - Includes examples in the repo and also a list of projects that use vulkano.
  • - Full Vulkano API documentation


Vulkano uses shaderc-rs for shader compilation. Refer to shaderc-rs documentation to provide a pre-built libshaderc for faster build times.

Unless you provide libshaderc, in order to build libshaderc with the shaderc-sys crate, the following tools must be installed and available on PATH:

  • CMake
  • Ninja Is optional except when building with MSVC. It may speed up build time for libshaderc.
  • Python (works with both Python 2.x and 3.x, on windows the executable must be named python.exe)

These requirements can be either installed with your favourite package manager or with installers from the projects' websites. Below are some example ways to get setup.

windows-msvc Specific Setup

  1. rustup default stable-x86_64-pc-windows-msvc
  2. Install Build Tools for Visual Studio 2017. If you have already been using this toolchain then its probably already installed.
  3. Install msys2, following ALL of the instructions.
  4. Then in the msys2 terminal run: pacman --noconfirm -Syu mingw-w64-x86_64-cmake mingw-w64-x86_64-python2 mingw-w64-x86_64-ninja
  5. Add the msys2 mingw64 binary path to the PATH environment variable.

Windows-gnu Specific Setup

windows-gnu toolchain is not supported but you can instead cross-compile to windows-gnu from windows-msvc

Steps 1 and 2 are to workaround by using the same mingw that rust uses.

  1. Download and extract
  2. Add the absolute path to mingw64\bin to your PATH environment variable. (This path needs to be before the msys2 path)
  3. Run the command: rustup default stable-x86_64-pc-windows-msvc
  4. Run the command: rustup target install x86_64-pc-windows-gnu
  5. Install Build Tools for Visual Studio 2017. If you have already been using this toolchain then its probably already installed.
  6. Install msys2, following ALL of the instructions.
  7. Then in the msys2 terminal run: pacman --noconfirm -Syu mingw64/mingw-w64-x86_64-pkg-config mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-make mingw-w64-x86_64-python2 mingw-w64-x86_64-ninja
  8. Add the msys2 mingw64 binary path to the PATH environment variable.
  9. Any cargo command that builds the project needs to include --target x86_64-pc-windows-gnu e.g. to run: cargo run --target x86_64-pc-windows-gnu

Linux Specific Setup

Use your package manager to install the required dev-tools and vulkan drivers

For example on ubuntu:

sudo apt-get install build-essential git python cmake libvulkan-dev vulkan-utils

macOS and iOS Specific Setup

Vulkan is not natively supported by macOS and iOS. However, there exists MoltenVK a Vulkan implementation on top of Apple's Metal API. This allows vulkano to build and run on macOS and iOS platforms.

The easiest way to get vulkano up and running on macOS is to install the Vulkan SDK for macOS. To install the SDK so that Vulkano will find it and dynamically link with libvulkan.dylib:

  1. Download the latest macOS release and unpack it somewhere, for the next step we'll assume that's ~/vulkan_sdk.
  2. Modify your environment to contain the SDK bin directory in PATH and the SDK lib directory in DYLD_LIBRARY_PATH. We also need to set VK_ICD_FILENAMES and VK_LAYER_PATH. When using the Bash shell, which is the default for macOS, it's easiest to do this by appending the following to the ~/.bash_profile file and then restarting the terminal.
export VULKAN_SDK=$HOME/vulkan_sdk/macOS
export VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json
export VK_LAYER_PATH=$VULKAN_SDK/etc/vulkan/explicit_layer.d

It is also possible to link with the MoltenVK framework (as vulkano did in previous versions) by adding the appropriate cargo output lines to your build script and implementing your own vulkano::instance::loader::Loader that calls the MoltenVK vkGetInstanceProcAddr implementation.

On iOS vulkano links directly to the MoltenVK framework. There is nothing else to do besides installing it. Note that the Vulkan SDK for macOS also comes with the iOS framework.

Note that as of writing, MoltenVK has some bugs that show up in the examples. Some minor modifications may be required as workarounds: see The examples also do not work properly on macOS 10.11 and lower without workarounds due to MoltenVK's Metal backend not getting the required features until macOS 10.12. See for workarounds.


Austin Johnson (Active maintainer) Become a patron

Rukai (Current maintainer) Become a patron

Tomaka (Original developer) Become a patron


Contributions are welcome! Feel free to submit pull requests.

Pull requests that fix bugs or improve documentation are likely to be quickly reviewed, while pull requests that add features or change the API may be more controversial and take more time.

If your change adds, removes or modifies a trait or a function, please add an entry to the file as part of your pull request.


This repository contains four libraries:

  • vulkano is the main one.
  • vulkano-shaders Provides the shader! macro for compiling glsl shaders.
  • vulkano-win provides a safe link between vulkano and the winit library which can create a window to render to.
  • vk-sys contains raw bindings for Vulkan. You can use it even if you don't care about vulkano.

In order to run tests, run cargo test --all at the root of the repository. Make sure your Vulkan driver is up to date before doing so.


Licensed under either of


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.


  • A bind-based alternative API for AutoCommandBufferBuilder?
    A bind-based alternative API for AutoCommandBufferBuilder?

    Jun 2, 2020

    Another ergonomics gripe I've been running into recently. Whenever you issue a draw call, you have to give the entire draw state, and this means that wherever draw calls are being issued, you have to have all this state on hand, and have to pass it around everywhere. Even if the state never actually changes. This seems slightly odd when you know that AutoCommandBufferBuilder actually remembers the previous state, and only binds what differs in each call. It only needs all that state for comparison purposes, not for binding.

    I think it would be more ergonomic if the API of draw calls were changed, so that state is bound before the call, and the draw call uses the currently-bound state, like it is in SyncCommandBufferBuilder and raw Vulkan. It would still check the current state before drawing (check_descriptor_sets_validity and friends). StateCacher would be run when bind calls are made, and the bind would be skipped if already bound. So you'd still get all of the benefits.

    I can see about making a PR for this, but I wanted to get feedback first. Especially as this is yet another breaking change.

  • Black screen when blitting onto swapchain image 0
    Black screen when blitting onto swapchain image 0

    Jun 3, 2020

    This is quite a weird issue, so I hope I explain it well enough.

    I want to set up my rendering to draw to an offscreen image, and then blit this image onto the swapchain image. To do this, I set up a series of command buffers right after creating the swapchain and attachment images, one for each swapchain image, generated with the following code:

    let blit_command_buffers = images.iter()
    	.map(|target_image| {
    		let mut builder = AutoCommandBufferBuilder::primary(
    			[0, 0, 0],
    			[width as i32, height as i32, depth as i32],
    			[0, 0, 0],
    			[width as i32, height as i32, depth as i32],

    In my draw loop, I build and execute a draw command buffer (draw_commands), and acquire a swapchain image. The futures are then submitted:

    let draw_future = draw_commands.execute(graphics_queue.clone())?;
    let (image_num, suboptimal, swapchain_future) = acquire_next_image(swapchain.clone(), None)?;

    All submissions happen on the same queue, so I don't think semaphores would be needed. The command buffer that blits the framebuffer onto the swapchain image is executed after both the drawing and the swapchain acquire.

    When doing it this way, I get flickering every few frames. I've determined that whenever swapchain image 0 is acquired, the presented frame is black. The other swapchain images are rendered properly. The odd part is that if I regenerate blit_command_buffers using the first code, immediately before the second code, there is no flickering, all frames are normal. There is no flickering either if I regenerate the command buffers after the present code if image_num == 0 only. The flickering only happens if the original command buffers are used, which are generated once on swapchain (re)creation. So I'm wondering if it has to do with the original state of the swapchain images before any rendering is done. In any case, it's a real mystery to me.

    status: unknown-cause 
  • macOS: BufferUsage::all() breaks examples
    macOS: BufferUsage::all() breaks examples

    Jun 9, 2020

    Running the triangle example on a fresh install of macOS with the vulkan SDK, I get a blue screen but no triangles:

    Screenshot 2020-06-09 at 23 24 26

    My laptop is a 2020 macbook air, still with the new computer smell, and an integrated GPU.

    I'm more than happy to debug myself, given some direction! I'm not really sure where to start.

    status: unknown-cause 
  • SyncCommandBufferBuilderError(Conflict) On Successive Calls to AutoCommandBuffeBuilder::blit_image
    SyncCommandBufferBuilderError(Conflict) On Successive Calls to AutoCommandBuffeBuilder::blit_image

    Jun 13, 2020

    • Versions of Vulkano: 0.19.0 and 0.18.0
    • OS: Linux (Kernel version: 5.6.15-1-MANJARO)
    • GPU (the selected PhysicalDevice): AMD Radeon RX580
    • GPU Driver: VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (rev e7) (prog-if 00 [VGA controller])

    Repository demonstrating the issue: Branch master uses Vulkano 0.11.1 and works as expected. Branch 'version_0-19-0' uses the latest version and panics on a BlitImageError.


    When adding image blitting commands to a command buffer, successive calls to AutoCommandBufferBuilder::blit_image return a SyncCommandBufferBuilderError(Conflict)). The tutorial I was following warns that this code "results in Validation Layer warnings and may not behave the same on all machines." In the time since the tutorial has been released, has a more reliable way of performing this type of blitting been introduced?


    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SyncCommandBufferBuilderError(Conflict { command1_name: "vkCmdBlitImage", command1_param: "source", command1_offset: 1, command2_name: "vkCmdBlitImage", command2_param: "destination", command2_offset: 1 })', src/
    stack backtrace:
       0: backtrace::backtrace::libunwind::trace
                 at /cargo/registry/src/
       1: backtrace::backtrace::trace_unsynchronized
                 at /cargo/registry/src/
       2: std::sys_common::backtrace::_print_fmt
                 at src/libstd/sys_common/
       3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
                 at src/libstd/sys_common/
       4: core::fmt::write
                 at src/libcore/fmt/
       5: std::io::Write::write_fmt
                 at src/libstd/io/
       6: std::sys_common::backtrace::_print
                 at src/libstd/sys_common/
       7: std::sys_common::backtrace::print
                 at src/libstd/sys_common/
       8: std::panicking::default_hook::{{closure}}
                 at src/libstd/
       9: std::panicking::default_hook
                 at src/libstd/
      10: std::panicking::rust_panic_with_hook
                 at src/libstd/
      11: rust_begin_unwind
                 at src/libstd/
      12: core::panicking::panic_fmt
                 at src/libcore/
      13: core::option::expect_none_failed
                 at src/libcore/
      14: core::result::Result<T,E>::unwrap
                 at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libcore/
      15: vulkan_tutorial::Renderer::create_texture_image
                 at src/
      16: vulkan_tutorial::Renderer::initialize
                 at src/
      17: vulkan_tutorial::HelloTriangleApplication::initialize
                 at src/
      18: vulkan_tutorial::main
                 at src/
      19: std::rt::lang_start::{{closure}}
                 at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/
      20: std::rt::lang_start_internal::{{closure}}
                 at src/libstd/
      21: std::panicking::try::do_call
                 at src/libstd/
      22: __rust_maybe_catch_panic
                 at src/libpanic_unwind/
      23: std::panicking::try
                 at src/libstd/
      24: std::panic::catch_unwind
                 at src/libstd/
      25: std::rt::lang_start_internal
                 at src/libstd/
      26: std::rt::lang_start
                 at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/
      27: main
      28: __libc_start_main
      29: _start
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    status: needs investigation 
  • Getting pointer to vk_sys::Instance?
    Getting pointer to vk_sys::Instance?

    Jun 15, 2020

    Once I have an Instance, how do I get the underlying pointer/vk_sys object?

    I'm trying to use vulkano with glfw, which has a wrapper for glfwCreateWindowSurface that uses vk_sys::Instance. My plan was to call that, and then use Surface::from_raw_surface.

    The glfw example would have me create the instance myself, but that seems a bit of a waste.

    type: question 
  • How would I implement the blas operation `SSCAL` (multiply vector by scalar)?
    How would I implement the blas operation `SSCAL` (multiply vector by scalar)?

    Jun 15, 2020

    This is just a question of me learning and asking for help with this.

    Seeing the example compute code given in the tutorial it multiplies every value in a given array by 12 (as written into the glsl):

    mod cs {
            ty: "compute",
            src: "
            #version 450
            layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
            layout(set = 0, binding = 0) buffer Data {
                uint data[];
            } buf;
            void main() {
                uint idx = gl_GlobalInvocationID.x;
      [idx] *= 12;

    How can I modify this and the rest of the example code to multiply every value in an array by a given value (replacing 12 with some x)?

    (Apologies about this question being bit dumb, I can't seem to find any good examples).

    Current project simply implementing compute tutorial code:

    type: question 
  • Radv leading to panicked main thread in triangle example
    Radv leading to panicked main thread in triangle example

    Feb 14, 2017

    Running the triangle example code gives me:

    WARNING: radv is not a conformant vulkan implementation, testing use only. Using device: AMD RADV POLARIS10 (type: DiscreteGpu) thread 'main' panicked at 'calledResult::unwrap()on anErrvalue: Timeout', /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libcore/ note: Run withRUST_BACKTRACE=1for a backtrace.

    I am not sure whether this is a RADV bug or one I could fix. Any ideas here? Will you test with Mesa/Radv as well?

  • Mac install
    Mac install

    Dec 27, 2018

    • [x] Added an entry to if knowledge of this change could be valuable to users
    • [x] Updated documentation to reflect any user-facing changes - in this repository

    This PR automatically downloads and installs the latest Vulkan SDK from lunarg. It will only do this if VULKAN_SDK is not set. The sdk will be installed at $HOME/.vulkan_sdk and the following environment variables will be set in the users .profile or .bash_profile

    export VULKAN_SDK=$HOME/.vulkan_sdk/macOS
    export PATH=$VULKAN_SDK/bin:$PATH
    export VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json
    export VK_LAYER_PATH=$VULKAN_SDK/etc/vulkan/explicit_layer.d

    The only thing that isn't automated is the user will get a error about failing to link the vulkan libs. This is because the changes to their profile are not automatically refreshed. They will need to either source ~/.profile or source ~/.bash_profile or reopen their terminal after the first time they build vulkano.

    If anyone knows how to automate this that would be super useful. So far I have tried to pass the env var settings along from the build script to the lib using cargo:rustc_env but that only works if you are directly using Vulkano and not if it's a dependency.

    One thing we could do is assume that if the env vars are not set when Vulkano is run then they must just be set to the defaults and but the user has not sourced their profile. Then just std::env::set_var to set them temporarily.

  • How to run the examples
    How to run the examples

    Sep 29, 2017

    I would like to test the examples but I am running into some problems.

    On Linux with a NVIDA 1060 I get this error:

    ➜  vulkano-examples git:(master) cargo run --bin triangle
        Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
         Running `target/debug/triangle`
    thread 'main' panicked at 'failed to create Vulkan instance: LoadingError(LibraryLoadFailure(" cannot open shared object file: No such file or directory"))', /checkout/src/libcore/
    note: Run with `RUST_BACKTRACE=1` for a backtrace.

    Do I need to install something from Vulkan?

    On MacOS I get this error:

      = note: ld: framework not found MoltenVK
              clang: error: linker command failed with exit code 1 (use -v to see invocation)
    error: aborting due to previous error
    error: Could not compile `vulkano-examples`.

    Do I need to install anything on macOS to make it work?

    Thank you very much for any help.

  • The triangle example crashes with UnsupportedDimensions on MacOS 10.12 + MoltenVK
    The triangle example crashes with UnsupportedDimensions on MacOS 10.12 + MoltenVK

    Aug 13, 2017

    I'm using a 2017 MacBook Pro with Intel Iris Graphics 550 1536 MB and a 2560 x 1600 display.

    The example builds successfully, and when I run it, it starts fine, printing some messages, including: [mvk-info] You require a license for the MoltenVK Vulkan Core feature set. Reverting to evaluation mode

    After that, it panics when creating a new Swapchain. The error is UnsupportedDimensions. Debug-printing the dimensions passed to the new method, the dimensions turn out to be [2048, 1536]. The device capabilities are

    Capabilities {
    	min_image_count: 2,
    	max_image_count: Some(2),
    	current_extent: Some([1024, 768]),
    	min_image_extent: [1024, 768],
    	max_image_extent: [1024, 768],
    	max_image_array_layers: 1, 
    	supported_transforms: SupportedSurfaceTransforms {
    		identity: true, 
    		rotate90: false, 
    		rotate180: false, 
    		rotate270: false, 
    		horizontal_mirror: false, 
    		horizontal_mirror_rotate90: false, 
    		horizontal_mirror_rotate180: false, 
    		horizontal_mirror_rotate270: false, 
    		inherit: false
    	current_transform: Identity, 
    	supported_composite_alpha: SupportedCompositeAlpha {
    		opaque: true, 
    		pre_multiplied: true, 
    		post_multiplied: true, 
    		inherit: false
    	supported_usage_flags: ImageUsage {
    		transfer_source: true, 
    		transfer_destination: true, 
    		sampled: true, 
    		storage: true, 
    		color_attachment: true, 
    		depth_stencil_attachment: false, 
    		transient_attachment: false, 
    		input_attachment: false
    	supported_formats: [
    		(B8G8R8A8Unorm, SrgbNonLinear),
    		(B8G8R8A8Srgb, SrgbNonLinear),
    		(R16G16B16A16Sfloat, SrgbNonLinear)
    	present_modes: SupportedPresentModes {
    		immediate: false, 
    		mailbox: false, 
    		fifo: true, 
    		relaxed: false

    So it seems that it fails because of the max/min image extent checks.

    I'm not knowledgeable enough to determine which of these values are wrong, but if I understand the meaning of max/min_image_extent capabilities right, it seems odd to me that the device supports only that. What should I do to fix this or to diagnose the problem further?

    type: bug 
  • About OomError
    About OomError

    Apr 3, 2016

    Most functions in Vulkan can return VK_ERROR_OUT_OF_HOST_MEMORY and VK_ERROR_OUT_OF_DEVICE_MEMORY. In fact most functions can only return one of these two errors.

    This is reflected in vulkano by the fact that a lot of functions can return OomError.

    However in practice it is very unlikely that an out-of-memory error actually happens, with the exception of vkAllocateMemory.

    The API would be much more convenient to use if an out of memory error returned by Vulkan resulted in a panic instead of returning an error, like it's the case for the core Rust. Again, with the exception of DeviceMemory which would still return OomError.

  • Support for MoltenVK
    Support for MoltenVK

    Oct 5, 2016

    cc #300

    Remains to do:

    • [ ] Expose the ActivateMoltenVKLicenseMVK function somewhere in vulkano.
    • [x] Tweak winit to allow exporting the NSView or UIView of the window. For MacOS this is done by adding an additional function here:
    • [x] Update vulkano-win to create surfaces on MacOS and iOS.
    • ~~Check that it's a correct thing to do to dlopen the MoltenVK library.~~

    After steps 2 and 3, it should "just work" if you put the MoltenVK file next to the executable. Step 1 is optional for now because the free trial doesn't require activating a license.

    I'm not sure that I'll finish this PR soon, so feel free to submit PRs to the moltenvk branch if you want to work on it. It should be fairly easy to do steps 2 and 3 (feel free to ask questions).

    I'm also unsure about whether we'll want to merge this branch until MoltenVK is stable enough. I don't really want to have obsolete code in vk-sys because they decided to modify their extensions.