diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:21 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:21 +0100 |
commit | 2f112ab34ac1458b038598f4d7ef6638df463dc6 (patch) | |
tree | c0100341b31276297fc9d2992797c5ca18cd2d99 /stockton-render/src/draw/texture | |
parent | 27760ec1ca7a93877b2b015a0a2e9db87de4204c (diff) |
feat(render): depth buffer and refactors
Diffstat (limited to 'stockton-render/src/draw/texture')
-rw-r--r-- | stockton-render/src/draw/texture/chunk.rs | 20 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/image.rs | 216 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/loader.rs | 5 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/mod.rs | 4 |
4 files changed, 152 insertions, 93 deletions
diff --git a/stockton-render/src/draw/texture/chunk.rs b/stockton-render/src/draw/texture/chunk.rs index 22541a5..40eb21e 100644 --- a/stockton-render/src/draw/texture/chunk.rs +++ b/stockton-render/src/draw/texture/chunk.rs @@ -31,7 +31,7 @@ use crate::{ use log::debug; use super::resolver::TextureResolver; -use super::image::LoadedImage; +use super::image::SampledImage; use stockton_levels::prelude::*; /// The size of a chunk. Needs to match up with the fragment shader @@ -40,7 +40,7 @@ pub const CHUNK_SIZE: usize = 8; /// An array of textures pub struct TextureChunk { pub(crate) descriptor_set: DescriptorSet, - loaded_images: Vec<LoadedImage>, + sampled_images: Vec<SampledImage>, } impl TextureChunk { @@ -65,7 +65,7 @@ impl TextureChunk { let mut store = TextureChunk { descriptor_set: descriptor_set, - loaded_images: Vec::with_capacity(CHUNK_SIZE), + sampled_images: Vec::with_capacity(CHUNK_SIZE), }; let mut local_idx = 0; @@ -110,12 +110,14 @@ impl TextureChunk { command_pool: &mut CommandPool) -> Result<(), &'static str>{ // Load the image - let texture = LoadedImage::load( + let texture = SampledImage::load_into_new( image, device, adapter, command_queue, command_pool, + hal::format::Format::Rgba8Srgb, // TODO + hal::image::Usage::empty() )?; // Write it to the descriptor set @@ -129,7 +131,7 @@ impl TextureChunk { binding: 0, array_offset: idx, descriptors: Some(Descriptor::Image( - texture.image_view.deref(), + texture.image.image_view.deref(), Layout::ShaderReadOnlyOptimal )), }, @@ -144,17 +146,17 @@ impl TextureChunk { // Store it so we can safely deactivate it when we need to // Deactivate the old image if we need to - if idx < self.loaded_images.len() { - replace(&mut self.loaded_images[idx], texture).deactivate(device); + if idx < self.sampled_images.len() { + replace(&mut self.sampled_images[idx], texture).deactivate(device); } else { - self.loaded_images.push(texture); + self.sampled_images.push(texture); } Ok(()) } pub fn deactivate(mut self, device: &mut Device) -> () { - for img in self.loaded_images.drain(..) { + for img in self.sampled_images.drain(..) { img.deactivate(device); } } diff --git a/stockton-render/src/draw/texture/image.rs b/stockton-render/src/draw/texture/image.rs index 583c2d9..530628a 100644 --- a/stockton-render/src/draw/texture/image.rs +++ b/stockton-render/src/draw/texture/image.rs @@ -26,7 +26,7 @@ use hal::{ MemoryTypeId, buffer::Usage as BufUsage, format::{Format, Swizzle, Aspects}, - image::{ViewKind, SubresourceRange}, + image::{ViewKind, SubresourceRange, Usage as ImgUsage}, queue::Submission, memory::{Properties as MemProperties, Dependencies as MemDependencies, Segment}, prelude::*, @@ -46,28 +46,91 @@ pub struct LoadedImage { /// The full view of the image pub image_view: ManuallyDrop<ImageView>, - /// A sampler for the image - pub sampler: ManuallyDrop<Sampler>, - /// The memory backing the image memory: ManuallyDrop<Memory> } +pub fn create_image_view(device: &mut Device, adapter: &Adapter, format: Format, usage: ImgUsage, width: usize, height: usize) -> Result<(Memory, Image), &'static str> { + // Round up the size to align properly + let initial_row_size = PIXEL_SIZE * width; + let limits = adapter.physical_device.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, + ViewCapabilities::empty() + ) + }.map_err(|_| "Couldn't create 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(MemProperties::DEVICE_LOCAL) + }) + .map(|(id, _)| MemoryTypeId(id)) + .ok_or("Couldn't find a memory type for image memory")?; + + let memory = device + .allocate_memory(memory_type_id, requirements.size) + .map_err(|_| "Couldn't allocate image memory")?; + + device.bind_image_memory(&memory, 0, &mut image_ref) + .map_err(|_| "Couldn't bind memory to image")?; + + Ok(memory) + }?; + + Ok((memory, image_ref)) + +} + impl LoadedImage { - /// Load the given image into a new buffer - pub fn load(img: RgbaImage, device: &mut Device, adapter: &Adapter, - command_queue: &mut CommandQueue, - command_pool: &mut CommandPool) -> Result<LoadedImage, &'static str> { - // Round up the size to align properly - let initial_row_size = PIXEL_SIZE * (img.width() as usize); + pub fn new(device: &mut Device, adapter: &Adapter, format: Format, usage: ImgUsage, resources: SubresourceRange, width: usize, height: usize) -> Result<LoadedImage, &'static str> { + let (memory, image_ref) = create_image_view(device, adapter, format, usage, width, height)?; + + // Create ImageView and sampler + let image_view = unsafe { device.create_image_view( + &image_ref, + ViewKind::D2, + format, + Swizzle::NO, + resources, + )}.map_err(|_| "Couldn't create the image view!")?; + + Ok(LoadedImage { + 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: RgbaImage, device: &mut Device, adapter: &Adapter, command_queue: &mut CommandQueue, + command_pool: &mut CommandPool) -> Result<(), &'static str> { + let initial_row_size = PIXEL_SIZE * img.width() as usize; let limits = adapter.physical_device.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); - let total_size = (row_size * img.height() as usize) as u64; - // Make a staging buffer let (staging_buffer, staging_memory) = create_buffer(device, adapter, BufUsage::TRANSFER_SRC, MemProperties::CPU_VISIBLE, total_size) .map_err(|_| "Couldn't create staging buffer")?; @@ -86,43 +149,6 @@ impl LoadedImage { device.unmap_memory(&staging_memory); } - // Make the image - let mut image_ref = unsafe { - use hal::image::{Kind, Tiling, Usage, ViewCapabilities}; - - device.create_image( - Kind::D2(img.width(), img.height(), 1, 1), - 1, - Format::Rgba8Srgb, - Tiling::Optimal, - Usage::TRANSFER_DST | Usage::SAMPLED, - ViewCapabilities::empty() - ) - }.map_err(|_| "Couldn't create 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(MemProperties::DEVICE_LOCAL) - }) - .map(|(id, _)| MemoryTypeId(id)) - .ok_or("Couldn't find a memory type for image memory")?; - - let memory = device - .allocate_memory(memory_type_id, requirements.size) - .map_err(|_| "Couldn't allocate image memory")?; - - device.bind_image_memory(&memory, 0, &mut image_ref) - .map_err(|_| "Couldn't bind memory to image")?; - - Ok(memory) - }?; - // Copy from staging to image memory let buf = unsafe { use hal::command::{CommandBufferFlags, BufferImageCopy}; @@ -141,7 +167,7 @@ impl LoadedImage { Access::TRANSFER_WRITE, Layout::TransferDstOptimal, ), - target: &image_ref, + target: &(*self.image), families: None, range: SubresourceRange { aspects: Aspects::COLOR, @@ -156,7 +182,7 @@ impl LoadedImage { ); // Copy from buffer to image - buf.copy_buffer_to_image(&staging_buffer, &image_ref, + buf.copy_buffer_to_image(&staging_buffer, &(*self.image), Layout::TransferDstOptimal, &[ BufferImageCopy { buffer_offset: 0, @@ -187,7 +213,7 @@ impl LoadedImage { Access::SHADER_READ, Layout::ShaderReadOnlyOptimal, ), - target: &image_ref, + target: &(*self.image), families: None, range: SubresourceRange { aspects: Aspects::COLOR, @@ -229,18 +255,49 @@ impl LoadedImage { device.destroy_buffer(staging_buffer); } - // Create ImageView and sampler - let image_view = unsafe { device.create_image_view( - &image_ref, - ViewKind::D2, - Format::Rgba8Srgb, - Swizzle::NO, - SubresourceRange { - aspects: Aspects::COLOR, - levels: 0..1, - layers: 0..1, - }, - )}.map_err(|_| "Couldn't create the image view!")?; + Ok(()) + } + + /// Load the given image into a new buffer + pub fn load_into_new(img: RgbaImage, device: &mut Device, adapter: &Adapter, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool, format: Format, usage: ImgUsage) -> Result<LoadedImage, &'static str> { + let mut loaded_image = Self::new(device, adapter, format, usage | ImgUsage::TRANSFER_DST, SubresourceRange { + aspects: Aspects::COLOR, + levels: 0..1, + layers: 0..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: &Device) -> () { + 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))); + } + } +} + + +pub struct SampledImage { + pub image: ManuallyDrop<LoadedImage>, + pub sampler: ManuallyDrop<Sampler> +} + +impl SampledImage { + pub fn new(device: &mut Device, adapter: &Adapter, format: Format, usage: ImgUsage, width: usize, height: usize) -> Result<SampledImage, &'static str> { + let image = LoadedImage::new(device, adapter, format, usage | ImgUsage::SAMPLED, SubresourceRange { + aspects: Aspects::COLOR, + levels: 0..1, + layers: 0..1, + }, width, height)?; let sampler = unsafe { use hal::image::{SamplerDesc, Filter, WrapMode}; @@ -251,24 +308,29 @@ impl LoadedImage { )) }.map_err(|_| "Couldn't create the sampler!")?; - Ok(LoadedImage { - image: ManuallyDrop::new(image_ref), - image_view: ManuallyDrop::new(image_view), - sampler: ManuallyDrop::new(sampler), - memory: ManuallyDrop::new(memory) + Ok(SampledImage { + image: ManuallyDrop::new(image), + sampler: ManuallyDrop::new(sampler) }) } - /// Properly frees/destroys all the objects in this struct - /// Dropping without doing this is a bad idea - pub fn deactivate(self, device: &Device) -> () { + pub fn load_into_new(img: RgbaImage, device: &mut Device, adapter: &Adapter, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool, format: Format, usage: ImgUsage) -> Result<SampledImage, &'static str> { + let mut sampled_image = SampledImage::new(device, adapter, format, usage | ImgUsage::TRANSFER_DST, img.width() as usize, img.height() as usize)?; + sampled_image.image.load(img, device, adapter, command_queue, command_pool)?; + + Ok(sampled_image) + + } + + pub fn deactivate(self, device: &mut Device) -> () { unsafe { use core::ptr::read; device.destroy_sampler(ManuallyDrop::into_inner(read(&self.sampler))); - 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))); + + ManuallyDrop::into_inner(read(&self.image)).deactivate(device); } } -}
\ No newline at end of file +} diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs index 483fb7d..1ac0961 100644 --- a/stockton-render/src/draw/texture/loader.rs +++ b/stockton-render/src/draw/texture/loader.rs @@ -165,11 +165,6 @@ impl TextureStore { } } - /// Get number of chunks being used - pub fn get_n_chunks(&self) -> usize { - self.chunks.len() - } - /// Get the descriptor set for a given chunk pub fn get_chunk_descriptor_set<'a>(&'a self, idx: usize) -> &'a DescriptorSet { &self.chunks[idx].descriptor_set diff --git a/stockton-render/src/draw/texture/mod.rs b/stockton-render/src/draw/texture/mod.rs index 9951eeb..05dfe38 100644 --- a/stockton-render/src/draw/texture/mod.rs +++ b/stockton-render/src/draw/texture/mod.rs @@ -16,9 +16,9 @@ //! Everything related to loading textures into GPU memory mod resolver; -mod image; +pub mod image; mod chunk; pub mod loader; pub use self::loader::TextureStore; -pub use self::image::LoadedImage;
\ No newline at end of file +pub use self::image::{LoadedImage, SampledImage};
\ No newline at end of file |