From e2ff6de8bf004753b363d858e094ea4da33e3071 Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Sun, 5 Jul 2026 23:57:27 -0700 Subject: TRIANGLE Force-Push: yes Change-Id: I3e3aa50c5de4b2ccb0719663e029aadb3056dc70 --- src/main.rs | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 263 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1528b1c..a7d3410 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,6 +138,14 @@ struct Surreality { pipeline: OnceCell, pipeline_layout: OnceCell, + + framebuffers: OnceCell>, + + command_pool: OnceCell, + command_buffers: OnceCell>, + + image_available_semaphore: OnceCell, + rendering_finished_semaphore: OnceCell, } impl Surreality { @@ -163,10 +171,17 @@ impl Surreality { render_pass: OnceCell::new(), pipeline: OnceCell::new(), pipeline_layout: OnceCell::new(), + framebuffers: OnceCell::new(), + command_pool: OnceCell::new(), + command_buffers: OnceCell::new(), + image_available_semaphore: OnceCell::new(), + rendering_finished_semaphore: OnceCell::new(), } } fn init(&mut self, event_loop: &ActiveEventLoop) -> Result<()> { + // TODO refactor all these to not be methods, for better isolation + if self.window.get().is_none() { self.init_window(event_loop)?; } @@ -201,6 +216,18 @@ impl Surreality { self.init_pipeline()?; } + if self.framebuffers.get().is_none() { + self.init_framebuffers()?; + } + + if self.command_buffers.get().is_none() { + self.init_commands()?; + } + + if self.image_available_semaphore.get().is_none() { + self.init_semaphores()?; + } + Ok(()) } @@ -574,7 +601,7 @@ impl Surreality { = image_count.clamp(0, features.capabilities.max_image_count); } - // We call this one last time. It needs to return the same thing here + // We call this yet again. It needs to return the same thing here // that it did before; fortunately it's simple enough that that's a safe // assumption. let indices = self.find_device_queue_family_indices(&physical_device)? @@ -686,11 +713,24 @@ impl Surreality { .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) .color_attachments(&subpass_attachments); + let dependency + = vk::SubpassDependency::builder() + .src_subpass(vk::SUBPASS_EXTERNAL) + .src_stage_mask( + vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .src_access_mask(vk::AccessFlags::empty()) + .dst_subpass(0) + .dst_stage_mask( + vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE); + let render_attachments = [color_attachment]; let subpasses = [subpass]; + let dependencies = [dependency]; let render_pass_info = vk::RenderPassCreateInfo::builder() .attachments(&render_attachments) - .subpasses(&subpasses); + .subpasses(&subpasses) + .dependencies(&dependencies); let render_pass = unsafe { device.create_render_pass(&render_pass_info, None) @@ -822,6 +862,153 @@ impl Surreality { Ok(()) } + #[allow(unsafe_code)] + fn init_framebuffers(&mut self) -> Result<()> { + if self.framebuffers.get().is_none() { + let device = self.device.get().unwrap().clone(); + let extent = self.extent.get().unwrap().clone(); + let image_views = self.swapchain_image_views.get().unwrap(); + let render_pass = self.render_pass.get().unwrap(); + + let mut framebuffers = Vec::new(); + + for image_view in image_views { + let attachments = [*image_view]; + + let framebuffer_info = vk::FramebufferCreateInfo::builder() + .render_pass(*render_pass) + .attachments(&attachments) + .width(extent.width) + .height(extent.height) + .layers(1); + + let framebuffer = unsafe { + device.create_framebuffer(&framebuffer_info, None) + }?; + + framebuffers.push(framebuffer); + } + + self.framebuffers.set(framebuffers).unwrap(); + } + + Ok(()) + } + + #[allow(unsafe_code)] + fn init_commands(&mut self) -> Result<()> { + if self.command_pool.get().is_none() { + let physical_device = self.physical_device.get().unwrap().clone(); + let device = self.device.get().unwrap().clone(); + + // We call this one last time. It's kind of a problem. + let indices = self.find_device_queue_family_indices(&physical_device)? + .unwrap(); + + let command_pool_info = vk::CommandPoolCreateInfo::builder() + .flags(vk::CommandPoolCreateFlags::empty()) + .queue_family_index(indices.graphics); + + let command_pool = unsafe { + device.create_command_pool(&command_pool_info, None) + }?; + + self.command_pool.set(command_pool).unwrap(); + } + + if self.command_buffers.get().is_none() { + let device = self.device.get().unwrap(); + let extent = self.extent.get().unwrap(); + let framebuffers = self.framebuffers.get().unwrap(); + let render_pass = self.render_pass.get().unwrap(); + let pipeline = self.pipeline.get().unwrap(); + let command_pool = self.command_pool.get().unwrap(); + + let command_buffer_allocation_info + = vk::CommandBufferAllocateInfo::builder() + .command_pool(*command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(framebuffers.len() as u32); + let command_buffers = unsafe { + device.allocate_command_buffers(&command_buffer_allocation_info) + }?; + + for (index, framebuffer) in framebuffers.iter().enumerate() { + let command_buffer = command_buffers[index]; + + let inheritance_info = vk::CommandBufferInheritanceInfo::builder(); + + let command_buffer_begin_info + = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::empty()) + .inheritance_info(&inheritance_info); + + unsafe { + device.begin_command_buffer(command_buffer, + &command_buffer_begin_info) + }?; + + let render_area = vk::Rect2D::builder() + .offset(vk::Offset2D::default()) + .extent(*extent); + + let clear_value = vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0] + } + }; + let clear_values = [clear_value]; + + let begin_pass_info = vk::RenderPassBeginInfo::builder() + .render_pass(*render_pass) + .framebuffer(*framebuffer) + .render_area(render_area) + .clear_values(&clear_values); + + unsafe { + device.cmd_begin_render_pass(command_buffer, &begin_pass_info, + vk::SubpassContents::INLINE) + }; + + unsafe { + device.cmd_bind_pipeline(command_buffer, + vk::PipelineBindPoint::GRAPHICS, + *pipeline) + }; + + unsafe { device.cmd_draw(command_buffer, 3, 1, 0, 0) }; + + unsafe { device.cmd_end_render_pass(command_buffer) }; + + unsafe { device.end_command_buffer(command_buffer) }?; + } + + self.command_buffers.set(command_buffers).unwrap(); + } + + Ok(()) + } + + #[allow(unsafe_code)] + fn init_semaphores(&mut self) -> Result<()> { + let device = self.device.get().unwrap(); + let semaphore_info = vk::SemaphoreCreateInfo::builder(); + + let image_available_semaphore = unsafe { + device.create_semaphore(&semaphore_info, None) + }?; + + let rendering_finished_semaphore = unsafe { + device.create_semaphore(&semaphore_info, None) + }?; + + self.image_available_semaphore.set(image_available_semaphore).unwrap(); + self.rendering_finished_semaphore + .set(rendering_finished_semaphore).unwrap(); + + Ok(()) + } + // To Vulkan, a "physical" device is the actual GPU, and a "logical" // device is per-process state that represents a connection to the GPU. // Before we can create a logical device, we must choose which physical @@ -958,6 +1145,7 @@ impl Surreality { Ok(Acceptable::Accepted(score)) } + // TODO: save the result of this somewhere and only call it once #[allow(unsafe_code)] fn find_device_queue_family_indices(&mut self, device: &vk::PhysicalDevice) -> Result> @@ -1099,13 +1287,53 @@ impl Surreality { Ok(module) } + #[allow(unsafe_code)] fn render(&mut self, window_id: WindowId) -> Result<()> { if let Some(window) = self.window.get() && window_id == window.id() { - println!("render the window"); - } else { - println!("render something unknown"); + let device = self.device.get().unwrap(); + let graphics_queue = self.graphics_queue.get().unwrap(); + let presentation_queue = self.presentation_queue.get().unwrap(); + let swapchain = self.swapchain.get().unwrap(); + let command_buffers = self.command_buffers.get().unwrap(); + let image_available_semaphore + = self.image_available_semaphore.get().unwrap(); + let rendering_finished_semaphore + = self.rendering_finished_semaphore.get().unwrap(); + + let image_index = unsafe { + device.acquire_next_image_khr(*swapchain, u64::MAX, + *image_available_semaphore, + vk::Fence::null()) + }?.0 as usize; + + let first_semaphores = [*image_available_semaphore]; + let second_semaphores = [*rendering_finished_semaphore]; + + let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + let command_buffers = [command_buffers[image_index]]; + let submit_info = vk::SubmitInfo::builder() + .wait_semaphores(&first_semaphores) + .wait_dst_stage_mask(&wait_stages) + .command_buffers(&command_buffers) + .signal_semaphores(&second_semaphores); + unsafe { + device.queue_submit(*graphics_queue, + &[submit_info], + vk::Fence::null()) + }?; + + let swapchains = [*swapchain]; + let image_indices = [image_index as u32]; + let present_info = vk::PresentInfoKHR::builder() + .wait_semaphores(&second_semaphores) + .swapchains(&swapchains) + .image_indices(&image_indices); + + unsafe { + device.queue_present_khr(*presentation_queue, &present_info) + }?; } Ok(()) @@ -1115,6 +1343,36 @@ impl Surreality { impl Drop for Surreality { #[allow(unsafe_code)] fn drop(&mut self) { + if let Some(image_available_semaphore) + = self.image_available_semaphore.get() + && let Some(device) = self.device.get() + { + unsafe { device.destroy_semaphore(*image_available_semaphore, None) }; + } + + if let Some(rendering_finished_semaphore) + = self.rendering_finished_semaphore.get() + && let Some(device) = self.device.get() + { + unsafe { + device.destroy_semaphore(*rendering_finished_semaphore, None) + }; + } + + if let Some(command_pool) = self.command_pool.get() + && let Some(device) = self.device.get() + { + unsafe { device.destroy_command_pool(*command_pool, None) }; + } + + if let Some(framebuffers) = self.framebuffers.get() + && let Some(device) = self.device.get() + { + for framebuffer in framebuffers { + unsafe { device.destroy_framebuffer(*framebuffer, None) }; + } + } + if let Some(pipeline) = self.pipeline.get() && let Some(device) = self.device.get() { -- cgit 1.4.1