summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-07-18 17:21:42 -0700
committerIrene Knapp <ireneista@irenes.space>2026-07-18 17:40:13 -0700
commit365c2f8bdc217f33264e3aed394f67840a4c075d (patch)
tree0836ea0bce5136d89d5d4e140f5ba22f657b54bd /src
parentcbfe9b855c11b1ef603b7212c244e089b4461753 (diff)
depth buffer
yay

Change-Id: I7795e22712f27b262cde807a942ddec342d07c55
Force-Push: yes
Diffstat (limited to 'src')
-rw-r--r--src/graphics_window_dressing.rs195
1 files changed, 156 insertions, 39 deletions
diff --git a/src/graphics_window_dressing.rs b/src/graphics_window_dressing.rs
index c1db68f..ce5ccda 100644
--- a/src/graphics_window_dressing.rs
+++ b/src/graphics_window_dressing.rs
@@ -30,6 +30,11 @@ pub const N_SIMULTANEOUS_FRAMES: usize = 5;
 pub struct WindowDressing {
   pub swapchain: Swapchain,
 
+  depth_image: vk::Image,
+  depth_image_memory: vk::DeviceMemory,
+  depth_image_view: vk::ImageView,
+  depth_format: vk::Format,
+
   render_pass: vk::RenderPass,
 
   pipeline: vk::Pipeline,
@@ -114,14 +119,20 @@ impl WindowDressing {
     let swapchain = init_swapchain(
             window, instance, surface, &physical_device, device, &indices)?;
 
-    let render_pass = init_render_pass(device, &swapchain.format)?;
+    let (depth_image, depth_image_memory, depth_image_view, depth_format)
+            = init_depth(instance, &physical_device, device,
+                         &swapchain.extent)?;
+
+    let render_pass = init_render_pass(device, &swapchain.format,
+                                       &depth_format)?;
 
     let (pipeline_layout, pipeline)
             = init_pipeline(device, descriptor_set_layout, &swapchain.extent,
                             &render_pass)?;
 
     let framebuffers = init_framebuffers(
-            device, &swapchain.extent, &swapchain.image_views, &render_pass)?;
+            device, &swapchain.extent, &swapchain.image_views,
+            &depth_image_view, &render_pass)?;
 
     let (primary_command_pool, transient_command_pool)
             = init_command_pools(device, indices)?;
@@ -158,6 +169,10 @@ impl WindowDressing {
 
     Ok(WindowDressing {
       swapchain,
+      depth_image,
+      depth_image_memory,
+      depth_image_view,
+      depth_format,
       render_pass,
       pipeline,
       pipeline_layout,
@@ -202,14 +217,20 @@ impl WindowDressing {
     let swapchain = init_swapchain(
             window, instance, surface, &physical_device, device, &indices)?;
 
-    let render_pass = init_render_pass(device, &swapchain.format)?;
+    let (depth_image, depth_image_memory, depth_image_view, depth_format)
+            = init_depth(instance, &physical_device, device,
+                         &swapchain.extent)?;
+
+    let render_pass = init_render_pass(device, &swapchain.format,
+                                       &depth_format)?;
 
     let (pipeline_layout, pipeline)
             = init_pipeline(device, descriptor_set_layout, &swapchain.extent,
                             &render_pass)?;
 
     let framebuffers = init_framebuffers(
-            device, &swapchain.extent, &swapchain.image_views, &render_pass)?;
+            device, &swapchain.extent, &swapchain.image_views,
+            &depth_image_view, &render_pass)?;
 
     let (uniform_buffers, uniform_buffer_memory)
             = init_uniform_buffers(instance, physical_device, device,
@@ -236,6 +257,10 @@ impl WindowDressing {
                                          vk::Fence::null());
 
     self.swapchain = swapchain;
+    self.depth_image = depth_image;
+    self.depth_image_memory = depth_image_memory;
+    self.depth_image_view = depth_image_view;
+    self.depth_format = depth_format;
     self.render_pass = render_pass;
     self.pipeline = pipeline;
     self.pipeline_layout = pipeline_layout;
@@ -316,6 +341,9 @@ impl WindowDressing {
     unsafe { device.destroy_pipeline(self.pipeline, None) };
     unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) };
     unsafe { device.destroy_render_pass(self.render_pass, None) };
+    unsafe { device.destroy_image(self.depth_image, None) };
+    unsafe { device.free_memory(self.depth_image_memory, None) };
+    unsafe { device.destroy_image_view(self.depth_image_view, None) };
 
     for view in &self.swapchain.image_views {
       unsafe { device.destroy_image_view(*view, None) };
@@ -391,7 +419,8 @@ fn init_swapchain(window: &Window, instance: &Instance,
 
   let mut image_views = Vec::new();
   for image in &images {
-    let view = init_image_view(device, image, format.format)?;
+    let view = init_image_view(device, image, format.format,
+                               vk::ImageAspectFlags::COLOR)?;
     image_views.push(view);
   }
 
@@ -404,42 +433,82 @@ fn init_swapchain(window: &Window, instance: &Instance,
 
 
 #[allow(unsafe_code)]
-fn init_render_pass(device: &Device, format: &vk::Format)
+fn init_depth(instance: &Instance, physical_device: &vk::PhysicalDevice,
+              device: &Device, extent: &vk::Extent2D)
+    -> Result<(vk::Image, vk::DeviceMemory, vk::ImageView, vk::Format)>
+{
+  let format = pick_depth_format(instance, physical_device)?;
+
+  let (image, image_memory)
+          = allocate_image(instance, physical_device, device,
+                           extent.width, extent.height,
+                           format,
+                           vk::ImageTiling::OPTIMAL,
+                           vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
+                           vk::MemoryPropertyFlags::DEVICE_LOCAL)?;
+
+  let image_view = init_image_view(device, &image, format,
+                                   vk::ImageAspectFlags::DEPTH)?;
+
+  Ok((image, image_memory, image_view, format))
+}
+
+
+#[allow(unsafe_code)]
+fn init_render_pass(device: &Device, color_format: &vk::Format,
+                    depth_format: &vk::Format)
     -> Result<vk::RenderPass>
 {
-  let color_attachment
-          = vk::AttachmentDescription::builder()
-                .format(*format)
-                .samples(vk::SampleCountFlags::_1)
-                .load_op(vk::AttachmentLoadOp::CLEAR)
-                .store_op(vk::AttachmentStoreOp::STORE)
-                .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
-                .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
-                .initial_layout(vk::ImageLayout::UNDEFINED)
-                .final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
-
-  let color_attachment_reference
-          = vk::AttachmentReference::builder()
-                .attachment(0)
-                .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
-
-  let subpass_attachments = [color_attachment_reference];
+  let color_attachment = vk::AttachmentDescription::builder()
+          .format(*color_format)
+          .samples(vk::SampleCountFlags::_1)
+          .load_op(vk::AttachmentLoadOp::CLEAR)
+          .store_op(vk::AttachmentStoreOp::STORE)
+          .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
+          .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
+          .initial_layout(vk::ImageLayout::UNDEFINED)
+          .final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
+
+  let color_attachment_reference = vk::AttachmentReference::builder()
+          .attachment(0)
+          .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
+
+  let depth_attachment = vk::AttachmentDescription::builder()
+          .format(*depth_format)
+          .samples(vk::SampleCountFlags::_1)
+          .load_op(vk::AttachmentLoadOp::CLEAR)
+          .store_op(vk::AttachmentStoreOp::DONT_CARE)
+          .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
+          .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
+          .initial_layout(vk::ImageLayout::UNDEFINED)
+          .final_layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+  let depth_attachment_reference = vk::AttachmentReference::builder()
+          .attachment(1)
+          .layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+  let color_attachments = [color_attachment_reference];
   let subpass = vk::SubpassDescription::builder()
                     .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
-                    .color_attachments(&subpass_attachments);
+                    .color_attachments(&color_attachments)
+                    .depth_stencil_attachment(&depth_attachment_reference);
 
   let dependency
         = vk::SubpassDependency::builder()
               .src_subpass(vk::SUBPASS_EXTERNAL)
               .src_stage_mask(
-                   vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
+                   vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
+                   | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS)
               .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);
+                   vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
+                   | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS)
+              .dst_access_mask(
+                   vk::AccessFlags::COLOR_ATTACHMENT_WRITE
+                   | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE);
 
-  let render_attachments = [color_attachment];
+  let render_attachments = [color_attachment, depth_attachment];
   let subpasses = [subpass];
   let dependencies = [dependency];
   let render_pass_info = vk::RenderPassCreateInfo::builder()
@@ -526,6 +595,15 @@ fn init_pipeline(device: &Device,
                 .sample_shading_enable(false)
                 .rasterization_samples(vk::SampleCountFlags::_1);
 
+  let depth_state_info = vk::PipelineDepthStencilStateCreateInfo::builder()
+          .depth_test_enable(true)
+          .depth_write_enable(true)
+          .depth_compare_op(vk::CompareOp::LESS)
+          .depth_bounds_test_enable(false)
+          .min_depth_bounds(0.0)
+          .max_depth_bounds(1.0)
+          .stencil_test_enable(false);
+
   let blend_attachment_info
           = vk::PipelineColorBlendAttachmentState::builder()
                 .color_write_mask(vk::ColorComponentFlags::all())
@@ -561,6 +639,7 @@ fn init_pipeline(device: &Device,
                 .viewport_state(&viewport_state_info)
                 .rasterization_state(&rasterizer_state_info)
                 .multisample_state(&multisample_state_info)
+                .depth_stencil_state(&depth_state_info)
                 .color_blend_state(&blend_info)
                 .layout(pipeline_layout)
                 .render_pass(*render_pass)
@@ -583,13 +662,14 @@ fn init_pipeline(device: &Device,
 #[allow(unsafe_code)]
 fn init_framebuffers(device: &Device, extent: &vk::Extent2D,
                      swapchain_image_views: &Vec<vk::ImageView>,
+                     depth_image_view: &vk::ImageView,
                      render_pass: &vk::RenderPass)
     -> Result<Vec<vk::Framebuffer>>
 {
   let mut framebuffers = Vec::new();
 
-  for image_view in swapchain_image_views {
-    let attachments = [*image_view];
+  for color_image_view in swapchain_image_views {
+    let attachments = [*color_image_view, *depth_image_view];
 
     let framebuffer_info = vk::FramebufferCreateInfo::builder()
                                .render_pass(*render_pass)
@@ -669,7 +749,8 @@ fn init_texture(instance: &Instance,
                       vk::ImageLayout::TRANSFER_DST_OPTIMAL,
                       vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)?;
 
-  let view = init_image_view(device, &image, vk::Format::R8G8B8A8_SRGB)?;
+  let view = init_image_view(device, &image, vk::Format::R8G8B8A8_SRGB,
+                             vk::ImageAspectFlags::COLOR)?;
 
   unsafe { device.destroy_buffer(staging_buffer, None) };
   unsafe { device.free_memory(staging_memory, None) };
@@ -861,12 +942,18 @@ fn init_commands(device: &Device,
                           .offset(vk::Offset2D::default())
                           .extent(*extent);
 
-    let clear_value = vk::ClearValue {
+    let color_clear_value = vk::ClearValue {
       color: vk::ClearColorValue {
         float32: [0.0, 0.0, 0.0, 1.0]
       }
     };
-    let clear_values = [clear_value];
+    let depth_clear_value = vk::ClearValue {
+      depth_stencil: vk::ClearDepthStencilValue {
+        depth: 1.0,
+        stencil: 0,
+      }
+    };
+    let clear_values = [color_clear_value, depth_clear_value];
 
     let begin_pass_info = vk::RenderPassBeginInfo::builder()
                               .render_pass(*render_pass)
@@ -959,17 +1046,20 @@ fn init_concurrency(device: &Device,
 
 
 #[allow(unsafe_code)]
-fn init_image_view(device: &Device, image: &vk::Image, format: vk::Format)
+fn init_image_view(device: &Device, image: &vk::Image, format: vk::Format,
+                   aspects: vk::ImageAspectFlags)
     -> Result<vk::ImageView>
 {
+  //   Component mapping is only for color components (not, for example, depth
+  // or stencil components), so we always just want it like this.
   let components = vk::ComponentMapping::builder()
-                       .r(vk::ComponentSwizzle::IDENTITY)
-                       .g(vk::ComponentSwizzle::IDENTITY)
-                       .b(vk::ComponentSwizzle::IDENTITY)
-                       .a(vk::ComponentSwizzle::IDENTITY);
+          .r(vk::ComponentSwizzle::IDENTITY)
+          .g(vk::ComponentSwizzle::IDENTITY)
+          .b(vk::ComponentSwizzle::IDENTITY)
+          .a(vk::ComponentSwizzle::IDENTITY);
 
   let subresource_range = vk::ImageSubresourceRange::builder()
-                              .aspect_mask(vk::ImageAspectFlags::COLOR)
+                              .aspect_mask(aspects)
                               .base_mip_level(0)
                               .level_count(1)
                               .base_array_layer(0)
@@ -1005,6 +1095,33 @@ fn pick_surface_format(available_formats: &Vec<vk::SurfaceFormatKHR>)
 }
 
 
+#[allow(unsafe_code)]
+fn pick_depth_format(instance: &Instance,
+                     physical_device: &vk::PhysicalDevice)
+    -> Result<vk::Format>
+{
+  let required_features = vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT;
+
+  for format in [vk::Format::D32_SFLOAT,
+                 vk::Format::D32_SFLOAT_S8_UINT,
+                 vk::Format::D24_UNORM_S8_UINT]
+  {
+    let properties = unsafe {
+      instance.get_physical_device_format_properties(
+                   *physical_device, format)
+    };
+
+    if properties.optimal_tiling_features.contains(required_features) {
+      return Ok(format);
+    }
+  }
+
+  Err(Error {
+    message: "There is no supported depth-buffer sample format.".to_string()
+  })
+}
+
+
 fn pick_presentation_mode(_available_modes: &Vec<vk::PresentModeKHR>)
     -> Result<vk::PresentModeKHR>
 {