summary refs log tree commit diff
path: root/src/graphics_window_dressing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics_window_dressing.rs')
-rw-r--r--src/graphics_window_dressing.rs177
1 files changed, 161 insertions, 16 deletions
diff --git a/src/graphics_window_dressing.rs b/src/graphics_window_dressing.rs
index fb56fb3..38d4188 100644
--- a/src/graphics_window_dressing.rs
+++ b/src/graphics_window_dressing.rs
@@ -3,10 +3,10 @@ use crate::error::*;
 use crate::graphics_permanent::{
   PermanentGraphicsState, GraphicsStateForReinit, QueueFamilyIndices
 };
-use crate::linear_algebra::{ Vertex, VERTICES, INDICES };
+use crate::linear_algebra::{ Vertex, VERTICES, INDICES, UniformBlock };
 
 use std::collections::BTreeSet;
-use std::ptr;
+use std::ptr::copy_nonoverlapping;
 use vulkanalia::{ Device, Instance };
 use vulkanalia::vk::{ self, Handle, HasBuilder, InstanceV1_0, DeviceV1_0,
                       KhrSwapchainExtensionDeviceCommands };
@@ -43,6 +43,12 @@ pub struct WindowDressing {
   index_buffer: vk::Buffer,
   index_buffer_memory: vk::DeviceMemory,
 
+  uniform_buffers: Vec<vk::Buffer>,
+  pub uniform_buffer_memory: Vec<vk::DeviceMemory>,
+
+  descriptor_pool: vk::DescriptorPool,
+  descriptor_sets: Vec<vk::DescriptorSet>,
+
   pub command_buffers: Vec<vk::CommandBuffer>,
 
   pub concurrency: Concurrency,
@@ -58,7 +64,7 @@ pub struct Swapchain {
   images: Vec<vk::Image>,
   image_views: Vec<vk::ImageView>,
   format: vk::Format,
-  extent: vk::Extent2D,
+  pub extent: vk::Extent2D,
 }
 
 #[derive(Debug)]
@@ -95,6 +101,7 @@ impl WindowDressing {
     let graphics_queue = &permanent.graphics_queue;
     let physical_device = &for_reinit.physical_device;
     let indices = &for_reinit.indices;
+    let descriptor_set_layout = &for_reinit.descriptor_set_layout;
 
     let swapchain = init_swapchain(
             window, instance, surface, &physical_device, device, &indices)?;
@@ -102,7 +109,8 @@ impl WindowDressing {
     let render_pass = init_render_pass(device, &swapchain.format)?;
 
     let (pipeline_layout, pipeline)
-            = init_pipeline(device, &swapchain.extent, &render_pass)?;
+            = init_pipeline(device, descriptor_set_layout, &swapchain.extent,
+                            &render_pass)?;
 
     let framebuffers = init_framebuffers(
             device, &swapchain.extent, &swapchain.image_views, &render_pass)?;
@@ -116,12 +124,21 @@ impl WindowDressing {
     let (index_buffer, index_buffer_memory)
             = init_index_buffer(instance, physical_device, device,
                                 graphics_queue, &transient_command_pool)?;
+    let (uniform_buffers, uniform_buffer_memory)
+            = init_uniform_buffers(instance, physical_device, device,
+                                   swapchain.images.len())?;
+
+    let descriptor_pool
+            = init_descriptor_pool(device, swapchain.images.len())?;
+    let descriptor_sets
+            = init_descriptor_sets(device, descriptor_set_layout,
+                                   &uniform_buffers, &descriptor_pool,
+                                   swapchain.images.len())?;
 
-    let command_buffers = init_commands(device, &swapchain.extent,
-                                        &framebuffers, &render_pass,
-                                        &pipeline,
-                                        &vertex_buffer, &index_buffer,
-                                        &primary_command_pool)?;
+    let command_buffers = init_commands(
+            device, &swapchain.extent, &framebuffers, &render_pass,
+            &pipeline_layout, &pipeline, &vertex_buffer, &index_buffer,
+            &descriptor_sets, &primary_command_pool)?;
 
     let concurrency = init_concurrency(device, &swapchain.images)?;
 
@@ -135,6 +152,10 @@ impl WindowDressing {
       vertex_buffer_memory,
       index_buffer,
       index_buffer_memory,
+      uniform_buffers,
+      uniform_buffer_memory,
+      descriptor_pool,
+      descriptor_sets,
       primary_command_pool,
       transient_command_pool,
       command_buffers,
@@ -154,6 +175,7 @@ impl WindowDressing {
     let device = &permanent.device;
     let physical_device = &for_reinit.physical_device;
     let indices = &for_reinit.indices;
+    let descriptor_set_layout = &for_reinit.descriptor_set_layout;
 
     unsafe { device.device_wait_idle() }.unwrap();
 
@@ -165,15 +187,30 @@ impl WindowDressing {
     let render_pass = init_render_pass(device, &swapchain.format)?;
 
     let (pipeline_layout, pipeline)
-            = init_pipeline(device, &swapchain.extent, &render_pass)?;
+            = init_pipeline(device, descriptor_set_layout, &swapchain.extent,
+                            &render_pass)?;
 
     let framebuffers = init_framebuffers(
             device, &swapchain.extent, &swapchain.image_views, &render_pass)?;
 
+    let (uniform_buffers, uniform_buffer_memory)
+            = init_uniform_buffers(instance, physical_device, device,
+                                   swapchain.images.len())?;
+
+    // Notice that we did NOT reuse the descriptor pool.
+    let descriptor_pool
+            = init_descriptor_pool(device, swapchain.images.len())?;
+
+    let descriptor_sets
+            = init_descriptor_sets(device, descriptor_set_layout,
+                                   &uniform_buffers, &descriptor_pool,
+                                   swapchain.images.len())?;
+
     // Notice that we reused the command pool.
     let command_buffers = init_commands(
             device, &swapchain.extent, &framebuffers, &render_pass,
-            &pipeline, &self.vertex_buffer, &self.index_buffer,
+            &pipeline_layout, &pipeline, &self.vertex_buffer,
+            &self.index_buffer, &descriptor_sets,
             &self.primary_command_pool)?;
 
     self.concurrency.image_fences.resize(swapchain.images.len(),
@@ -184,6 +221,10 @@ impl WindowDressing {
     self.pipeline = pipeline;
     self.pipeline_layout = pipeline_layout;
     self.framebuffers = framebuffers;
+    self.uniform_buffers = uniform_buffers;
+    self.uniform_buffer_memory = uniform_buffer_memory;
+    self.descriptor_pool = descriptor_pool;
+    self.descriptor_sets = descriptor_sets;
     self.command_buffers = command_buffers;
 
     Ok(())
@@ -236,6 +277,20 @@ impl WindowDressing {
                                   &self.command_buffers)
     };
 
+    //   While the descriptor pool is also a pool, it has a preallocated size
+    // which will be different next time. So, we destroy it all the way.
+    unsafe { device.destroy_descriptor_pool(self.descriptor_pool, None) };
+
+    //   Notice that, unlike the vertex and index buffers, we destroy and
+    // re-create these on every reinitialization. That's because the number of
+    // them depends on how many images the swapchain has.
+    for buffer in &self.uniform_buffers {
+      unsafe { device.destroy_buffer(*buffer, None) };
+    }
+    for memory in &self.uniform_buffer_memory {
+      unsafe { device.free_memory(*memory, None) };
+    }
+
     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) };
@@ -402,8 +457,9 @@ fn init_render_pass(device: &Device, format: &vk::Format)
 
 
 #[allow(unsafe_code)]
-fn init_pipeline(device: &Device, extent: &vk::Extent2D,
-                 render_pass: &vk::RenderPass)
+fn init_pipeline(device: &Device,
+                 descriptor_set_layout: &vk::DescriptorSetLayout,
+                 extent: &vk::Extent2D, render_pass: &vk::RenderPass)
     -> Result<(vk::PipelineLayout, vk::Pipeline)>
 {
   let vertex_binary = include_bytes!(
@@ -489,7 +545,9 @@ fn init_pipeline(device: &Device, extent: &vk::Extent2D,
                        .attachments(&blend_attachments)
                        .blend_constants([0.0, 0.0, 0.0, 0.0]);
 
-  let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder();
+  let layouts = [*descriptor_set_layout];
+  let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder()
+                                 .set_layouts(&layouts);
 
   let pipeline_layout = unsafe {
     device.create_pipeline_layout(&pipeline_layout_info, None)
@@ -571,6 +629,28 @@ fn init_index_buffer(instance: &Instance,
               vk::BufferUsageFlags::INDEX_BUFFER, INDICES)
 }
 
+fn init_uniform_buffers(instance: &Instance,
+                        physical_device: &vk::PhysicalDevice, device: &Device,
+                        count: usize)
+    -> Result<(Vec<vk::Buffer>, Vec<vk::DeviceMemory>)>
+{
+  let mut buffers = Vec::new();
+  let mut all_memory = Vec::new();
+
+  for _ in 0 .. count {
+    let (buffer, memory) = allocate_buffer(
+            instance, physical_device, device,
+            size_of::<UniformBlock<f32>>() as u64,
+            vk::BufferUsageFlags::UNIFORM_BUFFER,
+            vk::MemoryPropertyFlags::HOST_COHERENT
+            | vk::MemoryPropertyFlags::HOST_VISIBLE)?;
+    buffers.push(buffer);
+    all_memory.push(memory);
+  }
+
+  Ok((buffers, all_memory))
+}
+
 
 #[allow(unsafe_code)]
 fn init_buffer<T>(instance: &Instance,
@@ -593,8 +673,7 @@ fn init_buffer<T>(instance: &Instance,
   }?;
 
   unsafe {
-    ptr::copy_nonoverlapping(
-        contents.as_ptr(), host_memory.cast(), contents.len())
+    copy_nonoverlapping(contents.as_ptr(), host_memory.cast(), contents.len())
   };
 
   unsafe { device.unmap_memory(staging_memory) };
@@ -616,6 +695,61 @@ fn init_buffer<T>(instance: &Instance,
 
 
 #[allow(unsafe_code)]
+fn init_descriptor_pool(device: &Device, count: usize)
+    -> Result<vk::DescriptorPool>
+{
+  let uniform_block_size = vk::DescriptorPoolSize::builder()
+          .type_(vk::DescriptorType::UNIFORM_BUFFER)
+          .descriptor_count(count as u32);
+
+  let sizes = [uniform_block_size];
+  let pool_info = vk::DescriptorPoolCreateInfo::builder()
+          .pool_sizes(&sizes)
+          .max_sets(count as u32);
+  let pool = unsafe { device.create_descriptor_pool(&pool_info, None) }?;
+
+  Ok(pool)
+}
+
+
+#[allow(unsafe_code)]
+fn init_descriptor_sets(device: &Device, layout: &vk::DescriptorSetLayout,
+                        buffers: &Vec<vk::Buffer>, pool: &vk::DescriptorPool,
+                        count: usize)
+    -> Result<Vec<vk::DescriptorSet>>
+{
+  let layouts = vec![*layout; count];
+  let set_info = vk::DescriptorSetAllocateInfo::builder()
+          .descriptor_pool(*pool)
+          .set_layouts(&layouts);
+  let sets = unsafe { device.allocate_descriptor_sets(&set_info) }?;
+
+  for index in 0 .. count {
+    let buffer_info = vk::DescriptorBufferInfo::builder()
+            .buffer(buffers[index])
+            .offset(0)
+            .range(size_of::<UniformBlock<f32>>() as u64);
+
+    let buffer_info_list = [buffer_info];
+    let descriptor_write_info = vk::WriteDescriptorSet::builder()
+            .dst_set(sets[index])
+            .dst_binding(0)
+            .dst_array_element(0)
+            .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
+            .buffer_info(&buffer_info_list);
+    let write_info_list = [descriptor_write_info];
+    let copy_info_list: [vk::CopyDescriptorSet; 0] = [];
+
+    unsafe {
+      device.update_descriptor_sets(&write_info_list, &copy_info_list)
+    };
+  }
+
+  Ok(sets)
+}
+
+
+#[allow(unsafe_code)]
 fn init_command_pools(device: &Device, indices: &QueueFamilyIndices)
     -> Result<(vk::CommandPool, vk::CommandPool)>
 {
@@ -641,9 +775,11 @@ fn init_commands(device: &Device,
                  extent: &vk::Extent2D,
                  framebuffers: &Vec<vk::Framebuffer>,
                  render_pass: &vk::RenderPass,
+                 pipeline_layout: &vk::PipelineLayout,
                  pipeline: &vk::Pipeline,
                  vertex_buffer: &vk::Buffer,
                  index_buffer: &vk::Buffer,
+                 descriptor_sets: &Vec<vk::DescriptorSet>,
                  command_pool: &vk::CommandPool)
     -> Result<Vec<vk::CommandBuffer>>
 {
@@ -708,6 +844,15 @@ fn init_commands(device: &Device,
     };
 
     unsafe {
+      device.cmd_bind_descriptor_sets(command_buffer,
+                                      vk::PipelineBindPoint::GRAPHICS,
+                                      *pipeline_layout,
+                                      0,
+                                      &[descriptor_sets[index]],
+                                      &[])
+    };
+
+    unsafe {
       device.cmd_draw_indexed(command_buffer, INDICES.len() as u32,
                               1, 0, 0, 0)
     };