diff --git a/Cargo.toml b/Cargo.toml index 868eea4..57c2281 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,5 +14,5 @@ png = "0.17" pretty_env_logger = "0.4" thiserror = "1" tobj = { version = "3", features = ["log"] } -vulkanalia = { version = "=0.16.0", features = ["libloading", "window", "provisional"] } +vulkanalia = { version = "0.16.0", features = ["libloading", "window", "provisional"] } winit = "0.27" diff --git a/shaders/shader.vert b/shaders/shader.vert index 9f27f54..5ffbb2d 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,11 +1,17 @@ #version 450 +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + layout(location = 0) in vec2 inPosition; layout(location = 1) in vec3 inColor; layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(inPosition, 0.0, 1.0); + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); fragColor = inColor; } diff --git a/shaders/vert.spv b/shaders/vert.spv index 1e4ce0c..2b7afb0 100644 Binary files a/shaders/vert.spv and b/shaders/vert.spv differ diff --git a/src/app.rs b/src/app.rs index 6b25052..644d46a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,6 +9,8 @@ use ::anyhow::{anyhow, Result}; use ::lazy_static::lazy_static; use ::nalgebra_glm as glm; use ::std::mem::size_of; +use ::std::ptr::copy_nonoverlapping as memcpy; +use ::std::time::Instant; use ::vulkanalia::loader::{LibloadingLoader, LIBRARY}; use ::vulkanalia::prelude::v1_0::*; use ::vulkanalia::vk::{KhrSurfaceExtension, KhrSwapchainExtension}; @@ -49,6 +51,7 @@ pub struct App { pub device: Device, frame: usize, pub resized: bool, + start: Instant, } impl App { @@ -72,6 +75,7 @@ impl App { device, frame: 0, resized: false, + start: Instant::now(), }) } } @@ -82,7 +86,6 @@ impl App { /// Here be Dragons pub fn destroy(&mut self) { unsafe { - self.data.destroy_swapchain(&self.device); self.data.destroy(&self.instance, &self.device); } } @@ -117,6 +120,8 @@ impl App { self.data.images_in_flight[image_index] = in_flight_fence; + self.update_uniform_buffer(image_index)?; + let wait_semaphores = &[self.data.image_available_semaphores[self.frame]]; let wait_stages = &[vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; let command_buffers = &[self.data.command_buffers[image_index]]; @@ -158,6 +163,48 @@ impl App { Ok(()) } + unsafe fn update_uniform_buffer(&self, image_index: usize) -> Result<()> { + let time = self.start.elapsed().as_secs_f32(); + + let model = glm::rotate( + &glm::identity(), + time * glm::radians(&glm::vec1(90.0))[0], + &glm::vec3(0.0, 0.0, 1.0), + ); + + let view = glm::look_at( + &glm::vec3(2.0, 2.0, 2.0), + &glm::vec3(0.0, 0.0, 0.0), + &glm::vec3(0.0, 0.0, 1.0), + ); + + let mut proj = glm::perspective( + self.data.swapchain_extent.width as f32 / self.data.swapchain_extent.height as f32, + glm::radians(&glm::vec1(45.0))[0], + 0.1, + 10.0, + ); + + // Flip the image right-side-up + proj[(1, 1)] *= -1.0; + + let ubo = UniformBufferObject { model, view, proj }; + + let memory = self.device.map_memory( + self.data.uniform_buffers_memory[image_index], + 0, + size_of::() as u64, + vk::MemoryMapFlags::empty(), + )?; + + memcpy(&ubo, memory.cast(), 1); + + self.device + .unmap_memory(self.data.uniform_buffers_memory[image_index]); + + Ok(()) + } + /// Recreates the swapchain /// /// # Safety diff --git a/src/app/data.rs b/src/app/data.rs index 1de55eb..cc229c9 100644 --- a/src/app/data.rs +++ b/src/app/data.rs @@ -48,12 +48,13 @@ pub(crate) struct AppData { pub(super) present_queue: vk::Queue, // Swapchain swapchain_format: vk::Format, - swapchain_extent: vk::Extent2D, + pub(super) swapchain_extent: vk::Extent2D, pub(super) swapchain: vk::SwapchainKHR, swapchain_images: Vec, swapchain_image_views: Vec, // Pipeline render_pass: vk::RenderPass, + descriptor_set_layout: vk::DescriptorSetLayout, pipeline_layout: vk::PipelineLayout, pipeline: vk::Pipeline, // Framebuffers @@ -65,6 +66,8 @@ pub(crate) struct AppData { vertex_buffer_memory: vk::DeviceMemory, index_buffer: vk::Buffer, index_buffer_memory: vk::DeviceMemory, + uniform_buffers: Vec, + pub(super) uniform_buffers_memory: Vec, // Command Buffers pub(super) command_buffers: Vec, // Sync Objects @@ -93,22 +96,20 @@ impl AppData { self.create_swapchain(window, &instance, &device)?; self.create_swapchain_image_views(&device)?; self.create_render_pass(&instance, &device)?; + self.create_descriptor_set_layout(&device)?; self.create_pipeline(&device)?; self.create_framebuffers(&device)?; self.create_command_pool(&instance, &device)?; self.create_vertex_buffer(&instance, &device)?; self.create_index_buffer(&instance, &device)?; + self.create_uniform_buffers(&instance, &device)?; self.create_command_buffers(&device)?; self.create_sync_objects(&device)?; Ok((instance, device)) } - pub(super) unsafe fn create_instance( - &mut self, - window: &Window, - entry: &Entry, - ) -> Result { + unsafe fn create_instance(&mut self, window: &Window, entry: &Entry) -> Result { // Application Info let application_info = vk::ApplicationInfo::builder() .application_name(b"Vulkan Tutorial\0") @@ -192,7 +193,13 @@ impl AppData { /// /// # Safety /// Here be Dragons - pub(super) unsafe fn destroy_swapchain(&mut self, device: &Device) { + unsafe fn destroy_swapchain(&mut self, device: &Device) { + self.uniform_buffers + .iter() + .for_each(|b| device.destroy_buffer(*b, None)); + self.uniform_buffers_memory + .iter() + .for_each(|m| device.free_memory(*m, None)); self.framebuffers .iter() .for_each(|f| device.destroy_framebuffer(*f, None)); @@ -211,6 +218,9 @@ impl AppData { /// # Safety /// Here be Dragons pub unsafe fn destroy(&mut self, instance: &Instance, device: &Device) { + self.destroy_swapchain(device); + device.destroy_descriptor_set_layout(self.descriptor_set_layout, None); + device.destroy_buffer(self.index_buffer, None); device.free_memory(self.index_buffer_memory, None); device.destroy_buffer(self.vertex_buffer, None); @@ -240,7 +250,7 @@ impl AppData { // Physical Device //================================================ - pub(super) unsafe fn pick_physical_device(&mut self, instance: &Instance) -> Result<()> { + unsafe fn pick_physical_device(&mut self, instance: &Instance) -> Result<()> { for physical_device in instance.enumerate_physical_devices()? { let properties = instance.get_physical_device_properties(physical_device); @@ -279,7 +289,7 @@ impl AppData { // Logical Device //================================================ - pub(super) unsafe fn create_logical_device(&mut self, instance: &Instance) -> Result { + unsafe fn create_logical_device(&mut self, instance: &Instance) -> Result { // Queue Create Infos let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?; @@ -342,7 +352,7 @@ impl AppData { // Swapchain //================================================ - pub(super) unsafe fn create_swapchain( + unsafe fn create_swapchain( &mut self, window: &Window, instance: &Instance, @@ -412,6 +422,7 @@ impl AppData { self.create_render_pass(instance, device)?; self.create_pipeline(device)?; self.create_framebuffers(device)?; + self.create_uniform_buffers(instance, device)?; self.create_command_buffers(device)?; self.images_in_flight @@ -420,7 +431,7 @@ impl AppData { Ok(()) } - pub(super) unsafe fn create_swapchain_image_views(&mut self, device: &Device) -> Result<()> { + unsafe fn create_swapchain_image_views(&mut self, device: &Device) -> Result<()> { self.swapchain_image_views = self .swapchain_images .iter() @@ -456,11 +467,22 @@ impl AppData { // Pipeline //================================================ - pub(super) unsafe fn create_render_pass( - &mut self, - _instance: &Instance, - device: &Device, - ) -> Result<()> { + unsafe fn create_descriptor_set_layout(&mut self, device: &Device) -> Result<()> { + let ubo_binding = vk::DescriptorSetLayoutBinding::builder() + .binding(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::VERTEX); + + let bindings = &[ubo_binding]; + let info = vk::DescriptorSetLayoutCreateInfo::builder().bindings(bindings); + + self.descriptor_set_layout = device.create_descriptor_set_layout(&info, None)?; + + Ok(()) + } + + unsafe fn create_render_pass(&mut self, _instance: &Instance, device: &Device) -> Result<()> { let color_attachment = vk::AttachmentDescription::builder() .format(self.swapchain_format) .samples(vk::SampleCountFlags::_1) @@ -500,7 +522,7 @@ impl AppData { Ok(()) } - pub(super) unsafe fn create_pipeline(&mut self, device: &Device) -> Result<()> { + unsafe fn create_pipeline(&mut self, device: &Device) -> Result<()> { let vert = include_bytes!("../../shaders/vert.spv"); let frag = include_bytes!("../../shaders/frag.spv"); @@ -575,7 +597,8 @@ impl AppData { .attachments(attachments) .blend_constants([0.0, 0.0, 0.0, 0.0]); - let layout_info = vk::PipelineLayoutCreateInfo::builder(); + let set_layouts = &[self.descriptor_set_layout]; + let layout_info = vk::PipelineLayoutCreateInfo::builder().set_layouts(set_layouts); self.pipeline_layout = device.create_pipeline_layout(&layout_info, None)?; let stages = &[vert_stage, frag_stage]; @@ -602,7 +625,7 @@ impl AppData { Ok(()) } - pub(super) unsafe fn create_framebuffers(&mut self, device: &Device) -> Result<()> { + unsafe fn create_framebuffers(&mut self, device: &Device) -> Result<()> { self.framebuffers = self .swapchain_image_views .iter() @@ -626,11 +649,7 @@ impl AppData { // Command Pool //================================================ - pub(super) unsafe fn create_command_pool( - &mut self, - instance: &Instance, - device: &Device, - ) -> Result<()> { + unsafe fn create_command_pool(&mut self, instance: &Instance, device: &Device) -> Result<()> { let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?; let info = vk::CommandPoolCreateInfo::builder() @@ -711,11 +730,7 @@ impl AppData { Ok(()) } - pub(super) unsafe fn create_vertex_buffer( - &mut self, - instance: &Instance, - device: &Device, - ) -> Result<()> { + unsafe fn create_vertex_buffer(&mut self, instance: &Instance, device: &Device) -> Result<()> { // Create staging buffer let size = (size_of::() * VERTICES.len()) as u64; let (staging_buffer, staging_buffer_memory) = self.create_buffer( @@ -753,11 +768,7 @@ impl AppData { Ok(()) } - pub(super) unsafe fn create_index_buffer( - &mut self, - instance: &Instance, - device: &Device, - ) -> Result<()> { + unsafe fn create_index_buffer(&mut self, instance: &Instance, device: &Device) -> Result<()> { let size = (size_of::() * INDICES.len()) as u64; let (staging_buffer, staging_buffer_memory) = self.create_buffer( instance, @@ -791,11 +802,35 @@ impl AppData { Ok(()) } + unsafe fn create_uniform_buffers( + &mut self, + instance: &Instance, + device: &Device, + ) -> Result<()> { + self.uniform_buffers.clear(); + self.uniform_buffers_memory.clear(); + + for _ in 0..self.swapchain_images.len() { + let (uniform_buffer, uniform_buffer_memory) = self.create_buffer( + instance, + device, + size_of::() as u64, + vk::BufferUsageFlags::UNIFORM_BUFFER, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + self.uniform_buffers.push(uniform_buffer); + self.uniform_buffers_memory.push(uniform_buffer_memory); + } + + Ok(()) + } + //================================================ // Command Buffers //================================================ - pub(super) unsafe fn create_command_buffers(&mut self, device: &Device) -> Result<()> { + unsafe fn create_command_buffers(&mut self, device: &Device) -> Result<()> { // Create the buffers let allocate_info = vk::CommandBufferAllocateInfo::builder() .command_pool(self.command_pool) @@ -857,7 +892,7 @@ impl AppData { // Sync Objects //================================================ - pub(super) unsafe fn create_sync_objects(&mut self, device: &Device) -> Result<()> { + unsafe fn create_sync_objects(&mut self, device: &Device) -> Result<()> { let semaphore_info = vk::SemaphoreCreateInfo::builder(); let fence_info = vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED); diff --git a/src/app/structs.rs b/src/app/structs.rs index ff010cb..37f5e62 100644 --- a/src/app/structs.rs +++ b/src/app/structs.rs @@ -132,3 +132,14 @@ impl Vertex { [pos, color] } } + +// ---------------------------------------------------------------------------- +// Resource Descriptors +// ---------------------------------------------------------------------------- +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct UniformBufferObject { + pub(crate) model: glm::Mat4, + pub(crate) view: glm::Mat4, + pub(crate) proj: glm::Mat4, +}