aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:22 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:22 +0100
commit5da588c6223e4c30cc5ec349f318aa5203cb0ce7 (patch)
tree4e994259407507e0fd203ad5b861bb7701ad5763
parentb822c9794fb6f11bd793c2301ae9ec860de95bf5 (diff)
refactor(render): move to locks rather than unsafe ops
-rw-r--r--stockton-render/src/draw/context.rs107
-rw-r--r--stockton-render/src/draw/texture/load.rs83
-rw-r--r--stockton-render/src/draw/texture/loader.rs63
-rw-r--r--stockton-render/src/draw/texture/repo.rs45
-rw-r--r--stockton-render/src/lib.rs2
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() {