summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs268
1 files 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<vk::Pipeline>,
   pipeline_layout: OnceCell<vk::PipelineLayout>,
+
+  framebuffers: OnceCell<Vec<vk::Framebuffer>>,
+
+  command_pool: OnceCell<vk::CommandPool>,
+  command_buffers: OnceCell<Vec<vk::CommandBuffer>>,
+
+  image_available_semaphore: OnceCell<vk::Semaphore>,
+  rendering_finished_semaphore: OnceCell<vk::Semaphore>,
 }
 
 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<Acceptable<QueueFamilyIndices>>
@@ -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()
     {