pub mod enums; pub mod structs; mod overlay; mod vk_handles; use std::{ ffi::c_void, fs::{self, File, OpenOptions}, io::Write, mem, os::raw::c_char, path::Path, ptr, }; use enums::*; use overlay::{Overlay, OverlayConfig}; use structs::*; use vk_handles::*; use vulkan_rs::prelude::*; static mut LOG_ENABLED: bool = true; static mut LOG_FILE: String = String::new(); static mut OVERLAY: Overlay = Overlay::new(); static mut ACQUIRE_NEXT_IMAGE: PFN_vkAcquireNextImageKHR = unsafe { mem::transmute(vkVoidFunction as *const c_void) }; pub(crate) fn logging() -> bool { unsafe { LOG_ENABLED } } macro_rules! write_log { ($msg:expr) => { if crate::logging() { crate::log($msg); } }; } pub(crate) use write_log; #[no_mangle] #[allow(non_snake_case)] pub(crate) extern "C" fn vkNegotiateLoaderLayerInterfaceVersion( pVersionStruct: *mut VkNegotiateLayerInterface, ) -> VkResult { let log_enabled = match std::env::var("RFACTOR_HUD_LOG") { Ok(var) => { let i: u32 = var.parse().unwrap_or(0); i == 1 } Err(_) => false, }; unsafe { LOG_ENABLED = log_enabled }; let home = std::env::var("HOME").unwrap(); if logging() { unsafe { LOG_FILE = format!("{}/rf2_vk_hud.log", home); } if let Err(_) = File::create(unsafe { &LOG_FILE }) {} write_log!(" =================================================================="); write_log!(" ======================= New Negotiation =========================="); write_log!(" =================================================================="); } let config_path = Path::new(&home).join(".config/rFactorHUD/config.json"); let config = if config_path.exists() { fs::read_to_string(&config_path) .map(|s| { serde_json::from_str(&s).unwrap_or({ write_log!("failed to deserialize config file"); OverlayConfig::new() }) }) .unwrap_or({ write_log!(format!("failed to open config file: {:?}", config_path)); OverlayConfig::new() }) } else { if let Err(err) = std::fs::create_dir_all(config_path.parent().unwrap()) { write_log!(format!("failed to create dirs for config file: {:?}", err)); } let config = OverlayConfig::new(); match File::create(config_path) { Ok(mut file) => match serde_json::to_string(&config) { Ok(conf_str) => { if let Err(err) = file.write_all(conf_str.as_bytes()) { write_log!(format!("failed to write to config file: {:?}", err)); } } Err(err) => { write_log!(format!("failed to serialize config: {:?}", err)); } }, Err(err) => { write_log!(format!("failed to create config file: {:?}", err)); } } config }; unsafe { OVERLAY.set_config(config); } 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(crate) 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(crate) 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(crate) 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 { ACQUIRE_NEXT_IMAGE = match vk_handles().handle("vkAcquireNextImageKHR") { Some(acquire_next_image) => mem::transmute(acquire_next_image), None => { write_log!("failed querying vkAcquireNextImageKHR"); 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 queue_info = match Queue::create_non_presentable_request_info(&pdev, VK_QUEUE_GRAPHICS_BIT) { Ok(qi) => qi, Err(err) => { write_log!(format!("failed getting queue info: {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } }; unsafe { let create_queue_info = std::slice::from_raw_parts( (*create_info).pQueueCreateInfos, (*create_info).queueCreateInfoCount as usize, ); for info in create_queue_info { write_log!(format!( "pCreateDeviceInfo; queue fam: {}, queue count: {}", info.queueFamilyIndex, info.queueCount )); } write_log!(format!( "Queue: queue fam: {}, queue count: {}", queue_info.queue_create_info.queueFamilyIndex, queue_info.queue_create_info.queueCount )); } let ext_names = unsafe { (*create_info).extension_names() }; write_log!(format!("{:?}", ext_names)); let device = match Device::preinitialized(unsafe { *device }, proc_addr, pdev, &ext_names) { Ok(dev) => dev, Err(err) => { write_log!(format!("-> local device creation failed: {:?}", err)); return VK_ERROR_INITIALIZATION_FAILED; } }; write_log!("created device"); let queue = device.get_queue(queue_info.queue_family_index, queue_info.queue_index); write_log!("got queue from device"); unsafe { OVERLAY.set_device(device); OVERLAY.set_queue(queue); } VK_SUCCESS } pub(crate) 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(crate) 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!(format!("-> created swapchain vk handle {:?}", unsafe { *p_swapchain })); 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(crate) extern "system" fn acquire_next_image( device: VkDevice, swapchain: VkSwapchainKHR, timeout: u64, semaphore: VkSemaphore, fence: VkFence, image_index: *mut u32, ) -> VkResult { unsafe { match OVERLAY.swapchain(swapchain) { Some(sc) => { let device = OVERLAY.device(); let res = device.acquire_next_image( sc.vk_handle(), timeout, Some(semaphore), Some(fence), ); write_log!(format!( "acquire (swapchain: {:?}) res: {:?}", sc.vk_handle(), res )); match res { Ok(res) => match res { OutOfDate::Ok(index) => { sc.set_image_index(index); VK_SUCCESS } OutOfDate::OutOfDate => VK_ERROR_OUT_OF_DATE_KHR, OutOfDate::TimeOut => VK_TIMEOUT, }, Err(err) => { write_log!(format!("failed acquiring next image {:?}", err)); VK_ERROR_DEVICE_LOST } } } None => { write_log!("acquired other swapchain image"); ACQUIRE_NEXT_IMAGE(device, swapchain, timeout, semaphore, fence, image_index) } } } } pub(crate) extern "system" fn present_queue( queue: VkQueue, present_info: *const VkPresentInfoKHR, ) -> VkResult { if logging() { write_log!(" ================== vulkan layer queue present =================="); write_log!(format!("iq: {:?}, cq: {:?}", queue, unsafe { OVERLAY.queue().lock().unwrap().vk_handle() })); unsafe { let swapchains = std::slice::from_raw_parts( (*present_info).pSwapchains, (*present_info).swapchainCount as usize, ); write_log!(format!("present {} swapchain(s)", swapchains.len())); for swapchain in swapchains { write_log!(format!("present swapchain: {:?}", swapchain)); if let Some(swch) = OVERLAY.swapchain(*swapchain) { write_log!(format!( " -> internal swapchain found! ({:?})", swch.vk_handle() )); } } } } match unsafe { OVERLAY.render() } { Ok(_) => (), Err(err) => { write_log!(format!("overlay rendering failed: {:?}", err)); return VK_ERROR_DEVICE_LOST; } }; let pfn: PFN_vkQueuePresentKHR = match vk_handles().handle("vkQueuePresentKHR") { Some(pfn) => unsafe { mem::transmute(pfn) }, None => { write_log!("failed querying vkQueuePresentKHR"); return VK_ERROR_DEVICE_LOST; } }; pfn(queue, present_info) } pub fn log(msg: impl ToString) { assert!(logging()); if let Ok(mut file) = OpenOptions::new() .append(true) .create(true) .open(unsafe { &LOG_FILE }) { if let Err(_) = file.write_all(format!("{}\n", msg.to_string()).as_bytes()) {} } }