From 3aa79ef21ab4bb2cd3187c6cc7aaa97e2c186d7f Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Tue, 12 Mar 2024 14:22:57 +0900 Subject: [PATCH] WIP: "Graphics pipeline basics: Shader modules" TODO: "Graphics pipeline basics: Fixed functions" https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Fixed_functions --- build.rs | 15 +++++++ shaders/shader.frag | 9 ++++ shaders/shader.vert | 20 +++++++++ src/main.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 shaders/shader.frag create mode 100644 shaders/shader.vert diff --git a/build.rs b/build.rs index f654533..dc89094 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,6 @@ use std::env; use std::path::PathBuf; +use std::process::Command; fn main() { println!("cargo:rustc-link-lib=vulkan"); @@ -17,4 +18,18 @@ fn main() { glfw_vk_bindings .write_to_file(out_path.join("glfw_vk_bindings.rs")) .expect("Couldn't write glfw bindings!"); + + let _vert_shader_out = Command::new("glslc") + .arg("shaders/shader.vert") + .arg("-o") + .arg(out_path.join("vert.spv")) + .output() + .expect("Should be able to compile shader.vert!"); + + let _frag_shader_out = Command::new("glslc") + .arg("shaders/shader.frag") + .arg("-o") + .arg(out_path.join("frag.spv")) + .output() + .expect("Should be able to compile shader.frag!"); } diff --git a/shaders/shader.frag b/shaders/shader.frag new file mode 100644 index 0000000..7c5b0e7 --- /dev/null +++ b/shaders/shader.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/shaders/shader.vert b/shaders/shader.vert new file mode 100644 index 0000000..5d75bc5 --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,20 @@ +#version 450 + +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]; +} diff --git a/src/main.rs b/src/main.rs index 2a05c2f..4673abf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -131,6 +131,27 @@ impl Default for SwapChainSupportDetails { } } +struct ShaderModuleWrapper { + module: ffi::VkShaderModule, + device: ffi::VkDevice, +} + +impl ShaderModuleWrapper { + pub fn get_module(&self) -> ffi::VkShaderModule { + self.module + } +} + +impl Drop for ShaderModuleWrapper { + fn drop(&mut self) { + if !self.module.is_null() && !self.device.is_null() { + unsafe { + ffi::vkDestroyShaderModule(self.device, self.module, std::ptr::null()); + } + } + } +} + struct VulkanApp { window: *mut ffi::GLFWwindow, vk_instance: ffi::VkInstance, @@ -198,6 +219,8 @@ impl VulkanApp { self.create_logical_device(); self.create_swap_chain(); self.create_image_views(); + self.create_graphics_pipeline() + .expect("Should be able to set up graphics pipeline"); } fn create_instance(&mut self) { @@ -807,6 +830,84 @@ impl VulkanApp { } } } + + fn create_graphics_pipeline(&mut self) -> Result<(), String> { + let vert_shader_module = self.create_vertex_shader_module()?; + let frag_shader_module = self.create_fragment_shader_module()?; + + let mut vert_shader_stage_info: ffi::VkPipelineShaderStageCreateInfo = + unsafe { std::mem::zeroed() }; + vert_shader_stage_info.sType = + ffi::VkStructureType_VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.stage = ffi::VkShaderStageFlagBits_VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = vert_shader_module.get_module(); + vert_shader_stage_info.pName = "main\x00".as_ptr() as *const i8; + + let mut frag_shader_stage_info: ffi::VkPipelineShaderStageCreateInfo = + unsafe { std::mem::zeroed() }; + frag_shader_stage_info.sType = + ffi::VkStructureType_VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.stage = ffi::VkShaderStageFlagBits_VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = frag_shader_module.get_module(); + frag_shader_stage_info.pName = "main\x00".as_ptr() as *const i8; + + // TODO: Use the *_shader_stage_info structs before vert/frag_shader_module is cleaned up. + Ok(()) + } + + fn create_vertex_shader_module(&mut self) -> Result { + let vertex_shader = std::include_bytes!(concat!(env!("OUT_DIR"), "/vert.spv")); + + let mut create_info: ffi::VkShaderModuleCreateInfo = unsafe { std::mem::zeroed() }; + create_info.sType = ffi::VkStructureType_VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + create_info.codeSize = vertex_shader.len(); + create_info.pCode = vertex_shader.as_ptr() as *const u32; + + let mut shader_module: ffi::VkShaderModule = unsafe { std::mem::zeroed() }; + let result = unsafe { + ffi::vkCreateShaderModule( + self.device, + std::ptr::addr_of!(create_info), + std::ptr::null(), + std::ptr::addr_of_mut!(shader_module), + ) + }; + if result != ffi::VkResult_VK_SUCCESS { + Err(String::from("Failed to create vertex shader module!")) + } else { + Ok(ShaderModuleWrapper { + module: shader_module, + device: self.device, + }) + } + } + + fn create_fragment_shader_module(&mut self) -> Result { + let fragment_shader = std::include_bytes!(concat!(env!("OUT_DIR"), "/frag.spv")); + + let mut create_info: ffi::VkShaderModuleCreateInfo = unsafe { std::mem::zeroed() }; + create_info.sType = ffi::VkStructureType_VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + create_info.codeSize = fragment_shader.len(); + create_info.pCode = fragment_shader.as_ptr() as *const u32; + + let mut shader_module: ffi::VkShaderModule = unsafe { std::mem::zeroed() }; + let result = unsafe { + ffi::vkCreateShaderModule( + self.device, + std::ptr::addr_of!(create_info), + std::ptr::null(), + std::ptr::addr_of_mut!(shader_module), + ) + }; + if result != ffi::VkResult_VK_SUCCESS { + Err(String::from("Failed to create fragment shader module!")) + } else { + Ok(ShaderModuleWrapper { + module: shader_module, + device: self.device, + }) + } + } } impl Drop for VulkanApp {