aboutsummaryrefslogtreecommitdiff
path: root/stockton-render/src/draw/texture/loader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'stockton-render/src/draw/texture/loader.rs')
-rw-r--r--stockton-render/src/draw/texture/loader.rs125
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();