use std::sync::Arc;
use vulkano::{
command_buffer::{
allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo},
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferUsage,
PrimaryAutoCommandBuffer,
},
device::{Device, DeviceCreateInfo, Queue, QueueCreateInfo, QueueFlags},
format::Format,
image::{Image, ImageCreateInfo, ImageType, ImageUsage},
instance::{Instance, InstanceCreateInfo},
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
sync::{
self,
future::{FenceSignalFuture, NowFuture},
GpuFuture,
},
VulkanLibrary,
};
pub(crate) struct VulkanContext {
device: Arc<Device>,
memory_allocator: Arc<StandardMemoryAllocator>,
command_buffer_allocator: StandardCommandBufferAllocator,
graphics_queue: Arc<Queue>,
gpu_fence: Option<FenceSignalFuture<CommandBufferExecFuture<NowFuture>>>,
}
impl VulkanContext {
pub fn new() -> Self {
let library = VulkanLibrary::new().expect("no local Vulkan library/DLL");
let instance = Instance::new(library, InstanceCreateInfo::default())
.expect("failed to create instance");
let physical_device = instance
.enumerate_physical_devices()
.expect("could not enumerate devices")
.next()
.expect("no devices available");
let queue_family_index = physical_device
.queue_family_properties()
.iter()
.enumerate()
.position(|(_, q)| q.queue_flags.contains(QueueFlags::GRAPHICS))
.expect("couldn't find a graphical queue family")
as u32;
let (device, mut queues) = Device::new(
physical_device,
DeviceCreateInfo {
queue_create_infos: vec![QueueCreateInfo {
queue_family_index,
..Default::default()
}],
..Default::default()
},
)
.expect("failed to create device");
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
let command_buffer_allocator = StandardCommandBufferAllocator::new(
device.clone(),
StandardCommandBufferAllocatorCreateInfo::default(),
);
let graphics_queue = queues.next().unwrap();
Self {
device,
memory_allocator,
command_buffer_allocator,
graphics_queue,
gpu_fence: None,
}
}
pub fn device(&self) -> Arc<Device> {
self.device.clone()
}
pub fn memory_allocator(&self) -> Arc<StandardMemoryAllocator> {
self.memory_allocator.clone()
}
pub fn command_builder(
&self,
) -> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<StandardCommandBufferAllocator>> {
let builder = AutoCommandBufferBuilder::primary(
&self.command_buffer_allocator,
self.graphics_queue.queue_family_index(),
CommandBufferUsage::OneTimeSubmit,
)
.unwrap();
builder
}
pub fn run_command_buffer(&mut self, command_buffer: Arc<PrimaryAutoCommandBuffer>) -> () {
self.wait_gpu();
let fence = sync::now(self.device())
.then_execute(self.graphics_queue.clone(), command_buffer)
.unwrap()
.then_signal_fence_and_flush()
.unwrap();
self.gpu_fence.replace(fence);
}
pub fn wait_gpu(&mut self) {
if self.gpu_fence.is_some() {
let fence = self.gpu_fence.take().unwrap();
fence.wait(None).expect("waiting for GPU failed");
}
}
pub fn new_framebuffer(&self, width: u32, height: u32) -> Arc<Image> {
Image::new(
self.memory_allocator(),
ImageCreateInfo {
image_type: ImageType::Dim2d,
format: Format::R32G32B32A32_SFLOAT,
extent: [width, height, 1],
usage: ImageUsage::COLOR_ATTACHMENT | ImageUsage::TRANSFER_SRC,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE,
..Default::default()
},
)
.unwrap()
}
}