diff options
Diffstat (limited to 'stockton-skeleton/src/target.rs')
-rw-r--r-- | stockton-skeleton/src/target.rs | 228 |
1 files changed, 36 insertions, 192 deletions
diff --git a/stockton-skeleton/src/target.rs b/stockton-skeleton/src/target.rs index c3a212e..647aa96 100644 --- a/stockton-skeleton/src/target.rs +++ b/stockton-skeleton/src/target.rs @@ -1,4 +1,12 @@ //! Resources needed for drawing on the screen, including sync objects +//! You likely won't need to interact with this directly + +use crate::{ + context::ContextProperties, + draw_passes::{DrawPass, Singular}, + types::*, +}; +use stockton_types::Session; use std::{ borrow::Borrow, @@ -8,177 +16,53 @@ use std::{ use hal::{ command::CommandBufferFlags, - format::{ChannelType, Format, ImageFeature}, - image::{Extent, FramebufferAttachment, Usage as ImgUsage, ViewCapabilities}, - pso::Viewport, - window::{CompositeAlphaMode, Extent2D, PresentMode, SwapchainConfig}, + image::Usage as ImgUsage, + window::{Extent2D, SwapchainConfig}, }; -use super::draw_passes::DrawPass; -use crate::{draw_passes::Singular, error::EnvironmentError, types::*}; use anyhow::{Context, Result}; -use stockton_types::Session; - -#[derive(Debug, Clone)] -pub struct SwapchainProperties { - pub format: Format, - pub depth_format: Format, - pub present_mode: PresentMode, - pub composite_alpha_mode: CompositeAlphaMode, - pub viewport: Viewport, - pub extent: Extent, - pub image_count: u32, -} - -impl SwapchainProperties { - pub fn find_best( - adapter: &Adapter, - surface: &SurfaceT, - ) -> Result<SwapchainProperties, EnvironmentError> { - let caps = surface.capabilities(&adapter.physical_device); - let formats = surface.supported_formats(&adapter.physical_device); - - // Find which settings we'll actually use based on preset preferences - let format = match formats { - Some(formats) => formats - .iter() - .find(|format| format.base_format().1 == ChannelType::Srgb) - .copied() - .ok_or(EnvironmentError::ColorFormat), - None => Ok(Format::Rgba8Srgb), - }?; - - let depth_format = *[ - Format::D32SfloatS8Uint, - Format::D24UnormS8Uint, - Format::D32Sfloat, - ] - .iter() - .find(|format| { - format.is_depth() - && adapter - .physical_device - .format_properties(Some(**format)) - .optimal_tiling - .contains(ImageFeature::DEPTH_STENCIL_ATTACHMENT) - }) - .ok_or(EnvironmentError::DepthFormat)?; - - let present_mode = [ - PresentMode::MAILBOX, - PresentMode::FIFO, - PresentMode::RELAXED, - PresentMode::IMMEDIATE, - ] - .iter() - .cloned() - .find(|pm| caps.present_modes.contains(*pm)) - .ok_or(EnvironmentError::PresentMode)?; - - let composite_alpha_mode = [ - CompositeAlphaMode::OPAQUE, - CompositeAlphaMode::INHERIT, - CompositeAlphaMode::PREMULTIPLIED, - CompositeAlphaMode::POSTMULTIPLIED, - ] - .iter() - .cloned() - .find(|ca| caps.composite_alpha_modes.contains(*ca)) - .ok_or(EnvironmentError::CompositeAlphaMode)?; - - let extent = caps.extents.end().to_extent(); // Size - let viewport = Viewport { - rect: extent.rect(), - depth: 0.0..1.0, - }; - - Ok(SwapchainProperties { - format, - depth_format, - present_mode, - composite_alpha_mode, - extent, - viewport, - image_count: if present_mode == PresentMode::MAILBOX { - ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(3)) - } else { - ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(2)) - }, - }) - } - - pub fn framebuffer_attachment(&self) -> FramebufferAttachment { - FramebufferAttachment { - usage: ImgUsage::COLOR_ATTACHMENT, - format: self.format, - view_caps: ViewCapabilities::empty(), - } - } -} +/// Holds our swapchain and other resources for drawing each frame pub struct TargetChain { /// Surface we're targeting surface: ManuallyDrop<SurfaceT>, - properties: SwapchainProperties, - - /// Resources tied to each target frame in the swapchain - targets: Box<[TargetResources]>, - - /// Sync objects used in drawing - /// These are seperated from the targets because we don't necessarily always match up indexes - sync_objects: Box<[SyncObjects]>, - /// The last set of sync objects used - last_syncs: usize, + /// Command buffers and sync objects used when drawing + resources: Box<[(CommandBufferT, SyncObjects)]>, /// Last image index of the swapchain drawn to - last_image: u32, + last_resources: usize, } impl TargetChain { pub fn new( device: &mut DeviceT, - adapter: &Adapter, mut surface: SurfaceT, cmd_pool: &mut CommandPoolT, - properties: SwapchainProperties, + properties: &ContextProperties, ) -> Result<TargetChain> { - let caps = surface.capabilities(&adapter.physical_device); - - // Number of frames to pre-render - let image_count = if properties.present_mode == PresentMode::MAILBOX { - ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(3)) - } else { - ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(2)) - }; - - // Swap config + // Create swapchain let swap_config = SwapchainConfig { present_mode: properties.present_mode, composite_alpha_mode: properties.composite_alpha_mode, - format: properties.format, + format: properties.color_format, extent: Extent2D { width: properties.extent.width, height: properties.extent.height, }, - image_count, + image_count: properties.image_count, image_layers: 1, image_usage: ImgUsage::COLOR_ATTACHMENT, }; - let _fat = swap_config.framebuffer_attachment(); - let mut targets: Vec<TargetResources> = - Vec::with_capacity(swap_config.image_count as usize); - let mut sync_objects: Vec<SyncObjects> = - Vec::with_capacity(swap_config.image_count as usize); + // Create command buffers and sync objects + let mut resources = Vec::with_capacity(swap_config.image_count as usize); for _ in 0..swap_config.image_count { - targets.push( - TargetResources::new(device, cmd_pool, &properties) - .context("Error creating target resources")?, - ); - - sync_objects.push(SyncObjects::new(device).context("Error creating sync objects")?); + resources.push(( + unsafe { cmd_pool.allocate_one(hal::command::Level::Primary) }, + SyncObjects::new(device).context("Error creating sync objects")?, + )); } // Configure Swapchain @@ -190,11 +74,8 @@ impl TargetChain { Ok(TargetChain { surface: ManuallyDrop::new(surface), - targets: targets.into_boxed_slice(), - sync_objects: sync_objects.into_boxed_slice(), - properties, - last_syncs: (image_count - 1) as usize, // This means the next one to be used is index 0 - last_image: 0, + resources: resources.into_boxed_slice(), + last_resources: (properties.image_count - 1) as usize, // This means the next one to be used is index 0 }) } @@ -218,12 +99,10 @@ impl TargetChain { ) -> SurfaceT { use core::ptr::read; unsafe { - for i in 0..self.targets.len() { - read(&self.targets[i]).deactivate(device, cmd_pool); - } - - for i in 0..self.sync_objects.len() { - read(&self.sync_objects[i]).deactivate(device); + for i in 0..self.resources.len() { + let (cmd_buf, syncs) = read(&self.resources[i]); + cmd_pool.free(once(cmd_buf)); + syncs.deactivate(device); } self.surface.unconfigure_swapchain(device); @@ -239,11 +118,9 @@ impl TargetChain { dp: &mut DP, session: &Session, ) -> Result<()> { - self.last_syncs = (self.last_syncs + 1) % self.sync_objects.len(); - self.last_image = (self.last_image + 1) % self.targets.len() as u32; + self.last_resources = (self.last_resources + 1) % self.resources.len(); - let syncs = &mut self.sync_objects[self.last_syncs]; - let target = &mut self.targets[self.last_image as usize]; + let (cmd_buffer, syncs) = &mut self.resources[self.last_resources]; // Get the image let (img, _) = unsafe { @@ -264,18 +141,18 @@ impl TargetChain { // Record commands unsafe { - target.cmd_buffer.begin_primary(CommandBufferFlags::empty()); + cmd_buffer.begin_primary(CommandBufferFlags::empty()); - dp.queue_draw(session, img.borrow(), &mut target.cmd_buffer) + dp.queue_draw(session, img.borrow(), cmd_buffer) .context("Error in draw pass")?; - target.cmd_buffer.finish(); + cmd_buffer.finish(); } // Submit it unsafe { command_queue.submit( - once(&*target.cmd_buffer), + once(&*cmd_buffer), empty(), once(&*syncs.render_complete), Some(&mut syncs.present_complete), @@ -287,39 +164,6 @@ impl TargetChain { Ok(()) } - - /// Get a reference to the target chain's properties. - pub fn properties(&self) -> &SwapchainProperties { - &self.properties - } -} - -/// Resources for a single target frame, including sync objects -pub struct TargetResources { - /// Command buffer to use when drawing - pub cmd_buffer: ManuallyDrop<CommandBufferT>, -} - -impl TargetResources { - pub fn new( - _device: &mut DeviceT, - cmd_pool: &mut CommandPoolT, - _properties: &SwapchainProperties, - ) -> Result<TargetResources> { - // Command Buffer - let cmd_buffer = unsafe { cmd_pool.allocate_one(hal::command::Level::Primary) }; - - Ok(TargetResources { - cmd_buffer: ManuallyDrop::new(cmd_buffer), - }) - } - - pub fn deactivate(self, _device: &mut DeviceT, cmd_pool: &mut CommandPoolT) { - use core::ptr::read; - unsafe { - cmd_pool.free(once(ManuallyDrop::into_inner(read(&self.cmd_buffer)))); - } - } } pub struct SyncObjects { |