diff --git a/justfile b/justfile new file mode 100644 index 0000000..9d33e13 --- /dev/null +++ b/justfile @@ -0,0 +1,8 @@ +# Lists the available actions +default: + @just --list + +# Convert the human-readable shader code to Vulkan bytecode +compile-shaders: + glslc shaders/shader.vert -o shaders/vert.spv + glslc shaders/shader.frag -o shaders/frag.spv diff --git a/shaders/frag.spv b/shaders/frag.spv new file mode 100644 index 0000000..da37f7e Binary files /dev/null and b/shaders/frag.spv differ 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..f5b2f8d --- /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/shaders/vert.spv b/shaders/vert.spv new file mode 100644 index 0000000..a41dd2c Binary files /dev/null and b/shaders/vert.spv differ diff --git a/src/app.rs b/src/app.rs index 1814200..377a9df 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,7 +1,7 @@ mod functions; use functions::{ - create_instance, create_logical_device, create_swapchain, create_swapchain_image_views, - pick_physical_device, + create_instance, create_logical_device, create_pipeline, create_swapchain, + create_swapchain_image_views, pick_physical_device, }; use crate::VALIDATION_ENABLED; @@ -32,13 +32,17 @@ impl App { pub unsafe fn create(window: &Window) -> Result { let loader = LibloadingLoader::new(LIBRARY)?; let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?; + let mut data = AppData::default(); let instance = create_instance(window, &entry, &mut data)?; data.surface = vk_window::create_surface(&instance, window)?; + pick_physical_device(&instance, &mut data)?; let device = create_logical_device(&instance, &mut data)?; + create_swapchain(window, &instance, &device, &mut data)?; create_swapchain_image_views(&device, &mut data)?; + create_pipeline(&device, &mut data)?; Ok(Self { entry, @@ -61,13 +65,13 @@ impl App { .for_each(|v| self.device.destroy_image_view(*v, None)); self.device.destroy_swapchain_khr(self.data.swapchain, None); self.device.destroy_device(None); + self.instance.destroy_surface_khr(self.data.surface, None); if VALIDATION_ENABLED { self.instance .destroy_debug_utils_messenger_ext(self.data.messenger, None); } - self.instance.destroy_surface_khr(self.data.surface, None); self.instance.destroy_instance(None); } } @@ -83,6 +87,7 @@ pub struct AppData { physical_device: vk::PhysicalDevice, graphics_queue: vk::Queue, present_queue: vk::Queue, + // Swapchain swapchain_format: vk::Format, swapchain_extent: vk::Extent2D, swapchain: vk::SwapchainKHR, @@ -90,17 +95,19 @@ pub struct AppData { swapchain_image_views: Vec, } +impl AppData {} + #[derive(Debug, Error)] #[error("Missing {0}.")] pub struct SuitabilityError(pub &'static str); #[derive(Copy, Clone, Debug)] -pub(crate) struct QueueFamilyIndicies { +pub(crate) struct QueueFamilyIndices { graphics: u32, present: u32, } -impl QueueFamilyIndicies { +impl QueueFamilyIndices { unsafe fn get( instance: &Instance, data: &AppData, diff --git a/src/app/functions.rs b/src/app/functions.rs index 697b273..370af08 100644 --- a/src/app/functions.rs +++ b/src/app/functions.rs @@ -133,12 +133,12 @@ pub(super) unsafe fn pick_physical_device(instance: &Instance, data: &mut AppDat Err(anyhow!("Failed to find suitable physical device.")) } -pub(super) unsafe fn check_physical_device( +unsafe fn check_physical_device( instance: &Instance, data: &AppData, physical_device: vk::PhysicalDevice, ) -> Result<()> { - QueueFamilyIndicies::get(instance, data, physical_device)?; + QueueFamilyIndices::get(instance, data, physical_device)?; check_physical_device_extensions(instance, physical_device)?; let support = SwapchainSupport::get(instance, data, physical_device)?; @@ -149,7 +149,7 @@ pub(super) unsafe fn check_physical_device( Ok(()) } -pub(super) unsafe fn check_physical_device_extensions( +unsafe fn check_physical_device_extensions( instance: &Instance, physical_device: vk::PhysicalDevice, ) -> Result<()> { @@ -173,7 +173,7 @@ pub(super) unsafe fn create_logical_device( data: &mut AppData, ) -> Result { // Queue Create Infos - let indices = QueueFamilyIndicies::get(instance, data, data.physical_device)?; + let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; let mut unique_indices = HashSet::new(); unique_indices.insert(indices.graphics); @@ -230,9 +230,7 @@ pub(super) unsafe fn create_logical_device( Ok(device) } -pub(super) fn get_swapchain_surface_format( - formats: &[vk::SurfaceFormatKHR], -) -> vk::SurfaceFormatKHR { +fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR { formats .iter() .cloned() @@ -243,9 +241,7 @@ pub(super) fn get_swapchain_surface_format( .unwrap_or_else(|| formats[0]) } -pub(super) fn get_swapchain_present_mode( - present_modes: &[vk::PresentModeKHR], -) -> vk::PresentModeKHR { +fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::PresentModeKHR { present_modes .iter() .cloned() @@ -253,10 +249,7 @@ pub(super) fn get_swapchain_present_mode( .unwrap_or(vk::PresentModeKHR::FIFO) } -pub(super) fn get_swapchain_extent( - window: &Window, - capabilities: vk::SurfaceCapabilitiesKHR, -) -> vk::Extent2D { +fn get_swapchain_extent(window: &Window, capabilities: vk::SurfaceCapabilitiesKHR) -> vk::Extent2D { if capabilities.current_extent.width != u32::MAX { capabilities.current_extent } else { @@ -283,7 +276,7 @@ pub(super) unsafe fn create_swapchain( device: &Device, data: &mut AppData, ) -> Result<()> { - let indices = QueueFamilyIndicies::get(instance, data, data.physical_device)?; + let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; let support = SwapchainSupport::get(instance, data, data.physical_device)?; let surface_format = get_swapchain_surface_format(&support.formats); @@ -364,3 +357,40 @@ pub(super) unsafe fn create_swapchain_image_views( Ok(()) } + +pub(super) unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> { + let vert = include_bytes!("../../shaders/vert.spv"); + let frag = include_bytes!("../../shaders/frag.spv"); + + let vert_shader_module = create_shader_module(device, &vert[..])?; + let frag_shader_module = create_shader_module(device, &frag[..])?; + + let vert_stage = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::VERTEX) + .module(vert_shader_module) + .name(b"main\0"); + + let frag_stage = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::FRAGMENT) + .module(frag_shader_module) + .name(b"main\0"); + + device.destroy_shader_module(vert_shader_module, None); + device.destroy_shader_module(frag_shader_module, None); + + Ok(()) +} + +unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result { + let bytecode = Vec::::from(bytecode); + let (prefix, code, suffix) = bytecode.align_to::(); + if !prefix.is_empty() || !suffix.is_empty() { + return Err(anyhow!("Shader bytecode is not properly aligned.")); + } + + let info = vk::ShaderModuleCreateInfo::builder() + .code_size(bytecode.len()) + .code(code); + + Ok(device.create_shader_module(&info, None)?) +}