diff --git a/README.md b/README.md index d187ef529..f9d379894 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,15 @@ A very lightweight wrapper around Vulkan [![Crates.io Version](https://img.shields.io/crates/v/ash.svg)](https://crates.io/crates/ash) [![](https://tokei.rs/b1/github/maikklein/ash)](https://github.com/MaikKlein/ash) -## Stable yet? -I don't expect any big changes anymore. The library will still remain < 1.0 until I had time to use it in a real project. If you encounter any problems, feel free to open an [Issue](https://github.com/MaikKlein/ash/issues). - -## Why Ash? -- [x] Lightweight Vulkan wrapper -- [x] Low overhead -- [x] Additional type safety -- [x] Trait based, version specific loader - -## What does it do? - +## Overview +- [x]: A true Vulkan API without compromises +- [x]: Convenience features that don't limit the functionality +- [x]: Function pointer loading +- [x]: No validation, everything is **unsafe** +- [x]: Generated from `vk.xml` + +## Features ### Explicit returns with `Result` -Functions return a `type VkResult = Result` instead of an error code. No mutable references for the output are required. ```Rust // function signature pub fn create_instance(&self, @@ -35,7 +31,8 @@ let instance = entry.create_instance(&create_info, None) ``` -Always returns a `Vec` for functions that output multiple values. +### Returns a `Vec` (*when possible*) for functions that output multiple values. + ```Rust pub fn get_swapchain_images_khr(&self, swapchain: vk::SwapchainKHR) @@ -43,23 +40,8 @@ pub fn get_swapchain_images_khr(&self, let present_images = swapchain_loader.get_swapchain_images_khr(swapchain).unwrap(); ``` -### Slices -Ash always uses slices in functions. +### Slices in functions ```Rust -// 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, @@ -68,77 +50,61 @@ pub fn cmd_pipeline_barrier(&self, 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]); - ``` -### 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. +### Default implementation for all types ```Rust -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, +// No need to manually set the structure type +let desc_alloc_info = vk::DescriptorSetAllocateInfo { + descriptor_pool: self.pool, + descriptor_set_count: self.layouts.len() as u32, + p_set_layouts: self.layouts.as_ptr(), + ..Default::default() }; -let pool = device.create_command_pool(&pool_create_info, None).unwrap(); ``` - -Additionally pointers like `Instance`, `Device`, `Queue` etc are hidden behind a type. Those pointers can only be constructed from within `Ash` which eliminates some 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 will load its own function pointers to achieve better performance. Click [here](https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md) for more information. - -Ash also manages multiple versions of Vulkan without any breakage. You will never run into any runtime error because you tried to access a function pointer that failed to load. Function pointers either load successfully or fail and return an error. - +### Builder pattern ```Rust -use ash::{Device, Instance}; -// Specifies the version that you want to load -use ash::version::V1_0; -// Those traits implement the version specific functions -use ash::version::{InstanceV1_0, DeviceV1_0, EntryV1_0}; -let entry = Entry::::new().unwrap(); -let instance = entry.create_instance(...).expect("Instance creation error."); -let device = instance.create_device(...).expect("Device creation error."); +let pipeline_vertex_input_state_create_info = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_binding_descriptions(&Vertex::binding_descriptions()) + .vertex_attribute_descriptions(&Vertex::attribute_descriptions()).build(); ``` +*Note*: No validation is done, the lifetimes only have to live as long as the builder object. It is the responsibility of the user to make sure that the pointers are valid. +### Flags and constants as associated constants -A `V1_X` struct is used to indicate the version. ```Rust -// Define your types -type YourDevice = Device; -type YourInstance = Instance; +dst_access_mask: vk::AccessFlags::COLOR_ATTACHMENT_READ + | vk::AccessFlags::COLOR_ATTACHMENT_WRITE, ``` -You can upgrade to a future version without any breakage. ```Rust -// For example, switching from V1_0 to V1_3 will not cause any breakage. -type YourDevice = Device; -type YourInstance = Instance; +pipeline_bind_point: vk::PipelineBindPoint::GRAPHICS, ``` +### Debug/Display for Flags -A newer version can always be converted to an older version. ```Rust -let newer_device: Device = ...; -let older_device: Device = newer_device.into(); +let flag = vk::AccessFlags::COLOR_ATTACHMENT_READ + | vk::AccessFlags::COLOR_ATTACHMENT_WRITE; +println!("Debug: {:?}", flag); +println!("Display: {}", flag); +// Prints: +// Debug: AccessFlags(110000000) +// Display: COLOR_ATTACHMENT_READ | COLOR_ATTACHMENT_WRITE ``` -Or specify the *minimum* version that you require with a trait. +### Interop + ```Rust -fn do_something_with_a_device(device: &Device){} +PipelineBindPoint::from_raw(bindpoint); ``` +### 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 will load its own function pointers to achieve better performance. Click [here](https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md) for more information. + ### Extension loading -Additionally, every Vulkan extension has to be loaded explicitly. You can find all extensions under [ash::extensions](https://github.com/MaikKlein/ash/tree/master/ash/src/extensions). You still have to tell Vulkan which instance or device extensions you want to load. +Additionally, every Vulkan extension has to be loaded explicitly. You can find all extensions under [ash::extensions](https://github.com/MaikKlein/ash/tree/master/ash/src/extensions). ```Rust use ash::extensions::Swapchain; -let swapchain_loader = Swapchain::new(&instance, &device).expect("Unable to load swapchain"); +let swapchain_loader = Swapchain::new(&instance, &device); let swapchain = swapchain_loader.create_swapchain_khr(&swapchain_create_info).unwrap(); ``` @@ -156,16 +122,8 @@ fn extension_names() -> Vec<*const i8> { ``` ### Implicit handles -You don't have to pass an Instance or Device handle anymore, this is done implicitly for you. This makes sure that you will always use the most optimal implementation for your `Device`. +Handles from Instance or Device are passed implicitly. ```Rust -// 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; @@ -197,24 +155,6 @@ cargo run --bin texture ``` ![texture](http://i.imgur.com/trow00H.png) -## Roadmap - -### Extensions -- [x] Swapchain -- [x] Surface -- [x] XlibSurface -- [x] DebugReport -- [x] Win32Surface -- [x] MirSurface -- [x] XcbSurface -- [x] AndroidSurface -- [x] WaylandSurface -- [ ] Display - -### In progress -- Wrapping the complete spec -- Version specific loader - ## A thanks to * [Api with no secrets](https://software.intel.com/en-us/articles/api-without-secrets-introduction-to-vulkan-part-1)