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.rs148
1 files changed, 117 insertions, 31 deletions
diff --git a/src/graphics_window_dressing.rs b/src/graphics_window_dressing.rs
index eb08d53..f949af0 100644
--- a/src/graphics_window_dressing.rs
+++ b/src/graphics_window_dressing.rs
@@ -34,10 +34,12 @@ pub struct WindowDressing {
 
   framebuffers: Vec<vk::Framebuffer>,
 
+  primary_command_pool: vk::CommandPool,
+  transient_command_pool: vk::CommandPool,
+
   vertex_buffer: vk::Buffer,
   vertex_buffer_memory: vk::DeviceMemory,
 
-  command_pool: vk::CommandPool,
   pub command_buffers: Vec<vk::CommandBuffer>,
 
   pub concurrency: Concurrency,
@@ -87,6 +89,7 @@ impl WindowDressing {
     let instance = &permanent.instance;
     let surface = &permanent.surface;
     let device = &permanent.device;
+    let graphics_queue = &permanent.graphics_queue;
     let physical_device = &for_reinit.physical_device;
     let indices = &for_reinit.indices;
 
@@ -101,14 +104,17 @@ impl WindowDressing {
     let framebuffers = init_framebuffers(
             device, &swapchain.extent, &swapchain.image_views, &render_pass)?;
 
+    let (primary_command_pool, transient_command_pool)
+            = init_command_pools(device, indices)?;
+
     let (vertex_buffer, vertex_buffer_memory)
-            = init_vertex_buffer(instance, physical_device, device)?;
+            = init_vertex_buffer(instance, physical_device, device,
+                                 graphics_queue, &transient_command_pool)?;
 
-    let command_pool = init_command_pool(device, indices)?;
     let command_buffers = init_commands(device, &swapchain.extent,
                                         &framebuffers, &render_pass,
                                         &pipeline, &vertex_buffer,
-                                        &command_pool)?;
+                                        &primary_command_pool)?;
 
     let concurrency = init_concurrency(device, &swapchain.images)?;
 
@@ -120,7 +126,8 @@ impl WindowDressing {
       framebuffers,
       vertex_buffer,
       vertex_buffer_memory,
-      command_pool,
+      primary_command_pool,
+      transient_command_pool,
       command_buffers,
       concurrency,
     })
@@ -157,7 +164,7 @@ impl WindowDressing {
     // Notice that we reused the command pool.
     let command_buffers = init_commands(
             device, &swapchain.extent, &framebuffers, &render_pass,
-            &pipeline, &self.vertex_buffer, &self.command_pool)?;
+            &pipeline, &self.vertex_buffer, &self.primary_command_pool)?;
 
     self.concurrency.image_fences.resize(swapchain.images.len(),
                                          vk::Fence::null());
@@ -194,8 +201,10 @@ impl WindowDressing {
       unsafe { device.destroy_fence(fence, None) };
     }
 
-    // Notice that destroy_replaceable freed the pool, but did not destroy it.
-    unsafe { device.destroy_command_pool(self.command_pool, None) };
+    //   Notice that destroy_replaceable() freed the buffers in the pools, but
+    // did not destroy the pools.
+    unsafe { device.destroy_command_pool(self.primary_command_pool, None) };
+    unsafe { device.destroy_command_pool(self.transient_command_pool, None) };
   }
 
 
@@ -205,9 +214,14 @@ impl WindowDressing {
       unsafe { device.destroy_framebuffer(*framebuffer, None) };
     }
 
-    // Notice that we free the pool, but do not destroy it.
+    //   Notice that we free the buffers in the pool, but do not destroy the
+    // pool itself. Notice also that we only do this for the primary command
+    // pool, because that's the only one where we've kept track of the
+    // buffers. We promise ourselves to free buffers in the transient pool
+    // immediately after using them.
     unsafe {
-      device.free_command_buffers(self.command_pool, &self.command_buffers)
+      device.free_command_buffers(self.primary_command_pool,
+                                  &self.command_buffers)
     };
 
     unsafe { device.destroy_pipeline(self.pipeline, None) };
@@ -528,28 +542,44 @@ fn init_framebuffers(device: &Device, extent: &vk::Extent2D,
 
 #[allow(unsafe_code)]
 fn init_vertex_buffer(instance: &Instance,
-                      physical_device: &vk::PhysicalDevice, device: &Device)
+                      physical_device: &vk::PhysicalDevice, device: &Device,
+                      queue: &vk::Queue, command_pool: &vk::CommandPool)
     -> Result<(vk::Buffer, vk::DeviceMemory)>
 {
   let size = (size_of::<Vertex<f32>>() * VERTICES.len()) as u64;
-  let usage = vk::BufferUsageFlags::VERTEX_BUFFER;
-  let memory_flags = vk::MemoryPropertyFlags::HOST_COHERENT
-                     | vk::MemoryPropertyFlags::HOST_VISIBLE;
-  let (buffer, device_memory) = init_buffer(instance, physical_device, device,
-                                            size, usage, memory_flags)?;
+
+  let staging_usage = vk::BufferUsageFlags::TRANSFER_SRC;
+  let staging_memory_flags = vk::MemoryPropertyFlags::HOST_COHERENT
+                             | vk::MemoryPropertyFlags::HOST_VISIBLE;
+  let (staging_buffer, staging_memory)
+          = init_buffer(instance, physical_device, device,
+                        size, staging_usage, staging_memory_flags)?;
 
   let host_memory = unsafe {
-    device.map_memory(device_memory, 0, size, vk::MemoryMapFlags::empty())
+    device.map_memory(staging_memory, 0, size, vk::MemoryMapFlags::empty())
   }?;
 
   unsafe {
-    ptr::copy_nonoverlapping(VERTICES.as_ptr(), host_memory.cast(),
-                             VERTICES.len())
+    ptr::copy_nonoverlapping(
+        VERTICES.as_ptr(), host_memory.cast(), VERTICES.len())
   };
 
-  unsafe { device.unmap_memory(device_memory) };
+  unsafe { device.unmap_memory(staging_memory) };
 
-  Ok((buffer, device_memory))
+  let final_usage = vk::BufferUsageFlags::TRANSFER_DST
+                    | vk::BufferUsageFlags::VERTEX_BUFFER;
+  let final_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL;
+  let (final_buffer, device_memory)
+          = init_buffer(instance, physical_device, device,
+                        size, final_usage, final_memory_flags)?;
+
+  copy_buffer(device, queue, command_pool,
+              &staging_buffer, &final_buffer, size)?;
+
+  unsafe { device.destroy_buffer(staging_buffer, None) };
+  unsafe { device.free_memory(staging_memory, None) };
+
+  Ok((final_buffer, device_memory))
 }
 
 
@@ -590,16 +620,23 @@ fn init_buffer(instance: &Instance,
 
 
 #[allow(unsafe_code)]
-fn init_command_pool(device: &Device, indices: &QueueFamilyIndices)
-    -> Result<vk::CommandPool>
+fn init_command_pools(device: &Device, indices: &QueueFamilyIndices)
+    -> Result<(vk::CommandPool, vk::CommandPool)>
 {
   let command_pool_info = vk::CommandPoolCreateInfo::builder()
                               .flags(vk::CommandPoolCreateFlags::empty())
                               .queue_family_index(indices.graphics);
 
-  Ok(unsafe {
+  let primary = unsafe {
     device.create_command_pool(&command_pool_info, None)
-  }?)
+  }?;
+
+  command_pool_info.flags(vk::CommandPoolCreateFlags::TRANSIENT);
+  let transient = unsafe {
+    device.create_command_pool(&command_pool_info, None)
+  }?;
+
+  Ok((primary, transient))
 }
 
 
@@ -627,14 +664,12 @@ fn init_commands(device: &Device,
 
     let inheritance_info = vk::CommandBufferInheritanceInfo::builder();
 
-    let command_buffer_begin_info
-            = vk::CommandBufferBeginInfo::builder()
-                  .flags(vk::CommandBufferUsageFlags::empty())
-                  .inheritance_info(&inheritance_info);
+    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)
+      device.begin_command_buffer(command_buffer, &command_buffer_begin_info)
     }?;
 
     let render_area = vk::Rect2D::builder()
@@ -801,3 +836,54 @@ fn pick_memory_type(instance: &Instance,
   })
 }
 
+
+#[allow(unsafe_code)]
+fn copy_buffer(device: &Device, queue: &vk::Queue,
+               command_pool: &vk::CommandPool,
+               source: &vk::Buffer, destination: &vk::Buffer,
+               size: vk::DeviceSize)
+    -> Result<()>
+{
+  let command_buffer_allocation_info
+          = vk::CommandBufferAllocateInfo::builder()
+                .command_pool(*command_pool)
+                .level(vk::CommandBufferLevel::PRIMARY)
+                .command_buffer_count(1);
+  let command_buffer = unsafe {
+    device.allocate_command_buffers(&command_buffer_allocation_info)
+  }?[0];
+
+  let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder()
+          .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
+
+  unsafe {
+    device.begin_command_buffer(command_buffer, &command_buffer_begin_info)
+  }?;
+
+  let copy_info = vk::BufferCopy::builder().size(size);
+  unsafe {
+    device.cmd_copy_buffer(command_buffer, *source, *destination,
+                           &[copy_info])
+  };
+
+  unsafe { device.end_command_buffer(command_buffer) }?;
+
+  let command_buffers = [command_buffer];
+
+  let submit_info = vk::SubmitInfo::builder()
+          .command_buffers(&command_buffers);
+  unsafe {
+    device.queue_submit(*queue, &[submit_info], vk::Fence::null())
+  }?;
+
+  unsafe {
+    device.queue_wait_idle(*queue)
+  }?;
+
+  unsafe {
+    device.free_command_buffers(*command_pool, &command_buffers)
+  };
+
+  Ok(())
+}
+