From fb996488aa651cb2e7f46abc083c4318b47e77cd Mon Sep 17 00:00:00 2001 From: tcmal Date: Sun, 25 Aug 2024 17:44:23 +0100 Subject: wip refactor(render): more work on draw passes --- stockton-render/src/draw/buffer.rs | 231 --------------- .../src/draw/buffers/dedicated_image.rs | 325 +++++++++++++++++++++ stockton-render/src/draw/buffers/draw_buffers.rs | 43 +++ stockton-render/src/draw/buffers/mod.rs | 68 +++++ stockton-render/src/draw/buffers/staged.rs | 188 ++++++++++++ stockton-render/src/draw/camera.rs | 64 ++-- stockton-render/src/draw/context.rs | 28 +- stockton-render/src/draw/depth_buffer.rs | 324 -------------------- stockton-render/src/draw/draw_buffers.rs | 44 --- stockton-render/src/draw/draw_passes/cons.rs | 34 +-- stockton-render/src/draw/draw_passes/level.rs | 10 +- stockton-render/src/draw/draw_passes/mod.rs | 21 +- stockton-render/src/draw/mod.rs | 8 +- stockton-render/src/draw/target.rs | 13 +- stockton-render/src/draw/ui/render.rs | 2 +- stockton-render/src/lib.rs | 44 +-- stockton-render/src/systems.rs | 2 - stockton-render/src/window.rs | 10 +- 18 files changed, 719 insertions(+), 740 deletions(-) delete mode 100644 stockton-render/src/draw/buffer.rs create mode 100644 stockton-render/src/draw/buffers/dedicated_image.rs create mode 100644 stockton-render/src/draw/buffers/draw_buffers.rs create mode 100644 stockton-render/src/draw/buffers/mod.rs create mode 100644 stockton-render/src/draw/buffers/staged.rs delete mode 100644 stockton-render/src/draw/depth_buffer.rs delete mode 100644 stockton-render/src/draw/draw_buffers.rs (limited to 'stockton-render/src') diff --git a/stockton-render/src/draw/buffer.rs b/stockton-render/src/draw/buffer.rs deleted file mode 100644 index 77ac38a..0000000 --- a/stockton-render/src/draw/buffer.rs +++ /dev/null @@ -1,231 +0,0 @@ -use core::mem::{size_of, ManuallyDrop}; -use std::convert::TryInto; -use std::iter::{empty, once}; -use std::ops::{Index, IndexMut}; - -use anyhow::{Context, Result}; -use hal::{ - buffer::Usage, - memory::{Properties, Segment, SparseFlags}, - MemoryTypeId, -}; - -use crate::{error::EnvironmentError, types::*}; - -/// Create a buffer of the given specifications, allocating more device memory. -// TODO: Use a different memory allocator? -pub(crate) fn create_buffer( - device: &mut DeviceT, - adapter: &Adapter, - usage: Usage, - properties: Properties, - size: u64, -) -> Result<(BufferT, MemoryT)> { - let mut buffer = unsafe { device.create_buffer(size, usage, SparseFlags::empty()) } - .context("Error creating buffer")?; - - let requirements = unsafe { device.get_buffer_requirements(&buffer) }; - let memory_type_id = adapter - .physical_device - .memory_properties() - .memory_types - .iter() - .enumerate() - .find(|&(id, memory_type)| { - requirements.type_mask & (1 << id) != 0 && memory_type.properties.contains(properties) - }) - .map(|(id, _)| MemoryTypeId(id)) - .ok_or(EnvironmentError::NoMemoryTypes)?; - - let memory = unsafe { device.allocate_memory(memory_type_id, requirements.size) } - .context("Error allocating memory")?; - - unsafe { device.bind_buffer_memory(&memory, 0, &mut buffer) } - .context("Error binding memory to buffer")?; - - Ok((buffer, memory)) -} - -/// A buffer that can be modified by the CPU -pub trait ModifiableBuffer: IndexMut { - /// Get a handle to the underlying GPU buffer - fn get_buffer(&mut self) -> &BufferT; - - /// Commit all changes to GPU memory, returning a handle to the GPU buffer - fn commit<'a>( - &'a mut self, - device: &DeviceT, - command_queue: &mut QueueT, - command_pool: &mut CommandPoolT, - ) -> Result<&'a BufferT>; -} - -/// A GPU buffer that is written to using a staging buffer -pub struct StagedBuffer<'a, T: Sized> { - /// CPU-visible buffer - staged_buffer: ManuallyDrop, - - /// CPU-visible memory - staged_memory: ManuallyDrop, - - /// GPU Buffer - buffer: ManuallyDrop, - - /// GPU Memory - memory: ManuallyDrop, - - /// Where staged buffer is mapped in CPU memory - staged_mapped_memory: &'a mut [T], - - /// If staged memory has been changed since last `commit` - staged_is_dirty: bool, - - /// The highest index in the buffer that's been written to. - pub highest_used: usize, -} - -impl<'a, T: Sized> StagedBuffer<'a, T> { - /// size is the size in T - pub fn new(device: &mut DeviceT, adapter: &Adapter, usage: Usage, size: u64) -> Result { - // Convert size to bytes - let size_bytes = size * size_of::() as u64; - - // Get CPU-visible buffer - let (staged_buffer, mut staged_memory) = create_buffer( - device, - adapter, - Usage::TRANSFER_SRC, - Properties::CPU_VISIBLE, - size_bytes, - ) - .context("Error creating staging buffer")?; - - // Get GPU Buffer - let (buffer, memory) = create_buffer( - device, - adapter, - Usage::TRANSFER_DST | usage, - Properties::DEVICE_LOCAL | Properties::COHERENT, - size_bytes, - ) - .context("Error creating GPU buffer")?; - - // Map it somewhere and get a slice to that memory - let staged_mapped_memory = unsafe { - let ptr = device - .map_memory( - &mut staged_memory, - Segment { - offset: 0, - size: Some(size_bytes), - }, - ) - .context("Error mapping staged memory")?; - - std::slice::from_raw_parts_mut(ptr as *mut T, size.try_into()?) - }; - - Ok(StagedBuffer { - staged_buffer: ManuallyDrop::new(staged_buffer), - staged_memory: ManuallyDrop::new(staged_memory), - buffer: ManuallyDrop::new(buffer), - memory: ManuallyDrop::new(memory), - staged_mapped_memory, - staged_is_dirty: false, - highest_used: 0, - }) - } - - /// Call this before dropping - pub(crate) fn deactivate(mut self, device: &mut DeviceT) { - unsafe { - device.unmap_memory(&mut self.staged_memory); - - device.free_memory(ManuallyDrop::take(&mut self.staged_memory)); - device.destroy_buffer(ManuallyDrop::take(&mut self.staged_buffer)); - - device.free_memory(ManuallyDrop::take(&mut self.memory)); - device.destroy_buffer(ManuallyDrop::take(&mut self.buffer)); - }; - } -} - -impl<'a, T: Sized> ModifiableBuffer for StagedBuffer<'a, T> { - fn get_buffer(&mut self) -> &BufferT { - &self.buffer - } - - fn commit<'b>( - &'b mut self, - device: &DeviceT, - command_queue: &mut QueueT, - command_pool: &mut CommandPoolT, - ) -> Result<&'b BufferT> { - // Only commit if there's changes to commit. - if self.staged_is_dirty { - // Copy from staged to buffer - let buf = unsafe { - use hal::command::{BufferCopy, CommandBufferFlags}; - // Get a command buffer - let mut buf = command_pool.allocate_one(hal::command::Level::Primary); - - // Put in our copy command - buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); - buf.copy_buffer( - &self.staged_buffer, - &self.buffer, - std::iter::once(BufferCopy { - src: 0, - dst: 0, - size: ((self.highest_used + 1) * size_of::()) as u64, - }), - ); - buf.finish(); - - buf - }; - - // Submit it and wait for completion - // TODO: Proper management of transfer operations - unsafe { - let mut copy_finished = device.create_fence(false)?; - command_queue.submit( - once(&buf), - empty::<(&SemaphoreT, hal::pso::PipelineStage)>(), - empty::<&SemaphoreT>(), - Some(&mut copy_finished), - ); - - device - .wait_for_fence(©_finished, core::u64::MAX) - .context("Error waiting for fence")?; - - // Destroy temporary resources - device.destroy_fence(copy_finished); - command_pool.free(once(buf)); - } - - self.staged_is_dirty = false; - } - - Ok(&self.buffer) - } -} - -impl<'a, T: Sized> Index for StagedBuffer<'a, T> { - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - &self.staged_mapped_memory[index] - } -} - -impl<'a, T: Sized> IndexMut for StagedBuffer<'a, T> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.staged_is_dirty = true; - if index > self.highest_used { - self.highest_used = index; - } - &mut self.staged_mapped_memory[index] - } -} diff --git a/stockton-render/src/draw/buffers/dedicated_image.rs b/stockton-render/src/draw/buffers/dedicated_image.rs new file mode 100644 index 0000000..38a23c9 --- /dev/null +++ b/stockton-render/src/draw/buffers/dedicated_image.rs @@ -0,0 +1,325 @@ +//! A dedicated image. Used for depth buffers. + +use super::create_buffer; +use crate::draw::texture::{LoadableImage, PIXEL_SIZE}; +use crate::types::*; + +use std::{array::IntoIter, convert::TryInto, iter::empty, mem::ManuallyDrop}; + +use anyhow::{Context, Result}; +use hal::{ + buffer::Usage as BufUsage, + format::{Aspects, Format, Swizzle}, + image::{SubresourceRange, Usage, Usage as ImgUsage, ViewKind}, + memory, + memory::{Properties, Segment}, + MemoryTypeId, +}; +use thiserror::Error; + +/// Holds an image that's loaded into GPU memory dedicated only to that image, bypassing the memory allocator. +pub struct DedicatedLoadedImage { + /// The GPU Image handle + image: ManuallyDrop, + + /// The full view of the image + pub image_view: ManuallyDrop, + + /// The memory backing the image + memory: ManuallyDrop, +} + +#[derive(Debug, Error)] +pub enum ImageLoadError { + #[error("No suitable memory type for image memory")] + NoMemoryTypes, +} + +impl DedicatedLoadedImage { + pub fn new( + device: &mut DeviceT, + adapter: &Adapter, + format: Format, + usage: Usage, + resources: SubresourceRange, + width: usize, + height: usize, + ) -> Result { + let (memory, image_ref) = { + // Round up the size to align properly + let initial_row_size = PIXEL_SIZE * width; + let limits = adapter.physical_device.properties().limits; + let row_alignment_mask = limits.optimal_buffer_copy_pitch_alignment as u32 - 1; + + let row_size = + ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize; + debug_assert!(row_size as usize >= initial_row_size); + + // Make the image + let mut image_ref = unsafe { + use hal::image::{Kind, Tiling, ViewCapabilities}; + + device.create_image( + Kind::D2(width as u32, height as u32, 1, 1), + 1, + format, + Tiling::Optimal, + usage, + memory::SparseFlags::empty(), + ViewCapabilities::empty(), + ) + } + .context("Error creating image")?; + + // Allocate memory + let memory = unsafe { + let requirements = device.get_image_requirements(&image_ref); + + let memory_type_id = adapter + .physical_device + .memory_properties() + .memory_types + .iter() + .enumerate() + .find(|&(id, memory_type)| { + requirements.type_mask & (1 << id) != 0 + && memory_type.properties.contains(Properties::DEVICE_LOCAL) + }) + .map(|(id, _)| MemoryTypeId(id)) + .ok_or(ImageLoadError::NoMemoryTypes)?; + + let memory = device + .allocate_memory(memory_type_id, requirements.size) + .context("Error allocating memory for image")?; + + device + .bind_image_memory(&memory, 0, &mut image_ref) + .context("Error binding memory to image")?; + + memory + }; + + (memory, image_ref) + }; + + // Create ImageView and sampler + let image_view = unsafe { + device.create_image_view( + &image_ref, + ViewKind::D2, + format, + Swizzle::NO, + ImgUsage::DEPTH_STENCIL_ATTACHMENT, + resources, + ) + } + .context("Error creating image view")?; + + Ok(DedicatedLoadedImage { + image: ManuallyDrop::new(image_ref), + image_view: ManuallyDrop::new(image_view), + memory: ManuallyDrop::new(memory), + }) + } + + /// Load the given image + pub fn load( + &mut self, + img: T, + device: &mut DeviceT, + adapter: &Adapter, + command_queue: &mut QueueT, + command_pool: &mut CommandPoolT, + ) -> Result<()> { + let initial_row_size = PIXEL_SIZE * img.width() as usize; + let limits = adapter.physical_device.properties().limits; + let row_alignment_mask = limits.optimal_buffer_copy_pitch_alignment as u32 - 1; + + let row_size = + ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize; + let total_size = (row_size * (img.height() as usize)) as u64; + debug_assert!(row_size as usize >= initial_row_size); + + // Make a staging buffer + let (staging_buffer, mut staging_memory) = create_buffer( + device, + adapter, + BufUsage::TRANSFER_SRC, + memory::Properties::CPU_VISIBLE | memory::Properties::COHERENT, + total_size, + ) + .context("Error creating staging buffer")?; + + // Copy everything into it + unsafe { + let mapped_memory: *mut u8 = std::mem::transmute( + device + .map_memory( + &mut staging_memory, + Segment { + offset: 0, + size: None, + }, + ) + .context("Error mapping staging memory")?, + ); + + for y in 0..img.height() as usize { + let dest_base: isize = (y * row_size).try_into()?; + img.copy_row(y as u32, mapped_memory.offset(dest_base)); + } + + device.unmap_memory(&mut staging_memory); + } + + // Copy from staging to image memory + let buf = unsafe { + use hal::command::{BufferImageCopy, CommandBufferFlags}; + use hal::image::{Access, Extent, Layout, Offset, SubresourceLayers}; + use hal::memory::Barrier; + use hal::pso::PipelineStage; + + // Get a command buffer + let mut buf = command_pool.allocate_one(hal::command::Level::Primary); + buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); + + // Setup the layout of our image for copying + let image_barrier = Barrier::Image { + states: (Access::empty(), Layout::Undefined) + ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal), + target: &(*self.image), + families: None, + range: SubresourceRange { + aspects: Aspects::COLOR, + level_start: 0, + level_count: Some(1), + layer_start: 0, + layer_count: Some(1), + }, + }; + buf.pipeline_barrier( + PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER, + memory::Dependencies::empty(), + IntoIter::new([image_barrier]), + ); + + // Copy from buffer to image + buf.copy_buffer_to_image( + &staging_buffer, + &(*self.image), + Layout::TransferDstOptimal, + IntoIter::new([BufferImageCopy { + buffer_offset: 0, + buffer_width: (row_size / PIXEL_SIZE) as u32, + buffer_height: img.height(), + image_layers: SubresourceLayers { + aspects: Aspects::COLOR, + level: 0, + layers: 0..1, + }, + image_offset: Offset { x: 0, y: 0, z: 0 }, + image_extent: Extent { + width: img.width(), + height: img.height(), + depth: 1, + }, + }]), + ); + + // Setup the layout of our image for shaders + let image_barrier = Barrier::Image { + states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal) + ..(Access::SHADER_READ, Layout::ShaderReadOnlyOptimal), + target: &(*self.image), + families: None, + range: SubresourceRange { + aspects: Aspects::COLOR, + level_start: 0, + level_count: Some(1), + layer_start: 0, + layer_count: Some(1), + }, + }; + + buf.pipeline_barrier( + PipelineStage::TRANSFER..PipelineStage::FRAGMENT_SHADER, + memory::Dependencies::empty(), + IntoIter::new([image_barrier]), + ); + + buf.finish(); + + buf + }; + + // Submit our commands and wait for them to finish + unsafe { + let mut setup_finished = device + .create_fence(false) + .context("Error creating setup_finished fence")?; + command_queue.submit( + IntoIter::new([&buf]), + empty(), + empty(), + Some(&mut setup_finished), + ); + + device + .wait_for_fence(&setup_finished, core::u64::MAX) + .context("Error waiting for image load to finish")?; + device.destroy_fence(setup_finished); + }; + + // Clean up temp resources + unsafe { + command_pool.free(std::iter::once(buf)); + + device.free_memory(staging_memory); + device.destroy_buffer(staging_buffer); + } + + Ok(()) + } + + /// Load the given image into a new buffer + pub fn load_into_new( + img: T, + device: &mut DeviceT, + adapter: &Adapter, + command_queue: &mut QueueT, + command_pool: &mut CommandPoolT, + format: Format, + usage: Usage, + ) -> Result { + let mut loaded_image = Self::new( + device, + adapter, + format, + usage | Usage::TRANSFER_DST, + SubresourceRange { + aspects: Aspects::COLOR, + level_start: 0, + level_count: Some(1), + layer_start: 0, + layer_count: Some(1), + }, + img.width() as usize, + img.height() as usize, + )?; + loaded_image.load(img, device, adapter, command_queue, command_pool)?; + + Ok(loaded_image) + } + + /// Properly frees/destroys all the objects in this struct + /// Dropping without doing this is a bad idea + pub fn deactivate(self, device: &mut DeviceT) { + unsafe { + use core::ptr::read; + + device.destroy_image_view(ManuallyDrop::into_inner(read(&self.image_view))); + device.destroy_image(ManuallyDrop::into_inner(read(&self.image))); + device.free_memory(ManuallyDrop::into_inner(read(&self.memory))); + } + } +} diff --git a/stockton-render/src/draw/buffers/draw_buffers.rs b/stockton-render/src/draw/buffers/draw_buffers.rs new file mode 100644 index 0000000..5baec92 --- /dev/null +++ b/stockton-render/src/draw/buffers/draw_buffers.rs @@ -0,0 +1,43 @@ +//! A vertex and index buffer set for drawing + +use super::StagedBuffer; +use crate::types::*; + +use anyhow::{Context, Result}; +use hal::buffer::Usage; +use std::mem::ManuallyDrop; + +/// Initial size of vertex buffer. TODO: Way of overriding this +pub const INITIAL_VERT_SIZE: u64 = 3 * 3000; + +/// Initial size of index buffer. TODO: Way of overriding this +pub const INITIAL_INDEX_SIZE: u64 = 3000; + +/// The buffers used for drawing, ie index and vertex buffer +pub struct DrawBuffers<'a, T: Sized> { + pub vertex_buffer: ManuallyDrop>, + pub index_buffer: ManuallyDrop>, +} + +impl<'a, T> DrawBuffers<'a, T> { + pub fn new(device: &mut DeviceT, adapter: &Adapter) -> Result> { + let vert = StagedBuffer::new(device, adapter, Usage::VERTEX, INITIAL_VERT_SIZE) + .context("Error creating vertex buffer")?; + let index = StagedBuffer::new(device, adapter, Usage::INDEX, INITIAL_INDEX_SIZE) + .context("Error creating index buffer")?; + + Ok(DrawBuffers { + vertex_buffer: ManuallyDrop::new(vert), + index_buffer: ManuallyDrop::new(index), + }) + } + + pub fn deactivate(self, device: &mut DeviceT) { + unsafe { + use core::ptr::read; + + ManuallyDrop::into_inner(read(&self.vertex_buffer)).deactivate(device); + ManuallyDrop::into_inner(read(&self.index_buffer)).deactivate(device); + } + } +} diff --git a/stockton-render/src/draw/buffers/mod.rs b/stockton-render/src/draw/buffers/mod.rs new file mode 100644 index 0000000..5093872 --- /dev/null +++ b/stockton-render/src/draw/buffers/mod.rs @@ -0,0 +1,68 @@ +//! All sorts of buffers + +use std::ops::IndexMut; + +use crate::{error::EnvironmentError, types::*}; + +use anyhow::{Context, Result}; +use hal::{ + buffer::Usage, + memory::{Properties, SparseFlags}, + MemoryTypeId, +}; + +mod dedicated_image; +mod draw_buffers; +mod staged; + +pub use dedicated_image::DedicatedLoadedImage; +pub use draw_buffers::DrawBuffers; +pub use staged::StagedBuffer; + +/// Create a buffer of the given specifications, allocating more device memory. +// TODO: Use a different memory allocator? +pub(crate) fn create_buffer( + device: &mut DeviceT, + adapter: &Adapter, + usage: Usage, + properties: Properties, + size: u64, +) -> Result<(BufferT, MemoryT)> { + let mut buffer = unsafe { device.create_buffer(size, usage, SparseFlags::empty()) } + .context("Error creating buffer")?; + + let requirements = unsafe { device.get_buffer_requirements(&buffer) }; + let memory_type_id = adapter + .physical_device + .memory_properties() + .memory_types + .iter() + .enumerate() + .find(|&(id, memory_type)| { + requirements.type_mask & (1 << id) != 0 && memory_type.properties.contains(properties) + }) + .map(|(id, _)| MemoryTypeId(id)) + .ok_or(EnvironmentError::NoMemoryTypes)?; + + let memory = unsafe { device.allocate_memory(memory_type_id, requirements.size) } + .context("Error allocating memory")?; + + unsafe { device.bind_buffer_memory(&memory, 0, &mut buffer) } + .context("Error binding memory to buffer")?; + + Ok((buffer, memory)) +} + +/// A buffer that can be modified by the CPU +pub trait ModifiableBuffer: IndexMut { + /// Get a handle to the underlying GPU buffer + fn get_buffer(&mut self) -> &BufferT; + + /// Commit all changes to GPU memory, returning a handle to the GPU buffer + fn commit<'a>( + &'a mut self, + device: &DeviceT, + command_queue: &mut QueueT, + command_pool: &mut CommandPoolT, + ) -> Result<&'a BufferT>; +} diff --git a/stockton-render/src/draw/buffers/staged.rs b/stockton-render/src/draw/buffers/staged.rs new file mode 100644 index 0000000..f92c41d --- /dev/null +++ b/stockton-render/src/draw/buffers/staged.rs @@ -0,0 +1,188 @@ +//! A buffer that can be written to by the CPU using staging memory + +use super::{create_buffer, ModifiableBuffer}; +use crate::{error::EnvironmentError, types::*}; + +use core::mem::{size_of, ManuallyDrop}; +use std::{ + convert::TryInto, + iter::{empty, once}, + ops::{Index, IndexMut}, +}; + +use anyhow::{Context, Result}; +use hal::{ + buffer::Usage, + memory::{Properties, Segment, SparseFlags}, + MemoryTypeId, +}; + +/// A GPU buffer that is written to using a staging buffer +pub struct StagedBuffer<'a, T: Sized> { + /// CPU-visible buffer + staged_buffer: ManuallyDrop, + + /// CPU-visible memory + staged_memory: ManuallyDrop, + + /// GPU Buffer + buffer: ManuallyDrop, + + /// GPU Memory + memory: ManuallyDrop, + + /// Where staged buffer is mapped in CPU memory + staged_mapped_memory: &'a mut [T], + + /// If staged memory has been changed since last `commit` + staged_is_dirty: bool, + + /// The highest index in the buffer that's been written to. + pub highest_used: usize, +} + +impl<'a, T: Sized> StagedBuffer<'a, T> { + /// size is the size in T + pub fn new(device: &mut DeviceT, adapter: &Adapter, usage: Usage, size: u64) -> Result { + // Convert size to bytes + let size_bytes = size * size_of::() as u64; + + // Get CPU-visible buffer + let (staged_buffer, mut staged_memory) = create_buffer( + device, + adapter, + Usage::TRANSFER_SRC, + Properties::CPU_VISIBLE, + size_bytes, + ) + .context("Error creating staging buffer")?; + + // Get GPU Buffer + let (buffer, memory) = create_buffer( + device, + adapter, + Usage::TRANSFER_DST | usage, + Properties::DEVICE_LOCAL | Properties::COHERENT, + size_bytes, + ) + .context("Error creating GPU buffer")?; + + // Map it somewhere and get a slice to that memory + let staged_mapped_memory = unsafe { + let ptr = device + .map_memory( + &mut staged_memory, + Segment { + offset: 0, + size: Some(size_bytes), + }, + ) + .context("Error mapping staged memory")?; + + std::slice::from_raw_parts_mut(ptr as *mut T, size.try_into()?) + }; + + Ok(StagedBuffer { + staged_buffer: ManuallyDrop::new(staged_buffer), + staged_memory: ManuallyDrop::new(staged_memory), + buffer: ManuallyDrop::new(buffer), + memory: ManuallyDrop::new(memory), + staged_mapped_memory, + staged_is_dirty: false, + highest_used: 0, + }) + } + + /// Call this before dropping + pub(crate) fn deactivate(mut self, device: &mut DeviceT) { + unsafe { + device.unmap_memory(&mut self.staged_memory); + + device.free_memory(ManuallyDrop::take(&mut self.staged_memory)); + device.destroy_buffer(ManuallyDrop::take(&mut self.staged_buffer)); + + device.free_memory(ManuallyDrop::take(&mut self.memory)); + device.destroy_buffer(ManuallyDrop::take(&mut self.buffer)); + }; + } +} + +impl<'a, T: Sized> ModifiableBuffer for StagedBuffer<'a, T> { + fn get_buffer(&mut self) -> &BufferT { + &self.buffer + } + + fn commit<'b>( + &'b mut self, + device: &DeviceT, + command_queue: &mut QueueT, + command_pool: &mut CommandPoolT, + ) -> Result<&'b BufferT> { + // Only commit if there's changes to commit. + if self.staged_is_dirty { + // Copy from staged to buffer + let buf = unsafe { + use hal::command::{BufferCopy, CommandBufferFlags}; + // Get a command buffer + let mut buf = command_pool.allocate_one(hal::command::Level::Primary); + + // Put in our copy command + buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); + buf.copy_buffer( + &self.staged_buffer, + &self.buffer, + std::iter::once(BufferCopy { + src: 0, + dst: 0, + size: ((self.highest_used + 1) * size_of::()) as u64, + }), + ); + buf.finish(); + + buf + }; + + // Submit it and wait for completion + // TODO: Proper management of transfer operations + unsafe { + let mut copy_finished = device.create_fence(false)?; + command_queue.submit( + once(&buf), + empty::<(&SemaphoreT, hal::pso::PipelineStage)>(), + empty::<&SemaphoreT>(), + Some(&mut copy_finished), + ); + + device + .wait_for_fence(©_finished, core::u64::MAX) + .context("Error waiting for fence")?; + + // Destroy temporary resources + device.destroy_fence(copy_finished); + command_pool.free(once(buf)); + } + + self.staged_is_dirty = false; + } + + Ok(&self.buffer) + } +} + +impl<'a, T: Sized> Index for StagedBuffer<'a, T> { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.staged_mapped_memory[index] + } +} + +impl<'a, T: Sized> IndexMut for StagedBuffer<'a, T> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.staged_is_dirty = true; + if index > self.highest_used { + self.highest_used = index; + } + &mut self.staged_mapped_memory[index] + } +} diff --git a/stockton-render/src/draw/camera.rs b/stockton-render/src/draw/camera.rs index a9d10f4..421b661 100644 --- a/stockton-render/src/draw/camera.rs +++ b/stockton-render/src/draw/camera.rs @@ -22,35 +22,35 @@ fn euler_to_direction(euler: &Vector3) -> Vector3 { ) } -#[system(for_each)] -#[filter(maybe_changed::() | maybe_changed::())] -pub fn calc_vp_matrix( - transform: &Transform, - settings: &CameraSettings, - #[resource] renderer: &mut Renderer, -) { - let ratio = renderer.context.target_chain.properties.extent.width as f32 - / renderer.context.target_chain.properties.extent.height as f32; - // Get look direction from euler angles - let direction = euler_to_direction(&transform.rotation); - - // Converts world space to camera space - let view_matrix = look_at_lh( - &transform.position, - &(transform.position + direction), - &Vector3::new(0.0, 1.0, 0.0), - ); - - // Converts camera space to screen space - let projection_matrix = { - let mut temp = perspective_lh_zo(ratio, settings.fov, settings.near, settings.far); - - // Vulkan's co-ord system is different from OpenGLs - temp[(1, 1)] *= -1.0; - - temp - }; - - // Chain them together into a single matrix - renderer.context.vp_matrix = projection_matrix * view_matrix -} +// #[system(for_each)] +// #[filter(maybe_changed::() | maybe_changed::())] +// pub fn calc_vp_matrix( +// transform: &Transform, +// settings: &CameraSettings, +// #[resource] renderer: &mut Renderer, +// ) { +// let ratio = renderer.context.target_chain.properties.extent.width as f32 +// / renderer.context.target_chain.properties.extent.height as f32; +// // Get look direction from euler angles +// let direction = euler_to_direction(&transform.rotation); + +// // Converts world space to camera space +// let view_matrix = look_at_lh( +// &transform.position, +// &(transform.position + direction), +// &Vector3::new(0.0, 1.0, 0.0), +// ); + +// // Converts camera space to screen space +// let projection_matrix = { +// let mut temp = perspective_lh_zo(ratio, settings.fov, settings.near, settings.far); + +// // Vulkan's co-ord system is different from OpenGLs +// temp[(1, 1)] *= -1.0; + +// temp +// }; + +// // Chain them together into a single matrix +// renderer.context.vp_matrix = projection_matrix * view_matrix +// } diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index 2d3d92d..1a690fe 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -24,13 +24,12 @@ use crate::{ window::UiState, }; use stockton_levels::prelude::*; +use stockton_types::Session; /// Contains all the hal related stuff. /// In the end, this takes in a depth-sorted list of faces and a map file and renders them. // TODO: Settings for clear colour, buffer sizes, etc -pub struct RenderingContext> { - pub map: Arc>, - +pub struct RenderingContext { // Parents for most of these things /// Vulkan Instance instance: ManuallyDrop, @@ -60,19 +59,12 @@ pub struct RenderingContext RenderingContext -where - DP: DrawPass, -{ - // TODO: Arbitrary drawpass input +impl RenderingContext { /// Create a new RenderingContext for the given window. pub fn new>( window: &Window, - _ui: &mut UiState, - map: M, idp: ILDP, ) -> Result { - let map = Arc::new(RwLock::new(map)); // Create surface let (instance, surface, mut adapters) = unsafe { let instance = @@ -174,7 +166,6 @@ where drop(device); Ok(RenderingContext { - map, instance: ManuallyDrop::new(instance), device: device_lock, @@ -231,8 +222,8 @@ where Ok(()) } - /// Draw all vertices in the buffer - pub fn draw_next_frame(&mut self) -> Result<()> { + /// Draw onto the next frame of the swapchain + pub fn draw_next_frame(&mut self, session: &Session) -> Result<()> { let mut device = self .device .write() @@ -241,20 +232,19 @@ where let mut queue = self .queue .write() - .map_err(|_| LockPoisoned::Map) - .context("Error getting map lock")?; - let map = self.map.read().or(Err(LockPoisoned::Map))?; + .map_err(|_| LockPoisoned::Queue) + .context("Error getting draw queue lock")?; // Level draw pass self.target_chain - .do_draw_with(&mut device, &mut queue, &*self.draw_pass, &*map) + .do_draw_with(&mut device, &mut queue, &*self.draw_pass, session) .context("Error preparing next target")?; Ok(()) } } -impl core::ops::Drop for RenderingContext { +impl core::ops::Drop for RenderingContext { fn drop(&mut self) { { self.device.write().unwrap().wait_idle().unwrap(); diff --git a/stockton-render/src/draw/depth_buffer.rs b/stockton-render/src/draw/depth_buffer.rs deleted file mode 100644 index e3306c5..0000000 --- a/stockton-render/src/draw/depth_buffer.rs +++ /dev/null @@ -1,324 +0,0 @@ -use crate::draw::buffer::create_buffer; -use gfx_hal::{format::Aspects, memory::Properties, MemoryTypeId}; -use hal::{ - buffer::Usage as BufUsage, - format::{Format, Swizzle}, - image::{SubresourceRange, Usage, Usage as ImgUsage, ViewKind}, - memory, - memory::Segment, -}; -use std::{array::IntoIter, convert::TryInto, iter::empty}; - -use crate::types::*; -use anyhow::{Context, Result}; -use std::mem::ManuallyDrop; -use thiserror::Error; - -use super::texture::{LoadableImage, PIXEL_SIZE}; - -/// Holds an image that's loaded into GPU memory dedicated only to that image, bypassing the memory allocator. -pub struct DedicatedLoadedImage { - /// The GPU Image handle - image: ManuallyDrop, - - /// The full view of the image - pub image_view: ManuallyDrop, - - /// The memory backing the image - memory: ManuallyDrop, -} - -#[derive(Debug, Error)] -pub enum ImageLoadError { - #[error("No suitable memory type for image memory")] - NoMemoryTypes, -} - -impl DedicatedLoadedImage { - pub fn new( - device: &mut DeviceT, - adapter: &Adapter, - format: Format, - usage: Usage, - resources: SubresourceRange, - width: usize, - height: usize, - ) -> Result { - let (memory, image_ref) = { - // Round up the size to align properly - let initial_row_size = PIXEL_SIZE * width; - let limits = adapter.physical_device.properties().limits; - let row_alignment_mask = limits.optimal_buffer_copy_pitch_alignment as u32 - 1; - - let row_size = - ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize; - debug_assert!(row_size as usize >= initial_row_size); - - // Make the image - let mut image_ref = unsafe { - use hal::image::{Kind, Tiling, ViewCapabilities}; - - device.create_image( - Kind::D2(width as u32, height as u32, 1, 1), - 1, - format, - Tiling::Optimal, - usage, - memory::SparseFlags::empty(), - ViewCapabilities::empty(), - ) - } - .context("Error creating image")?; - - // Allocate memory - let memory = unsafe { - let requirements = device.get_image_requirements(&image_ref); - - let memory_type_id = adapter - .physical_device - .memory_properties() - .memory_types - .iter() - .enumerate() - .find(|&(id, memory_type)| { - requirements.type_mask & (1 << id) != 0 - && memory_type.properties.contains(Properties::DEVICE_LOCAL) - }) - .map(|(id, _)| MemoryTypeId(id)) - .ok_or(ImageLoadError::NoMemoryTypes)?; - - let memory = device - .allocate_memory(memory_type_id, requirements.size) - .context("Error allocating memory for image")?; - - device - .bind_image_memory(&memory, 0, &mut image_ref) - .context("Error binding memory to image")?; - - memory - }; - - (memory, image_ref) - }; - - // Create ImageView and sampler - let image_view = unsafe { - device.create_image_view( - &image_ref, - ViewKind::D2, - format, - Swizzle::NO, - ImgUsage::DEPTH_STENCIL_ATTACHMENT, - resources, - ) - } - .context("Error creating image view")?; - - Ok(DedicatedLoadedImage { - image: ManuallyDrop::new(image_ref), - image_view: ManuallyDrop::new(image_view), - memory: ManuallyDrop::new(memory), - }) - } - - /// Load the given image - pub fn load( - &mut self, - img: T, - device: &mut DeviceT, - adapter: &Adapter, - command_queue: &mut QueueT, - command_pool: &mut CommandPoolT, - ) -> Result<()> { - let initial_row_size = PIXEL_SIZE * img.width() as usize; - let limits = adapter.physical_device.properties().limits; - let row_alignment_mask = limits.optimal_buffer_copy_pitch_alignment as u32 - 1; - - let row_size = - ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize; - let total_size = (row_size * (img.height() as usize)) as u64; - debug_assert!(row_size as usize >= initial_row_size); - - // Make a staging buffer - let (staging_buffer, mut staging_memory) = create_buffer( - device, - adapter, - BufUsage::TRANSFER_SRC, - memory::Properties::CPU_VISIBLE | memory::Properties::COHERENT, - total_size, - ) - .context("Error creating staging buffer")?; - - // Copy everything into it - unsafe { - let mapped_memory: *mut u8 = std::mem::transmute( - device - .map_memory( - &mut staging_memory, - Segment { - offset: 0, - size: None, - }, - ) - .context("Error mapping staging memory")?, - ); - - for y in 0..img.height() as usize { - let dest_base: isize = (y * row_size).try_into()?; - img.copy_row(y as u32, mapped_memory.offset(dest_base)); - } - - device.unmap_memory(&mut staging_memory); - } - - // Copy from staging to image memory - let buf = unsafe { - use hal::command::{BufferImageCopy, CommandBufferFlags}; - use hal::image::{Access, Extent, Layout, Offset, SubresourceLayers}; - use hal::memory::Barrier; - use hal::pso::PipelineStage; - - // Get a command buffer - let mut buf = command_pool.allocate_one(hal::command::Level::Primary); - buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); - - // Setup the layout of our image for copying - let image_barrier = Barrier::Image { - states: (Access::empty(), Layout::Undefined) - ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal), - target: &(*self.image), - families: None, - range: SubresourceRange { - aspects: Aspects::COLOR, - level_start: 0, - level_count: Some(1), - layer_start: 0, - layer_count: Some(1), - }, - }; - buf.pipeline_barrier( - PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER, - memory::Dependencies::empty(), - IntoIter::new([image_barrier]), - ); - - // Copy from buffer to image - buf.copy_buffer_to_image( - &staging_buffer, - &(*self.image), - Layout::TransferDstOptimal, - IntoIter::new([BufferImageCopy { - buffer_offset: 0, - buffer_width: (row_size / PIXEL_SIZE) as u32, - buffer_height: img.height(), - image_layers: SubresourceLayers { - aspects: Aspects::COLOR, - level: 0, - layers: 0..1, - }, - image_offset: Offset { x: 0, y: 0, z: 0 }, - image_extent: Extent { - width: img.width(), - height: img.height(), - depth: 1, - }, - }]), - ); - - // Setup the layout of our image for shaders - let image_barrier = Barrier::Image { - states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal) - ..(Access::SHADER_READ, Layout::ShaderReadOnlyOptimal), - target: &(*self.image), - families: None, - range: SubresourceRange { - aspects: Aspects::COLOR, - level_start: 0, - level_count: Some(1), - layer_start: 0, - layer_count: Some(1), - }, - }; - - buf.pipeline_barrier( - PipelineStage::TRANSFER..PipelineStage::FRAGMENT_SHADER, - memory::Dependencies::empty(), - IntoIter::new([image_barrier]), - ); - - buf.finish(); - - buf - }; - - // Submit our commands and wait for them to finish - unsafe { - let mut setup_finished = device - .create_fence(false) - .context("Error creating setup_finished fence")?; - command_queue.submit( - IntoIter::new([&buf]), - empty(), - empty(), - Some(&mut setup_finished), - ); - - device - .wait_for_fence(&setup_finished, core::u64::MAX) - .context("Error waiting for image load to finish")?; - device.destroy_fence(setup_finished); - }; - - // Clean up temp resources - unsafe { - command_pool.free(std::iter::once(buf)); - - device.free_memory(staging_memory); - device.destroy_buffer(staging_buffer); - } - - Ok(()) - } - - /// Load the given image into a new buffer - pub fn load_into_new( - img: T, - device: &mut DeviceT, - adapter: &Adapter, - command_queue: &mut QueueT, - command_pool: &mut CommandPoolT, - format: Format, - usage: Usage, - ) -> Result { - let mut loaded_image = Self::new( - device, - adapter, - format, - usage | Usage::TRANSFER_DST, - SubresourceRange { - aspects: Aspects::COLOR, - level_start: 0, - level_count: Some(1), - layer_start: 0, - layer_count: Some(1), - }, - img.width() as usize, - img.height() as usize, - )?; - loaded_image.load(img, device, adapter, command_queue, command_pool)?; - - Ok(loaded_image) - } - - /// Properly frees/destroys all the objects in this struct - /// Dropping without doing this is a bad idea - pub fn deactivate(self, device: &mut DeviceT) { - unsafe { - use core::ptr::read; - - device.destroy_image_view(ManuallyDrop::into_inner(read(&self.image_view))); - device.destroy_image(ManuallyDrop::into_inner(read(&self.image))); - device.free_memory(ManuallyDrop::into_inner(read(&self.memory))); - } - } -} diff --git a/stockton-render/src/draw/draw_buffers.rs b/stockton-render/src/draw/draw_buffers.rs deleted file mode 100644 index 2d2fce4..0000000 --- a/stockton-render/src/draw/draw_buffers.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::{draw::buffer::StagedBuffer, types::*}; -use anyhow::{Context, Result}; -use hal::buffer::Usage; -use std::mem::ManuallyDrop; -use stockton_types::{Vector2, Vector3}; - -/// Represents a point of a triangle, including UV and texture information. -#[derive(Debug, Clone, Copy)] -pub struct UvPoint(pub Vector3, pub i32, pub Vector2); - -/// Initial size of vertex buffer. TODO: Way of overriding this -pub const INITIAL_VERT_SIZE: u64 = 3 * 3000; - -/// Initial size of index buffer. TODO: Way of overriding this -pub const INITIAL_INDEX_SIZE: u64 = 3000; - -/// The buffers used for drawing, ie index and vertex buffer -pub struct DrawBuffers<'a, T: Sized> { - pub vertex_buffer: ManuallyDrop>, - pub index_buffer: ManuallyDrop>, -} - -impl<'a, T> DrawBuffers<'a, T> { - pub fn new(device: &mut DeviceT, adapter: &Adapter) -> Result> { - let vert = StagedBuffer::new(device, adapter, Usage::VERTEX, INITIAL_VERT_SIZE) - .context("Error creating vertex buffer")?; - let index = StagedBuffer::new(device, adapter, Usage::INDEX, INITIAL_INDEX_SIZE) - .context("Error creating index buffer")?; - - Ok(DrawBuffers { - vertex_buffer: ManuallyDrop::new(vert), - index_buffer: ManuallyDrop::new(index), - }) - } - - pub fn deactivate(self, device: &mut DeviceT) { - unsafe { - use core::ptr::read; - - ManuallyDrop::into_inner(read(&self.vertex_buffer)).deactivate(device); - ManuallyDrop::into_inner(read(&self.index_buffer)).deactivate(device); - } - } -} diff --git a/stockton-render/src/draw/draw_passes/cons.rs b/stockton-render/src/draw/draw_passes/cons.rs index 274bd76..76e2f32 100644 --- a/stockton-render/src/draw/draw_passes/cons.rs +++ b/stockton-render/src/draw/draw_passes/cons.rs @@ -1,22 +1,22 @@ //! Code for using multiple draw passes in place of just one //! Note that this can be extended to an arbitrary amount of draw passes. -use super::{DrawPass, DrawPassInput}; +use super::DrawPass; use crate::{draw::queue_negotiator::QueueNegotiator, types::*}; +use stockton_types::Session; + use anyhow::Result; /// One draw pass, then another. -struct ConsDrawPass { +pub struct ConsDrawPass { a: A, b: B, } impl DrawPass for ConsDrawPass { - type Input = ConsDrawPassInput; - - fn queue_draw(&self, input: &Self::Input, cmd_buffer: &mut CommandBufferT) -> Result<()> { - self.a.queue_draw(&input.a, cmd_buffer)?; - self.b.queue_draw(&input.b, cmd_buffer)?; + fn queue_draw(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()> { + self.a.queue_draw(&session, cmd_buffer)?; + self.b.queue_draw(&session, cmd_buffer)?; Ok(()) } @@ -34,21 +34,12 @@ impl DrawPass for ConsDrawPass { } } -/// Input for a ConsDrawPass. -struct ConsDrawPassInput { - pub a: A, - pub b: B, -} - -impl DrawPassInput for ConsDrawPassInput {} - /// A draw pass that does nothing. Can be used at the end of sequences if there's an odd number of draw passes. -struct NilDrawPass; +pub struct NilDrawPass; impl DrawPass for NilDrawPass { - type Input = NilDrawPassInput; - fn queue_draw(&self, _input: &Self::Input, _cmd_buffer: &mut CommandBufferT) -> Result<()> { + fn queue_draw(&self, _input: &Session, _cmd_buffer: &mut CommandBufferT) -> Result<()> { Ok(()) } @@ -58,9 +49,4 @@ impl DrawPass for NilDrawPass { ) -> Result)>> { Ok(vec![]) } -} - -/// Input for a NilDrawPass. -struct NilDrawPassInput; - -impl DrawPassInput for NilDrawPassInput {} +} \ No newline at end of file diff --git a/stockton-render/src/draw/draw_passes/level.rs b/stockton-render/src/draw/draw_passes/level.rs index afcb703..b968a1a 100644 --- a/stockton-render/src/draw/draw_passes/level.rs +++ b/stockton-render/src/draw/draw_passes/level.rs @@ -1,6 +1,6 @@ //! Minimal code for drawing any level, based on traits from stockton-levels -use super::{DrawPass, DrawPassInput, IntoDrawPass}; +use super::{DrawPass, IntoDrawPass}; use crate::{ draw::{queue_negotiator::QueueNegotiator, target::SwapchainProperties, texture::TextureRepo}, error::EnvironmentError, @@ -30,16 +30,10 @@ pub struct LevelDrawPass { _d: PhantomData, } -/// Any map can be used as draw pass input. -/// TODO: Restrict this based on the type of the renderer. -impl DrawPassInput for T {} - impl DrawPass for LevelDrawPass { - type Input = M; - fn queue_draw( &self, - _file: &Self::Input, + _input: &Session, _cmd_buffer: &mut crate::types::CommandBufferT, ) -> anyhow::Result<()> { todo!() diff --git a/stockton-render/src/draw/draw_passes/mod.rs b/stockton-render/src/draw/draw_passes/mod.rs index 76dd8d6..566a64b 100644 --- a/stockton-render/src/draw/draw_passes/mod.rs +++ b/stockton-render/src/draw/draw_passes/mod.rs @@ -1,26 +1,23 @@ //! Traits and common draw passes. +use super::{queue_negotiator::QueueNegotiator, target::SwapchainProperties}; +use crate::types::*; +use stockton_types::Session; -mod cons; -mod level; use std::sync::{Arc, RwLock}; -pub use level::LevelDrawPass; - -use super::{queue_negotiator::QueueNegotiator, target::SwapchainProperties}; -use crate::types::*; use anyhow::Result; -/// Type can be used as input to a draw pass. This requires it being available from only the resources at draw time. -pub trait DrawPassInput {} +mod cons; +mod level; + +pub use level::LevelDrawPass; +pub use cons::{ConsDrawPass, NilDrawPass}; /// One of several 'passes' that draw on each frame. pub trait DrawPass { - /// Extra input required for this draw pass. - type Input: DrawPassInput; - /// Queue any necessary draw commands to cmd_buffer /// This should assume the command buffer isn't in the middle of a renderpass, and should leave it as such. - fn queue_draw(&self, input: &Self::Input, cmd_buffer: &mut CommandBufferT) -> Result<()>; + fn queue_draw(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()>; /// This function should ask the queue negotatior to find families for any auxilary operations this draw pass needs to perform /// For example, .find(&TexLoadQueue) diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs index 5e1d2cd..411e835 100644 --- a/stockton-render/src/draw/mod.rs +++ b/stockton-render/src/draw/mod.rs @@ -2,17 +2,15 @@ pub mod target; -mod buffer; +mod buffers; mod camera; mod context; -mod depth_buffer; -mod draw_buffers; pub mod draw_passes; mod queue_negotiator; mod texture; mod ui; mod utils; -pub use self::camera::calc_vp_matrix_system; pub use self::context::RenderingContext; -pub use self::draw_buffers::UvPoint; + +pub use self::draw_passes::*; diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs index 754bad3..c46feb5 100644 --- a/stockton-render/src/draw/target.rs +++ b/stockton-render/src/draw/target.rs @@ -6,15 +6,17 @@ use std::{ }; use hal::{ + command::CommandBufferFlags, format::{ChannelType, Format, ImageFeature}, image::{Extent, Usage as ImgUsage}, pso::Viewport, window::{CompositeAlphaMode, Extent2D, PresentMode, SwapchainConfig}, }; -use super::{depth_buffer::DedicatedLoadedImage, draw_passes::DrawPass}; +use super::{buffers::DedicatedLoadedImage, draw_passes::DrawPass}; use crate::{error::EnvironmentError, types::*}; use anyhow::{Context, Result}; +use stockton_types::Session; #[derive(Debug, Clone)] pub struct SwapchainProperties { @@ -249,7 +251,7 @@ impl TargetChain { device: &mut DeviceT, command_queue: &mut QueueT, dp: &DP, - dpi: &DP::Input, + 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; @@ -275,9 +277,12 @@ impl TargetChain { }; // Record commands - dp.queue_draw(dpi, &mut target.cmd_buffer) - .context("Error in draw pass")?; unsafe { + target.cmd_buffer.begin_primary(CommandBufferFlags::empty()); + + dp.queue_draw(session, &mut target.cmd_buffer) + .context("Error in draw pass")?; + target.cmd_buffer.finish(); } diff --git a/stockton-render/src/draw/ui/render.rs b/stockton-render/src/draw/ui/render.rs index a3e0f04..009a1b7 100644 --- a/stockton-render/src/draw/ui/render.rs +++ b/stockton-render/src/draw/ui/render.rs @@ -2,7 +2,7 @@ use crate::draw::texture::TextureRepo; use hal::pso::{Rect, ShaderStageFlags}; use super::UiPoint; -use crate::draw::draw_buffers::DrawBuffers; +use crate::draw::buffers::DrawBuffers; use crate::types::*; use crate::UiState; use anyhow::{anyhow, Result}; diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs index 4eb51e5..850d3eb 100644 --- a/stockton-render/src/lib.rs +++ b/stockton-render/src/lib.rs @@ -14,7 +14,10 @@ pub mod systems; mod types; pub mod window; -use draw::RenderingContext; +use draw::{ + RenderingContext, + draw_passes::{DrawPass, IntoDrawPass} +}; use error::full_error_display; use legion::world::SubWorld; use legion::IntoQuery; @@ -27,7 +30,7 @@ use anyhow::Result; use log::error; use stockton_levels::prelude::*; use stockton_types::components::{CameraSettings, Transform}; -use stockton_types::Vector3; +use stockton_types::{Vector3, Session}; use winit::event_loop::ControlFlow; use winit::window::Window; @@ -35,9 +38,9 @@ use std::sync::mpsc::channel; /// Renders a world to a window when you tell it to. /// Also takes ownership of the window and channels window events to be processed outside winit's event loop. -pub struct Renderer { +pub struct Renderer { /// All the vulkan stuff - pub(crate) context: RenderingContext, + pub(crate) context: RenderingContext, /// For getting events from the winit event loop pub window_events: Receiver, @@ -46,15 +49,15 @@ pub struct Renderer { pub update_control_flow: Arc>, } -impl Renderer { +impl Renderer { /// Create a new Renderer. - pub fn new(window: &Window, ui: &mut UiState, file: M) -> Result<(Self, Sender)> { + pub fn new>(window: &Window, ui: &mut UiState, idp: IDP) -> Result<(Self, Sender)> { let (tx, rx) = channel(); let update_control_flow = Arc::new(RwLock::new(ControlFlow::Poll)); Ok(( Renderer { - context: RenderingContext::new(window, ui, file, ())?, + context: RenderingContext::new(window, idp)?, window_events: rx, update_control_flow, }, @@ -62,15 +65,15 @@ impl Renderer { )) } - /// Render a single frame of the given map. - fn render(&mut self, _ui: &mut UiState, _pos: Vector3) -> Result<()> { + /// Render a single frame of the given session. + fn render(&mut self, session: &Session) -> Result<()> { // Try to draw - if self.context.draw_next_frame().is_err() { + if self.context.draw_next_frame(session).is_err() { // Probably the surface changed unsafe { self.context.handle_surface_change()? }; // If it fails twice, then error - self.context.draw_next_frame()?; + self.context.draw_next_frame(session)?; } Ok(()) @@ -79,21 +82,4 @@ impl Renderer { fn resize(&mut self) -> Result<()> { unsafe { self.context.handle_surface_change() } } -} - -/// A system that just renders the world. -#[system] -#[read_component(Transform)] -#[read_component(CameraSettings)] -pub fn do_render( - #[resource] renderer: &mut Renderer, - #[resource] ui: &mut UiState, - world: &SubWorld, -) { - let mut query = <(&Transform, &CameraSettings)>::query(); - for (transform, _) in query.iter(world) { - if let Err(err) = renderer.render(ui, transform.position) { - error!("{}", full_error_display(err)); - } - } -} +} \ No newline at end of file diff --git a/stockton-render/src/systems.rs b/stockton-render/src/systems.rs index b0c33c2..67cea84 100644 --- a/stockton-render/src/systems.rs +++ b/stockton-render/src/systems.rs @@ -1,3 +1 @@ -pub use crate::do_render_system; -pub use crate::draw::calc_vp_matrix_system; pub use crate::window::process_window_events_system; diff --git a/stockton-render/src/window.rs b/stockton-render/src/window.rs index 7b63bc3..6e6a0e1 100644 --- a/stockton-render/src/window.rs +++ b/stockton-render/src/window.rs @@ -1,4 +1,4 @@ -use crate::{error::full_error_display, Renderer}; +use crate::{error::full_error_display, Renderer, DrawPass}; use egui::{Modifiers, Rect, Vec2}; use legion::systems::Runnable; use log::debug; @@ -177,8 +177,8 @@ impl UiState { #[system] /// A system to process the window events sent to renderer by the winit event loop. -pub fn _process_window_events( - #[resource] renderer: &mut Renderer, +pub fn _process_window_events( + #[resource] renderer: &mut Renderer, #[resource] manager: &mut T, #[resource] mouse: &mut Mouse, #[resource] ui_state: &mut UiState, @@ -237,7 +237,7 @@ pub fn _process_window_events( +pub fn process_window_events_system( ) -> impl Runnable { - _process_window_events_system::(Vec::with_capacity(4)) + _process_window_events_system::(Vec::with_capacity(4)) } -- cgit v1.2.3