diff options
Diffstat (limited to 'stockton-skeleton/src/texture/repo.rs')
-rw-r--r-- | stockton-skeleton/src/texture/repo.rs | 80 |
1 files changed, 55 insertions, 25 deletions
diff --git a/stockton-skeleton/src/texture/repo.rs b/stockton-skeleton/src/texture/repo.rs index 341d355..635eebb 100644 --- a/stockton-skeleton/src/texture/repo.rs +++ b/stockton-skeleton/src/texture/repo.rs @@ -4,14 +4,15 @@ use super::{ loader::{BlockRef, LoaderRequest, TextureLoader, TextureLoaderRemains, NUM_SIMULTANEOUS_CMDS}, resolver::TextureResolver, }; -use crate::error::LockPoisoned; -use crate::queue_negotiator::QueueFamilySelector; use crate::types::*; +use crate::{context::RenderingContext, error::LockPoisoned, mem::MappableBlock}; +use crate::{mem::MemoryPool, queue_negotiator::QueueFamilySelector}; use std::{ array::IntoIter, collections::HashMap, iter::empty, + marker::PhantomData, mem::ManuallyDrop, sync::{ mpsc::{channel, Receiver, Sender}, @@ -21,10 +22,7 @@ use std::{ }; use anyhow::{Context, Result}; -use hal::{ - pso::{DescriptorSetLayoutBinding, DescriptorType, ImageDescriptorType, ShaderStageFlags}, - queue::family::QueueFamilyId, -}; +use hal::pso::{DescriptorSetLayoutBinding, DescriptorType, ImageDescriptorType, ShaderStageFlags}; use log::debug; /// The number of textures in one 'block' @@ -32,26 +30,46 @@ use log::debug; /// Whenever a texture is needed, the whole block its in is loaded. pub const BLOCK_SIZE: usize = 8; -pub struct TextureRepo { +/// An easy way to load [`super::LoadableImage`]s into GPU memory using another thread. +/// This assumes each texture has a numeric id, and will group them into blocks of `[BLOCK_SIZE]`, +/// yielding descriptor sets with that many samplers and images. +/// You only need to supply a [`super::resolver::TextureResolver`] and create one from the main thread. +/// Then, use [`get_ds_layout`] in your graphics pipeline. +/// Make sure to call [`process_responses`] every frame. +/// Then, whenever you draw, use [`attempt_get_descriptor_set`] to see if that texture has finished loading, +/// or `queue_load` to start loading it ASAP. + +pub struct TextureRepo<TP, SP> +where + TP: MemoryPool, + SP: MemoryPool, + SP::Block: MappableBlock, +{ joiner: ManuallyDrop<JoinHandle<Result<TextureLoaderRemains>>>, ds_layout: Arc<RwLock<DescriptorSetLayoutT>>, req_send: Sender<LoaderRequest>, - resp_recv: Receiver<TexturesBlock<DynamicBlock>>, - blocks: HashMap<BlockRef, Option<TexturesBlock<DynamicBlock>>>, + resp_recv: Receiver<TexturesBlock<TP>>, + blocks: HashMap<BlockRef, Option<TexturesBlock<TP>>>, + _d: PhantomData<(TP, SP)>, } -impl TextureRepo { - pub fn new<R: 'static + TextureResolver + Send + Sync>( - device_lock: Arc<RwLock<DeviceT>>, - family: QueueFamilyId, - queue: Arc<RwLock<QueueT>>, - adapter: &Adapter, +impl<TP, SP> TextureRepo<TP, SP> +where + TP: MemoryPool, + SP: MemoryPool, + SP::Block: MappableBlock, +{ + /// Create a new TextureRepo from the given context. + /// Q should most likely be [`TexLoadQueue`] + pub fn new<R: 'static + TextureResolver + Send + Sync, Q: QueueFamilySelector>( + context: &mut RenderingContext, config: TextureLoadConfig<R>, ) -> Result<Self> { // Create Channels let (req_send, req_recv) = channel(); let (resp_send, resp_recv) = channel(); - let device = device_lock + let device = context + .device() .write() .map_err(|_| LockPoisoned::Device) .context("Error getting device lock")?; @@ -91,10 +109,8 @@ impl TextureRepo { drop(device); let joiner = { - let loader = TextureLoader::new( - adapter, - device_lock.clone(), - (family, queue), + let loader = <TextureLoader<_, TP, SP>>::new::<Q>( + context, ds_lock.clone(), (req_recv, resp_send), config, @@ -109,9 +125,12 @@ impl TextureRepo { blocks: HashMap::new(), req_send, resp_recv, + _d: PhantomData, }) } + /// Get the descriptor layout used for each texture descriptor + /// This can be used when creating graphics pipelines. pub fn get_ds_layout(&self) -> Result<RwLockReadGuard<DescriptorSetLayoutT>> { self.ds_layout .read() @@ -119,6 +138,7 @@ impl TextureRepo { .context("Error locking descriptor set layout") } + /// Ask for the given block to be loaded, if it's not already. pub fn queue_load(&mut self, block_id: BlockRef) -> Result<()> { if self.blocks.contains_key(&block_id) { return Ok(()); @@ -127,6 +147,7 @@ impl TextureRepo { self.force_queue_load(block_id) } + /// Ask for the given block to be loaded, even if it already has been. pub fn force_queue_load(&mut self, block_id: BlockRef) -> Result<()> { self.req_send .send(LoaderRequest::Load(block_id)) @@ -137,12 +158,14 @@ impl TextureRepo { Ok(()) } + /// Get the descriptor set for the given block, if it's loaded. pub fn attempt_get_descriptor_set(&mut self, block_id: BlockRef) -> Option<&DescriptorSetT> { self.blocks .get(&block_id) .and_then(|opt| opt.as_ref().map(|z| z.descriptor_set.raw())) } + /// Process any textures that just finished loading. This should be called every frame. pub fn process_responses(&mut self) { let resp_iter: Vec<_> = self.resp_recv.try_iter().collect(); for resp in resp_iter { @@ -151,7 +174,8 @@ impl TextureRepo { } } - pub fn deactivate(mut self, device_lock: &Arc<RwLock<DeviceT>>) { + /// Destroy all vulkan objects. Should be called before dropping. + pub fn deactivate(mut self, context: &mut RenderingContext) { unsafe { use std::ptr::read; @@ -162,22 +186,27 @@ impl TextureRepo { // Process any ones that just got done loading self.process_responses(); + let mut tex_allocator = context + .existing_memory_pool::<TP>() + .unwrap() + .write() + .unwrap(); + // Only now can we lock device without deadlocking - let mut device = device_lock.write().unwrap(); + let mut device = context.device().write().unwrap(); // Return all the texture memory and descriptors. for (_, v) in self.blocks.drain() { if let Some(block) = v { block.deactivate( &mut device, - &mut *remains.tex_allocator, + &mut *tex_allocator, &mut remains.descriptor_allocator, ); } } - // Dispose of both allocators - read(&*remains.tex_allocator).dispose(); + // Dispose of the descriptor allocator read(&*remains.descriptor_allocator).dispose(&device); // Deactivate DS Layout @@ -190,6 +219,7 @@ impl TextureRepo { } } +/// The queue to use when loading textures pub struct TexLoadQueue; impl QueueFamilySelector for TexLoadQueue { |