aboutsummaryrefslogtreecommitdiff
path: root/stockton-render/src/draw/target.rs
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:23 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:23 +0100
commit6ab13f2d0cb345795f761181a06777ade61ff09c (patch)
tree42007acef9846d5e79f1bf418a96647f34b530d1 /stockton-render/src/draw/target.rs
parentccf0074b08ce835cf22e7d46153d1cb3f3d06d32 (diff)
refactor(all): separate rendering from framework
stockton-passes is mostly just a stand-in until this is properly separated
Diffstat (limited to 'stockton-render/src/draw/target.rs')
-rw-r--r--stockton-render/src/draw/target.rs392
1 files changed, 0 insertions, 392 deletions
diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs
deleted file mode 100644
index 3861192..0000000
--- a/stockton-render/src/draw/target.rs
+++ /dev/null
@@ -1,392 +0,0 @@
-//! Resources needed for drawing on the screen, including sync objects
-
-use std::{
- borrow::Borrow,
- iter::{empty, once},
- mem::ManuallyDrop,
-};
-
-use hal::{
- command::CommandBufferFlags,
- format::{Aspects, ChannelType, Format, ImageFeature},
- image::{
- Access, Extent, FramebufferAttachment, Layout, SubresourceRange, Usage as ImgUsage,
- ViewCapabilities,
- },
- memory::{Barrier, Dependencies},
- pso::{PipelineStage, Viewport},
- window::{CompositeAlphaMode, Extent2D, PresentMode, SwapchainConfig},
-};
-
-use super::draw_passes::DrawPass;
-use crate::{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(),
- }
- }
-}
-
-pub struct TargetChain {
- /// Surface we're targeting
- pub surface: ManuallyDrop<SurfaceT>,
- pub properties: SwapchainProperties,
-
- /// Resources tied to each target frame in the swapchain
- pub targets: Box<[TargetResources]>,
-
- /// Sync objects used in drawing
- /// These are seperated from the targets because we don't necessarily always match up indexes
- pub sync_objects: Box<[SyncObjects]>,
-
- /// The last set of sync objects used
- last_syncs: usize,
-
- /// Last image index of the swapchain drawn to
- last_image: u32,
-}
-
-impl TargetChain {
- pub fn new(
- device: &mut DeviceT,
- adapter: &Adapter,
- mut surface: SurfaceT,
- cmd_pool: &mut CommandPoolT,
- properties: SwapchainProperties,
- ) -> 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
- let swap_config = SwapchainConfig {
- present_mode: properties.present_mode,
- composite_alpha_mode: properties.composite_alpha_mode,
- format: properties.format,
- extent: Extent2D {
- width: properties.extent.width,
- height: properties.extent.height,
- },
- 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);
-
- 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")?);
- }
-
- // Configure Swapchain
- unsafe {
- surface
- .configure_swapchain(device, swap_config)
- .context("Error configuring swapchain")?;
- }
-
- 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,
- })
- }
-
- pub fn deactivate(
- self,
- instance: &mut InstanceT,
- device: &mut DeviceT,
- cmd_pool: &mut CommandPoolT,
- ) {
- let surface = self.deactivate_with_recyling(device, cmd_pool);
-
- unsafe {
- instance.destroy_surface(surface);
- }
- }
-
- pub fn deactivate_with_recyling(
- mut self,
- device: &mut DeviceT,
- cmd_pool: &mut CommandPoolT,
- ) -> 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);
- }
-
- self.surface.unconfigure_swapchain(device);
- }
-
- unsafe { ManuallyDrop::into_inner(read(&self.surface)) }
- }
-
- pub fn do_draw_with<'a, DP: DrawPass>(
- &'a mut self,
- device: &mut DeviceT,
- command_queue: &mut QueueT,
- 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;
-
- let syncs = &mut self.sync_objects[self.last_syncs];
- let target = &mut self.targets[self.last_image as usize];
-
- // Get the image
- let (img, _) = unsafe {
- self.surface
- .acquire_image(core::u64::MAX)
- .context("Error getting image from swapchain")?
- };
-
- // Make sure whatever was last using this has finished
- unsafe {
- device
- .wait_for_fence(&syncs.present_complete, core::u64::MAX)
- .context("Error waiting for present_complete")?;
- device
- .reset_fence(&mut syncs.present_complete)
- .context("Error resetting present_complete fence")?;
- };
-
- // Record commands
- unsafe {
- target.cmd_buffer.begin_primary(CommandBufferFlags::empty());
-
- target.cmd_buffer.pipeline_barrier(
- PipelineStage::TOP_OF_PIPE..PipelineStage::TOP_OF_PIPE,
- Dependencies::empty(),
- once(Barrier::Image {
- states: (Access::empty(), Layout::Undefined)
- ..(Access::empty(), Layout::ColorAttachmentOptimal),
- target: img.borrow(),
- range: SubresourceRange {
- aspects: Aspects::COLOR,
- level_start: 0,
- level_count: Some(1),
- layer_start: 0,
- layer_count: Some(1),
- },
- families: None,
- }),
- );
-
- dp.queue_draw(session, img.borrow(), &mut target.cmd_buffer)
- .context("Error in draw pass")?;
-
- target.cmd_buffer.pipeline_barrier(
- PipelineStage::BOTTOM_OF_PIPE..PipelineStage::BOTTOM_OF_PIPE,
- Dependencies::empty(),
- once(Barrier::Image {
- states: (Access::empty(), Layout::ColorAttachmentOptimal)
- ..(Access::empty(), Layout::Present),
- target: img.borrow(),
- range: SubresourceRange {
- aspects: Aspects::COLOR,
- level_start: 0,
- level_count: Some(1),
- layer_start: 0,
- layer_count: Some(1),
- },
- families: None,
- }),
- );
-
- target.cmd_buffer.finish();
- }
-
- // Submit it
- unsafe {
- command_queue.submit(
- once(&*target.cmd_buffer),
- empty(),
- once(&*syncs.render_complete),
- Some(&mut syncs.present_complete),
- );
- command_queue
- .present(&mut self.surface, img, Some(&mut *syncs.render_complete))
- .context("Error presenting to surface")?;
- };
-
- Ok(())
- }
-}
-
-/// 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 {
- /// Triggered when rendering is done
- pub render_complete: ManuallyDrop<SemaphoreT>,
-
- /// Triggered when the image is on screen
- pub present_complete: ManuallyDrop<FenceT>,
-}
-
-impl SyncObjects {
- pub fn new(device: &mut DeviceT) -> Result<Self> {
- // Sync objects
- let render_complete = device
- .create_semaphore()
- .context("Error creating render_complete semaphore")?;
- let present_complete = device
- .create_fence(true)
- .context("Error creating present_complete fence")?;
-
- Ok(SyncObjects {
- render_complete: ManuallyDrop::new(render_complete),
- present_complete: ManuallyDrop::new(present_complete),
- })
- }
-
- pub fn deactivate(self, device: &mut DeviceT) {
- use core::ptr::read;
-
- unsafe {
- device.destroy_semaphore(ManuallyDrop::into_inner(read(&self.render_complete)));
- device.destroy_fence(ManuallyDrop::into_inner(read(&self.present_complete)));
- }
- }
-}