diff --git a/.gitignore b/.gitignore index cb54759..64cf459 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ /Cargo.lock *.spv +image_to_file_*.png vk_functions \ No newline at end of file diff --git a/build.rs b/build.rs index 5586f94..dbbfd6d 100644 --- a/build.rs +++ b/build.rs @@ -14,6 +14,8 @@ const SHADER: &[&str] = &[ "src/overlay/elements/radar/single_color.frag", "src/overlay/elements/pedals/history.vert", "src/overlay/elements/pedals/history.frag", + "src/overlay/elements/leaderboard/generator.frag", + "src/overlay/elements/leaderboard/generator.vert", ]; fn query_vulkan_function_typedefs() { diff --git a/src/lib.rs b/src/lib.rs index 479f30b..57198a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,30 +1,17 @@ -pub mod enums; -pub mod structs; - mod overlay; -mod vk_handles; +mod vk_layer; 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 } @@ -82,463 +69,6 @@ fn get_config(home: &str) -> OverlayConfig { } } -#[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!(" =================================================================="); - } - - unsafe { - OVERLAY.set_config(get_config(&home)); - } - - 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()); diff --git a/src/overlay/elements/leaderboard/bg_generator.rs b/src/overlay/elements/leaderboard/bg_generator.rs new file mode 100644 index 0000000..7a931a6 --- /dev/null +++ b/src/overlay/elements/leaderboard/bg_generator.rs @@ -0,0 +1,246 @@ +use anyhow::Result; +use cgmath::{ortho, vec2, Deg}; +use vulkan_rs::prelude::*; + +use std::{ + mem, + sync::{Arc, Mutex}, + time::Duration, +}; + +use crate::overlay::elements::PositionOnlyVertex; + +pub struct BackgroundGenerator; + +impl BackgroundGenerator { + pub fn generate( + device: &Arc, + queue: &Arc>, + color: [f32; 4], + image_infos: [(u32, u32); N], + ) -> Result<[Arc; N]> { + let vertex_shader = ShaderModule::from_slice( + device.clone(), + include_bytes!("generator.vert.spv"), + ShaderType::Vertex, + )?; + let fragment_shader = ShaderModule::from_slice( + device.clone(), + include_bytes!("generator.frag.spv"), + ShaderType::Fragment, + )?; + + Ok(image_infos + .iter() + .map(|(width, height)| { + let image = Image::empty( + *width, + *height, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_SAMPLE_COUNT_1_BIT, + ) + .format(VK_FORMAT_R8G8B8A8_UNORM) + .attach_sampler(Sampler::nearest_sampler().build(&device)?) + .build(&device, &queue)?; + + image.convert_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)?; + + let render_target = RenderTarget::builder() + .add_sub_pass( + SubPass::builder(image.width(), image.height()) + .set_prepared_targets(&[image.clone()], 0, [0.0, 0.0, 0.0, 0.0], true) + .build(&device, &queue)?, + ) + .build(&device)?; + + let viewport = VkViewport { + x: 0.0, + y: 0.0, + width: image.width() as f32, + height: image.height() as f32, + minDepth: 0.0, + maxDepth: 1.0, + }; + + let scissor = VkRect2D { + offset: VkOffset2D { x: 0, y: 0 }, + extent: VkExtent2D { + width: image.width(), + height: image.height(), + }, + }; + + let descriptor_layout = DescriptorSetLayout::builder() + .add_layout_binding( + 0, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, + ) + .build(device.clone())?; + + let pipeline = Pipeline::new_graphics() + .set_vertex_shader( + vertex_shader.clone(), + vec![VkVertexInputBindingDescription { + binding: 0, + stride: mem::size_of::() as u32, + inputRate: VK_VERTEX_INPUT_RATE_VERTEX, + }], + vec![ + // position + VkVertexInputAttributeDescription { + location: 0, + binding: 0, + format: VK_FORMAT_R32G32B32A32_SFLOAT, + offset: 0, + }, + ], + ) + .set_fragment_shader(fragment_shader.clone()) + .input_assembly(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, false) + .default_depth_stencil(false, false) + .default_color_blend(vec![VkPipelineColorBlendAttachmentState::default()]) + .default_rasterization(VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE) + .default_multisample(VK_SAMPLE_COUNT_1_BIT) + .add_viewport(viewport) + .add_scissor(scissor) + .build( + device.clone(), + &PipelineLayout::builder() + .add_descriptor_set_layout(&descriptor_layout) + .build(device.clone())?, + render_target.render_pass(), + 0, + )?; + + let color_buffer = Buffer::builder() + .set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) + .set_memory_usage(MemoryUsage::CpuOnly) + .set_data(&color) + .build(device.clone())?; + + let desc_pool = DescriptorPool::builder() + .set_layout(descriptor_layout) + .build(device.clone())?; + + let descriptor_set = desc_pool.prepare_set().allocate()?; + descriptor_set.update(&[DescriptorWrite::uniform_buffers(0, &[&color_buffer])])?; + + let ortho = ortho( + 0.0, + image.width() as f32, + 0.00, + image.height() as f32, + -1.0, + 1.0, + ); + + let command_buffer = + CommandBuffer::new_primary().build(device.clone(), queue.clone())?; + + // angle 70° + let angle: Deg = Deg(70.0); + let tan = angle.0.atan(); + + let vertices = PositionOnlyVertex::from_2d_corners( + ortho, + [ + vec2(0.0, image.height() as f32), + vec2((image.height() as f32) / tan, 0.0), + vec2(image.width() as f32, 0.0), + vec2( + image.width() as f32 - (image.height() as f32) / tan, + image.height() as f32, + ), + ], + ); + + let vertex_buffer = Buffer::builder() + .set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) + .set_memory_usage(MemoryUsage::CpuOnly) + .set_data(&vertices) + .build(device.clone())?; + + SingleSubmit::builder(&command_buffer, queue, |recorder| { + render_target.begin(recorder, VK_SUBPASS_CONTENTS_INLINE, 0); + + recorder.bind_pipeline(&pipeline)?; + + recorder.bind_descriptor_sets_minimal(&[&descriptor_set]); + recorder.bind_vertex_buffer(&vertex_buffer); + recorder.draw_complete_single_instance(vertex_buffer.size() as u32); + + render_target.end(recorder); + + Ok(()) + }) + .wait_for_timeout(Duration::from_secs(1)) + .submit()?; + + Ok(image) + }) + .collect::>>>()? + .try_into() + .unwrap_or_else(|_: Vec>| { + unreachable!("create array from vec from an array") + })) + } +} + +#[cfg(test)] +mod test { + use anyhow::Result; + use vulkan_rs::prelude::*; + + use std::sync::{Arc, Mutex}; + + use super::BackgroundGenerator; + + fn create_vk_handles() -> Result<(Arc, Arc>)> { + let instance = Instance::new( + VkApplicationInfo::new( + &VkString::new("Test: image::to_file"), + 1, + &VkString::new("no name"), + 1, + VK_MAKE_VERSION(1, 3, 0), + ), + VulkanDebugInfo::default(), + InstanceExtensions::default(), + )?; + + let physical_device = PhysicalDevice::new(instance)?; + + let queue_info = Queue::create_non_presentable_request_info( + &physical_device, + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT, + )?; + + let device = Device::new( + physical_device, + DeviceExtensions::default(), + &[queue_info.queue_create_info], + DeviceFeatures::default(), + )?; + + let queue = device.get_queue(queue_info.queue_family_index, queue_info.queue_index); + + Ok((device, queue)) + } + + #[test] + fn generate_image_test() { + let (device, queue) = create_vk_handles().unwrap(); + + let images = + BackgroundGenerator::generate(&device, &queue, [1.0, 0.0, 0.0, 1.0], [(120, 40)]) + .unwrap(); + + for (index, image) in images.iter().enumerate() { + image + .to_file(&format!("image_to_file_{}.png", index)) + .unwrap() + } + } +} diff --git a/src/overlay/elements/leaderboard/deltaboard_grid.xml b/src/overlay/elements/leaderboard/deltaboard_grid.xml index ad12bae..3cb0254 100644 --- a/src/overlay/elements/leaderboard/deltaboard_grid.xml +++ b/src/overlay/elements/leaderboard/deltaboard_grid.xml @@ -1,6 +1,6 @@ - - + \ No newline at end of file diff --git a/src/overlay/elements/leaderboard/generator.frag b/src/overlay/elements/leaderboard/generator.frag new file mode 100644 index 0000000..07bd8fa --- /dev/null +++ b/src/overlay/elements/leaderboard/generator.frag @@ -0,0 +1,12 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Color { + vec4 val; +} color; + +layout (location = 0) out vec4 out_color; + +void main() +{ + out_color = color.val; +} diff --git a/src/overlay/elements/leaderboard/generator.vert b/src/overlay/elements/leaderboard/generator.vert new file mode 100644 index 0000000..126ef86 --- /dev/null +++ b/src/overlay/elements/leaderboard/generator.vert @@ -0,0 +1,8 @@ +#version 450 + +layout (location = 0) in vec4 position; + +void main() +{ + gl_Position = position; +} \ No newline at end of file diff --git a/src/overlay/elements/leaderboard/leaderboard_entry.rs b/src/overlay/elements/leaderboard/leaderboard_entry.rs index 6d5a9db..07aa06d 100644 --- a/src/overlay/elements/leaderboard/leaderboard_entry.rs +++ b/src/overlay/elements/leaderboard/leaderboard_entry.rs @@ -3,12 +3,15 @@ use std::sync::Arc; use anyhow::Result; use ui::prelude::*; -use utilities::prelude::Color; +use vulkan_rs::prelude::*; #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub enum BehindLeader { Time(f64), Laps(i32), + DNF, + DSQ, + PITS, } pub struct LeaderBoardEntry { @@ -22,9 +25,9 @@ pub struct LeaderBoardEntry { snippet: Arc, - name_label: Arc