diff --git a/Cargo.toml b/Cargo.toml index 9b3f851..9c9ca12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ crate-type = ["cdylib"] vulkan-rs = { path = "/home/michael/Dokumente/Workspace/Gavania/vulkan-rs" } anyhow = { version = "1.0.68", features = ["backtrace"] } rfactor_sm_reader = { path = "../rfactor_sm_reader" } +cgmath = "0.18.0" diff --git a/build.rs b/build.rs index 1ff51e6..d0fb369 100644 --- a/build.rs +++ b/build.rs @@ -9,6 +9,11 @@ const VK_HEADER: &[&str] = &[ ]; const FN_PREFIX: &str = "PFN_"; +const SHADER: &[&str] = &[ + "src/overlay/shader/single_color.vert", + "src/overlay/shader/single_color.frag", +]; + fn query_vulkan_function_typedefs() { let mut fns = Vec::new(); @@ -48,21 +53,15 @@ fn compile_shader() { .output() .expect("Failed to execute glslangValidator. Maybe you need to install it first?"); - Command::new("glslangValidator") - .arg("-V") - .arg("src/overlay/shader/single_color.vert") - .arg("-o") - .arg("src/overlay/shader/single_color.vert.spv") - .output() - .expect("Failed to compile single_color.vert"); - - Command::new("glslangValidator") - .arg("-V") - .arg("src/overlay/shader/single_color.frag") - .arg("-o") - .arg("src/overlay/shader/single_color.frag.spv") - .output() - .expect("Failed to compile single_color.frag"); + for shader in SHADER { + Command::new("glslangValidator") + .arg("-V") + .arg(shader) + .arg("-o") + .arg(&format!("{}.spv", shader)) + .output() + .expect(&format!("Failed to compile {}", shader)); + } } fn main() { diff --git a/src/lib.rs b/src/lib.rs index 44e39f2..61b7b13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -325,8 +325,6 @@ extern "system" fn submit_queue( submits: *const VkSubmitInfo, fence: VkFence, ) -> VkResult { - write_log(" ================== vulkan layer submit queue =================="); - unsafe { let input_submit_info = slice::from_raw_parts(submits, submit_count as usize); let overlay_submit = match OVERLAY.render() { diff --git a/src/overlay/mod.rs b/src/overlay/mod.rs index a8c9b1b..91376b5 100644 --- a/src/overlay/mod.rs +++ b/src/overlay/mod.rs @@ -16,7 +16,7 @@ pub struct Overlay { queue: Option>>, rendering: Option, - rfactor_data: RFactorData, + rfactor_data: Option, } impl Overlay { @@ -27,7 +27,7 @@ impl Overlay { queue: None, rendering: None, - rfactor_data: RFactorData::default(), + rfactor_data: None, } } @@ -80,7 +80,27 @@ impl Overlay { } pub fn render(&mut self) -> Result { - self.rfactor_data.update()?; + if self.rfactor_data.is_none() { + self.rfactor_data = RFactorData::new( + self.device(), + self.rendering + .as_mut() + .unwrap() + .single_color_pipeline() + .descriptor_layout(), + ) + .ok(); + } + + // check twice for rfactor data, because of borrowing rules + if let Some(rfactor) = &mut self.rfactor_data { + rfactor.update()?; + } + + let objects = match &self.rfactor_data { + Some(rfactor) => rfactor.objects(), + None => Vec::new(), + }; let device = self.device(); let queue = self.queue(); @@ -89,6 +109,6 @@ impl Overlay { self.rendering .as_mut() .unwrap() - .render(device, queue, swapchain, &self.rfactor_data) + .render(device, queue, swapchain, &objects) } } diff --git a/src/overlay/pipeline.rs b/src/overlay/pipeline.rs index 82a0ed2..97de372 100644 --- a/src/overlay/pipeline.rs +++ b/src/overlay/pipeline.rs @@ -3,9 +3,12 @@ use vulkan_rs::prelude::*; use std::{mem, sync::Arc}; +use super::rendering::PositionOnlyVertex; + pub struct SingleColorPipeline { pipeline: Arc, pipeline_layout: Arc, + descriptor_layout: Arc, vertex_shader: Arc, fragment_shader: Arc, @@ -24,14 +27,25 @@ impl SingleColorPipeline { ShaderType::Fragment, )?; - let pipeline_layout = PipelineLayout::builder().build(device.clone())?; + 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_layout = PipelineLayout::builder() + .add_descriptor_set_layout(&descriptor_layout) + .build(device.clone())?; let pipeline = Pipeline::new_graphics() .set_vertex_shader( vertex_shader.clone(), vec![VkVertexInputBindingDescription { binding: 0, - stride: mem::size_of::<[f32; 4]>() as u32, + stride: mem::size_of::() as u32, inputRate: VK_VERTEX_INPUT_RATE_VERTEX, }], vec![ @@ -55,6 +69,7 @@ impl SingleColorPipeline { Ok(Self { vertex_shader, fragment_shader, + descriptor_layout, pipeline, pipeline_layout, }) @@ -63,4 +78,8 @@ impl SingleColorPipeline { pub fn pipeline(&self) -> &Arc { &self.pipeline } + + pub fn descriptor_layout(&self) -> &Arc { + &self.descriptor_layout + } } diff --git a/src/overlay/rendering.rs b/src/overlay/rendering.rs index f833453..85bf1e2 100644 --- a/src/overlay/rendering.rs +++ b/src/overlay/rendering.rs @@ -1,16 +1,52 @@ use anyhow::Result; +use cgmath::{Vector2, Vector4}; use vulkan_rs::prelude::*; use std::sync::{Arc, Mutex}; -use super::{pipeline::SingleColorPipeline, rfactor_data::RFactorData}; +use super::{pipeline::SingleColorPipeline, rfactor_data::RenderObject}; use crate::write_log; +#[derive(Clone)] +pub struct PositionOnlyVertex { + pub position: Vector4, +} + +impl PositionOnlyVertex { + /// + /// corners[0] - bottom left + /// corners[1] - top left + /// corners[2] - top right + /// corners[3] - bottom right + /// + pub fn from_2d_corners(corners: [Vector2; 4]) -> [Self; 6] { + [ + Self { + position: corners[0].extend(0.0).extend(1.0), + }, + Self { + position: corners[1].extend(0.0).extend(1.0), + }, + Self { + position: corners[2].extend(0.0).extend(1.0), + }, + Self { + position: corners[2].extend(0.0).extend(1.0), + }, + Self { + position: corners[3].extend(0.0).extend(1.0), + }, + Self { + position: corners[0].extend(0.0).extend(1.0), + }, + ] + } +} + pub struct Rendering { swapchain: Arc, pipeline: SingleColorPipeline, render_target: RenderTarget, - images: Vec>, submit_info: SubmitInfo, } @@ -49,7 +85,6 @@ impl Rendering { swapchain, pipeline: SingleColorPipeline::new(device, render_target.render_pass())?, render_target, - images, submit_info: SubmitInfo::default(), }) } @@ -58,15 +93,17 @@ impl Rendering { &self.swapchain } + pub fn single_color_pipeline(&self) -> &SingleColorPipeline { + &self.pipeline + } + pub fn render( &mut self, device: Arc, queue: Arc>, swapchain: Arc, - rfactor_data: &RFactorData, + objects: &[&dyn RenderObject], ) -> Result { - write_log(" ================== vulkan layer enter rendering =================="); - let image_index = self.swapchain.current_index(); let viewport = [VkViewport { @@ -88,15 +125,11 @@ impl Rendering { let command_buffer = CommandBuffer::new_primary().build(device, queue)?; - write_log(" ================== vulkan layer created command buffer =================="); - { let mut recorder = command_buffer.begin(VkCommandBufferBeginInfo::new( VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, ))?; - write_log(" ================== vulkan layer begin command buffer =================="); - self.render_target .begin(&recorder, VK_SUBPASS_CONTENTS_INLINE, image_index as usize); @@ -104,7 +137,13 @@ impl Rendering { recorder.set_scissor(&scissor); recorder.set_viewport(&viewport); - // // recorder.bind_vertex_buffer(); + for object in objects { + let buffer = object.buffer(); + + recorder.bind_descriptor_sets_minimal(&[object.descriptor()]); + recorder.bind_vertex_buffer(buffer); + recorder.draw_complete_single_instance(buffer.size() as u32); + } self.render_target.end(&recorder); } diff --git a/src/overlay/rfactor_data.rs b/src/overlay/rfactor_data.rs index c46c244..f47de8d 100644 --- a/src/overlay/rfactor_data.rs +++ b/src/overlay/rfactor_data.rs @@ -1,15 +1,137 @@ use anyhow::Result; +use cgmath::vec2; +use rfactor_sm_reader::*; +use vulkan_rs::prelude::*; + +use std::sync::Arc; + +use super::rendering::PositionOnlyVertex; + +pub trait RenderObject { + fn descriptor(&self) -> &Arc; + fn buffer(&self) -> &Arc>; +} pub struct RFactorData { - // TODO + // rf2 memory mapped data + telemetry_reader: TelemetryReader, + scoring_reader: ScoringReader, + + // radar objects + background: RadarObject, + player_car: RadarObject, + cars: Vec, } impl RFactorData { - pub const fn default() -> Self { - Self {} + pub fn new(device: Arc, descriptor_layout: &Arc) -> Result { + let radar_extent = 0.2; + let car_height = 0.05; + let car_width = 0.025; + + Ok(Self { + telemetry_reader: TelemetryReader::new()?, + scoring_reader: ScoringReader::new()?, + + background: RadarObject::new( + device.clone(), + descriptor_layout, + PositionOnlyVertex::from_2d_corners([ + vec2(-radar_extent, -radar_extent), + vec2(-radar_extent, radar_extent), + vec2(radar_extent, radar_extent), + vec2(radar_extent, -radar_extent), + ]), + [0.5, 0.5, 0.5, 0.5], + )?, + player_car: RadarObject::new( + device.clone(), + descriptor_layout, + PositionOnlyVertex::from_2d_corners([ + vec2(-car_width, -car_height), + vec2(-car_width, car_height), + vec2(car_width, car_height), + vec2(car_width, -car_height), + ]), + [0.9, 0.9, 0.0, 0.9], + )?, + cars: Vec::new(), + }) } pub fn update(&mut self) -> Result<()> { Ok(()) } + + pub fn objects(&self) -> Vec<&dyn RenderObject> { + let mut objects: Vec<&dyn RenderObject> = Vec::new(); + + objects.push(&self.background); + + for other_player_cars in &self.cars { + objects.push(other_player_cars); + } + + objects.push(&self.player_car); + + objects + } +} + +struct RadarObject { + descriptor_set: Arc, + + // uniform buffer + color_buffer: Arc>, + + // vertex buffer + position_buffer: Arc>, +} + +impl RadarObject { + fn new( + device: Arc, + descriptor_layout: &Arc, + positions: [PositionOnlyVertex; 6], + color: [f32; 4], + ) -> Result { + 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 position_buffer = Buffer::builder() + .set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) + .set_memory_usage(MemoryUsage::CpuOnly) + .set_data(&positions) + .build(device.clone())?; + + let descriptor_pool = DescriptorPool::builder() + .set_layout(descriptor_layout.clone()) + .build(device.clone())?; + + let descriptor_set = descriptor_pool.prepare_set().allocate()?; + descriptor_set.update(&[DescriptorWrite::uniform_buffers(0, &[&color_buffer])])?; + + Ok(Self { + descriptor_set, + color_buffer, + position_buffer, + }) + } + + pub fn update_color(&self, color: [f32; 4]) -> Result<()> { + self.color_buffer.fill(&color) + } +} + +impl RenderObject for RadarObject { + fn descriptor(&self) -> &Arc { + &self.descriptor_set + } + + fn buffer(&self) -> &Arc> { + &self.position_buffer + } }