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 | 5da588c6223e4c30cc5ec349f318aa5203cb0ce7 (patch) | |
tree | 4e994259407507e0fd203ad5b861bb7701ad5763 /stockton-render | |
parent | b822c9794fb6f11bd793c2301ae9ec860de95bf5 (diff) |
refactor(render): move to locks rather than unsafe ops
Diffstat (limited to 'stockton-render')
-rw-r--r-- | stockton-render/src/draw/context.rs | 107 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/load.rs | 83 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/loader.rs | 63 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/repo.rs | 45 | ||||
-rw-r--r-- | stockton-render/src/lib.rs | 2 |
5 files changed, 171 insertions, 129 deletions
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index c9b30d8..87fb0a2 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -2,7 +2,10 @@ //! In the end, this takes in a depth-sorted list of faces and a map file and renders them. //! You'll need something else to actually find/sort the faces though. -use std::{mem::ManuallyDrop, pin::Pin}; +use std::{ + mem::ManuallyDrop, + sync::{Arc, RwLock}, +}; use arrayvec::ArrayVec; use hal::{pool::CommandPoolCreateFlags, prelude::*}; @@ -31,14 +34,14 @@ use stockton_levels::prelude::*; /// 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<'a, M: 'static + MinBspFeatures<VulkanSystem>> { - pub map: Pin<Box<M>>, + pub map: Arc<RwLock<M>>, // Parents for most of these things /// Vulkan Instance instance: ManuallyDrop<back::Instance>, /// Device we're using - device: Pin<Box<Device>>, + device: Arc<RwLock<Device>>, /// Adapter we're using adapter: Adapter, @@ -88,8 +91,7 @@ pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> { impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { /// Create a new RenderingContext for the given window. pub fn new(window: &Window, map: M) -> Result<Self, error::CreationError> { - let map = Box::pin(map); - + let map = Arc::new(RwLock::new(map)); // Create surface let (instance, mut surface, mut adapters) = unsafe { use hal::Instance; @@ -108,7 +110,7 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { let adapter = adapters.remove(0); // Device & Queue group - let (mut device, queue_group) = { + let (device_lock, queue_group) = { let family = adapter .queue_families .iter() @@ -124,9 +126,14 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { .unwrap() }; - (Box::pin(gpu.device), gpu.queue_groups.pop().unwrap()) + ( + Arc::new(RwLock::new(gpu.device)), + gpu.queue_groups.pop().unwrap(), + ) }; + let mut device = device_lock.write().unwrap(); + // Figure out what our swapchain will look like let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface) .map_err(|_| error::CreationError::BadSurface)?; @@ -194,32 +201,34 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { ) }; - // Texture repos - let long_device_pointer = unsafe { &mut *(&mut *device as *mut Device) }; - let long_texs_pointer: &'static M = unsafe { &*(&*map as *const M) }; + drop(device); + // Texture repos let tex_repo = TextureRepo::new( - long_device_pointer, + device_lock.clone(), &adapter, - long_texs_pointer, + map.clone(), BasicFsResolver::new(std::path::Path::new(".")), ) .unwrap(); // TODO - let long_device_pointer = unsafe { &mut *(&mut *device as *mut Device) }; let ui_tex_repo = TextureRepo::new( - long_device_pointer, + device_lock.clone(), &adapter, - &UiTextures, + Arc::new(RwLock::new(UiTextures)), BasicFsResolver::new(std::path::Path::new(".")), ) .unwrap(); // TODO + let mut device = device_lock.write().unwrap(); + + let ds_layout_lock = tex_repo.get_ds_layout(); + let ui_ds_layout_lock = ui_tex_repo.get_ds_layout(); let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new(); - descriptor_set_layouts.push(tex_repo.get_ds_layout()); + descriptor_set_layouts.push(&*ds_layout_lock); let mut ui_descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new(); - ui_descriptor_set_layouts.push(tex_repo.get_ds_layout()); + ui_descriptor_set_layouts.push(&*ui_ds_layout_lock); // Graphics pipeline let pipeline = CompletePipeline::new( @@ -250,12 +259,16 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { ) .map_err(error::CreationError::TargetChainCreationError)?; + drop(device); + drop(ds_layout_lock); + drop(ui_ds_layout_lock); + Ok(RenderingContext { map, instance: ManuallyDrop::new(instance), surface: ManuallyDrop::new(surface), - device, + device: device_lock, adapter, queue_group, @@ -283,7 +296,9 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { /// # Safety /// The context must not be used while this is being called pub unsafe fn handle_surface_change(&mut self) -> Result<(), error::CreationError> { - self.device.wait_idle().unwrap(); + let mut device = self.device.write().unwrap(); + + device.wait_idle().unwrap(); let properties = SwapchainProperties::find_best(&self.adapter, &self.surface) .map_err(|_| error::CreationError::BadSurface)?; @@ -292,13 +307,16 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { // Graphics pipeline // TODO: Recycle - ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut self.device); + let ds_layout_handle = self.tex_repo.get_ds_layout(); + let ui_ds_layout_handle = self.tex_repo.get_ds_layout(); + + ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut device); self.pipeline = ManuallyDrop::new({ let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new(); - descriptor_set_layouts.push(self.tex_repo.get_ds_layout()); + descriptor_set_layouts.push(&*ds_layout_handle); CompletePipeline::new( - &mut self.device, + &mut device, properties.extent, &properties, descriptor_set_layouts, @@ -307,13 +325,13 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { // 2D Graphics pipeline // TODO: Recycle - ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut self.device); + ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut device); self.ui_pipeline = ManuallyDrop::new({ let mut descriptor_set_layouts: ArrayVec<[_; 1]> = ArrayVec::new(); - descriptor_set_layouts.push(self.ui_tex_repo.get_ds_layout()); + descriptor_set_layouts.push(&*ui_ds_layout_handle); UiPipeline::new( - &mut self.device, + &mut device, properties.extent, &properties, descriptor_set_layouts, @@ -321,10 +339,10 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { }); let old_swapchain = ManuallyDrop::into_inner(read(&self.target_chain)) - .deactivate_with_recyling(&mut self.device, &mut self.cmd_pool); + .deactivate_with_recyling(&mut device, &mut self.cmd_pool); self.target_chain = ManuallyDrop::new( TargetChain::new( - &mut self.device, + &mut device, &self.adapter, &mut self.surface, &self.pipeline, @@ -341,11 +359,12 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { /// Draw all vertices in the buffer pub fn draw_vertices(&mut self, ui: &mut UiState, faces: &[u32]) -> Result<(), &'static str> { + let mut device = self.device.write().unwrap(); // Ensure UI texture(s) are loaded ensure_textures_ui( &mut self.ui_tex_repo, ui, - &mut self.device, + &mut device, &mut self.adapter, &mut self.texture_allocator, &mut self.queue_group.queues[0], @@ -357,7 +376,7 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { // 3D Pass let cmd_buffer = self.target_chain.prep_next_target( - &mut self.device, + &mut device, &mut self.draw_buffers, &self.pipeline, &self.vp_matrix, @@ -367,7 +386,7 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { &mut self.draw_buffers, &mut self.tex_repo, &self.pipeline.pipeline_layout, - &*self.map, + &*self.map.read().unwrap(), faces, ); @@ -385,25 +404,25 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { // Update our buffers before we actually start drawing self.draw_buffers.vertex_buffer.commit( - &self.device, + &device, &mut self.queue_group.queues[0], &mut self.cmd_pool, ); self.draw_buffers.index_buffer.commit( - &self.device, + &device, &mut self.queue_group.queues[0], &mut self.cmd_pool, ); self.ui_draw_buffers.vertex_buffer.commit( - &self.device, + &device, &mut self.queue_group.queues[0], &mut self.cmd_pool, ); self.ui_draw_buffers.index_buffer.commit( - &self.device, + &device, &mut self.queue_group.queues[0], &mut self.cmd_pool, ); @@ -418,26 +437,30 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> { impl<'a, M: MinBspFeatures<VulkanSystem>> core::ops::Drop for RenderingContext<'a, M> { fn drop(&mut self) { - self.device.wait_idle().unwrap(); + { + self.device.write().unwrap().wait_idle().unwrap(); + } unsafe { use core::ptr::read; - ManuallyDrop::into_inner(read(&self.draw_buffers)).deactivate(&mut self.device); - ManuallyDrop::into_inner(read(&self.ui_draw_buffers)).deactivate(&mut self.device); ManuallyDrop::into_inner(read(&self.tex_repo)).deactivate(&mut self.device); ManuallyDrop::into_inner(read(&self.ui_tex_repo)).deactivate(&mut self.device); + let mut device = self.device.write().unwrap(); + + ManuallyDrop::into_inner(read(&self.draw_buffers)).deactivate(&mut device); + ManuallyDrop::into_inner(read(&self.ui_draw_buffers)).deactivate(&mut device); + ManuallyDrop::into_inner(read(&self.texture_allocator)).dispose(); ManuallyDrop::into_inner(read(&self.target_chain)) - .deactivate(&mut self.device, &mut self.cmd_pool); + .deactivate(&mut device, &mut self.cmd_pool); - self.device - .destroy_command_pool(ManuallyDrop::into_inner(read(&self.cmd_pool))); + device.destroy_command_pool(ManuallyDrop::into_inner(read(&self.cmd_pool))); - ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut self.device); - ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut self.device); + ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut device); + ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut device); self.instance .destroy_surface(ManuallyDrop::into_inner(read(&self.surface))); diff --git a/stockton-render/src/draw/texture/load.rs b/stockton-render/src/draw/texture/load.rs index 011ae29..b54b37d 100644 --- a/stockton-render/src/draw/texture/load.rs +++ b/stockton-render/src/draw/texture/load.rs @@ -41,7 +41,7 @@ impl<B: Block<back::Backend>> QueuedLoad<B> { } } -impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<'a, T, R, I> { +impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R, I> { const FORMAT: Format = Format::Rgba8Srgb; const RESOURCES: SubresourceRange = SubresourceRange { aspects: Aspects::COLOR, @@ -58,11 +58,42 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< &mut self, block_ref: usize, ) -> Option<QueuedLoad<DynamicBlock>> { + let mut device = self.device.write().unwrap(); + let textures = self.textures.read().unwrap(); + // Get assets to use let (fence, mut buf) = self.buffers.pop_front()?; // Create descriptor set - let descriptor_set = self.create_descriptor_set(); + let descriptor_set = { + let mut v: ArrayVec<[RDescriptorSet; 1]> = ArrayVec::new(); + self.descriptor_allocator + .allocate( + &device, + &*self.ds_layout.read().unwrap(), + DescriptorRanges::from_bindings(&[ + DescriptorSetLayoutBinding { + binding: 0, + ty: DescriptorType::SampledImage, + count: BLOCK_SIZE, + stage_flags: ShaderStageFlags::FRAGMENT, + immutable_samplers: false, + }, + DescriptorSetLayoutBinding { + binding: 1, + ty: DescriptorType::Sampler, + count: BLOCK_SIZE, + stage_flags: ShaderStageFlags::FRAGMENT, + immutable_samplers: false, + }, + ]), + 1, + &mut v, + ) + .unwrap(); + + v.pop().unwrap() + }; // Get a command buffer buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); @@ -74,7 +105,7 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< // For each texture in block for tex_idx in (block_ref * BLOCK_SIZE)..(block_ref + 1) * BLOCK_SIZE { // Get texture and Resolve image - let tex = self.textures.get_texture(tex_idx as u32); + let tex = textures.get_texture(tex_idx as u32); if tex.is_none() { break; // Past the end // TODO: We should actually write blank descriptors @@ -89,7 +120,7 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< // Create staging buffer let mut staging_buffer = StagingBuffer::new( - &mut self.device, + &mut device, &mut self.staging_allocator, total_size as u64, self.staging_memory_type, @@ -98,16 +129,16 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< // Write to staging buffer let mapped_memory = staging_buffer - .map_memory(&mut self.device) + .map_memory(&mut device) .expect("Error mapping staged memory"); img_data.copy_into(mapped_memory, row_size); - staging_buffer.unmap_memory(&mut self.device); + staging_buffer.unmap_memory(&mut device); // Create image let (img_mem, img) = create_image_view( - &mut self.device, + &mut device, &mut *self.tex_allocator, Self::FORMAT, ImgUsage::SAMPLED, @@ -116,8 +147,7 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< .unwrap(); // Create image view - let img_view = self - .device + let img_view = device .create_image_view( &img, ViewKind::D2, @@ -142,14 +172,13 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< }); // Create sampler - let sampler = self - .device + let sampler = device .create_sampler(&SamplerDesc::new(Filter::Nearest, WrapMode::Tile)) .expect("Failed to create sampler"); // Write to descriptor set { - self.device.write_descriptor_sets(vec![ + device.write_descriptor_sets(vec![ DescriptorSetWrite { set: descriptor_set.raw(), binding: 0, @@ -265,36 +294,6 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< }, }) } - - pub(crate) unsafe fn create_descriptor_set(&mut self) -> RDescriptorSet { - let mut v: ArrayVec<[RDescriptorSet; 1]> = ArrayVec::new(); - self.descriptor_allocator - .allocate( - self.device, - &*self.ds_layout, - DescriptorRanges::from_bindings(&[ - DescriptorSetLayoutBinding { - binding: 0, - ty: DescriptorType::SampledImage, - count: BLOCK_SIZE, - stage_flags: ShaderStageFlags::FRAGMENT, - immutable_samplers: false, - }, - DescriptorSetLayoutBinding { - binding: 1, - ty: DescriptorType::Sampler, - count: BLOCK_SIZE, - stage_flags: ShaderStageFlags::FRAGMENT, - immutable_samplers: false, - }, - ]), - 1, - &mut v, - ) - .unwrap(); - - v.pop().unwrap() - } } pub fn tex_size_info<T: LoadableImage>(img: &T, obcpa: hal::buffer::Offset) -> (usize, usize) { diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs index 38ff6fd..34ce87d 100644 --- a/stockton-render/src/draw/texture/loader.rs +++ b/stockton-render/src/draw/texture/loader.rs @@ -7,7 +7,10 @@ use std::{ collections::VecDeque, marker::PhantomData, mem::ManuallyDrop, - sync::mpsc::{Receiver, Sender}, + sync::{ + mpsc::{Receiver, Sender}, + Arc, RwLock, + }, thread::sleep, time::Duration, }; @@ -29,9 +32,9 @@ 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<'a, T, R, I> { +pub struct TextureLoader<T, R, I> { /// Handle to the device we're using - pub(crate) device: &'a mut Device, + 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]>, @@ -57,7 +60,7 @@ pub struct TextureLoader<'a, T, R, I> { /// Allocator for descriptor sets pub(crate) descriptor_allocator: ManuallyDrop<DescriptorAllocator>, - pub(crate) ds_layout: &'a DescriptorSetLayout, + pub(crate) ds_layout: Arc<RwLock<DescriptorSetLayout>>, /// Type ID for staging memory pub(crate) staging_memory_type: MemoryTypeId, @@ -66,7 +69,7 @@ pub struct TextureLoader<'a, T, R, I> { pub(crate) optimal_buffer_copy_pitch_alignment: hal::buffer::Offset, /// The textures lump to get info from - pub(crate) textures: &'a T, + pub(crate) textures: Arc<RwLock<T>>, /// The resolver which gets image data for a given texture. pub(crate) resolver: R, @@ -81,7 +84,7 @@ pub struct TextureLoader<'a, T, R, I> { pub(crate) _li: PhantomData<I>, } -impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<'a, T, R, I> { +impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R, I> { pub fn loop_forever(mut self) -> Result<TextureLoaderRemains, &'static str> { debug!("TextureLoader starting main loop"); let mut res = Ok(()); @@ -103,21 +106,23 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< } } fn main(&mut self) -> Result<(), LoopEndReason> { + let mut device = self.device.write().unwrap(); + // Check for blocks that are finished, then send them back let mut i = 0; while i < self.commands_queued.len() { - let signalled = unsafe { self.device.get_fence_status(&self.commands_queued[i].fence) } + let signalled = unsafe { device.get_fence_status(&self.commands_queued[i].fence) } .map_err(|_| LoopEndReason::Error("Device lost by TextureManager"))?; if signalled { - let (assets, staging_bufs, block) = self.commands_queued.remove(i).dissolve(); + let (assets, mut staging_bufs, block) = self.commands_queued.remove(i).dissolve(); debug!("Done loading texture block {:?}", block.id); // Destroy staging buffers - staging_bufs - .into_iter() - .map(|x| x.deactivate(self.device, &mut self.staging_allocator)) - .for_each(|_| {}); + while staging_bufs.len() > 0 { + let buf = staging_bufs.pop().unwrap(); + buf.deactivate(&mut device, &mut self.staging_allocator); + } self.buffers.push_back(assets); self.return_channel.send(block).unwrap(); @@ -126,6 +131,8 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< } } + drop(device); + // Check for messages to start loading blocks let req_iter: Vec<_> = self.request_channel.try_iter().collect(); for to_load in req_iter { @@ -144,16 +151,18 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< } pub fn new( - device: &'a mut Device, + device_lock: Arc<RwLock<Device>>, adapter: &Adapter, family: QueueFamilyId, gpu: Gpu, - ds_layout: &'a DescriptorSetLayout, + ds_layout: Arc<RwLock<DescriptorSetLayout>>, request_channel: Receiver<LoaderRequest>, return_channel: Sender<TexturesBlock<DynamicBlock>>, - texs: &'a T, + texs: Arc<RwLock<T>>, resolver: R, ) -> Result<Self, &'static str> { + let device = device_lock.write().unwrap(); + // Pool let mut pool = unsafe { use hal::pool::CommandPoolCreateFlags; @@ -248,8 +257,10 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< .position(|x| x.family == family) .unwrap(); + std::mem::drop(device); + Ok(TextureLoader { - device, + device: device_lock, commands_queued: ArrayVec::new(), buffers, pool: ManuallyDrop::new(pool), @@ -281,13 +292,14 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< fn deactivate(mut self) -> TextureLoaderRemains { use std::ptr::read; + let mut device = self.device.write().unwrap(); + unsafe { // Wait for any currently queued loads to be done while self.commands_queued.len() > 0 { let mut i = 0; while i < self.commands_queued.len() { - let signalled = self - .device + let signalled = device .get_fence_status(&self.commands_queued[i].fence) .expect("Device lost by TextureManager"); @@ -296,12 +308,13 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< let (assets, mut staging_bufs, block) = self.commands_queued.remove(i).dissolve(); - self.device.destroy_fence(assets.0); + device.destroy_fence(assets.0); // Command buffer will be freed when we reset the command pool - staging_bufs - .drain(..) - .map(|x| x.deactivate(self.device, &mut self.staging_allocator)) - .for_each(|_| {}); + // Destroy staging buffers + while staging_bufs.len() > 0 { + let buf = staging_bufs.pop().unwrap(); + buf.deactivate(&mut device, &mut self.staging_allocator); + } self.return_channel .send(block) @@ -318,12 +331,12 @@ impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader< let vec: Vec<_> = self.buffers.drain(..).collect(); vec.into_iter() - .map(|(f, _)| self.device.destroy_fence(f)) + .map(|(f, _)| device.destroy_fence(f)) .for_each(|_| {}); // Free command pool self.pool.reset(true); - self.device.destroy_command_pool(read(&*self.pool)); + device.destroy_command_pool(read(&*self.pool)); debug!("Done deactivating TextureLoader"); diff --git a/stockton-render/src/draw/texture/repo.rs b/stockton-render/src/draw/texture/repo.rs index 7bc8fb5..bb68479 100644 --- a/stockton-render/src/draw/texture/repo.rs +++ b/stockton-render/src/draw/texture/repo.rs @@ -11,9 +11,12 @@ use crate::types::*; use std::{ collections::HashMap, marker::PhantomData, + mem::drop, mem::ManuallyDrop, - pin::Pin, - sync::mpsc::{channel, Receiver, Sender}, + sync::{ + mpsc::{channel, Receiver, Sender}, + Arc, RwLock, RwLockReadGuard, + }, thread::JoinHandle, }; @@ -31,7 +34,7 @@ pub const BLOCK_SIZE: usize = 8; pub struct TextureRepo<'a> { joiner: ManuallyDrop<JoinHandle<Result<TextureLoaderRemains, &'static str>>>, - ds_layout: Pin<Box<DescriptorSetLayout>>, + ds_layout: Arc<RwLock<DescriptorSetLayout>>, req_send: Sender<LoaderRequest>, resp_recv: Receiver<TexturesBlock<DynamicBlock>>, blocks: HashMap<BlockRef, Option<TexturesBlock<DynamicBlock>>>, @@ -41,13 +44,13 @@ pub struct TextureRepo<'a> { impl<'a> TextureRepo<'a> { pub fn new< - T: HasTextures + Send + Sync, + T: 'static + HasTextures + Send + Sync, R: 'static + TextureResolver<I> + Send + Sync, I: 'static + LoadableImage + Send, >( - device: &'static mut Device, + device_lock: Arc<RwLock<Device>>, adapter: &Adapter, - texs: &'static T, + texs_lock: Arc<RwLock<T>>, resolver: R, ) -> Result<Self, &'static str> { let (req_send, req_recv) = channel(); @@ -67,7 +70,9 @@ impl<'a> TextureRepo<'a> { .unwrap() }; - let mut ds_layout = Box::pin( + let device = device_lock.write().unwrap(); + + let ds_lock = Arc::new(RwLock::new( unsafe { device.create_descriptor_set_layout( &[ @@ -90,21 +95,20 @@ impl<'a> TextureRepo<'a> { ) } .map_err(|_| "Couldn't create descriptor set layout")?, - ); + )); - let long_ds_pointer: &'static DescriptorSetLayout = - unsafe { &mut *(&mut *ds_layout as *mut DescriptorSetLayout) }; + drop(device); let joiner = { let loader = TextureLoader::new( - device, + device_lock, adapter, family.id(), gpu, - long_ds_pointer, + ds_lock.clone(), req_recv, resp_send, - texs, + texs_lock, resolver, )?; @@ -113,7 +117,7 @@ impl<'a> TextureRepo<'a> { Ok(TextureRepo { joiner: ManuallyDrop::new(joiner), - ds_layout, + ds_layout: ds_lock, blocks: HashMap::new(), req_send, resp_recv, @@ -121,8 +125,8 @@ impl<'a> TextureRepo<'a> { }) } - pub fn get_ds_layout(&self) -> &DescriptorSetLayout { - &*self.ds_layout + pub fn get_ds_layout(&self) -> RwLockReadGuard<DescriptorSetLayout> { + self.ds_layout.read().unwrap() } pub fn queue_load(&mut self, block_id: BlockRef) -> Result<(), &'static str> { @@ -157,7 +161,7 @@ impl<'a> TextureRepo<'a> { } } - pub fn deactivate(mut self, device: &mut Device) { + pub fn deactivate(mut self, device_lock: &mut Arc<RwLock<Device>>) { unsafe { use std::ptr::read; @@ -168,12 +172,15 @@ impl<'a> TextureRepo<'a> { // Process any ones that just got done loading self.process_responses(); + // Only now can we lock device without deadlocking + let mut device = device_lock.write().unwrap(); + // Return all the texture memory and descriptors. for (i, v) in self.blocks.drain() { debug!("Deactivating blockref {:?}", i); if let Some(block) = v { block.deactivate( - device, + &mut device, &mut *remains.tex_allocator, &mut remains.descriptor_allocator, ); @@ -184,7 +191,7 @@ impl<'a> TextureRepo<'a> { // Dispose of both allocators read(&*remains.tex_allocator).dispose(); - read(&*remains.descriptor_allocator).dispose(device); + read(&*remains.descriptor_allocator).dispose(&device); debug!("Disposed of allocators"); } diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs index 5943ed4..a0d745c 100644 --- a/stockton-render/src/lib.rs +++ b/stockton-render/src/lib.rs @@ -64,7 +64,7 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> Renderer<'a, M> { /// Render a single frame of the given map. fn render(&mut self, ui: &mut UiState, pos: Vector3) { // Get visible faces - let faces = get_visible_faces(pos, &*self.context.map); + let faces = get_visible_faces(pos, &*self.context.map.read().unwrap()); // Then draw them if self.context.draw_vertices(ui, &faces).is_err() { |