From ef720708aa73593be6035e4ecf09914ec80c7a81 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Thu, 12 Jan 2023 13:52:44 +0100 Subject: [PATCH] Start rendering work --- .gitignore | 2 + build.rs | 30 +++++++- src/enums.rs | 4 + src/lib.rs | 107 +++++++++++++++++++++++---- src/overlay/mod.rs | 48 ++++++++++-- src/overlay/pipeline.rs | 65 ++++++++++++++++ src/overlay/rendering.rs | 34 ++++++++- src/overlay/shader/single_color.frag | 12 +++ src/overlay/shader/single_color.vert | 8 ++ 9 files changed, 284 insertions(+), 26 deletions(-) create mode 100644 src/overlay/pipeline.rs create mode 100644 src/overlay/shader/single_color.frag create mode 100644 src/overlay/shader/single_color.vert diff --git a/.gitignore b/.gitignore index 7aeb431..cb54759 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /target /Cargo.lock +*.spv + vk_functions \ No newline at end of file diff --git a/build.rs b/build.rs index cae31dc..1ff51e6 100644 --- a/build.rs +++ b/build.rs @@ -9,7 +9,7 @@ const VK_HEADER: &[&str] = &[ ]; const FN_PREFIX: &str = "PFN_"; -fn main() { +fn query_vulkan_function_typedefs() { let mut fns = Vec::new(); for header in VK_HEADER { @@ -41,3 +41,31 @@ fn main() { file.write_all(format!("{}\n", func).as_bytes()).unwrap(); } } + +fn compile_shader() { + Command::new("glslangValidator") + .arg("--help") + .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"); +} + +fn main() { + query_vulkan_function_typedefs(); + compile_shader(); +} diff --git a/src/enums.rs b/src/enums.rs index 5eb56ae..f470913 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -27,6 +27,8 @@ pub enum Functions { DestroyDevice(PFN_vkDestroyDevice), CreateSwapchain(PFN_vkCreateSwapchainKHR), QueueSubmit(PFN_vkQueueSubmit), + GetDeviceQueue(PFN_vkGetDeviceQueue), + AcquireNextImageKHR(PFN_vkAcquireNextImageKHR), } impl Functions { @@ -41,6 +43,8 @@ impl Functions { Functions::DestroyDevice(func) => unsafe { mem::transmute(func) }, Functions::CreateSwapchain(func) => unsafe { mem::transmute(func) }, Functions::QueueSubmit(func) => unsafe { mem::transmute(func) }, + Functions::GetDeviceQueue(func) => unsafe { mem::transmute(func) }, + Functions::AcquireNextImageKHR(func) => unsafe { mem::transmute(func) }, } } } diff --git a/src/lib.rs b/src/lib.rs index 4c19f1f..fe00ece 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -283,19 +283,30 @@ extern "system" fn create_swapchain( ) -> VkResult { write_log(" ================== vulkan layer create swapchain =================="); - let swapchain = match unsafe { Swapchain::from_ci(OVERLAY.device(), &*create_info) } { - Ok(swapchain) => swapchain, - Err(err) => { - write_log(format!("create swapchain failed: {:?}", err)); - return VK_ERROR_INITIALIZATION_FAILED; - } - }; + 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; + } + }; - unsafe { *p_swapchain = swapchain.vk_handle() }; - if let Err(err) = unsafe { OVERLAY.create_rendering(swapchain) } { - write_log(format!("create overlay rendering struct failed: {:?}", err)); - return VK_ERROR_INITIALIZATION_FAILED; - } + create_swapchain(_device, create_info, _allocator, 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; + } + }; + + // if let Err(err) = unsafe { OVERLAY.create_rendering(swapchain) } { + // write_log(format!("create overlay rendering struct failed: {:?}", err)); + // return VK_ERROR_INITIALIZATION_FAILED; + // } VK_SUCCESS } @@ -306,11 +317,15 @@ extern "system" fn submit_queue( submits: *const VkSubmitInfo, fence: VkFence, ) -> VkResult { - // unsafe { return QUEUE_SUBMIT(queue, submit_count, submits, fence): } + write_log(" ================== vulkan layer submit queue =================="); + + unsafe { + return QUEUE_SUBMIT(queue, submit_count, submits, fence); + } unsafe { let input_submit_info = slice::from_raw_parts(submits, submit_count as usize); - let overlay_submit = match OVERLAY.render() { + let overlay_submit = match OVERLAY.render(queue) { Ok(submit) => submit, Err(err) => { write_log(format!("overlay rendering failed: {:?}", err)); @@ -329,6 +344,67 @@ extern "system" fn submit_queue( } } +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 { + let arc_device = OVERLAY.device(); + OVERLAY.add_queue(Queue::new( + arc_device, + *p_queue, + queue_family_index, + queue_index, + )); + } +} + +extern "system" fn acquire_next_image( + _device: VkDevice, + swapchain: VkSwapchainKHR, + timeout: u64, + semaphore: VkSemaphore, + fence: VkFence, + image_index: *mut u32, +) -> VkResult { + write_log(" ================== vulkan layer acquire next image =================="); + + unsafe { + *image_index = match OVERLAY.device().acquire_next_image( + swapchain, + timeout, + Some(semaphore), + Some(fence), + ) { + Ok(res) => match res { + OutOfDate::Ok(index) => index, + OutOfDate::OutOfDate => return VK_ERROR_OUT_OF_DATE_KHR, + OutOfDate::TimeOut => return VK_TIMEOUT, + }, + Err(err) => { + write_log(format!("Failed acquiring next image: {:?}", err)); + return VK_ERROR_DEVICE_LOST; + } + } + } + + 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()) {} @@ -343,7 +419,8 @@ pub fn get_vk_func(s: &str) -> Option { "vkDestroyInstance" => Some(Functions::DestroyInstance(destroy_instance)), "vkCreateSwapchainKHR" => Some(Functions::CreateSwapchain(create_swapchain)), "vkQueueSubmit" => Some(Functions::QueueSubmit(submit_queue)), - + "vkGetDeviceQueue" => Some(Functions::GetDeviceQueue(get_device_queue)), + // "vkAcquireNextImageKHR" => Some(Functions::AcquireNextImageKHR(acquire_next_image)), _ => None, } } diff --git a/src/overlay/mod.rs b/src/overlay/mod.rs index 0390178..4c33604 100644 --- a/src/overlay/mod.rs +++ b/src/overlay/mod.rs @@ -1,16 +1,18 @@ use self::rendering::Rendering; +mod pipeline; mod rendering; use anyhow::Result; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use vulkan_rs::prelude::*; #[derive(Default)] pub struct Overlay { instance: Option>, device: Option>, - rendering: Option, + queues: Vec>>, + renderings: Vec, } impl Overlay { @@ -18,7 +20,8 @@ impl Overlay { Self { instance: None, device: None, - rendering: None, + queues: Vec::new(), + renderings: Vec::new(), } } @@ -38,13 +41,44 @@ impl Overlay { self.device.as_ref().unwrap().clone() } - pub fn create_rendering(&mut self, swapchain: Arc) -> Result<()> { - self.rendering = Some(Rendering::new(swapchain)); + pub fn add_queue(&mut self, queue: Arc>) { + self.queues.push(queue); + } + + pub fn queue(&self, queue: VkQueue) -> Arc> { + match self + .queues + .iter() + .find(|q| q.lock().unwrap().vk_handle() == queue) + { + Some(q) => q.clone(), + None => panic!(), + } + } + + pub fn swapchain(&self, swapchain: VkSwapchainKHR) -> &Arc { + match self + .renderings + .iter() + .find(|r| r.swapchain().vk_handle() == swapchain) + { + Some(s) => s.swapchain(), + None => panic!(), + } + } + + pub fn add_rendering(&mut self, swapchain: Arc) -> Result<()> { + // self.renderings + // .push(Rendering::new(self.device(), self.queue(), swapchain)?); Ok(()) } - pub fn render(&mut self) -> Result { - self.rendering.as_mut().unwrap().render() + pub fn render(&mut self, queue: VkQueue) -> Result { + // for rendering in self.renderings { + // rendering.render() + // } + + todo!() } } diff --git a/src/overlay/pipeline.rs b/src/overlay/pipeline.rs new file mode 100644 index 0000000..3030bc3 --- /dev/null +++ b/src/overlay/pipeline.rs @@ -0,0 +1,65 @@ +use anyhow::Result; +use vulkan_rs::prelude::*; + +use std::{mem, sync::Arc}; + +pub struct SingleColorPipeline { + pipeline: Arc, + pipeline_layout: Arc, + + vertex_shader: Arc, + fragment_shader: Arc, +} + +impl SingleColorPipeline { + pub fn new(device: Arc, renderpass: &Arc) -> Result { + let vertex_shader = ShaderModule::from_slice( + device.clone(), + include_bytes!("shader/single_color.vert.spv"), + ShaderType::Vertex, + )?; + let fragment_shader = ShaderModule::from_slice( + device.clone(), + include_bytes!("shader/single_color.frag.spv"), + ShaderType::Fragment, + )?; + + let pipeline_layout = PipelineLayout::builder().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, + 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_rasterization(VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE) + .default_multisample(VK_SAMPLE_COUNT_1_BIT) + .build(device, &pipeline_layout, &renderpass, 0)?; + + Ok(Self { + vertex_shader, + fragment_shader, + pipeline, + pipeline_layout, + }) + } + + pub fn pipeline(&self) -> &Arc { + &self.pipeline + } +} diff --git a/src/overlay/rendering.rs b/src/overlay/rendering.rs index cc369f7..cf635ee 100644 --- a/src/overlay/rendering.rs +++ b/src/overlay/rendering.rs @@ -1,15 +1,43 @@ use anyhow::Result; use vulkan_rs::prelude::*; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; + +use super::pipeline::SingleColorPipeline; pub struct Rendering { swapchain: Arc, + pipeline: SingleColorPipeline, + render_target: RenderTarget, + images: Vec>, } impl Rendering { - pub fn new(swapchain: Arc) -> Self { - Self { swapchain } + pub fn new( + device: Arc, + queue: Arc>, + swapchain: Arc, + ) -> Result { + let images = swapchain.wrap_images(&swapchain.vk_images()?, &queue)?; + + let render_target = RenderTarget::builder() + .add_sub_pass( + SubPass::builder(swapchain.width(), swapchain.height()) + .set_prepared_targets(&images, 0, [0.0, 0.0, 0.0, 1.0], false) + .build(&device, &queue)?, + ) + .build(&device)?; + + Ok(Self { + swapchain, + pipeline: SingleColorPipeline::new(device, render_target.render_pass())?, + render_target, + images, + }) + } + + pub fn swapchain(&self) -> &Arc { + &self.swapchain } pub fn render(&mut self) -> Result { diff --git a/src/overlay/shader/single_color.frag b/src/overlay/shader/single_color.frag new file mode 100644 index 0000000..d29bd8a --- /dev/null +++ b/src/overlay/shader/single_color.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 = vec4(color.val); +} diff --git a/src/overlay/shader/single_color.vert b/src/overlay/shader/single_color.vert new file mode 100644 index 0000000..126ef86 --- /dev/null +++ b/src/overlay/shader/single_color.vert @@ -0,0 +1,8 @@ +#version 450 + +layout (location = 0) in vec4 position; + +void main() +{ + gl_Position = position; +} \ No newline at end of file