Repository: PistonDevelopers/glfw-rs (language: rust)

Issue:
vk-sys is deprecated
The `vk-sys` crate is deprecated. It used to be provided by the Vulkano project, but they now rely on Ash instead. While `vk-sys` still exists, it’s not receiving any updates (Vulkano no longer even has it in their repo) it might make sense to migrate to something else.


Discussion / hints:
In my opinion, [ash](https://github.com/ash-rs/ash) is the best candidate. I’m willing to prepare a PR for integrating ash, but I see two ways forward:
* Remove `vk-sys` entirely and replace it with ash. This would be a breaking change but the cleanest option.
* Add a `ash` feature and leave `vk-sys` as a dependency of the `vulkan` flag. This would avoid the breaking change but be messy. 

Which is preferred?
I think migrating to Ash is fine.

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index 4ccec1a3..e9b7e863 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,9 +32,9 @@ version = "^0.24.1"
 optional = true
 version = "0.4"
 
-[dependencies.vk-sys]
+[dependencies.ash]
 optional = true
-version = "^0.4"
+version = "0.37.2"
 
 [dev-dependencies]
 log = "0.4"
@@ -42,5 +42,5 @@ log = "0.4"
 [features]
 all = ["image", "vulkan", "log", "wayland"]
 default = ["glfw-sys"]
-vulkan = ["vk-sys"]
+vulkan = ["ash"]
 wayland = ["glfw-sys/wayland"]
diff --git a/examples/vulkan.rs b/examples/vulkan.rs
index 22c590ae..d4de3acd 100644
--- a/examples/vulkan.rs
+++ b/examples/vulkan.rs
@@ -19,29 +19,22 @@ fn main() {
 }
 
 #[cfg(feature = "vulkan")]
-use vk_sys::{
-    self as vk, EntryPoints, Instance as VkInstance, InstanceCreateInfo, InstancePointers,
-    Result as VkResult,
-};
+use ash::vk;
 
 #[cfg(feature = "vulkan")]
-use std::{mem, os::raw::c_void, ptr};
-
-#[cfg(feature = "vulkan")]
-use glfw::Context;
+use std::ptr;
 
 #[cfg(feature = "vulkan")]
 fn main() {
     let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
 
     glfw.window_hint(glfw::WindowHint::Visible(true));
+    glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::NoApi));
 
-    let (mut window, _) = glfw
+    let (window, _) = glfw
         .create_window(640, 480, "Defaults", glfw::WindowMode::Windowed)
         .expect("Failed to create GLFW window.");
 
-    window.make_current();
-
     assert!(glfw.vulkan_supported());
 
     let required_extensions = glfw.get_required_instance_extensions().unwrap_or(vec![]);
@@ -53,55 +46,39 @@ fn main() {
 
     //Load up all the entry points using 0 as the VkInstance,
     //since you can't have an instance before you get vkCreateInstance...
-    let mut entry_points: EntryPoints = EntryPoints::load(|func| {
-        window.get_instance_proc_address(0, func.to_str().unwrap()) as *const c_void
-    });
+    let entry = unsafe { ash::Entry::load().expect("Failed to load Vulkan library.") };
 
-    let instance: VkInstance = unsafe { create_instance(&mut entry_points) };
+    let instance: ash::Instance = unsafe { create_instance(&entry, &required_extensions) };
 
-    let mut instance_ptrs: InstancePointers = InstancePointers::load(|func| {
-        window.get_instance_proc_address(instance, func.to_str().unwrap()) as *const c_void
-    });
+    let mut surface: std::mem::MaybeUninit<vk::SurfaceKHR> = std::mem::MaybeUninit::uninit();
 
-    //Load other pointers and do other Vulkan stuff here
-
-    unsafe {
-        destroy_instance(instance, &mut instance_ptrs);
+    if window.create_window_surface(instance.handle(), ptr::null(), surface.as_mut_ptr())
+        != vk::Result::SUCCESS
+    {
+        panic!("Failed to create GLFW window surface.");
     }
 
-    println!("Vulkan instance successfully created and destroyed.");
+    // Use other vulkan stuff here.
+
+    println!("Vulkan instance successfully created. Destruction is automatic with Drop.");
 }
 
 #[cfg(feature = "vulkan")]
-unsafe fn create_instance(entry_points: &mut EntryPoints) -> VkInstance {
-    let mut instance: mem::MaybeUninit<VkInstance> = mem::MaybeUninit::uninit();
-
+unsafe fn create_instance(entry: &ash::Entry, extensions: &Vec<String>) -> ash::Instance {
+    // Turn the list of extensions into a format that can be passed in InstanceCreateInfo
+    let extensions: Vec<std::ffi::CString> = extensions
+        .iter()
+        .map(|ext| std::ffi::CString::new(ext.clone()).expect("Failed to convert extension name"))
+        .collect();
+    let extension_pointers: Vec<*const i8> = extensions.iter().map(|ext| ext.as_ptr()).collect();
     //This is literally the bare minimum required to create a blank instance
     //You'll want to fill in this with real data yourself
-    let info: InstanceCreateInfo = InstanceCreateInfo {
-        sType: vk::STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
-        pNext: ptr::null(),
-        flags: 0,
-        pApplicationInfo: ptr::null(),
-        enabledLayerCount: 0,
-        ppEnabledLayerNames: ptr::null(),
-        //These two should use the extensions returned by window.get_required_instance_extensions
-        enabledExtensionCount: 0,
-        ppEnabledExtensionNames: ptr::null(),
-    };
-
-    let res: VkResult = entry_points.CreateInstance(
-        &info as *const InstanceCreateInfo,
-        ptr::null(),
-        instance.as_mut_ptr(),
-    );
-
-    assert_eq!(res, vk::SUCCESS);
-
-    instance.assume_init()
-}
+    let info: vk::InstanceCreateInfoBuilder =
+        vk::InstanceCreateInfo::builder().enabled_extension_names(&extension_pointers);
 
-#[cfg(feature = "vulkan")]
-unsafe fn destroy_instance(instance: VkInstance, instance_ptrs: &mut InstancePointers) {
-    instance_ptrs.DestroyInstance(instance, ptr::null());
+    unsafe {
+        entry
+            .create_instance(&info, None)
+            .expect("Unable to create instance.")
+    }
 }
diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs
index fd917f73..d2c9fb95 100644
--- a/src/ffi/mod.rs
+++ b/src/ffi/mod.rs
@@ -22,10 +22,7 @@ use std::os::raw::{c_char, c_double, c_float, c_int, c_ulonglong};
 use std::os::raw::{c_uchar, c_uint, c_ushort, c_void};
 
 #[cfg(feature = "vulkan")]
-use vk_sys::{
-    AllocationCallbacks as VkAllocationCallbacks, Instance as VkInstance,
-    PhysicalDevice as VkPhysicalDevice, Result as VkResult, SurfaceKHR as VkSurfaceKHR,
-};
+use ash::vk;
 
 mod link;
 
@@ -658,20 +655,20 @@ extern "C" {
     #[cfg(feature = "vulkan")]
     pub fn glfwGetRequiredInstanceExtensions(count: *mut c_uint) -> *const *const c_char;
     #[cfg(feature = "vulkan")]
-    pub fn glfwGetInstanceProcAddress(instance: VkInstance, procname: *const c_char) -> GLFWvkproc;
+    pub fn glfwGetInstanceProcAddress(instance: vk::Instance, procname: *const c_char) -> GLFWvkproc;
     #[cfg(feature = "vulkan")]
     pub fn glfwGetPhysicalDevicePresentationSupport(
-        instance: VkInstance,
-        device: VkPhysicalDevice,
+        instance: vk::Instance,
+        device: vk::PhysicalDevice,
         queuefamily: c_uint,
     ) -> c_int;
     #[cfg(feature = "vulkan")]
     pub fn glfwCreateWindowSurface(
-        instance: VkInstance,
+        instance: vk::Instance,
         window: *mut GLFWwindow,
-        allocator: *const VkAllocationCallbacks,
-        surface: *mut VkSurfaceKHR,
-    ) -> VkResult;
+        allocator: *const vk::AllocationCallbacks,
+        surface: *mut vk::SurfaceKHR,
+    ) -> vk::Result;
 
     // native APIs
 
@@ -689,7 +686,7 @@ extern "C" {
     pub fn glfwGetX11Window(window: *mut GLFWwindow) -> *mut c_void;
     #[cfg(all(any(target_os = "linux", target_os = "freebsd"), not(feature = "wayland")))]
     pub fn glfwGetX11Display() -> *mut c_void;
-    
+
     #[cfg(any(target_os = "linux", target_os = "freebsd"))]
     pub fn glfwGetGLXContext(window: *mut GLFWwindow) -> *mut c_void;
 
diff --git a/src/lib.rs b/src/lib.rs
index 99d9bc20..4f1e555c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -81,8 +81,6 @@
 
 // TODO: Document differences between GLFW and glfw-rs
 
-#[cfg(feature = "vulkan")]
-extern crate vk_sys;
 #[cfg(feature = "log")]
 #[macro_use]
 extern crate log;
@@ -112,10 +110,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::mpsc::{channel, Receiver, Sender};
 
 #[cfg(feature = "vulkan")]
-use vk_sys::{
-    self as vk, AllocationCallbacks as VkAllocationCallbacks, Instance as VkInstance,
-    PhysicalDevice as VkPhysicalDevice, Result as VkResult, SurfaceKHR as VkSurfaceKHR,
-};
+use ash::vk;
 
 /// Alias to `MouseButton1`, supplied for improved clarity.
 pub use self::MouseButton::Button1 as MouseButtonLeft;
@@ -1343,7 +1338,7 @@ impl Glfw {
     ///
     /// Wrapper for `glfwGetInstanceProcAddress`
     #[cfg(feature = "vulkan")]
-    pub fn get_instance_proc_address_raw(&self, instance: VkInstance, procname: &str) -> VkProc {
+    pub fn get_instance_proc_address_raw(&self, instance: vk::Instance, procname: &str) -> VkProc {
         with_c_str(procname, |procname| unsafe {
             ffi::glfwGetInstanceProcAddress(instance, procname)
         })
@@ -1356,8 +1351,8 @@ impl Glfw {
     #[cfg(feature = "vulkan")]
     pub fn get_physical_device_presentation_support_raw(
         &self,
-        instance: VkInstance,
-        device: VkPhysicalDevice,
+        instance: vk::Instance,
+        device: vk::PhysicalDevice,
         queue_family: u32,
     ) -> bool {
         vk::TRUE
@@ -1989,7 +1984,7 @@ impl Window {
     ///
     /// Wrapper for `glfwGetInstanceProcAddress`
     #[cfg(feature = "vulkan")]
-    pub fn get_instance_proc_address(&mut self, instance: VkInstance, procname: &str) -> VkProc {
+    pub fn get_instance_proc_address(&mut self, instance: vk::Instance, procname: &str) -> VkProc {
         self.glfw.get_instance_proc_address_raw(instance, procname)
     }
 
@@ -2000,8 +1995,8 @@ impl Window {
     #[cfg(feature = "vulkan")]
     pub fn get_physical_device_presentation_support(
         &self,
-        instance: VkInstance,
-        device: VkPhysicalDevice,
+        instance: vk::Instance,
+        device: vk::PhysicalDevice,
         queue_family: u32,
     ) -> bool {
         self.glfw
@@ -2012,10 +2007,10 @@ impl Window {
     #[cfg(feature = "vulkan")]
     pub fn create_window_surface(
         &self,
-        instance: VkInstance,
-        allocator: *const VkAllocationCallbacks,
-        surface: *mut VkSurfaceKHR,
-    ) -> VkResult {
+        instance: vk::Instance,
+        allocator: *const vk::AllocationCallbacks,
+        surface: *mut vk::SurfaceKHR,
+    ) -> vk::Result {
         unsafe { ffi::glfwCreateWindowSurface(instance, self.ptr, allocator, surface) }
     }
     /// Wrapper for `glfwCreateWindow`.


Test patch: