iv/src/renderer/swap_system.rs
Steins7 012393e04b Fixed shutdown ressource cleaning
* changed drop order in Renderer
* cleaned dropping logs
* cleaned unnecessary code
2021-02-03 09:38:12 +01:00

343 lines
11 KiB
Rust

#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
mem::ManuallyDrop,
ptr::read,
collections::VecDeque,
};
use gfx_hal::{
window::{Extent2D, AcquireError, PresentationSurface, SurfaceCapabilities, SwapchainConfig},
pso::Rect as GfxRect,
format::Format,
};
mod frame;
use frame::Frame;
use super::gpu::Gpu;
//--SwapSystem implementation-----------------------------------------------------------------------
#[derive(Debug)]
pub struct SwapSystem<B: gfx_hal::Backend> {
surface: ManuallyDrop<B::Surface>,
format: Format,
extent: Extent2D,
pub render_area: GfxRect, //TODO may not be needed (duplicate of extent)
pub render_pass: ManuallyDrop<B::RenderPass>, //TODO move to Pipeline ?
frames: VecDeque<Frame<B>>,
frame_nb: usize,
}
impl<B> SwapSystem<B>
where
B: gfx_hal::Backend,
{
pub fn drop(&mut self, gpu: &mut Gpu<B>) -> B::Surface {
use gfx_hal::device::Device;
trace!("Dropping frames...");
for mut frame in self.frames.drain(..) {
frame.drop(gpu);
}
unsafe {
gpu.device().destroy_render_pass(
ManuallyDrop::into_inner(read(&mut self.render_pass)));
//render_area extent and format can be dropped automatically
self.surface.unconfigure_swapchain(gpu.device());
trace!("SwapSystem dropped !");
ManuallyDrop::take(&mut self.surface)
}
}
pub fn new(gpu: &mut Gpu<B>, mut surface: B::Surface)
-> Result<SwapSystem<B>, &'static str>
{
debug!("Creating SwapSystem...");
trace!("Obtaining surface capabilities...");
let capabilities = {
use gfx_hal::window::Surface;
surface.capabilities(&gpu.adapter().physical_device)
};
debug!("Surface capabitlities : {:#?}", capabilities);
trace!("Selecting image format...");
let format = {
use gfx_hal::{
format::ChannelType,
window::Surface,
};
match surface.supported_formats(&gpu.adapter().physical_device) {
None => Format::Rgba8Srgb,
Some(formats) => formats
.iter()
.find(|f| f.base_format().1 == ChannelType::Srgb)
.cloned()
.ok_or("Could no find suitable format")?
}};
trace!("Getting surface's render area size...");
let extent = capabilities.current_extent
.unwrap_or(*capabilities.extents.end())
.clone();
let render_area = GfxRect{x: 0, y: 0, w: extent.width as i16, h: extent.height as i16};
trace!("Generating Swapchain configuration...");
let (swapchain_config, frame_nb) =
generate_swapchain_config(capabilities, &format, &extent)?;
debug!("Swapchain configuration : {:#?}", swapchain_config);
trace!("Configuring Swapchain...");
let _ = unsafe {
surface
.configure_swapchain(gpu.device(), swapchain_config)
.map_err(|_| "Failed to create swapchain and backbuffer")?
};
trace!("Creating RenderPass...");
let render_pass = {
use gfx_hal::{
pass::{Attachment, AttachmentOps, AttachmentLoadOp, AttachmentStoreOp, SubpassDesc},
image::Layout,
device::Device,
};
let color_attachment = Attachment {
format : Some(format),
samples : 1,
ops : AttachmentOps {
load : AttachmentLoadOp::Clear,
store : AttachmentStoreOp::Store,
},
stencil_ops : AttachmentOps::DONT_CARE,
layouts : (Layout::Undefined..Layout::Present),
};
let subpass = SubpassDesc {
colors : &[(0, Layout::ColorAttachmentOptimal)],
depth_stencil : None,
inputs : &[],
resolves : &[],
preserves : &[],
};
unsafe {
gpu.device().create_render_pass(&[color_attachment], &[subpass], &[])
.map_err(|_| "Could not create render pass")?
}
};
warn!("Generating hard-coded number of frames ({}) !", frame_nb);
let mut frames = VecDeque::with_capacity(frame_nb);
for _ in 0..frame_nb {
let frame = Frame::new(gpu)
.map_err(|_| "Could not create frame")?;
frames.push_back(frame);
};
let frame_nb = frames.len();
trace!("Created SwapSystem !");
Ok( SwapSystem {
surface: ManuallyDrop::new(surface),
format,
extent,
render_area,
render_pass: ManuallyDrop::new(render_pass),
frames,
frame_nb,
})
}
pub fn recreate(&mut self, gpu: &mut Gpu<B>) -> Result<(), &'static str> {
trace!("Obtaining surface capabilities...");
let capabilities = {
use gfx_hal::window::Surface;
self.surface.capabilities(&gpu.adapter().physical_device)
};
debug!("Surface capabitlities : {:#?}", capabilities);
trace!("Getting surface's render area size...");
self.extent = capabilities.current_extent
.unwrap_or(*capabilities.extents.end())
.clone();
self.render_area =
GfxRect{x: 0, y: 0, w: self.extent.width as i16, h: self.extent.height as i16};
trace!("Generating Swapchain configuration...");
let (swapchain_config, _frame_nb) = //TODO check frame nb change
generate_swapchain_config(capabilities, &self.format, &self.extent)?;
debug!("Swapchain configuration : {:#?}", swapchain_config);
trace!("Configuring Swapchain...");
let _ = unsafe {
self.surface
.configure_swapchain(gpu.device(), swapchain_config)
.map_err(|_| "Failed to create swapchain and backbuffer")?
};
Ok(())
}
pub fn acquire_frame(&mut self, gpu: &Gpu<B>) -> Result<Frame<B>, AcquireError> {
//println!("Frame nb : {}", self.frames.len());
//TODO frames number diminish sometimes at resize...
//static mut id: i32 = 0;
let mut frame = self.frames.pop_back().unwrap();
//unsafe {
// id = (id+1)%3;
//}
trace!("Waiting for Frame...");
unsafe {
use gfx_hal::device::Device;
let _ = gpu.device()
.wait_for_fence(&frame.fences[0], !0)
.map_err(|_| "Failed to wait for Fence"); //TODO error
let _ = gpu.device()
.reset_fence(&frame.fences[0])
.map_err(|_| "Failed to reset Fence"); //TODO error
}
trace!("Reseting CommandBuffer...");
unsafe {
use gfx_hal::command::CommandBuffer;
frame.command_buffer.reset(false); //TODO may be needed at some point...
};
//unsafe {
// trace!("Acquiring Frame {}...", id);
//}
trace!("Acquiring Frame...");
let image = unsafe {
match self.surface.acquire_image(core::u64::MAX) {
Ok((image, suboptimal)) => {
match suboptimal {
Some(_) => return Err(AcquireError::OutOfDate),
None => image,
}},
Err(err) => return Err(err),
}};
trace!("Creating Framebuffer...");
let framebuffer = unsafe {
use gfx_hal::device::Device;
use std::borrow::Borrow;
gpu.device()
.create_framebuffer(&self.render_pass,
vec![image.borrow()],
self.extent.clone().to_extent())
.unwrap() //TODO improve that
};
//unsafe {
// use gfx_hal::{device::Device};
// gpu.device()
// .set_framebuffer_name(&mut framebuffer, format!("frambuffer {}", id).as_str());
//}
frame.link_swapchain_image(gpu, image, framebuffer);
Ok(frame)
}
pub fn present_frame(&mut self, mut frame: Frame<B>, gpu: &mut Gpu<B>)
-> Result<(), &'static str> {
use gfx_hal::queue::CommandQueue;
let image = frame
.unlink_swapchain_image()
.unwrap(); //TODO improve that
trace!("Presenting Frame...");
let _ = unsafe {
gpu.queue_mut()
.present(&mut self.surface, image, Some(&frame.signal_semaphores[0]))
.map_err(|_| "Failed to present into the swapchain")?;
};
frame.destroy_framebuffer(gpu);
self.frames.push_front(frame);
Ok(())
}
}
fn generate_swapchain_config(capabilities: SurfaceCapabilities,
format: &Format,
extent: &Extent2D)
-> Result<(SwapchainConfig, usize), &'static str> {
trace!("Generating Swapchain configuration...");
let present_mode = {
use gfx_hal::window::PresentMode;
[PresentMode::MAILBOX, PresentMode::FIFO, PresentMode::RELAXED,
PresentMode::IMMEDIATE]
.iter()
.cloned()
.find(|pm| capabilities.present_modes.contains(*pm))
.ok_or("No PresentMode values specified!")?
};
let composite_alpha_mode = {
use gfx_hal::window::CompositeAlphaMode;
[CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT,
CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED]
.iter()
.cloned()
.find(|ca| capabilities.composite_alpha_modes.contains(*ca))
.ok_or("No CompositeAlpha values specified!")?
};
let image_count = {
use std::cmp::{min, max};
use gfx_hal::window::PresentMode;
let count = match present_mode {
PresentMode::MAILBOX => 3,
_ => 2, //TODO to be checked
};
max(capabilities.image_count.start().clone(),
min(capabilities.image_count.end().clone(), count))
};
warn!("Hard-coding number of layers per image !");
let image_layers = 1;
let image_usage = {
use gfx_hal::image::Usage;
if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) {
Usage::COLOR_ATTACHMENT
} else {
Err("The Surface isn't capable of supporting color!")?
}};
Ok ((
SwapchainConfig {
present_mode,
composite_alpha_mode,
format: format.clone(),
extent: extent.clone(),
image_count: image_count.clone(),
image_layers,
image_usage,
},
image_count as usize
))
}