+ Pipeline new() and drop() + Attachement new(() and drop() + draw_triangle_frame ! crashes at pipeline creation
308 lines
9.8 KiB
Rust
308 lines
9.8 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;
|
|
|
|
debug!("Dropping SwapSystem...");
|
|
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 !");
|
|
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> {
|
|
|
|
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),
|
|
}};
|
|
//println!("Frame nb : {}", self.frames.len());
|
|
//frames number diminish sometimes at resize...
|
|
let mut frame = self.frames.pop_back().unwrap();
|
|
|
|
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
|
|
};
|
|
|
|
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")?;
|
|
};
|
|
|
|
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
|
|
))
|
|
}
|
|
|