Read me update

This commit is contained in:
maik klein 2016-12-09 19:25:48 +01:00
parent 72f85fc77f
commit 4edadcdf4a
9 changed files with 167 additions and 100 deletions

102
README.md
View file

@ -1,5 +1,103 @@
#ASH
An experimental wrapper for Vulkan. This library is not stable use [Vulkano](https://github.com/tomaka/vulkano) instead.
A low level Vulkan wrapper for Rust
The main goal for this library is to familiarize myself with Vulkan.
## Why ASH?
Functions return a `type VkResult<T> = Result<T, vk::Result>` instead of an error code. No mutable references for the output are required.
```Rust
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.
```Rust
pub fn get_swapchain_images_khr(&self,
swapchain: vk::SwapchainKHR)
-> VkResult<Vec<vk::Image>>;
let present_images = device.get_swapchain_images_khr(swapchain).unwrap();
```
Ash uses always uses 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,
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]);
```
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.
```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,
};
let pool = device.create_command_pool(&pool_create_info).unwrap();
```
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.
```Rust
// 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();
```
You don't have to pass an Instance or Device handle anymore, this is done implicitly for you.
```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<vk::CommandPool>;
let pool = device.create_command_pool(&pool_create_info).unwrap();
```
```Rust
```
```Rust
```
## Complete
## In progress
- Wrapping the complete spec
- Optional extension loading
## Not started
- Custom allocators

View file

@ -1,14 +1,16 @@
#![allow(dead_code)]
use prelude::*;
use std::ptr;
use std::mem;
use vk_loader2 as vk;
type VkResult<T> = Result<T, vk::Result>;
pub struct Device<'r> {
handle: vk::Device,
device_fn: vk::DeviceFn,
_lifetime: ::std::marker::PhantomData<&'r ()>,
}
impl<'r> Device<'r> {
pub unsafe fn from_raw(handle: vk::Device, device_fn: vk::DeviceFn) -> Self {
Device {

View file

@ -1,10 +1,10 @@
use prelude::*;
use std::mem;
use std::ptr;
use vk_loader2 as vk;
use instance::Instance;
use shared_library::dynamic_library::DynamicLibrary;
use std::path::Path;
type VkResult<T> = Result<T, vk::Result>;
#[cfg(windows)]
fn get_path() -> &'static Path {
Path::new("vulkan-1.dll")
@ -34,53 +34,55 @@ pub enum LoadingError {
EntryLoadError(String),
}
#[derive(Debug)]
pub enum InstanceError {
LoadError(String),
VkError(vk::Result),
}
impl Entry {
pub fn load_vulkan_path(path: &Path) -> Result<Entry, LoadingError> {
let lib = try!(DynamicLibrary::open(Some(path))
.map_err(|err| LoadingError::LibraryLoadFailure(err)));
let static_fn = try!(vk::StaticFn::load(|name| unsafe {
let lib =
DynamicLibrary::open(Some(path)).map_err(|err| LoadingError::LibraryLoadFailure(err))?;
let static_fn = vk::StaticFn::load(|name| unsafe {
let name = name.to_str().unwrap();
let f = match lib.symbol(name) {
Ok(s) => s,
Err(_) => ptr::null(),
};
f
})
.map_err(|err| LoadingError::StaticLoadError(err)));
let entry_fn = try!(vk::EntryFn::load(|name| unsafe {
}).map_err(|err| LoadingError::StaticLoadError(err))?;
let entry_fn = vk::EntryFn::load(|name| unsafe {
mem::transmute(static_fn.get_instance_proc_addr(ptr::null_mut(), name.as_ptr()))
})
.map_err(|err| LoadingError::EntryLoadError(err)));
}).map_err(|err| LoadingError::EntryLoadError(err))?;
Ok(Entry {
lib: lib,
static_fn: static_fn,
entry_fn: entry_fn,
})
}
pub fn load_vulkan() -> Result<Entry, LoadingError> {
Entry::load_vulkan_path(get_path())
}
pub fn create_instance(&self,
create_info: &vk::InstanceCreateInfo)
-> Result<Instance, vk::Result> {
-> Result<Instance, InstanceError> {
unsafe {
let mut instance: vk::Instance = mem::uninitialized();
let err_code = self.entry_fn.create_instance(create_info, ptr::null(), &mut instance);
if err_code != vk::Result::Success {
return Err(err_code);
return Err(InstanceError::VkError(err_code));
}
let instance_fn = vk::InstanceFn::load(|name| unsafe {
mem::transmute(self.static_fn.get_instance_proc_addr(instance, name.as_ptr()))
})
.unwrap();
}).map_err(|err| InstanceError::LoadError(err))?;
Ok(Instance::from_raw(instance, instance_fn))
}
}
pub fn enumerate_instance_layer_properties(&self)
-> Result<Vec<vk::LayerProperties>, vk::Result> {
pub fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
unsafe {
let mut num = 0;
self.entry_fn.enumerate_instance_layer_properties(&mut num, ptr::null_mut());
@ -96,9 +98,8 @@ impl Entry {
}
}
pub fn enumerate_instance_extension_properties
(&self)
-> Result<Vec<vk::ExtensionProperties>, vk::Result> {
pub fn enumerate_instance_extension_properties(&self)
-> VkResult<Vec<vk::ExtensionProperties>> {
unsafe {
let mut num = 0;
self.entry_fn

View file

@ -1,4 +1,5 @@
#![allow(dead_code)]
use prelude::*;
use std::ptr;
use std::mem;
use std::os::raw::*;
@ -7,8 +8,11 @@ use vk_loader2 as vk;
use device::Device;
use shared_library::dynamic_library::DynamicLibrary;
type VkResult<T> = Result<T, vk::Result>;
#[derive(Debug)]
pub enum DeviceError {
LoadError(String),
VkError(vk::Result),
}
#[derive(Debug)]
pub struct Instance<'r> {
@ -16,6 +20,7 @@ pub struct Instance<'r> {
instance_fn: vk::InstanceFn,
_lifetime: ::std::marker::PhantomData<&'r ()>,
}
impl<'r> Instance<'r> {
pub unsafe fn from_raw(handle: vk::Instance, instance_fn: vk::InstanceFn) -> Self {
Instance {
@ -25,6 +30,24 @@ impl<'r> Instance<'r> {
}
}
pub fn create_device(&self,
physical_device: vk::PhysicalDevice,
create_info: &vk::DeviceCreateInfo)
-> Result<Device, DeviceError> {
unsafe {
let mut device = mem::uninitialized();
let err_code = self.instance_fn
.create_device(physical_device, create_info, ptr::null(), &mut device);
if err_code != vk::Result::Success {
return Err(DeviceError::VkError(err_code));
}
let device_fn = vk::DeviceFn::load(|name| unsafe {
mem::transmute(self.instance_fn.get_device_proc_addr(device, name.as_ptr()))
}).map_err(|err| DeviceError::LoadError(err))?;
Ok(Device::from_raw(device, device_fn))
}
}
pub fn destroy_instance(&self) {
unsafe {
self.instance_fn.destroy_instance(self.handle, ptr::null());
@ -186,24 +209,6 @@ impl<'r> Instance<'r> {
}
}
pub fn create_device(&self,
physical_device: vk::PhysicalDevice,
create_info: &vk::DeviceCreateInfo)
-> VkResult<Device> {
unsafe {
let mut device = mem::uninitialized();
let err_code = self.instance_fn
.create_device(physical_device, create_info, ptr::null(), &mut device);
if err_code != vk::Result::Success {
return Err(err_code);
}
let device_fn = vk::DeviceFn::load(|name| unsafe {
mem::transmute(self.instance_fn.get_device_proc_addr(device, name.as_ptr()))
})
.unwrap();
Ok(Device::from_raw(device, device_fn))
}
}
pub fn enumerate_physical_devices(&self) -> VkResult<Vec<vk::PhysicalDevice>> {
unsafe {

View file

@ -1,10 +1,9 @@
#[macro_use]
extern crate shared_library;
extern crate vk_loader;
#[macro_use]
extern crate vk_loader2;
extern crate glfw;
pub mod instance;
pub mod device;
pub mod entry;
pub mod prelude;

2
ash/src/prelude.rs Normal file
View file

@ -0,0 +1,2 @@
use vk_loader2;
pub type VkResult<T> = Result<T, vk_loader2::Result>;

34
examples/Cargo.lock generated
View file

@ -4,7 +4,6 @@ version = "0.1.0"
dependencies = [
"ash 0.1.0",
"glfw 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"vk_loader 0.1.0",
"vk_loader2 0.1.0",
]
@ -69,15 +68,6 @@ dependencies = [
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.1"
@ -194,16 +184,6 @@ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vk_loader"
version = "0.1.0"
@ -218,16 +198,6 @@ dependencies = [
"shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
@ -235,7 +205,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum gcc 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb000abd6df9df4c637f75190297ebe56c1d7e66b56bbf3b4aa7aece15f61a2"
"checksum glfw 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b14e68c4ccefdf293ecb65390a5761971b83fcfc54d153a5b73d438327633965"
"checksum glfw-sys 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eaff144079cb22d6f17009e29e87c02f5fd6c4669093ce12b0b2faa6027f0d23"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
@ -251,6 +220,3 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d5b7638a1f03815d94e88cb3b3c08e87f0db4d683ef499d1836aaf70a45623f"
"checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View file

@ -5,7 +5,6 @@ authors = ["maik klein <maikklein@googlemail.com>"]
[dependencies]
glfw = "0.9.1"
time = "0.1"
vk_loader = { version = "0.1.0", path = "../vk_loader"}
vk_loader2 = { version = "0.1.0", path = "../vk_loader2"}
ash = { version = "0.1.0", path = "../ash"}

View file

@ -5,7 +5,6 @@ extern crate ash;
#[macro_use]
extern crate vk_loader2 as vk;
extern crate glfw;
extern crate time;
use std::default::Default;
use glfw::*;
@ -44,6 +43,20 @@ fn create_surface(instance: &Instance, window: &Window) -> Result<vk::SurfaceKHR
instance.create_xlib_surface_khr(&x11_create_info)
}
#[cfg(all(unix, not(target_os = "android")))]
fn extension_names() -> Vec<CString> {
vec![CString::new("VK_KHR_surface").unwrap(),
CString::new("VK_KHR_xlib_surface").unwrap(),
CString::new("VK_EXT_debug_report").unwrap()]
}
#[cfg(all(windows))]
fn extension_names() -> Vec<CString> {
vec![CString::new("VK_KHR_surface").unwrap(),
CString::new("VK_KHR_win32_surface").unwrap(),
CString::new("VK_EXT_debug_report").unwrap()]
}
unsafe extern "system" fn vulkan_debug_callback(flags: vk::DebugReportFlagsEXT,
obj_type: vk::DebugReportObjectTypeEXT,
obj: u64,
@ -76,6 +89,7 @@ pub fn find_memorytype_index(memory_req: &vk::MemoryRequirements,
}
None
}
#[derive(Clone, Debug, Copy)]
struct Vertex {
pos: [f32; 4],
@ -106,9 +120,7 @@ fn main() {
let layers_names_raw: Vec<*const i8> = layer_names.iter()
.map(|raw_name| raw_name.as_ptr())
.collect();
let extension_names = [CString::new("VK_KHR_surface").unwrap(),
CString::new("VK_KHR_xlib_surface").unwrap(),
CString::new("VK_EXT_debug_report").unwrap()];
let extension_names = extension_names();
let extension_names_raw: Vec<*const i8> = extension_names.iter()
.map(|raw_name| raw_name.as_ptr())
.collect();
@ -141,16 +153,6 @@ fn main() {
p_user_data: ptr::null_mut(),
};
let debug_call_back = instance.create_debug_report_callback_ext(&debug_info).unwrap();
//let x11_display = window.glfw.get_x11_display();
//let x11_window = window.get_x11_window();
//let x11_create_info = vk::XlibSurfaceCreateInfoKHR {
// s_type: vk::StructureType::XlibSurfaceCreateInfoKhr,
// p_next: ptr::null(),
// flags: Default::default(),
// window: x11_window as vk::Window,
// dpy: x11_display as *mut vk::Display,
//};
//let surface = instance.create_xlib_surface_khr(&x11_create_info).unwrap();
let surface = create_surface(&instance, &window).unwrap();
let pdevices = instance.enumerate_physical_devices().expect("Physical device error");
let (pdevice, queue_family_index) = pdevices.iter()
@ -815,19 +817,12 @@ fn main() {
let present_complete_semaphore = device.create_semaphore(&semaphore_create_info).unwrap();
let rendering_complete_semaphore = device.create_semaphore(&semaphore_create_info).unwrap();
let mut current = time::precise_time_ns();
let mut last = current;
let draw_fence = device.create_fence(&fence_create_info).unwrap();
while !window.should_close() {
glfw.poll_events();
for (_, event) in glfw::flush_messages(&events) {
handle_window_event(&mut window, event);
}
current = time::precise_time_ns();
let dt = current - last;
last = current;
let present_index = device.acquire_next_image_khr(swapchain,
std::u64::MAX,
present_complete_semaphore,