[][src]Crate nobs_vk

nobs-vk

no bullshit vulkan bindings.

This crate is auto generated by python scripts and provides types, constants and functions for vulkan.

  1. Existential questions
  2. Examples
    1. Vulkan core initialisation
    2. Manual Instance creation and extension loading
    3. Convenience Instance and Device creation
  3. Details
    1. Namespaces
    2. Function pointers
    3. Check macros
    4. Instance and Device builder patterns

Existential questions

Why does nobs-vk exists? nobs-vk...

  1. is used how the vulkan api is documented
  2. is auto generated from a python script that sources the vk.xml from the vulkan registry
  3. gives you the freedom to do as you please in your design decisions (but therefore doesn't protect you from your own stupidity)
  4. is not a full blown window creating bloat library in the back, just to execute some small compute shader with a headless vulkan build

While more involved wrappers for vulkan do exist they also strife to completely hide the vulkan api behind another layer of rust code and might force you into design decisions you would normally try to avoid. This library tries to be as simple as possible and just exposes callable functions to vulkan.

Examples

Vulkan core initialisation

This is a simple example that retrieves the version of vulkan that is installed on the system

#[macro_use] extern crate nobs_vk as vk;
//...
 
// loads vulkan core
let _vk_lib = vk::Core::new();
 
// good to go from here, we can use any vulkan function that is supported by this system
// make sure _vk_lib lives throughout the time that vulkan is used and is dropped afterwards
 
// global vulkan version
let mut inst_ver: u32 = 0;
if vk::EnumerateInstanceVersion(&mut inst_ver) != vk::SUCCESS { 
  panic!("something went terribly wrong");
}
 
assert_eq!(1, version_major!(inst_ver));
assert_eq!(1, version_minor!(inst_ver));
assert_eq!(0, version_patch!(inst_ver));

Manual Instance creation and extension loading

After we created a vulkan instance we can load extensions

#[macro_use] extern crate nobs_vk as vk;
use std::ffi::CString;
use std::ffi::CStr;
use std::ptr;
use std::os::raw::c_char;
// ...
let _vk_lib = vk::Core::new();
 
// Define some extensions and convert them to c-strings
let ext_names = vec![vk::KHR_SURFACE_EXTENSION_NAME, vk::KHR_XLIB_SURFACE_EXTENSION_NAME];
let ext_names_cstr = ext_names
  .iter()
  .map(|e| CString::new(*e).unwrap())
  .collect::<Vec<CString>>();
let ext_names_ptr = ext_names_cstr
  .iter()
  .map(|e| e.as_ptr())
  .collect::<Vec<*const c_char>>();
 
// create the instance
let appinfo = vk::InstanceCreateInfo {
  sType: vk::STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
  pNext: ptr::null(),
  flags: 0,
  pApplicationInfo: ptr::null(),
  enabledLayerCount: 0,
  ppEnabledLayerNames: ptr::null(),
  enabledExtensionCount: ext_names.len() as u32,   // <- extension names go here
  ppEnabledExtensionNames: ext_names_ptr.as_ptr(), // <-
};
 
let mut inst = vk::NULL_HANDLE;
vk::CreateInstance(&appinfo, ptr::null(), &mut inst);
 
// not an extension, so we can call it no matter what
let mut num_devices: u32 = 0;
vk::EnumeratePhysicalDevices(inst, &mut num_devices, ptr::null_mut());
println!("num devices:  {}", num_devices);
 
// load extensions
// note that only extensions are loaded, that have been specified in ext_names
let ie = vk::InstanceExtensions::new(inst);
// we can now use instence extensions, e.g.:
// ie.CreateXlibSurfaceKHR(...)
 
// don't forget to clean up
vk::DestroyInstance(inst, ptr::null());

Convenience Instance and Device creation

Instance and device creation are a large portion of the boiler plate code that comes with implementing a vulkan application, so it makes sence to have a convenient way of doing this in the library (which is why you could argue that it barely does not contradicts the "no bullshit" paradigm)

#[macro_use]
extern crate nobs_vk;
 
use nobs_vk as vk;
use std::ffi::CStr;
 
fn main() {
  let lib = vk::Core::new();
  let inst = vk::instance::new()
    .validate(vk::DEBUG_REPORT_ERROR_BIT_EXT | vk::DEBUG_REPORT_WARNING_BIT_EXT)
    .application("awesome app", 0)
    .add_extension(vk::KHR_SURFACE_EXTENSION_NAME)
    .add_extension(vk::KHR_XLIB_SURFACE_EXTENSION_NAME)
    .create(lib)
    .unwrap();
 
  for pd in vk::device::PhysicalDevice::enumerate_all(inst.handle) {
    println!(
      "instance api version:  {} {} {}",
      version_major!(pd.properties.apiVersion),
      version_minor!(pd.properties.apiVersion),
      version_patch!(pd.properties.apiVersion)
    );
    println!("driver version:        {}", pd.properties.driverVersion);
    println!("vendor id:             {}", pd.properties.vendorID);
    println!("device id:             {}", pd.properties.deviceID);
    println!("vendor:                {}", unsafe {
      CStr::from_ptr(&pd.properties.deviceName[0]).to_str().unwrap()
    });
     
    println!("layers:                {:?}", pd.supported_layers);
    println!("extensions:            {:?}", pd.supported_extensions);
  }
 
  let (_pdevice, _device) = vk::device::PhysicalDevice::enumerate_all(inst.handle)
    .remove(0)
    .into_device()
    .add_queue(vk::device::QueueProperties {
      present: false,
      graphics: true,
      compute: true,
      transfer: true,
    }).create()
    .unwrap();
}

Details

Namespaces

Name prefixes of the C-types, enums and functions are removed in favor of the module namespace. For example VK_Result becomes vk::Result, VK_SUCCESS becomes vk::SUCCESS, vkCreateInstance() becomes vk::CreateInstance().

Function pointers

Entry points to vulkan commands are placed in objects containing funcion pointes. After loading the function pointers contain the address to the respective vulkan API call. Vulkan commands are either core or extension. We provide two different mechanisms to load function pointers:

Core commands are loaded with nobs_vk::Core::new or nobs_vk::Core::with_version. The returned object holds entry points to core vulkan commands and defines member function to call them. Additionaly global functions in the nobs_vk namespace are defined that may be called as long as a valid instance of nobs_vk::Core exists. Warning: do not create multiple instances of nobs_vk::Core.

Instance and device extensions are loaded with nobs_vk::[InstanceExtensions|DeviceExtensions]. The two types hold entry points to vulkan extensions and define member functions to call them. Only those extension are loaded, that have been specified during instance/device creation (enabledExtensionCount and ppEnabledExtensionNames fields of fields of VkInstanceCreateInfo and VkDeviceCreateInfo).

Objects with function pointes define all commands that are listed the vulkan reference. In case a specific feature level is selected as well as platform or hardware vendor specific extensions the definitions for the functions or methods are not removed. However calling such a function, that is not supported will always cause a panic.

Check macros

Additionally to the result integer constants that are defined by the vulkan api, the two enums Success and Error are declared. These capture the successful and unsuccessful error codes. The vk_check! converts the error code returned from vulkan with make_result and prints debug information when the command failed. vk_uncheck! will consume the result and panic on error, while vk_check! returns the Result<Success, Error>

Instance and Device builder patterns

As the sole convenience feature this library introduces builder patterns for instance and device creation. This enables a convenient way of configuring e.g. debug layers for a vulkan instance, or extensions and properties of queues for devices. See instance::Builder and device::Builder for more details

Vulkan reference

For documentation of the defined enums, structs and funcions see the vulkan reference.

Modules

device
instance

Macros

make_version

Create a version number from a major, minor and patch as it is defined in vulkan version numbers and semantics

version_major

Extract major number from version, created with make_version or retrieved from vulkan

version_minor

Extract minor number from version, created with make_version or retrieved from vulkan

version_patch

Extract patch number from version, created with make_version or retrieved from vulkan

vk_check

Wraps a call to a vulkan command and converts it's returned error code with make_result.

vk_uncheck

Same as vk_check but instead of returning the Result calls unwrap on it.

Structs

Core

Vulkan core commands

DeviceExtensions

Vulkan device extensions

InstanceExtensions

Vulkan instance extensions

Enums

Error

Enum type for all unsuccessful return codes in nobs_vk::Result

Success

Enum type for all successful return codes in nobs_vk::Result

Constants

VERSION_1_0
VERSION_1_1

Traits

DeviceWrapper[
Deprecated
]

Trait with default pass-through implementations for vulkan commands associated with a device

InstanceWrapper[
Deprecated
]

Trait with default pass-through implementations for vulkan commands associated with an instance

Functions

make_result

Converts the integer error code from a vulkan command into a Result<Success, Error>