From b2d28ef4089b1400350e91cc8d2e8a26296ad96d Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 17 Nov 2024 20:19:34 +0100 Subject: [PATCH] Continue vulkan c++ tutorial --- .gitignore | 3 +- Cargo.lock | 7 ++++ Cargo.toml | 7 +++- build.rs | 24 ++++++++++++ res/shaders/main.frag | 8 ++++ res/shaders/main.vert | 1 + src/vulkan/mod.rs | 1 + src/vulkan/vk_render_context.rs | 66 +++++++++++++++++++++++++++++++++ src/vulkan/vk_shader_module.rs | 42 +++++++++++++++++++++ 9 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 build.rs create mode 100644 res/shaders/main.frag create mode 100644 res/shaders/main.vert create mode 100644 src/vulkan/vk_shader_module.rs diff --git a/.gitignore b/.gitignore index 1edb211..5719f75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -/.direnv \ No newline at end of file +/.direnv +res/shaders/*.spv \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index fe73f51..b33b8d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,6 +490,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "hashbrown" version = "0.15.1" @@ -1076,6 +1082,7 @@ dependencies = [ "ash", "ash-window", "env_logger", + "glob", "log", "winit", ] diff --git a/Cargo.toml b/Cargo.toml index 4ba8b4d..7126ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,10 +7,13 @@ publish = false [dependencies] anyhow = "1.0" -winit = { version = "0.30", features = [ "rwh_06" ] } +winit = { version = "0.30", features = ["rwh_06"] } ash = { version = "0.38", default-features = false, features = ["linked", "debug", "std"] } ash-window = "0.13" # Log and tracing log = "0.4" -env_logger = "0.11.5" \ No newline at end of file +env_logger = "0.11.5" + +[build-dependencies] +glob = "0.3" \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..be949e6 --- /dev/null +++ b/build.rs @@ -0,0 +1,24 @@ +use std::process::Command; + +fn main() { + for shader in glob::glob("res/shaders/*").unwrap().filter_map(Result::ok) { + if !shader.is_file() { + continue; + } + + let shader_file_name = shader.to_str().unwrap(); + + let mut command = Command::new("glslc"); + command.arg(&shader); + + let out_file = match shader.extension().unwrap().to_str().unwrap() { + "vert" => shader_file_name.replace(".vert", ".vert.spv"), + "frag" => shader_file_name.replace(".frag", ".frag.spv"), + _ => continue, + }; + + command.arg("-o"); + command.arg(out_file); + command.output().unwrap(); + } +} diff --git a/res/shaders/main.frag b/res/shaders/main.frag new file mode 100644 index 0000000..33ca4af --- /dev/null +++ b/res/shaders/main.frag @@ -0,0 +1,8 @@ +#version 450 + +layout (location = 0) in vec3 fragColor; +layout (location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/res/shaders/main.vert b/res/shaders/main.vert new file mode 100644 index 0000000..d141c1d --- /dev/null +++ b/res/shaders/main.vert @@ -0,0 +1 @@ +#version 450 out gl_PerVertex { vec4 gl_Position; }; layout (location = 0) out vec3 fragColor; vec2 positions[3] = vec2[]( vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5) ); vec3 colors[3] = vec3[]( vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0) ); void main() { gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); fragColor = colors[gl_VertexIndex]; } \ No newline at end of file diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index fd330f9..63a1c74 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -17,3 +17,4 @@ pub(self) mod vk_swapchain; pub use vk_swapchain::VkSwapchain; mod utils; +mod vk_shader_module; diff --git a/src/vulkan/vk_render_context.rs b/src/vulkan/vk_render_context.rs index f6e5aff..620e2a1 100644 --- a/src/vulkan/vk_render_context.rs +++ b/src/vulkan/vk_render_context.rs @@ -1,5 +1,8 @@ +use crate::vulkan::vk_shader_module::VkShaderModule; use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSurface, VkSwapchain}; use ash::vk; +use ash::vk::PrimitiveTopology; +use std::ffi::{CStr, CString}; use std::sync::Arc; pub struct VkRenderContext { @@ -57,6 +60,69 @@ impl VkRenderContext { &physical_device, )?); + let shader_entry_name = CStr::from_bytes_with_nul(b"main\0")?; + + let vert_shader_module = + VkShaderModule::from_spv_file(device.clone(), "res/shaders/main.vert.spv")?; + + let vert_shader_info = vk::PipelineShaderStageCreateInfo::default() + .module(vert_shader_module.handle) + .name(shader_entry_name) + .stage(vk::ShaderStageFlags::VERTEX); + + let frag_shader_module = + VkShaderModule::from_spv_file(device.clone(), "res/shaders/main.frag.spv")?; + + let frag_shader_info = vk::PipelineShaderStageCreateInfo::default() + .module(frag_shader_module.handle) + .name(shader_entry_name) + .stage(vk::ShaderStageFlags::FRAGMENT); + + let shader_stage_create_infos = [vert_shader_info, frag_shader_info]; + + let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default(); + + let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default() + .topology(PrimitiveTopology::TRIANGLE_LIST); + + let viewport = vk::Viewport::default() + .width(swapchain.surface_resolution.width as f32) + .height(swapchain.surface_resolution.height as f32) + .max_depth(1.0); + + let scissor = vk::Rect2D::default().extent(swapchain.surface_resolution); + + let viewport_state = vk::PipelineViewportStateCreateInfo::default() + .viewports(&[viewport]) + .scissors(&[scissor]); + + let rasterizer = vk::PipelineRasterizationStateCreateInfo::default() + .polygon_mode(vk::PolygonMode::FILL) + .cull_mode(vk::CullModeFlags::BACK) + .front_face(vk::FrontFace::CLOCKWISE); + + let multisampling = vk::PipelineMultisampleStateCreateInfo::default() + .rasterization_samples(vk::SampleCountFlags::TYPE_1) + .min_sample_shading(1.0); + + let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default() + .color_write_mask(vk::ColorComponentFlags::RGBA); + + let color_blending = + vk::PipelineColorBlendStateCreateInfo::default().attachments(&[color_blend_attachment]); + + let dynamic_state = vk::PipelineDynamicStateCreateInfo::default() + .dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::LINE_WIDTH]); + + let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default(); + let pipeline_layout = unsafe { + device + .handle + .create_pipeline_layout(&pipeline_layout_info, None)? + }; + + unsafe { device.handle.destroy_pipeline_layout(pipeline_layout, None) }; + // let present_queue = device.get_device_queue(0); // // let pool_create_info = vk::CommandPoolCreateInfo::default() diff --git a/src/vulkan/vk_shader_module.rs b/src/vulkan/vk_shader_module.rs new file mode 100644 index 0000000..02f934b --- /dev/null +++ b/src/vulkan/vk_shader_module.rs @@ -0,0 +1,42 @@ +use crate::vulkan::VkDevice; +use ash::vk; +use std::path::Path; +use std::sync::Arc; + +pub struct VkShaderModule { + device: Arc, + + pub(super) handle: vk::ShaderModule, +} + +impl VkShaderModule { + pub fn from_spv_file>(device: Arc, path: P) -> anyhow::Result { + let mut file = std::fs::File::open(&path)?; + let frag_shader_str = ash::util::read_spv(&mut file)?; + + let shader_create_info = vk::ShaderModuleCreateInfo::default().code(&frag_shader_str); + let shader_module = unsafe { + device + .handle + .create_shader_module(&shader_create_info, None)? + }; + log::debug!( + "Shader module created ({shader_module:?}) from {:?}", + path.as_ref() + ); + + Ok(Self { + device, + handle: shader_module, + }) + } +} + +impl Drop for VkShaderModule { + fn drop(&mut self) { + unsafe { + self.device.handle.destroy_shader_module(self.handle, None); + log::debug!("Shader module destroyed ({:?})", self.handle); + } + } +}