6 releases

Uses old Rust 2015

0.1.6 Jul 11, 2016
0.1.5 Jul 8, 2016
0.1.2 Jun 30, 2016

#621 in Graphics APIs


Used in dvk_ext_debug_report

MIT license

265KB
4.5K SLoC

Dvk is a library providing bindings to Vulkan API. Unlike many other alternatives Dvk loads all Vulkan commands dynamically at run time, making compilation much more straightforward, to the point that you don't even need Vulkan to be installed to compile it.

This library is designed following the principle of minimum surprise, it deviates very little from the official headers and does not needlessly pollute official Vulkan namespace. There are only a handful of places where either language differences or the requirment to load dynamically had forced design to deviate from canonical, all such peculiarities are thoroughly documented on this page. Regular Khronos documentation should be sufficient to learn about all the types and functions provided by this library.

NOTE: In current version only khr_win32_surface is complete out of all platform-specific WSI extensions.

Documentation

https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html

Organization

All definitions are orginized into modules, the main one is core, the rest khr_surface, ext_debug_report, khr_display, khr_display_swapchain, khr_swapchain, khr_win32_surface are all extensions. This library does not export any ready-to-use command prototypes. All definitions are in the same order as in vulkan.h header file.

Changes to official API

Types

  • VkClearValueUnion
  • VkClearColorValueUnion
  • VkCoreCommands
  • VkKhrSurfaceCommands
  • VkKhrSwapchainCommands
  • VkKhrDisplayCommands
  • VkKhrDisplaySwapchainCommands
  • VkKhrWin32SurfaceCommands
  • VkExtDebugReportCommands
  • No separate *FlagBits and *Flags types just *Flags
  • VkDescriptorPoolSize.type is renamed to dType due to naming collision with Rust keyword type
  • Platform types are redefined as part of the library
  • No universal VK_NULL_HANDLE constant, it's incompatible with type-safe handles

Functions

  • Vulkan*::new() and Vulkan*::load(&mut self, VkInstance)
  • ::null() constructor and ::is_null(&self) method for all handles
  • From trait implementation for *Union types

Loading

Dynamic loading has advantage over static linking in that no static library is needed to compile. Vulkan standard is fairly conservative on that point and only guarantees that a single command will be exported from the dynamic library. That command is vkGetInstanceProcAddr. Once that command is acquired, it can be used to load the next tier of API consisting of three global commands:

  1. vkCreateInstance
  2. vkEnumerateInstanceExtensionProperties
  3. vkEnumerateInstanceLayerProperties

The rest of the API, consisting of 134 core commands can similarly be loaded with vkGetInstanceProcAddr, but require a VkInstance object to load them. A VkInstance object not surprisingly can be created via global command vkCreateInstance. Extension commands are loaded in exactly the same way.

This library does not export any ready-to-use command prototypes, instead you get all commands dynamically loaded and returned in structs.

The core of Vulkan functionality resides in VkCoreCommands struct. It provides all the core Vulkan commands as methods. When VkCoreCommands is initially created by calling VkCoreCommands::new(), it will already have the 3 global commands loaded and ready to use. If you attempt to call any of the unloaded commands at this point it will result in panic. The next step should be to create a VkInstance object and call VkCoreCommands::load(&mut self, VkInstance instance) method passing it as argument. Vulkan is ready to use.

Extensions are loaded similarly by VkKhrSurfaceCommands, VkKhrSwapchainCommands, VkKhrDisplayCommands, VkKhrDisplaySwapchainCommands, VkKhrWin32SurfaceCommands

One thing this library does not support is loading device optimized command pointers using vkGetDeviceProcAddr. The reason for this omission is that loading functions in this way introduces a lot of incidental complexity and makes library awkward to use.

Platform types

Platform types are redefined to avoid operating system specific dependencies, use std::mem::transmute to cast between them. The current platform types are:

  • dvk::khr_win32_surface::platform::HINSTANCE
  • dvk::khr_win32_surface::platform::HWND

Unions

Since Rust has no analog to C unions they are simulated using combination of tagged union types and a From trait. Whenever Vulkan demands a union with a name VkSomeTypeName, construct a value of type VkSomeTypeNameUnion and call into(self) method on it to get VkSomeTypeName. For example:

let foo: VkClearColorValue = VkClearColorValueUnion::Float32([1,2,3]).into();

Handles

All handles are type-safe, which unfortunately makes it awkward to produce "NULL" handles. For that reason all handle types implement null function to construct empty handles, as well as corresponding method is_null to check if a handle is empty.

Usage

Here's a short example to illustrate basic use

#[macro_use]
extern crate dvk;

use dvk::core::*;
use dvk::khr_surface::*;
use dvk::khr_win32_surface::*;

...
// This will load vulkan shared library and 3 global commands
let mut core = VkCoreCommands::new().unwrap(); 

// The null method is used to get type-safe "NULL" handles
let mut instance = VkInstance::null();

// vkCreateInstance is one of the 3 global commands
// that can be loaded without an instance object
core.vkCreateInstance(&instance_create_info, null(), &mut context.instance);

// Calling unloaded command will cause a panic
core.vkEnumeratePhysicalDevices(...); // ERROR!

// After you've acquired an instance object the remaining commands can be loaded
core.load(instance).unwrap(); 

// The rest of commands are loaded and ready to use now
core.vkEnumeratePhysicalDevices(...); 
core.vkCreateDevice(...); 
core.vkQueueSubmit(...);

// Using intermediate VkClearValueUnion Rust-style enum to 
// construct VkClearValue corresponding to C-style union
let clear_depth_stencil_value = VkClearDepthStencilValue{depth:0.0f32, stencil: 0u32};
let clear_value: VkClearValue = VkClearValueUnion::DepthStencil(clear_depth_stencil_value).into();

Sample code

A more complete example is available in examples/triangle.rs. To compile( or run) it do:

> cargo build(or run) --examples triangle

Dependencies

~220KB