Skip to content

unschlagbar/pyronyx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pyronyx

Lightweight fully generated next gen Vulkan bindings for Rust — focused on zero overhead and natural Rust ergonomics.

Crates.io Version Vulkan 1.4 LICENSE

Overview

  • Generated from vk.xml & video.xml — complete Vulkan 1.0 through 1.4 coverage
  • Full Vulkan Video support
  • Commands dispatch from the handle they belong to
  • Extensions are just methods — enable them in CreateInfo, call them directly
  • Zero-cost handles — a vtable pointer and nothing else
  • Result-returning commands
  • No hidden runtime cost


Everything is on the right handle

Device, PhysicalDevice, Instance, Queue, CommandBuffer — every handle knows its commands directly. There is nothing to construct beyond the handle itself:

// physical device queries
let caps = physical_device.get_surface_capabilities(surface)?;
let formats = physical_device.get_surface_formats(surface)?;
let props = physical_device.get_properties();

// device commands
let swapchain = device.create_swapchain(&create_info, None)?;
let images = device.get_swapchain_images(swapchain)?;

// queue
queue.submit(&[submit_info], fence)?;

// command buffer
command_buffer.bind_pipeline(PipelineBindPoint::Graphics, pipeline);
command_buffer.bind_vertex_buffers(0, &[vertex_buffer], &[0]);
command_buffer.draw_indexed(index_count, 1, 0, 0, 0);

Extensions — no loaders required

Enable an extension in CreateInfo and its functions are immediately available on the handle. No separate objects, no extra allocation:

let extensions = [surface::NAME.as_ptr(), wayland_surface::NAME.as_ptr()];

let create_info = vk::InstanceCreateInfo {
    enabled_extension_names: extensions.as_ptr(),
    enabled_extension_count: extensions.len() as u32,
    ..Default::default()
};
let instance = vk::Instance::create(&create_info, None)?;

// surface and debug functions are already on instance
let surface = instance.create_wayland_surface(&surface_info, None)?;
instance.destroy_surface(surface, None);

Same for device extensions — khr::swapchain, khr::acceleration_structure, anything:

let device = physical_device.create_device(&create_info, None, &instance)?;

// no SwapchainDevice::new(), just call it
let swapchain = device.create_swapchain(&swapchain_info, None)?;
device.destroy_swapchain(swapchain, None);

Zero-cost handles

Every handle is a raw Vulkan handle plus a single pointer to its vtable — nothing else. No Arc, no reference counting, no allocation. Calling a method is one pointer dereference, identical to calling the function pointer directly.

Slices and Vec returns

let images = device.get_swapchain_images(swapchain)?;  // Vec<Image>
let devices = instance.enumerate_physical_devices()?;  // Vec<PhysicalDevice>

// count/pointer pairs become slices
command_buffer.bind_descriptor_sets(
    PipelineBindPoint::Graphics,
    layout,
    0,
    &descriptor_sets,
    &[],
);

Vulkan Video

Complete generated bindings for video:

use pyronyx::vk::video::*;

let profile = VideoProfileInfoKHR {
    video_codec_operation: VideoCodecOperationFlagsKHR::DecodeH264,
    ..Default::default()
};

Pointer chains

Use base.next(ext) to insert ext into the start of the pointer chain attached to base.

let mut features11 = vk::PhysicalDeviceVulkan11Features {
    shader_draw_parameters: vk::TRUE,
    ..Default::default()
};

let create_info = vk::DeviceCreateInfo {
    enabled_extension_names: extensions.as_ptr().cast(),
    enabled_extension_count: extensions.len() as u32,
    // ...
    ..Default::default()
}.next(&mut features11);

Why not Ash?

Ash has been effectively unmaintained a good time now. Beyond that, its model requires a separate loader struct per extension — khr::Swapchain::new(&instance, &device), ext::DebugUtils::new(&entry, &instance) — which you then carry alongside your device for the lifetime of your program. Command buffer commands live on Device rather than CommandBuffer because that is where the loader is. Device is just the huge struct that you need everywhere

Pyronyx does not have that distinction. Enable an extension, call its functions on the handle, done.

Example

Hello Triangle: pyronyx Triangle

Hello Triangle


License

MIT

About

Next gen Rust Vulkan bindings

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages