summary refs log tree commit diff
path: root/src/graphics/util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics/util.rs')
-rw-r--r--src/graphics/util.rs173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/graphics/util.rs b/src/graphics/util.rs
new file mode 100644
index 0000000..2debc4e
--- /dev/null
+++ b/src/graphics/util.rs
@@ -0,0 +1,173 @@
+#![allow(unsafe_code)]
+use crate::error::*;
+
+use std::mem::size_of;
+use std::ptr::copy_nonoverlapping;
+
+use vulkanalia::{ Device, Instance };
+use vulkanalia::vk::{ self, Handle, HasBuilder, InstanceV1_0, DeviceV1_0 };
+
+
+pub fn stage_in_buffer<T>(instance: &Instance,
+                          physical_device: &vk::PhysicalDevice,
+                          device: &Device, contents: &[T])
+    -> Result<(vk::Buffer, vk::DeviceMemory, usize)>
+{
+  let size = size_of::<T>() * contents.len();
+
+  let staging_usage = vk::BufferUsageFlags::TRANSFER_SRC;
+  let staging_memory_flags = vk::MemoryPropertyFlags::HOST_COHERENT
+                             | vk::MemoryPropertyFlags::HOST_VISIBLE;
+  let (staging_buffer, staging_memory)
+          = allocate_buffer(instance, physical_device, device,
+                            size as vk::DeviceSize, staging_usage,
+                            staging_memory_flags)?;
+
+  let host_memory = unsafe {
+    device.map_memory(staging_memory, 0, size as vk::DeviceSize,
+                      vk::MemoryMapFlags::empty())
+  }?;
+
+  unsafe {
+    copy_nonoverlapping(contents.as_ptr(), host_memory.cast(), contents.len())
+  };
+
+  unsafe { device.unmap_memory(staging_memory) };
+
+  Ok((staging_buffer, staging_memory, size))
+}
+
+
+#[allow(unsafe_code)]
+pub fn allocate_buffer(instance: &Instance,
+                       physical_device: &vk::PhysicalDevice, device: &Device,
+                       size: vk::DeviceSize, usage: vk::BufferUsageFlags,
+                       memory_flags: vk::MemoryPropertyFlags)
+    -> Result<(vk::Buffer, vk::DeviceMemory)>
+{
+  let buffer_info = vk::BufferCreateInfo::builder()
+                        .size(size)
+                        .usage(usage)
+                        .sharing_mode(vk::SharingMode::EXCLUSIVE);
+
+  let buffer = unsafe { device.create_buffer(&buffer_info, None) }?;
+
+  //   The requirements are mostly what you'd think: size and alignment. The
+  // bits field is something special; see pick_memory_type() for the
+  // explanation. Despite the simplicity of this data, Vulkan wants to be the
+  // one to tell us about it, and we let it.
+  let requirements = unsafe { device.get_buffer_memory_requirements(buffer) };
+
+  let type_index = pick_memory_type(instance, physical_device,
+                                    &memory_flags, &requirements)?;
+
+  let memory_info = vk::MemoryAllocateInfo::builder()
+          .allocation_size(requirements.size)
+          .memory_type_index(type_index);
+
+  let device_memory = unsafe { device.allocate_memory(&memory_info, None) }?;
+
+  unsafe { device.bind_buffer_memory(buffer, device_memory, 0) }?;
+
+  Ok((buffer, device_memory))
+}
+
+
+#[allow(unsafe_code)]
+pub 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 = begin_transient_commands(device, command_pool)?;
+
+  let copy_info = vk::BufferCopy::builder().size(size);
+  unsafe {
+    device.cmd_copy_buffer(command_buffer, *source, *destination,
+                           &[copy_info])
+  };
+
+  end_transient_commands(command_buffer, device, queue, command_pool)?;
+
+  Ok(())
+}
+
+
+#[allow(unsafe_code)]
+pub fn pick_memory_type(instance: &Instance,
+                        physical_device: &vk::PhysicalDevice,
+                        properties: &vk::MemoryPropertyFlags,
+                        requirements: &vk::MemoryRequirements)
+    -> Result<u32>
+{
+  let memory_map = unsafe {
+    instance.get_physical_device_memory_properties(*physical_device)
+  };
+
+  //   So. The memory_type_bits field is a map of which indices are suitable,
+  // based on the buffer our caller passed to
+  // get_buffer_memory_requirements(). Yes, that means there's a hard cap on
+  // how many memory types there can be, based on the size of the bitfield.
+  for index in 0 .. memory_map.memory_type_count {
+    if requirements.memory_type_bits & (1 << index) == 0 {
+      continue;
+    }
+
+    let memory_type = memory_map.memory_types[index as usize];
+
+    if memory_type.property_flags.contains(*properties) {
+      return Ok(index);
+    }
+  }
+
+  Err(Error {
+    message: "The system has no suitable memory for a buffer.".to_string()
+  })
+}
+
+
+#[allow(unsafe_code)]
+pub fn begin_transient_commands(device: &Device,
+                                command_pool: &vk::CommandPool)
+    -> Result<vk::CommandBuffer>
+{
+  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)
+  }?;
+
+  Ok(command_buffer)
+}
+
+
+#[allow(unsafe_code)]
+pub fn end_transient_commands(command_buffer: vk::CommandBuffer,
+                              device: &Device, queue: &vk::Queue,
+                              command_pool: &vk::CommandPool)
+    -> Result<()>
+{
+  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(())
+}
+