diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:22 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:22 +0100 |
commit | bf9573764c695e65b1504419fafb76ccabb0322b (patch) | |
tree | 1702411472e080b436d27f34655ae4ada68ecc7b /stockton-render | |
parent | dfb74318dae09b3430acf533374dc7004df65c65 (diff) |
feat(render): generic and empty texture stores
Diffstat (limited to 'stockton-render')
-rw-r--r-- | stockton-render/src/draw/texture/chunk.rs | 37 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/image.rs | 49 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/loader.rs | 133 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/mod.rs | 1 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/resolver.rs | 8 | ||||
-rw-r--r-- | stockton-render/src/systems.rs | 20 |
6 files changed, 230 insertions, 18 deletions
diff --git a/stockton-render/src/draw/texture/chunk.rs b/stockton-render/src/draw/texture/chunk.rs index 8abdb4a..f1b88e9 100644 --- a/stockton-render/src/draw/texture/chunk.rs +++ b/stockton-render/src/draw/texture/chunk.rs @@ -18,6 +18,7 @@ //! A chunk of textures is an array of textures, the size of which is known at compile time. //! This reduces the number of times we need to re-bind our descriptor sets +use crate::draw::texture::image::LoadableImage; use hal::prelude::*; use image::{Rgba, RgbaImage}; @@ -42,9 +43,39 @@ pub struct TextureChunk { } impl TextureChunk { + /// Create a new empty texture chunk + pub fn new_empty( + device: &mut Device, + adapter: &mut Adapter, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool, + descriptor_set: DescriptorSet, + ) -> Result<TextureChunk, error::CreationError> { + let mut store = TextureChunk { + descriptor_set, + sampled_images: Vec::with_capacity(CHUNK_SIZE), + }; + + for i in 0..CHUNK_SIZE { + debug!("Putting a placeholder in slot {}", i); + store + .put_texture( + RgbaImage::from_pixel(1, 1, Rgba([0, 0, 0, 1])), + i, + device, + adapter, + command_queue, + command_pool, + ) + .unwrap(); + } + + Ok(store) + } + /// Create a new texture chunk and load in the textures specified by `range` from `file` using `resolver` /// Can error if the descriptor pool is too small or if a texture isn't found - pub fn new<'a, I, R: TextureResolver>( + pub fn new<'a, I, R: TextureResolver<T>, T: LoadableImage>( device: &mut Device, adapter: &mut Adapter, command_queue: &mut CommandQueue, @@ -99,9 +130,9 @@ impl TextureChunk { Ok(store) } - pub fn put_texture( + pub fn put_texture<T: LoadableImage>( &mut self, - image: RgbaImage, + image: T, idx: usize, device: &mut Device, adapter: &mut Adapter, diff --git a/stockton-render/src/draw/texture/image.rs b/stockton-render/src/draw/texture/image.rs index 4a0fa08..2e0b27b 100644 --- a/stockton-render/src/draw/texture/image.rs +++ b/stockton-render/src/draw/texture/image.rs @@ -35,7 +35,34 @@ use crate::draw::buffer::create_buffer; use crate::types::*; /// The size of each pixel in an image -const PIXEL_SIZE: usize = size_of::<image::Rgba<u8>>(); +const PIXEL_SIZE: usize = size_of::<u8>() * 4; + +/// An object that can be loaded as an image into GPU memory +pub trait LoadableImage { + fn width(&self) -> u32; + fn height(&self) -> u32; + fn copy_row(&self, y: u32, ptr: *mut u8) -> (); +} + +impl LoadableImage for RgbaImage { + fn width(&self) -> u32 { + self.width() + } + + fn height(&self) -> u32 { + self.height() + } + + fn copy_row(&self, y: u32, ptr: *mut u8) -> () { + let row_size_bytes = self.width() as usize * PIXEL_SIZE; + let raw: &Vec<u8> = self.as_raw(); + let row = &raw[y as usize * row_size_bytes..(y as usize + 1) * row_size_bytes]; + + unsafe { + copy_nonoverlapping(row.as_ptr(), ptr, row.len()); + } + } +} /// Holds an image that's loaded into GPU memory and can be sampled from pub struct LoadedImage { @@ -137,9 +164,9 @@ impl LoadedImage { } /// Load the given image - pub fn load( + pub fn load<T: LoadableImage>( &mut self, - img: RgbaImage, + img: T, device: &mut Device, adapter: &Adapter, command_queue: &mut CommandQueue, @@ -166,15 +193,13 @@ impl LoadedImage { // Copy everything into it unsafe { - let mapped_memory: *mut u8 = device + let mapped_memory: *mut u8 = std::mem::transmute(device .map_memory(&staging_memory, Segment::ALL) - .map_err(|_| "Couldn't map buffer memory")?; + .map_err(|_| "Couldn't map buffer memory")?); for y in 0..img.height() as usize { - let row = &(*img)[y * initial_row_size..(y + 1) * initial_row_size]; let dest_base: isize = (y * row_size).try_into().unwrap(); - - copy_nonoverlapping(row.as_ptr(), mapped_memory.offset(dest_base), row.len()); + img.copy_row(y as u32, mapped_memory.offset(dest_base)); } device .flush_mapped_memory_ranges(once((&staging_memory, Segment::ALL))) @@ -288,8 +313,8 @@ impl LoadedImage { } /// Load the given image into a new buffer - pub fn load_into_new( - img: RgbaImage, + pub fn load_into_new<T: LoadableImage>( + img: T, device: &mut Device, adapter: &Adapter, command_queue: &mut CommandQueue, @@ -369,8 +394,8 @@ impl SampledImage { }) } - pub fn load_into_new( - img: RgbaImage, + pub fn load_into_new<T: LoadableImage>( + img: T, device: &mut Device, adapter: &Adapter, command_queue: &mut CommandQueue, diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs index dbd9d70..30c89dc 100644 --- a/stockton-render/src/draw/texture/loader.rs +++ b/stockton-render/src/draw/texture/loader.rs @@ -19,6 +19,7 @@ use super::chunk::TextureChunk; use crate::draw::texture::chunk::CHUNK_SIZE; +use crate::draw::texture::image::LoadableImage; use crate::draw::texture::resolver::BasicFSResolver; use core::mem::ManuallyDrop; use std::path::Path; @@ -43,6 +44,117 @@ pub struct TextureStore { } impl TextureStore { + pub fn new_empty( + device: &mut Device, + adapter: &mut Adapter, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool, + size: usize, + ) -> Result<TextureStore, error::CreationError> { + // Figure out how many textures in this file / how many chunks needed + let num_chunks = { + let mut x = size / CHUNK_SIZE; + if size % CHUNK_SIZE != 0 { + x += 1; + } + x + }; + let rounded_size = num_chunks * CHUNK_SIZE; + + // Descriptor pool, where we get our sets from + let mut descriptor_pool = unsafe { + use hal::pso::{ + DescriptorPoolCreateFlags, DescriptorRangeDesc, DescriptorType, ImageDescriptorType, + }; + + device + .create_descriptor_pool( + num_chunks, + &[ + DescriptorRangeDesc { + ty: DescriptorType::Image { + ty: ImageDescriptorType::Sampled { + with_sampler: false, + }, + }, + count: rounded_size, + }, + DescriptorRangeDesc { + ty: DescriptorType::Sampler, + count: rounded_size, + }, + ], + DescriptorPoolCreateFlags::empty(), + ) + .map_err(|e| { + println!("{:?}", e); + error::CreationError::OutOfMemoryError + })? + }; + + // Layout of our descriptor sets + let descriptor_set_layout = unsafe { + use hal::pso::{ + DescriptorSetLayoutBinding, DescriptorType, ImageDescriptorType, ShaderStageFlags, + }; + + device.create_descriptor_set_layout( + &[ + DescriptorSetLayoutBinding { + binding: 0, + ty: DescriptorType::Image { + ty: ImageDescriptorType::Sampled { + with_sampler: false, + }, + }, + count: CHUNK_SIZE, + stage_flags: ShaderStageFlags::FRAGMENT, + immutable_samplers: false, + }, + DescriptorSetLayoutBinding { + binding: 1, + ty: DescriptorType::Sampler, + count: CHUNK_SIZE, + stage_flags: ShaderStageFlags::FRAGMENT, + immutable_samplers: false, + }, + ], + &[], + ) + } + .map_err(|_| error::CreationError::OutOfMemoryError)?; + + log::debug!("texture ds layout: {:?}", descriptor_set_layout); + + // Create texture chunks + debug!("Starting to load textures..."); + let mut chunks = Vec::with_capacity(num_chunks); + for i in 0..num_chunks { + debug!("Chunk {} / {}", i + 1, num_chunks); + + let descriptor_set = unsafe { + descriptor_pool + .allocate_set(&descriptor_set_layout) + .map_err(|_| error::CreationError::OutOfMemoryError)? + }; + chunks.push(TextureChunk::new_empty( + device, + adapter, + command_queue, + command_pool, + descriptor_set, + )?); + } + + debug!("All textures loaded."); + + Ok(TextureStore { + descriptor_pool: ManuallyDrop::new(descriptor_pool), + descriptor_set_layout: ManuallyDrop::new(descriptor_set_layout), + chunks: chunks.into_boxed_slice(), + }) + } + /// Create a new texture store for the given file, loading all textures from it. pub fn new<T: HasTextures>( device: &mut Device, @@ -180,4 +292,25 @@ impl TextureStore { pub fn get_chunk_descriptor_set(&self, idx: usize) -> &DescriptorSet { &self.chunks[idx].descriptor_set } + + pub fn put_texture<T: LoadableImage>( + &mut self, + idx: usize, + img: T, + device: &mut Device, + adapter: &mut Adapter, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool, + ) -> Result<(), &'static str> { + // TODO: Resizing, etc? + let chunk = &mut self.chunks[idx / CHUNK_SIZE]; + chunk.put_texture( + img, + idx % CHUNK_SIZE, + device, + adapter, + command_queue, + command_pool, + ) + } } diff --git a/stockton-render/src/draw/texture/mod.rs b/stockton-render/src/draw/texture/mod.rs index 91b15dc..ec36502 100644 --- a/stockton-render/src/draw/texture/mod.rs +++ b/stockton-render/src/draw/texture/mod.rs @@ -24,3 +24,4 @@ mod resolver; pub use self::image::{LoadedImage, SampledImage}; pub use self::loader::TextureStore; +pub use self::image::LoadableImage;
\ No newline at end of file diff --git a/stockton-render/src/draw/texture/resolver.rs b/stockton-render/src/draw/texture/resolver.rs index 21e7628..610d43a 100644 --- a/stockton-render/src/draw/texture/resolver.rs +++ b/stockton-render/src/draw/texture/resolver.rs @@ -17,6 +17,7 @@ //! Resolves a texture in a BSP File to an image +use crate::draw::texture::image::LoadableImage; use stockton_levels::traits::textures::Texture; use image::{io::Reader, RgbaImage}; @@ -24,9 +25,10 @@ use image::{io::Reader, RgbaImage}; use std::path::Path; /// An object that can be used to resolve a texture from a BSP File -pub trait TextureResolver { +pub trait TextureResolver<T: LoadableImage> { + /// Get the given texture, or None if it's corrupt/not there. - fn resolve(&mut self, texture: &Texture) -> Option<RgbaImage>; + fn resolve(&mut self, texture: &Texture) -> Option<T>; } /// A basic filesystem resolver which expects no file extension and guesses the image format @@ -40,7 +42,7 @@ impl<'a> BasicFSResolver<'a> { } } -impl<'a> TextureResolver for BasicFSResolver<'a> { +impl<'a> TextureResolver<RgbaImage> for BasicFSResolver<'a> { fn resolve(&mut self, tex: &Texture) -> Option<RgbaImage> { let path = self.path.join(&tex.name); diff --git a/stockton-render/src/systems.rs b/stockton-render/src/systems.rs new file mode 100644 index 0000000..8001e1b --- /dev/null +++ b/stockton-render/src/systems.rs @@ -0,0 +1,20 @@ +/* + * Copyright (C) Oscar Shrimpton 2020 + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +pub use crate::window::process_window_events_system; +pub use crate::draw::calc_vp_matrix_system; +pub use crate::do_render_system;
\ No newline at end of file |