diff options
Diffstat (limited to 'stockton-render/src/draw/texture/loader.rs')
-rw-r--r-- | stockton-render/src/draw/texture/loader.rs | 125 |
1 files changed, 73 insertions, 52 deletions
diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs index f505de5..a23d633 100644 --- a/stockton-render/src/draw/texture/loader.rs +++ b/stockton-render/src/draw/texture/loader.rs @@ -1,17 +1,17 @@ //! Manages the loading/unloading of textures use super::{ - block::TexturesBlock, + block::{LoadedImage, TexturesBlock}, load::{QueuedLoad, TextureLoadError}, resolver::TextureResolver, LoadableImage, }; -use crate::{draw::utils::find_memory_type_id, types::*}; +use crate::{draw::utils::find_memory_type_id, error::LockPoisoned, types::*}; use std::{ collections::VecDeque, marker::PhantomData, - mem::ManuallyDrop, + mem::{drop, ManuallyDrop}, sync::{ mpsc::{Receiver, Sender}, Arc, RwLock, @@ -23,7 +23,9 @@ use std::{ use anyhow::{Context, Result}; use arrayvec::ArrayVec; use hal::{ - format::Format, memory::Properties as MemProps, prelude::*, queue::family::QueueFamilyId, + format::Format, + memory::{Properties as MemProps, SparseFlags}, + queue::family::QueueFamilyId, MemoryTypeId, }; use log::*; @@ -40,23 +42,20 @@ pub type BlockRef = usize; /// Manages the loading/unloading of textures /// This is expected to load the textures, then send the loaded blocks back pub struct TextureLoader<T, R, I> { - /// Handle to the device we're using - pub(crate) device: Arc<RwLock<Device>>, - /// Blocks for which commands have been queued and are done loading once the fence is triggered. pub(crate) commands_queued: ArrayVec<[QueuedLoad<DynamicBlock>; NUM_SIMULTANEOUS_CMDS]>, /// The command buffers used and a fence to go with them - pub(crate) buffers: VecDeque<(Fence, CommandBuffer)>, + pub(crate) buffers: VecDeque<(FenceT, CommandBufferT)>, /// The command pool buffers were allocated from - pub(crate) pool: ManuallyDrop<CommandPool>, + pub(crate) pool: ManuallyDrop<CommandPoolT>, /// The GPU we're submitting to - pub(crate) gpu: ManuallyDrop<Gpu>, + pub(crate) device: Arc<RwLock<DeviceT>>, - /// The index of the command queue being used - pub(crate) cmd_queue_idx: usize, + /// The command queue being used + pub(crate) queue: Arc<RwLock<QueueT>>, /// The memory allocator being used for textures pub(crate) tex_allocator: ManuallyDrop<DynamicAllocator>, @@ -67,7 +66,7 @@ pub struct TextureLoader<T, R, I> { /// Allocator for descriptor sets pub(crate) descriptor_allocator: ManuallyDrop<DescriptorAllocator>, - pub(crate) ds_layout: Arc<RwLock<DescriptorSetLayout>>, + pub(crate) ds_layout: Arc<RwLock<DescriptorSetLayoutT>>, /// Type ID for staging memory pub(crate) staging_memory_type: MemoryTypeId, @@ -88,6 +87,9 @@ pub struct TextureLoader<T, R, I> { /// The channel blocks are returned to. pub(crate) return_channel: Sender<TexturesBlock<DynamicBlock>>, + /// A filler image for descriptors that aren't needed but still need to be written to + pub(crate) blank_image: ManuallyDrop<LoadedImage<DynamicBlock>>, + pub(crate) _li: PhantomData<I>, } @@ -121,18 +123,20 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R } } fn main(&mut self) -> Result<bool> { - let mut device = self.device.write().unwrap(); - + let mut device = self + .device + .write() + .map_err(|_| LockPoisoned::Device) + .context("Error getting device lock")?; // Check for blocks that are finished, then send them back let mut i = 0; while i < self.commands_queued.len() { let signalled = unsafe { device.get_fence_status(&self.commands_queued[i].fence) } - .map_err::<HalErrorWrapper, _>(|e| e.into()) .context("Error checking fence status")?; if signalled { let (assets, mut staging_bufs, block) = self.commands_queued.remove(i).dissolve(); - debug!("Done loading texture block {:?}", block.id); + debug!("Load finished for texture block {:?}", block.id); // Destroy staging buffers while staging_bufs.len() > 0 { @@ -155,11 +159,15 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R match to_load { LoaderRequest::Load(to_load) => { // Attempt to load given block + debug!("Attempting to queue load for texture block {:?}", to_load); + let result = unsafe { self.attempt_queue_load(to_load) }; match result { Ok(queued_load) => self.commands_queued.push(queued_load), Err(x) => match x.downcast_ref::<TextureLoadError>() { - Some(TextureLoadError::NoResources) => {} + Some(TextureLoadError::NoResources) => { + debug!("No resources, trying again later"); + } _ => return Err(x).context("Error queuing texture load"), }, } @@ -172,29 +180,21 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R } pub fn new( - device_lock: Arc<RwLock<Device>>, adapter: &Adapter, + device_lock: Arc<RwLock<DeviceT>>, family: QueueFamilyId, - gpu: Gpu, - ds_layout: Arc<RwLock<DescriptorSetLayout>>, + queue_lock: Arc<RwLock<QueueT>>, + ds_layout: Arc<RwLock<DescriptorSetLayoutT>>, request_channel: Receiver<LoaderRequest>, return_channel: Sender<TexturesBlock<DynamicBlock>>, texs: Arc<RwLock<T>>, resolver: R, ) -> Result<Self> { - let device = device_lock + let mut device = device_lock .write() .map_err(|_| LockPoisoned::Device) .context("Error getting device lock")?; - - // Pool - let mut pool = unsafe { - use hal::pool::CommandPoolCreateFlags; - - device.create_command_pool(family, CommandPoolCreateFlags::RESET_INDIVIDUAL) - } - .map_err::<HalErrorWrapper, _>(|e| e.into()) - .context("Error creating command pool")?; + let device_props = adapter.physical_device.properties(); let type_mask = unsafe { use hal::image::{Kind, Tiling, Usage, ViewCapabilities}; @@ -214,9 +214,9 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R Format::Rgba8Srgb, Tiling::Optimal, Usage::SAMPLED, + SparseFlags::empty(), ViewCapabilities::empty(), ) - .map_err::<HalErrorWrapper, _>(|e| e.into()) .context("Error creating test image to get buffer settings")?; let type_mask = device.get_image_requirements(&img).type_mask; @@ -226,8 +226,10 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R type_mask }; + debug!("Using type mask {:?}", type_mask); + // Tex Allocator - let tex_allocator = { + let mut tex_allocator = { let props = MemProps::DEVICE_LOCAL; DynamicAllocator::new( @@ -239,10 +241,11 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R max_chunk_size: u64::pow(2, 63), min_device_allocation: 4 * 32 * 32, }, + device_props.limits.non_coherent_atom_size as u64, ) }; - let (staging_memory_type, staging_allocator) = { + let (staging_memory_type, mut staging_allocator) = { let props = MemProps::CPU_VISIBLE | MemProps::COHERENT; let t = find_memory_type_id(&adapter, type_mask, props) .ok_or(TextureLoaderError::NoMemoryTypes)?; @@ -256,20 +259,28 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R max_chunk_size: u64::pow(2, 63), min_device_allocation: 4 * 32 * 32, }, + device_props.limits.non_coherent_atom_size as u64, ), ) }; - let buffers = { + // Pool + let mut pool = unsafe { + use hal::pool::CommandPoolCreateFlags; + + device.create_command_pool(family, CommandPoolCreateFlags::RESET_INDIVIDUAL) + } + .context("Error creating command pool")?; + + // Command buffers and fences + debug!("Creating resources..."); + let mut buffers = { let mut data = VecDeque::with_capacity(NUM_SIMULTANEOUS_CMDS); for _ in 0..NUM_SIMULTANEOUS_CMDS { unsafe { data.push_back(( - device - .create_fence(false) - .map_err::<HalErrorWrapper, _>(|e| e.into()) - .context("Error creating fence")?, + device.create_fence(false).context("Error creating fence")?, pool.allocate_one(hal::command::Level::Primary), )); }; @@ -278,21 +289,30 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R data }; - let cmd_queue_idx = gpu - .queue_groups - .iter() - .position(|x| x.family == family) - .unwrap(); + let optimal_buffer_copy_pitch_alignment = + device_props.limits.optimal_buffer_copy_pitch_alignment; + + let blank_image = unsafe { + Self::get_blank_image( + &mut device, + &mut buffers[0].1, + &queue_lock, + &mut staging_allocator, + &mut tex_allocator, + staging_memory_type, + optimal_buffer_copy_pitch_alignment, + ) + } + .context("Error creating blank image")?; - std::mem::drop(device); + drop(device); Ok(TextureLoader { - device: device_lock, commands_queued: ArrayVec::new(), buffers, pool: ManuallyDrop::new(pool), - gpu: ManuallyDrop::new(gpu), - cmd_queue_idx, + device: device_lock, + queue: queue_lock, ds_layout, tex_allocator: ManuallyDrop::new(tex_allocator), @@ -300,15 +320,13 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R descriptor_allocator: ManuallyDrop::new(DescriptorAllocator::new()), staging_memory_type, - optimal_buffer_copy_pitch_alignment: adapter - .physical_device - .limits() - .optimal_buffer_copy_pitch_alignment, + optimal_buffer_copy_pitch_alignment, request_channel, return_channel, textures: texs, resolver, + blank_image: ManuallyDrop::new(blank_image), _li: PhantomData::default(), }) } @@ -354,6 +372,9 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R sleep(Duration::from_secs(0)); } + // Destroy blank image + read(&*self.blank_image).deactivate(&mut device, &mut *self.tex_allocator); + // Destroy fences let vec: Vec<_> = self.buffers.drain(..).collect(); |