pub mod enums; pub mod structs; mod overlay; mod vk_handles; use std::{ ffi::c_void, fs::{File, OpenOptions}, io::Write, mem, os::raw::c_char, ptr, slice, }; use enums::*; use overlay::Overlay; use structs::*; use vk_handles::*; use vulkan_rs::prelude::*; const LOG_FILE: &'static str = "/home/michael/rf2_vk_hud.log"; static mut OVERLAY: Overlay = Overlay::new(); static mut QUEUE_SUBMIT: PFN_vkQueueSubmit = unsafe { mem::transmute(vkVoidFunction as *const c_void) }; #[no_mangle] #[allow(non_snake_case)] pub extern "C" fn vkNegotiateLoaderLayerInterfaceVersion( pVersionStruct: *mut VkNegotiateLayerInterface, ) -> VkResult { if let Err(_) = File::create(LOG_FILE) {} write_log(" =================================================================="); write_log(" ======================= New Negotiation =========================="); write_log(" =================================================================="); unsafe { *pVersionStruct = VkNegotiateLayerInterface { sType: enums::VkNegotiateLayerStructType::LAYER_NEGOTIATE_INTERFACE_STRUCT, pNext: ptr::null_mut(), loaderLayerInterfaceVersion: 2, pfnGetInstanceProcAddr: Some(get_instance_proc_addr), pfnGetDeviceProcAddr: Some(get_device_proc_addr), pfnGetPhysicalDeviceProcAddr: None, } }; set_vk_handles(match VkTypedefHandles::new() { Ok(handles) => handles, Err(err) => { write_log(format!("failed to load typedef handles {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } }); VK_SUCCESS } #[no_mangle] extern "system" fn get_device_proc_addr( _device: VkDevice, function_name: *const c_char, ) -> PFN_vkVoidFunction { let func_string = match VkString::try_from(function_name) { Ok(func) => func, Err(_) => { write_log("Err: failed creating string"); return Functions::Null.convert(); } }; let s = func_string.as_str(); if let Some(func) = Functions::get_vk_func(s) { return func.convert(); } if let Some(func) = vk_handles().handle(s) { return func; } Functions::Null.convert() } #[no_mangle] extern "system" fn get_instance_proc_addr( _instance: VkInstance, function_name: *const c_char, ) -> PFN_vkVoidFunction { let func_string = match VkString::try_from(function_name) { Ok(func) => func, Err(_) => { write_log("Err: failed creating string"); return Functions::Null.convert(); } }; let s = func_string.as_str(); if let Some(func) = Functions::get_vk_func(s) { return func.convert(); } if let Some(func) = vk_handles().handle(s) { return func; } Functions::Null.convert() } pub extern "system" fn create_instance( create_info: *const VkInstanceCreateInfo, allocator: *const VkAllocationCallbacks, instance: *mut VkInstance, ) -> VkResult { write_log(" ================== vulkan layer create instance =================="); let chain_info = match VkLayerInstanceCreateInfo::get_chain_info( unsafe { &*create_info }, VK_LAYER_LINK_INFO, ) { Some(info) => info, None => { write_log("instance chain info not found."); return VK_ERROR_LAYER_NOT_PRESENT; } }; let proc_addr = chain_info.layer_info().next_instance_proc_addr; let create_instance: PFN_vkCreateInstance = unsafe { mem::transmute(proc_addr( VkInstance::NULL_HANDLE, VkString::new("vkCreateInstance").as_ptr(), )) }; chain_info.advance_layer_info(); let result = create_instance(create_info, allocator, instance); if result != VK_SUCCESS { return result; }; vk_handles_mut().load_instance_functions(unsafe { *instance }, proc_addr); write_log("-> successfully created instance."); let ext_names = unsafe { (*create_info).extension_names() }; write_log(format!("{:?}", ext_names)); // DXVK workaround, it creates the instance twice with different properties if ext_names.contains(&VkString::new("VK_KHR_surface")) { unsafe { let ins = match Instance::preinitialized( *instance, proc_addr, &ext_names, (*(*create_info).pApplicationInfo).apiVersion, ) { Ok(ins) => ins, Err(err) => { write_log(format!("-> local instance creation failed: {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } }; OVERLAY.set_instance(ins); } write_log("-> created local instance handle"); } VK_SUCCESS } pub extern "system" fn destroy_instance( instance: VkInstance, allocator: *const VkAllocationCallbacks, ) { write_log(" ================== vulkan layer destroy instance =================="); unsafe { if let Some(vk_fn) = vk_handles().handle("vkDestroyInstance") { let destroy_instance: PFN_vkDestroyInstance = mem::transmute(vk_fn); destroy_instance(instance, allocator); } } } pub extern "system" fn create_device( physical_device: VkPhysicalDevice, create_info: *const VkDeviceCreateInfo<'_>, allocator: *const VkAllocationCallbacks, device: *mut VkDevice, ) -> VkResult { write_log(" ================== vulkan layer create device =================="); let chain_info = match VkLayerDeviceCreateInfo::get_chain_info(unsafe { &*create_info }, VK_LAYER_LINK_INFO) { Some(info) => info, None => { write_log("device chain info not found."); return VK_ERROR_LAYER_NOT_PRESENT; } }; let proc_addr = chain_info.layer_info().next_device_proc_addr; chain_info.advance_layer_info(); let result = unsafe { match vk_handles().handle("vkCreateDevice") { Some(vk_fn) => { let create_device: PFN_vkCreateDevice = mem::transmute(vk_fn); create_device(physical_device, create_info, allocator, device) } None => { write_log("failed creating device"); return VK_ERROR_INITIALIZATION_FAILED; } } }; if result != VK_SUCCESS { return result; } vk_handles_mut().load_device_functions(unsafe { *device }, proc_addr); unsafe { QUEUE_SUBMIT = match vk_handles().handle("vkQueueSubmit") { Some(submit) => mem::transmute(submit), None => { write_log("failed querying vkQueueSubmit"); return VK_ERROR_INITIALIZATION_FAILED; } } }; let pdev = match PhysicalDevice::from_raw(unsafe { OVERLAY.instance() }, physical_device) { Ok(pdev) => pdev, Err(err) => { write_log(format!("failed creating physical device: {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } }; let ext_names = unsafe { (*create_info).extension_names() }; write_log(format!("{:?}", ext_names)); unsafe { OVERLAY.set_device( match Device::preinitialized(*device, proc_addr, pdev, &ext_names) { Ok(dev) => dev, Err(err) => { write_log(format!("-> local device creation failed: {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } }, ); } VK_SUCCESS } pub extern "system" fn destroy_device(device: VkDevice, allocator: *const VkAllocationCallbacks) { write_log(" ================== vulkan layer destroy device =================="); unsafe { if let Some(vk_fn) = vk_handles().handle("vkDestroyDevice") { let destroy_device: PFN_vkDestroyDevice = mem::transmute(vk_fn); destroy_device(device, allocator); } } } pub extern "system" fn create_swapchain( _device: VkDevice, create_info: *const VkSwapchainCreateInfoKHR, _allocator: *const VkAllocationCallbacks, p_swapchain: *mut VkSwapchainKHR, ) -> VkResult { write_log(" ================== vulkan layer create swapchain =================="); let create_swapchain: PFN_vkCreateSwapchainKHR = match vk_handles().handle("vkCreateSwapchainKHR") { Some(create_swapchain) => unsafe { mem::transmute(create_swapchain) }, None => { write_log("failed querying vkCreateSwapchainKHR"); return VK_ERROR_INITIALIZATION_FAILED; } }; create_swapchain(_device, create_info, _allocator, p_swapchain); write_log("-> created swapchain vk handle"); // if unsafe { !OVERLAY.has_rendering() } { let swapchain = match unsafe { Swapchain::from_raw(OVERLAY.device(), &*create_info, *p_swapchain) } { Ok(swapchain) => swapchain, Err(err) => { write_log(format!("create swapchain failed: {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } }; write_log("-> created Arc"); if let Err(err) = unsafe { OVERLAY.create_rendering(swapchain) } { write_log(format!("create overlay rendering struct failed: {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } write_log("-> created renderer"); // } VK_SUCCESS } pub extern "system" fn submit_queue( queue: VkQueue, submit_count: u32, submits: *const VkSubmitInfo, fence: VkFence, ) -> VkResult { unsafe { let input_submit_info = slice::from_raw_parts(submits, submit_count as usize); let overlay_submit = match OVERLAY.render() { Ok(submit) => submit, Err(err) => { write_log(format!("overlay rendering failed: {:?}", err)); return VK_ERROR_DEVICE_LOST; } }; let complete_submits = [input_submit_info, &[overlay_submit]].concat(); QUEUE_SUBMIT( queue, complete_submits.len() as u32, complete_submits.as_ptr(), fence, ) } } pub extern "system" fn get_device_queue( device: VkDevice, queue_family_index: u32, queue_index: u32, p_queue: *mut VkQueue, ) { write_log(" ================== vulkan layer get device queue =================="); let get_device_queue: PFN_vkGetDeviceQueue = match vk_handles().handle("vkGetDeviceQueue") { Some(get_queue) => unsafe { mem::transmute(get_queue) }, None => { write_log("failed querying vkGetDeviceQueue"); panic!("failed querying vkGetDeviceQueue"); } }; get_device_queue(device, queue_family_index, queue_index, p_queue); unsafe { if !OVERLAY.has_queue() { let arc_device = OVERLAY.device(); OVERLAY.add_queue(Queue::new( arc_device, *p_queue, queue_family_index, queue_index, )); } } } pub extern "system" fn acquire_next_image( device: VkDevice, swapchain: VkSwapchainKHR, timeout: u64, semaphore: VkSemaphore, fence: VkFence, pImageIndex: *mut u32, ) -> VkResult { VK_SUCCESS } pub fn write_log(msg: impl ToString) { if let Ok(mut file) = OpenOptions::new().append(true).create(true).open(LOG_FILE) { if let Err(_) = file.write_all(format!("{}\n", msg.to_string()).as_bytes()) {} } }