Go to file
2016-12-28 09:24:24 +01:00
examples Added allocators to the examples 2016-12-28 09:24:24 +01:00
src Add allocation callbacks everywhere 2016-12-28 09:07:27 +01:00
.gitignore Remove lockfile in Ash and update lockfile for the examples 2016-12-28 05:09:54 +01:00
.travis.yml Only build on stable for now 2016-12-09 20:30:30 +01:00
appveyor.yml Update to stable rust 2016-12-26 03:38:50 +01:00
Cargo.toml bump minior version 2016-12-28 05:15:38 +01:00
LICENSE-APACHE init 2016-08-14 01:13:39 +02:00
LICENSE-MIT init 2016-08-14 01:13:39 +02:00
README.md Restructure the readme 2016-12-28 04:31:48 +01:00

#Ash

A very lightweight wrapper around Vulkan

LICENSE LICENSE Documentation Build Status Build status Join the chat at https://gitter.im/MaikKlein/ash Crates.io Version

Stable yet?

No.

Why Ash?

  • Lightweight Vulkan wrapper
  • Low overhead
  • Added type safety
  • More convenient to use than raw Vulkan
  • Includes a loader
  • Extensions have their own loader

What does it do?

Explicit returns with Result

Functions return a type VkResult<T> = Result<T, vk::Result> instead of an error code. No mutable references for the output are required.

pub fn create_swapchain_khr(&self,
                            create_info: &vk::SwapchainCreateInfoKHR)
                            -> VkResult<vk::SwapchainKHR>;
let swapchain = device.create_swapchain_khr(&swapchain_create_info).unwrap();

Always returns a Vec<T> for functions that output multiple values.

pub fn get_swapchain_images_khr(&self,
                                swapchain: vk::SwapchainKHR)
                                -> VkResult<Vec<vk::Image>>;
let present_images = device.get_swapchain_images_khr(swapchain).unwrap();

Slices

Ash always uses slices in functions.

// C
void vkCmdPipelineBarrier(
    VkCommandBuffer                             commandBuffer,
    VkPipelineStageFlags                        srcStageMask,
    VkPipelineStageFlags                        dstStageMask,
    VkDependencyFlags                           dependencyFlags,
    uint32_t                                    memoryBarrierCount,
    const VkMemoryBarrier*                      pMemoryBarriers,
    uint32_t                                    bufferMemoryBarrierCount,
    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
    uint32_t                                    imageMemoryBarrierCount,
    const VkImageMemoryBarrier*                 pImageMemoryBarriers);

// Rust
pub fn cmd_pipeline_barrier(&self,
                            command_buffer: vk::CommandBuffer,
                            src_stage_mask: vk::PipelineStageFlags,
                            dst_stage_mask: vk::PipelineStageFlags,
                            dependency_flags: vk::DependencyFlags,
                            memory_barriers: &[vk::MemoryBarrier],
                            buffer_memory_barriers: &[vk::BufferMemoryBarrier],
                            image_memory_barriers: &[vk::ImageMemoryBarrier]);

device.cmd_pipeline_barrier(setup_command_buffer,
                            vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT,
                            vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT,
                            vk::DependencyFlags::empty(),
                            &[],
                            &[],
                            &[layout_transition_barrier]);

// or

let slice = device.map_memory::<Vertex>(vertex_input_buffer_memory,
                          0,
                          vertex_input_buffer_info.size,
                          vk::MemoryMapFlags::empty())
    .unwrap();
slice.copy_from_slice(&vertices);

Type safety

Ash still uses raw Vulkan structs. The only difference is type safety. Everything that can be an enum is an enum like vk::StructureType, flags are implemented similar to the Bitflags crate. Ash also follows the Rust style guide. The reason that Ash uses raw Vulkan structs is to be extensible, just like the Vulkan spec.

let pool_create_info = vk::CommandPoolCreateInfo {
    s_type: vk::StructureType::CommandPoolCreateInfo,
    p_next: ptr::null(),
    flags: vk::COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
    queue_family_index: queue_family_index,
};
let pool = device.create_command_pool(&pool_create_info).unwrap();

Additionally pointers like Instance, Device, Queue etc are hidden behind a type. Those pointers can only be constructed from within Ash which elimites invalid API usage and has the benefit of making some functions in Vulkan safe.

Function pointer loading

Ash also takes care of loading the function pointers. Function pointers are split into 3 categories. Entry, Instance and Device. The reason for not loading it into a global is that in Vulkan you can have multiple devices and each device must load its own function pointers.

// Looks for the vulkan lib in your path, alternatively you can supply the path explicitly.
let entry = Entry::load_vulkan().unwrap();
let instance: Instance = entry.create_instance(&create_info).expect("Instance creation error");
let device: Device = instance.create_device(pdevice, &device_create_info)
    .unwrap();

Extension loading

Additionally, every Vulkan extension has to be loaded explicity. You can find all extensions under ash::extensions. You still have to tell Vulkan which instance or device extensions you want to load.

use ash::extensions::Swapchain;
let swapchain_loader = Swapchain::new(&instance, &device).expect("Unable to load swapchain");
let swapchain = swapchain_loader.create_swapchain_khr(&swapchain_create_info).unwrap();

Implicit handles

You don't have to pass an Instance or Device handle anymore, this is done implicitly for you.

// C
VkResult vkCreateCommandPool(
    VkDevice                                    device,
    const VkCommandPoolCreateInfo*              pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkCommandPool*                              pCommandPool);

// Rust
pub fn create_command_pool(&self,
                           create_info: &vk::CommandPoolCreateInfo)
                           -> VkResult<vk::CommandPool>;

let pool = device.create_command_pool(&pool_create_info).unwrap();

Support for extension names

use ash::extensions::{Swapchain, XlibSurface, Surface, DebugReport};
#[cfg(all(unix, not(target_os = "android")))]
fn extension_names() -> Vec<*const i8> {
    vec![
        Surface::name().as_ptr(),
        XlibSurface::name().as_ptr(),
        DebugReport::name().as_ptr()
    ]
}

Example

You can find the examples here. All examples currently require: the LunarG Validation layers and a Vulkan library that is visible in your PATH.

Triangle

Displays a triangle with vertex colors.

cd examples
cargo run --bin triangle

screenshot

Texture

Displays a texture on a quad.

cd examples
cargo run --bin texture

texture

Roadmap

Extensions

  • Swapchain
  • Surface
  • XlibSurface
  • DebugReport
  • Win32Surface
  • MirSurface
  • XcbSurface
  • AndroidSurface
  • WaylandSurface
  • Display

In progress

  • Wrapping the complete spec

Not started

A thanks to