Use Arc to store reference and store dependencies for each vulkan types
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 0s
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 0s
Arc it's used because later, i can use on multi-threaded programs
This commit is contained in:
parent
1cb9309a56
commit
174e12591c
5 changed files with 290 additions and 320 deletions
|
@ -1,15 +1,18 @@
|
|||
use crate::vulkan::{VkInstance, VkPhysicalDevice};
|
||||
use std::sync::Arc;
|
||||
use crate::vulkan::{VkInstance, VkPhysicalDevice, LOG_TARGET};
|
||||
use ash::prelude::VkResult;
|
||||
use ash::vk;
|
||||
|
||||
pub struct VkDevice {
|
||||
instance: Arc<VkInstance>,
|
||||
pub(super) handle: ash::Device,
|
||||
pub(super) swapchain_loader: ash::khr::swapchain::Device,
|
||||
queue_family_index: u32,
|
||||
}
|
||||
|
||||
impl VkDevice {
|
||||
pub(super) fn new_graphics_device(
|
||||
instance: &VkInstance,
|
||||
instance: Arc<VkInstance>,
|
||||
physical_device: &VkPhysicalDevice,
|
||||
queue_family_index: u32,
|
||||
) -> anyhow::Result<Self> {
|
||||
|
@ -33,11 +36,17 @@ impl VkDevice {
|
|||
.enabled_extension_names(&device_extension_names_raw)
|
||||
.enabled_features(&features);
|
||||
|
||||
let device = instance
|
||||
.create_device(physical_device, &device_create_info, None)?;
|
||||
let device = unsafe {
|
||||
instance.handle.create_device(physical_device.handle, &device_create_info, None)?
|
||||
};
|
||||
log::debug!(target: LOG_TARGET, "Device created ({:?})", device.handle());
|
||||
|
||||
let swapchain_loader = ash::khr::swapchain::Device::new(&instance.handle, &device);
|
||||
|
||||
Ok(Self {
|
||||
instance,
|
||||
handle: device,
|
||||
swapchain_loader,
|
||||
queue_family_index,
|
||||
})
|
||||
}
|
||||
|
@ -93,6 +102,7 @@ impl Drop for VkDevice {
|
|||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.handle.destroy_device(None);
|
||||
log::debug!(target: LOG_TARGET, "Device destroyed ({:?})", self.handle.handle());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
|||
pub struct VkInstance {
|
||||
pub(super) entry: Entry,
|
||||
pub(super) handle: Instance,
|
||||
pub(super) surface_loader: surface::Instance,
|
||||
}
|
||||
|
||||
impl VkInstance {
|
||||
|
@ -79,11 +80,14 @@ impl VkInstance {
|
|||
.expect("Instance creation error")
|
||||
};
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Vulkan instance created");
|
||||
let surface_loader = surface::Instance::new(&entry, &instance);
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Vulkan instance created ({:?})", instance.handle());
|
||||
|
||||
Self {
|
||||
entry,
|
||||
handle: instance,
|
||||
surface_loader
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,52 +98,12 @@ impl VkInstance {
|
|||
.iter().map(|physical_device| VkPhysicalDevice::new(&self.handle, *physical_device))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn create_surface(
|
||||
&self,
|
||||
window: &crate::display::Window,
|
||||
) -> anyhow::Result<VkSurface> {
|
||||
let window_handle = window.handle()
|
||||
.ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?;
|
||||
|
||||
let surface_loader = surface::Instance::new(&self.entry, &self.handle);
|
||||
|
||||
let surface = unsafe {
|
||||
ash_window::create_surface(
|
||||
&self.entry,
|
||||
&self.handle,
|
||||
window_handle.display_handle()?.as_raw(),
|
||||
window_handle.window_handle()?.as_raw(),
|
||||
None,
|
||||
)?
|
||||
};
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Surface created");
|
||||
|
||||
Ok(VkSurface::new(
|
||||
surface_loader,
|
||||
surface,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_device(
|
||||
&self,
|
||||
physical_device: &VkPhysicalDevice,
|
||||
create_info: &vk::DeviceCreateInfo,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> VkResult<ash::Device> {
|
||||
unsafe {
|
||||
self.handle.create_device(physical_device.handle, &create_info, allocation_callbacks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VkInstance {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.handle.destroy_instance(None);
|
||||
}
|
||||
log::debug!(target: LOG_TARGET, "Vulkan instance destroyed");
|
||||
unsafe { self.handle.destroy_instance(None); }
|
||||
log::debug!(target: LOG_TARGET, "Vulkan instance destroyed ({:?})", self.handle.handle());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
use std::sync::Arc;
|
||||
use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSurface, VkSwapchain};
|
||||
use ash::vk;
|
||||
use ash::vk::QueueFlags;
|
||||
|
||||
pub struct VkRenderContext {
|
||||
instance: VkInstance,
|
||||
surface: VkSurface,
|
||||
device: VkDevice,
|
||||
instance: Arc<VkInstance>,
|
||||
surface: Arc<VkSurface>,
|
||||
device: Arc<VkDevice>,
|
||||
|
||||
swapchain: VkSwapchain,
|
||||
present_images: Vec<vk::Image>,
|
||||
present_image_views: Vec<vk::ImageView>,
|
||||
swapchain: Arc<VkSwapchain>,
|
||||
|
||||
present_queue: vk::Queue,
|
||||
|
||||
pool: vk::CommandPool,
|
||||
|
||||
setup_command_buffer: vk::CommandBuffer,
|
||||
draw_command_buffer: vk::CommandBuffer,
|
||||
|
||||
draw_commands_reuse_fence: vk::Fence,
|
||||
setup_commands_reuse_fence: vk::Fence,
|
||||
|
||||
present_complete_semaphore: vk::Semaphore,
|
||||
rendering_complete_semaphore: vk::Semaphore,
|
||||
// present_queue: vk::Queue,
|
||||
//
|
||||
// pool: vk::CommandPool,
|
||||
//
|
||||
// setup_command_buffer: vk::CommandBuffer,
|
||||
// draw_command_buffer: vk::CommandBuffer,
|
||||
//
|
||||
// draw_commands_reuse_fence: vk::Fence,
|
||||
// setup_commands_reuse_fence: vk::Fence,
|
||||
//
|
||||
// present_complete_semaphore: vk::Semaphore,
|
||||
// rendering_complete_semaphore: vk::Semaphore,
|
||||
}
|
||||
|
||||
impl VkRenderContext {
|
||||
|
@ -30,75 +28,67 @@ impl VkRenderContext {
|
|||
let required_extensions = window
|
||||
.required_extensions()?;
|
||||
|
||||
let instance = VkInstance::new(&required_extensions);
|
||||
let surface = instance.create_surface(&window)?;
|
||||
let instance = Arc::new(VkInstance::new(&required_extensions));
|
||||
let surface = Arc::new(VkSurface::new(
|
||||
&window,
|
||||
instance.clone()
|
||||
)?);
|
||||
|
||||
let mut physical_devices = instance.get_physical_devices();
|
||||
physical_devices.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
||||
|
||||
let (physical_device, queue_family_index, _) = VkPhysicalDevice::pick_physical_device_and_queue_by(
|
||||
&physical_devices,
|
||||
Some(QueueFlags::GRAPHICS),
|
||||
Some(vk::QueueFlags::GRAPHICS),
|
||||
Some(&surface),
|
||||
).expect("Unable to find physical device");
|
||||
).ok_or_else(|| anyhow::anyhow!("Unable to find physical device"))?;
|
||||
|
||||
let device = VkDevice::new_graphics_device(&instance, &physical_device, queue_family_index)
|
||||
.expect("Unable to create device");
|
||||
|
||||
let swapchain = surface.create_swapchain(
|
||||
let device = Arc::new(VkDevice::new_graphics_device(instance.clone(), &physical_device, queue_family_index)?);
|
||||
|
||||
let swapchain = Arc::new(VkSwapchain::new(
|
||||
&window,
|
||||
&instance,
|
||||
&device,
|
||||
&physical_device,
|
||||
).expect("Unable to create swapchain");
|
||||
surface.clone(),
|
||||
device.clone(),
|
||||
&physical_device
|
||||
)?);
|
||||
|
||||
let present_images = swapchain.get_swapchain_images()
|
||||
.expect("Failed to get present images");
|
||||
let present_image_views = present_images
|
||||
.iter()
|
||||
.map(|i| {
|
||||
device.create_image_view(*i, swapchain.surface_format)
|
||||
.expect("Failed to create image view")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let present_queue = device.get_device_queue(0);
|
||||
|
||||
let pool_create_info = vk::CommandPoolCreateInfo::default()
|
||||
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER);
|
||||
|
||||
let pool = device.create_command_pool(&pool_create_info)
|
||||
.expect("Failed to create command pool");
|
||||
|
||||
let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::default()
|
||||
.command_buffer_count(2)
|
||||
.command_pool(pool)
|
||||
.level(vk::CommandBufferLevel::PRIMARY);
|
||||
|
||||
let command_buffers = device
|
||||
.allocate_command_buffers(&command_buffer_allocate_info)
|
||||
.expect("Failed to create command buffers");
|
||||
let setup_command_buffer = command_buffers[0];
|
||||
let draw_command_buffer = command_buffers[1];
|
||||
|
||||
let fence_create_info =
|
||||
vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED);
|
||||
|
||||
let draw_commands_reuse_fence = device
|
||||
.create_fence(&fence_create_info)
|
||||
.expect("Failed to create draw commands fence");
|
||||
let setup_commands_reuse_fence = device
|
||||
.create_fence(&fence_create_info)
|
||||
.expect("Failed to create setup commands fence");
|
||||
|
||||
let semaphore_create_info = vk::SemaphoreCreateInfo::default();
|
||||
|
||||
let present_complete_semaphore = device
|
||||
.create_semaphore(&semaphore_create_info)
|
||||
.expect("Failed to create present complete semaphore");
|
||||
let rendering_complete_semaphore = device
|
||||
.create_semaphore(&semaphore_create_info)
|
||||
.expect("Failed to create rendering complete semaphore");
|
||||
// let present_queue = device.get_device_queue(0);
|
||||
//
|
||||
// let pool_create_info = vk::CommandPoolCreateInfo::default()
|
||||
// .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER);
|
||||
//
|
||||
// let pool = device.create_command_pool(&pool_create_info)
|
||||
// .expect("Failed to create command pool");
|
||||
//
|
||||
// let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::default()
|
||||
// .command_buffer_count(2)
|
||||
// .command_pool(pool)
|
||||
// .level(vk::CommandBufferLevel::PRIMARY);
|
||||
//
|
||||
// let command_buffers = device
|
||||
// .allocate_command_buffers(&command_buffer_allocate_info)
|
||||
// .expect("Failed to create command buffers");
|
||||
// let setup_command_buffer = command_buffers[0];
|
||||
// let draw_command_buffer = command_buffers[1];
|
||||
//
|
||||
// let fence_create_info =
|
||||
// vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED);
|
||||
//
|
||||
// let draw_commands_reuse_fence = device
|
||||
// .create_fence(&fence_create_info)
|
||||
// .expect("Failed to create draw commands fence");
|
||||
// let setup_commands_reuse_fence = device
|
||||
// .create_fence(&fence_create_info)
|
||||
// .expect("Failed to create setup commands fence");
|
||||
//
|
||||
// let semaphore_create_info = vk::SemaphoreCreateInfo::default();
|
||||
//
|
||||
// let present_complete_semaphore = device
|
||||
// .create_semaphore(&semaphore_create_info)
|
||||
// .expect("Failed to create present complete semaphore");
|
||||
// let rendering_complete_semaphore = device
|
||||
// .create_semaphore(&semaphore_create_info)
|
||||
// .expect("Failed to create rendering complete semaphore");
|
||||
|
||||
Ok(Self {
|
||||
instance,
|
||||
|
@ -106,72 +96,72 @@ impl VkRenderContext {
|
|||
device,
|
||||
|
||||
swapchain,
|
||||
present_images,
|
||||
present_image_views,
|
||||
|
||||
present_queue,
|
||||
|
||||
pool,
|
||||
|
||||
setup_command_buffer,
|
||||
draw_command_buffer,
|
||||
|
||||
present_complete_semaphore,
|
||||
rendering_complete_semaphore,
|
||||
|
||||
draw_commands_reuse_fence,
|
||||
setup_commands_reuse_fence,
|
||||
// present_queue,
|
||||
//
|
||||
// pool,
|
||||
//
|
||||
// setup_command_buffer,
|
||||
// draw_command_buffer,
|
||||
//
|
||||
// present_complete_semaphore,
|
||||
// rendering_complete_semaphore,
|
||||
//
|
||||
// draw_commands_reuse_fence,
|
||||
// setup_commands_reuse_fence,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render(&mut self) -> anyhow::Result<()> {
|
||||
unsafe {
|
||||
self.device.handle
|
||||
.wait_for_fences(&[self.draw_commands_reuse_fence], true, u64::MAX)
|
||||
.expect("Wait for fence failed.");
|
||||
|
||||
self.device.handle
|
||||
.reset_fences(&[self.draw_commands_reuse_fence])
|
||||
.expect("Reset fences failed.");
|
||||
|
||||
self.device.handle
|
||||
.reset_command_buffer(
|
||||
self.draw_command_buffer,
|
||||
vk::CommandBufferResetFlags::RELEASE_RESOURCES,
|
||||
)
|
||||
.expect("Reset command buffer failed.");
|
||||
|
||||
let command_buffer_begin_info = vk::CommandBufferBeginInfo::default()
|
||||
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||
|
||||
self.device.handle
|
||||
.begin_command_buffer(self.draw_command_buffer, &command_buffer_begin_info)
|
||||
.expect("Begin commandbuffer");
|
||||
|
||||
self.device.handle
|
||||
.end_command_buffer(self.draw_command_buffer)
|
||||
.expect("End commandbuffer");
|
||||
|
||||
let command_buffers = vec![self.draw_command_buffer];
|
||||
let semaphores = vec![self.rendering_complete_semaphore];
|
||||
let wait_mask = vec![vk::PipelineStageFlags::default()];
|
||||
|
||||
let submit_info = vk::SubmitInfo::default()
|
||||
.wait_semaphores(&semaphores)
|
||||
.wait_dst_stage_mask(&wait_mask)
|
||||
.command_buffers(&command_buffers)
|
||||
.signal_semaphores(&semaphores);
|
||||
|
||||
self.device.handle
|
||||
.queue_submit(self.present_queue, &[submit_info], self.draw_commands_reuse_fence)
|
||||
.expect("queue submit failed.");
|
||||
}
|
||||
// unsafe {
|
||||
// self.device.handle
|
||||
// .wait_for_fences(&[self.draw_commands_reuse_fence], true, u64::MAX)
|
||||
// .expect("Wait for fence failed.");
|
||||
//
|
||||
// self.device.handle
|
||||
// .reset_fences(&[self.draw_commands_reuse_fence])
|
||||
// .expect("Reset fences failed.");
|
||||
//
|
||||
// self.device.handle
|
||||
// .reset_command_buffer(
|
||||
// self.draw_command_buffer,
|
||||
// vk::CommandBufferResetFlags::RELEASE_RESOURCES,
|
||||
// )
|
||||
// .expect("Reset command buffer failed.");
|
||||
//
|
||||
// let command_buffer_begin_info = vk::CommandBufferBeginInfo::default()
|
||||
// .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||
//
|
||||
// self.device.handle
|
||||
// .begin_command_buffer(self.draw_command_buffer, &command_buffer_begin_info)
|
||||
// .expect("Begin commandbuffer");
|
||||
//
|
||||
// self.device.handle
|
||||
// .end_command_buffer(self.draw_command_buffer)
|
||||
// .expect("End commandbuffer");
|
||||
//
|
||||
// let command_buffers = vec![self.draw_command_buffer];
|
||||
// let semaphores = vec![self.rendering_complete_semaphore];
|
||||
// let wait_mask = vec![vk::PipelineStageFlags::default()];
|
||||
//
|
||||
// let submit_info = vk::SubmitInfo::default()
|
||||
// .wait_semaphores(&semaphores)
|
||||
// .wait_dst_stage_mask(&wait_mask)
|
||||
// .command_buffers(&command_buffers)
|
||||
// .signal_semaphores(&semaphores);
|
||||
//
|
||||
// self.device.handle
|
||||
// .queue_submit(self.present_queue, &[submit_info], self.draw_commands_reuse_fence)
|
||||
// .expect("queue submit failed.");
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_resolution(&mut self, width: u32, height: u32) -> anyhow::Result<()> {
|
||||
self.swapchain.update_resolution(&self.surface, width, height)?;
|
||||
if let Some(swapchain) = Arc::get_mut(&mut self.swapchain) {
|
||||
swapchain.update_resolution(width, height)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,27 +1,43 @@
|
|||
use crate::display::Window;
|
||||
use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSwapchain, LOG_TARGET};
|
||||
use std::sync::Arc;
|
||||
use crate::vulkan::{VkInstance, VkPhysicalDevice, LOG_TARGET};
|
||||
use ash::prelude::VkResult;
|
||||
use ash::vk;
|
||||
use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
|
||||
pub struct VkSurface {
|
||||
surface_loader: ash::khr::surface::Instance,
|
||||
instance: Arc<VkInstance>,
|
||||
pub(super) surface: vk::SurfaceKHR,
|
||||
}
|
||||
|
||||
impl VkSurface {
|
||||
pub fn new(
|
||||
surface_loader: ash::khr::surface::Instance,
|
||||
surface: vk::SurfaceKHR,
|
||||
) -> Self {
|
||||
Self {
|
||||
surface_loader,
|
||||
window: &crate::display::Window,
|
||||
instance: Arc<VkInstance>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let window_handle = window.handle()
|
||||
.ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?;
|
||||
|
||||
let surface = unsafe {
|
||||
ash_window::create_surface(
|
||||
&instance.entry,
|
||||
&instance.handle,
|
||||
window_handle.display_handle()?.as_raw(),
|
||||
window_handle.window_handle()?.as_raw(),
|
||||
None,
|
||||
)?
|
||||
};
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Surface created ({:?})", surface);
|
||||
|
||||
Ok(Self {
|
||||
instance,
|
||||
surface,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn physical_device_queue_supported(&self, physical_device: &VkPhysicalDevice, queue_index: u32) -> VkResult<bool> {
|
||||
unsafe {
|
||||
self.surface_loader.get_physical_device_surface_support(
|
||||
self.instance.surface_loader.get_physical_device_surface_support(
|
||||
physical_device.handle,
|
||||
queue_index,
|
||||
self.surface,
|
||||
|
@ -29,115 +45,37 @@ impl VkSurface {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_physical_device_surface_formats(&self, physical_device: &VkPhysicalDevice) -> VkResult<Vec<vk::SurfaceFormatKHR>> {
|
||||
pub fn get_physical_device_surface_infos(&self, physical_device: &VkPhysicalDevice) -> VkResult<(
|
||||
Vec<vk::SurfaceFormatKHR>,
|
||||
vk::SurfaceCapabilitiesKHR,
|
||||
Vec<vk::PresentModeKHR>
|
||||
)> {
|
||||
unsafe {
|
||||
self.surface_loader.get_physical_device_surface_formats(
|
||||
let formats = self.instance.surface_loader.get_physical_device_surface_formats(
|
||||
physical_device.handle,
|
||||
self.surface,
|
||||
)
|
||||
}
|
||||
}
|
||||
)?;
|
||||
|
||||
pub fn get_physical_device_surface_capabilities(&self, physical_device: &VkPhysicalDevice) -> VkResult<vk::SurfaceCapabilitiesKHR> {
|
||||
unsafe {
|
||||
self.surface_loader.get_physical_device_surface_capabilities(
|
||||
let capabilities = self.instance.surface_loader.get_physical_device_surface_capabilities(
|
||||
physical_device.handle,
|
||||
self.surface,
|
||||
)
|
||||
}
|
||||
}
|
||||
)?;
|
||||
|
||||
pub fn get_physical_device_surface_present_modes(&self, physical_device: &VkPhysicalDevice) -> VkResult<Vec<vk::PresentModeKHR>> {
|
||||
unsafe {
|
||||
self.surface_loader.get_physical_device_surface_present_modes(
|
||||
let present_modes = self.instance.surface_loader.get_physical_device_surface_present_modes(
|
||||
physical_device.handle,
|
||||
self.surface,
|
||||
)
|
||||
)?;
|
||||
|
||||
Ok((formats, capabilities, present_modes))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_swapchain(
|
||||
&self,
|
||||
window: &Window,
|
||||
instance: &VkInstance,
|
||||
device: &VkDevice,
|
||||
physical_device: &VkPhysicalDevice,
|
||||
) -> anyhow::Result<VkSwapchain> {
|
||||
log::debug!(target: LOG_TARGET, "Creating swapchain");
|
||||
|
||||
let surface_formats = self.get_physical_device_surface_formats(physical_device)?;
|
||||
log::debug!(target: LOG_TARGET, "Supported surface formats by physical device: {surface_formats:#?}");
|
||||
|
||||
let surface_format = surface_formats
|
||||
.first()
|
||||
.and_then(|f| Some(*f))
|
||||
.ok_or_else(|| anyhow::anyhow!("No available surface formats"))?;
|
||||
log::debug!(target: LOG_TARGET, "Selected surface format: {surface_format:?}");
|
||||
|
||||
let surface_capabilities = self.get_physical_device_surface_capabilities(physical_device)?;
|
||||
log::debug!(target: LOG_TARGET, "Surface capabilities: {surface_capabilities:#?}");
|
||||
|
||||
let mut desired_image_count = surface_capabilities.min_image_count + 1;
|
||||
if surface_capabilities.max_image_count > 0
|
||||
&& desired_image_count > surface_capabilities.max_image_count
|
||||
{
|
||||
desired_image_count = surface_capabilities.max_image_count;
|
||||
}
|
||||
log::debug!(target: LOG_TARGET, "Selected surface image count: {desired_image_count}");
|
||||
|
||||
let window_size = window.size()
|
||||
.ok_or_else(|| anyhow::anyhow!("Window size is not valid"))?
|
||||
.to_physical::<u32>(1.0);
|
||||
log::debug!(target: LOG_TARGET, "Window size: {window_size:?}");
|
||||
|
||||
let surface_resolution = match surface_capabilities.current_extent.width {
|
||||
u32::MAX => vk::Extent2D {
|
||||
width: window_size.width,
|
||||
height: window_size.height,
|
||||
},
|
||||
_ => surface_capabilities.current_extent,
|
||||
};
|
||||
log::debug!(target: LOG_TARGET, "Surface resolution: {surface_resolution:?}");
|
||||
|
||||
let pre_transform = if surface_capabilities
|
||||
.supported_transforms
|
||||
.contains(vk::SurfaceTransformFlagsKHR::IDENTITY)
|
||||
{
|
||||
vk::SurfaceTransformFlagsKHR::IDENTITY
|
||||
} else {
|
||||
surface_capabilities.current_transform
|
||||
};
|
||||
|
||||
let present_modes = self
|
||||
.get_physical_device_surface_present_modes(physical_device)?;
|
||||
|
||||
let present_mode = present_modes
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|&mode| mode == vk::PresentModeKHR::MAILBOX)
|
||||
.unwrap_or(vk::PresentModeKHR::FIFO);
|
||||
let swapchain_loader = ash::khr::swapchain::Device::new(&instance.handle, &device.handle);
|
||||
|
||||
let mut swapchain = VkSwapchain::new(
|
||||
swapchain_loader,
|
||||
desired_image_count,
|
||||
surface_format,
|
||||
surface_resolution,
|
||||
present_mode,
|
||||
pre_transform,
|
||||
);
|
||||
|
||||
swapchain.create_swapchain(&self)?;
|
||||
|
||||
Ok(swapchain)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VkSurface {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.surface_loader.destroy_surface(self.surface, None);
|
||||
self.instance.surface_loader.destroy_surface(self.surface, None);
|
||||
}
|
||||
log::debug!(target: LOG_TARGET, "Surface destroyed");
|
||||
log::debug!(target: LOG_TARGET, "Surface destroyed ({:?})", self.surface);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
use crate::vulkan::{VkSurface, LOG_TARGET};
|
||||
use std::sync::Arc;
|
||||
use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSurface, LOG_TARGET};
|
||||
use ash::prelude::VkResult;
|
||||
use ash::vk;
|
||||
use crate::display::Window;
|
||||
|
||||
pub struct VkSwapchain {
|
||||
pub(super) swapchain_loader: ash::khr::swapchain::Device,
|
||||
surface: Arc<VkSurface>,
|
||||
device: Arc<VkDevice>,
|
||||
swapchain: Option<vk::SwapchainKHR>,
|
||||
|
||||
pub(super) desired_image_count: u32,
|
||||
|
@ -11,70 +14,136 @@ pub struct VkSwapchain {
|
|||
pub(super) surface_resolution: vk::Extent2D,
|
||||
pub(super) present_mode: vk::PresentModeKHR,
|
||||
pub(super) pre_transform: vk::SurfaceTransformFlagsKHR,
|
||||
|
||||
pub(super) present_images: Option<Vec<vk::Image>>,
|
||||
pub(super) present_image_views: Option<Vec<vk::ImageView>>,
|
||||
}
|
||||
|
||||
impl VkSwapchain {
|
||||
pub(super) fn new(
|
||||
swapchain_loader: ash::khr::swapchain::Device,
|
||||
desired_image_count: u32,
|
||||
surface_format: vk::SurfaceFormatKHR,
|
||||
surface_resolution: vk::Extent2D,
|
||||
present_mode: vk::PresentModeKHR,
|
||||
pre_transform: vk::SurfaceTransformFlagsKHR,
|
||||
) -> Self {
|
||||
Self {
|
||||
swapchain_loader,
|
||||
pub(super) fn new<'a, 'b>(
|
||||
window: &Window,
|
||||
surface: Arc<VkSurface>,
|
||||
device: Arc<VkDevice>,
|
||||
physical_device: &VkPhysicalDevice,
|
||||
) -> anyhow::Result<Self> {
|
||||
log::debug!(target: LOG_TARGET, "Creating swapchain");
|
||||
|
||||
let (
|
||||
surface_formats,
|
||||
surface_capabilities,
|
||||
present_modes
|
||||
) = surface.get_physical_device_surface_infos(physical_device)?;
|
||||
log::debug!(target: LOG_TARGET, "Supported surface formats by physical device: {surface_formats:#?}");
|
||||
log::debug!(target: LOG_TARGET, "Surface capabilities: {surface_capabilities:#?}");
|
||||
|
||||
let surface_format = surface_formats
|
||||
.first()
|
||||
.and_then(|f| Some(*f))
|
||||
.ok_or_else(|| anyhow::anyhow!("No available surface formats"))?;
|
||||
log::debug!(target: LOG_TARGET, "Selected surface format: {surface_format:?}");
|
||||
|
||||
let mut desired_image_count = surface_capabilities.min_image_count + 1;
|
||||
if surface_capabilities.max_image_count > 0
|
||||
&& desired_image_count > surface_capabilities.max_image_count
|
||||
{
|
||||
desired_image_count = surface_capabilities.max_image_count;
|
||||
}
|
||||
log::debug!(target: LOG_TARGET, "Selected surface image count: {desired_image_count}");
|
||||
|
||||
let window_size = window.size()
|
||||
.ok_or_else(|| anyhow::anyhow!("Window size is not valid"))?
|
||||
.to_physical::<u32>(1.0);
|
||||
log::debug!(target: LOG_TARGET, "Window size: {window_size:?}");
|
||||
|
||||
let surface_resolution = match surface_capabilities.current_extent.width {
|
||||
u32::MAX => vk::Extent2D {
|
||||
width: window_size.width,
|
||||
height: window_size.height,
|
||||
},
|
||||
_ => surface_capabilities.current_extent,
|
||||
};
|
||||
log::debug!(target: LOG_TARGET, "Surface resolution: {surface_resolution:?}");
|
||||
|
||||
let pre_transform = if surface_capabilities
|
||||
.supported_transforms
|
||||
.contains(vk::SurfaceTransformFlagsKHR::IDENTITY)
|
||||
{
|
||||
vk::SurfaceTransformFlagsKHR::IDENTITY
|
||||
} else {
|
||||
surface_capabilities.current_transform
|
||||
};
|
||||
|
||||
let present_mode = present_modes
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|&mode| mode == vk::PresentModeKHR::MAILBOX)
|
||||
.unwrap_or(vk::PresentModeKHR::FIFO);
|
||||
|
||||
let mut swapchain = Self {
|
||||
surface,
|
||||
device,
|
||||
desired_image_count,
|
||||
surface_format,
|
||||
surface_resolution,
|
||||
present_mode,
|
||||
pre_transform,
|
||||
swapchain: None,
|
||||
}
|
||||
present_images: None,
|
||||
present_image_views: None,
|
||||
};
|
||||
|
||||
swapchain.create_swapchain()?;
|
||||
|
||||
Ok(swapchain)
|
||||
}
|
||||
|
||||
pub(super) fn create_swapchain(&mut self, surface: &VkSurface) -> VkResult<()> {
|
||||
let mut swapchain_create_info = self.create_swapchain_info(surface);
|
||||
pub(super) fn create_swapchain(&mut self) -> VkResult<()> {
|
||||
let mut swapchain_create_info = self.create_swapchain_info(&self.surface);
|
||||
|
||||
if let Some(old_swapchain) = self.swapchain {
|
||||
swapchain_create_info.old_swapchain = old_swapchain;
|
||||
}
|
||||
|
||||
let swapchain = unsafe {
|
||||
self.swapchain_loader.create_swapchain(&swapchain_create_info, None)?
|
||||
self.device.swapchain_loader.create_swapchain(&swapchain_create_info, None)?
|
||||
};
|
||||
|
||||
match self.swapchain {
|
||||
Some(_) => log::debug!(target: LOG_TARGET, "Swapchain created : {swapchain_create_info:#?}"),
|
||||
None => log::debug!(target: LOG_TARGET, "Swapchain updated : {swapchain_create_info:#?}")
|
||||
let present_images = unsafe { self.device.swapchain_loader.get_swapchain_images(swapchain)? };
|
||||
let present_images_view = present_images
|
||||
.iter()
|
||||
.map(|i| {
|
||||
self.device.create_image_view(*i, self.surface_format)
|
||||
.expect("Failed to create image view")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if log::log_enabled!(target: LOG_TARGET, log::Level::Debug) {
|
||||
let label = match self.swapchain {
|
||||
None => "Swapchain created",
|
||||
Some(_) => "Swapchain updated"
|
||||
};
|
||||
log::debug!(target: LOG_TARGET, "{label} ({swapchain:?}) : {swapchain_create_info:#?}");
|
||||
}
|
||||
|
||||
self.swapchain = Some(swapchain);
|
||||
self.present_image_views = Some(present_images_view);
|
||||
self.present_images = Some(present_images);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn update_resolution(&mut self, surface: &VkSurface, width: u32, height: u32) -> VkResult<()> {
|
||||
pub(super) fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> {
|
||||
log::debug!(target: LOG_TARGET, "New resolution requested for swapchain {width}x{height}");
|
||||
self.surface_resolution = vk::Extent2D {
|
||||
width,
|
||||
height,
|
||||
};
|
||||
|
||||
self.create_swapchain(surface)?;
|
||||
self.create_swapchain()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn get_swapchain_images(&self) -> anyhow::Result<Vec<vk::Image>> {
|
||||
let swapchain = self.swapchain
|
||||
.ok_or_else(|| anyhow::anyhow!("Can't get swapchain images : Swapchain is not set"))?;
|
||||
|
||||
let images = unsafe { self.swapchain_loader.get_swapchain_images(swapchain)? };
|
||||
|
||||
Ok(images)
|
||||
}
|
||||
|
||||
fn create_swapchain_info(&self, surface: &VkSurface) -> vk::SwapchainCreateInfoKHR {
|
||||
vk::SwapchainCreateInfoKHR::default()
|
||||
.surface(surface.surface)
|
||||
|
@ -91,18 +160,17 @@ impl VkSwapchain {
|
|||
.image_array_layers(1)
|
||||
}
|
||||
|
||||
fn drop_current_swapchain(&mut self) {
|
||||
fn drop_swapchain(&mut self) {
|
||||
if let Some(swapchain) = self.swapchain {
|
||||
unsafe {
|
||||
self.swapchain_loader.destroy_swapchain(swapchain, None);
|
||||
self.swapchain = None;
|
||||
}
|
||||
unsafe { self.device.swapchain_loader.destroy_swapchain(swapchain, None); }
|
||||
self.swapchain = None;
|
||||
log::debug!(target: LOG_TARGET, "Swapchain destroyed ({swapchain:?})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VkSwapchain {
|
||||
fn drop(&mut self) {
|
||||
self.drop_current_swapchain()
|
||||
self.drop_swapchain()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue