aboutsummaryrefslogtreecommitdiff
path: root/stockton-skeleton/src/texture/repo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'stockton-skeleton/src/texture/repo.rs')
-rw-r--r--stockton-skeleton/src/texture/repo.rs80
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 {