diff options
Diffstat (limited to 'stockton-render/src')
-rw-r--r-- | stockton-render/src/draw/texture/load.rs | 338 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/loader.rs | 356 | ||||
-rw-r--r-- | stockton-render/src/draw/texture/repo.rs | 2 |
3 files changed, 346 insertions, 350 deletions
diff --git a/stockton-render/src/draw/texture/load.rs b/stockton-render/src/draw/texture/load.rs index be1aa27..eea820a 100644 --- a/stockton-render/src/draw/texture/load.rs +++ b/stockton-render/src/draw/texture/load.rs @@ -2,31 +2,22 @@ use super::{ block::LoadedImage, block::TexturesBlock, loader::TextureLoader, repo::BLOCK_SIZE, resolver::TextureResolver, staging_buffer::StagingBuffer, LoadableImage, PIXEL_SIZE, }; -use crate::{error::LockPoisoned, types::*}; +use crate::types::*; use stockton_levels::prelude::*; use anyhow::{Context, Result}; use arrayvec::ArrayVec; use hal::{ - command::{BufferImageCopy, CommandBufferFlags}, format::{Aspects, Format, Swizzle}, image::{ - Access, Extent, Filter, Layout, Offset, SamplerDesc, SubresourceLayers, SubresourceRange, - Usage as ImgUsage, ViewKind, WrapMode, + Filter, SamplerDesc, SubresourceLayers, SubresourceRange, Usage as ImgUsage, ViewKind, + WrapMode, }, - memory::{Barrier, Dependencies, SparseFlags}, - pso::{Descriptor, DescriptorSetWrite, ImageDescriptorType, PipelineStage, ShaderStageFlags}, + memory::SparseFlags, MemoryTypeId, }; -use image::{Rgba, RgbaImage}; -use rendy_descriptor::{DescriptorRanges, DescriptorSetLayoutBinding, DescriptorType}; use rendy_memory::{Allocator, Block}; -use std::{ - array::IntoIter, - iter::{empty, once}, - mem::ManuallyDrop, - sync::{Arc, RwLock}, -}; +use std::mem::ManuallyDrop; use thiserror::Error; #[derive(Error, Debug)] @@ -38,15 +29,15 @@ pub enum TextureLoadError { ResolveFailed(usize), } -const FORMAT: Format = Format::Rgba8Srgb; -const RESOURCES: SubresourceRange = SubresourceRange { +pub const FORMAT: Format = Format::Rgba8Srgb; +pub const RESOURCES: SubresourceRange = SubresourceRange { aspects: Aspects::COLOR, level_start: 0, level_count: Some(1), layer_start: 0, layer_count: Some(1), }; -const LAYERS: SubresourceLayers = SubresourceLayers { +pub const LAYERS: SubresourceLayers = SubresourceLayers { aspects: Aspects::COLOR, level: 0, layers: 0..1, @@ -71,314 +62,7 @@ impl<B: Block<back::Backend>> QueuedLoad<B> { } } -impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R, I> { - pub(crate) unsafe fn attempt_queue_load( - &mut self, - block_ref: usize, - ) -> Result<QueuedLoad<DynamicBlock>> { - let mut device = self - .device - .write() - .map_err(|_| LockPoisoned::Device) - .context("Error getting device lock")?; - - let textures = self - .textures - .read() - .map_err(|_| LockPoisoned::Map) - .context("Error getting map lock")?; - - // Get assets to use - let (mut fence, mut buf) = self - .buffers - .pop_front() - .ok_or(TextureLoadError::NoResources) - .context("Error getting resources to use")?; - - // Create descriptor set - let mut 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::Image { - ty: ImageDescriptorType::Sampled { - with_sampler: false, - }, - }, - 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, - ) - .context("Error creating descriptor set")?; - - v.pop().unwrap() - }; - - // Get a command buffer - buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); - - let mut imgs: ArrayVec<[_; BLOCK_SIZE]> = ArrayVec::new(); - let mut staging_bufs: ArrayVec<[_; BLOCK_SIZE]> = ArrayVec::new(); - - // 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 = textures.get_texture(tex_idx as u32); - if tex.is_none() { - // Write a blank descriptor - device.write_descriptor_set(DescriptorSetWrite { - set: descriptor_set.raw_mut(), - binding: 0, - array_offset: tex_idx % BLOCK_SIZE, - descriptors: once(Descriptor::Image( - &*self.blank_image.img_view, - Layout::ShaderReadOnlyOptimal, - )), - }); - device.write_descriptor_set(DescriptorSetWrite { - set: descriptor_set.raw_mut(), - binding: 1, - array_offset: tex_idx % BLOCK_SIZE, - descriptors: once(Descriptor::Sampler(&*self.blank_image.sampler)), - }); - - continue; - } - - let tex = tex.unwrap(); - - let img_data = self - .resolver - .resolve(tex) - .ok_or(TextureLoadError::ResolveFailed(tex_idx))?; - let array_offset = tex_idx % BLOCK_SIZE; - - let (staging_buffer, img) = load_image( - &mut device, - &mut self.staging_allocator, - &mut self.tex_allocator, - self.staging_memory_type, - self.optimal_buffer_copy_pitch_alignment, - img_data, - )?; - - // Write to descriptor set - { - device.write_descriptor_set(DescriptorSetWrite { - set: descriptor_set.raw_mut(), - binding: 0, - array_offset, - descriptors: once(Descriptor::Image( - &*img.img_view, - Layout::ShaderReadOnlyOptimal, - )), - }); - device.write_descriptor_set(DescriptorSetWrite { - set: descriptor_set.raw_mut(), - binding: 1, - array_offset, - descriptors: once(Descriptor::Sampler(&*img.sampler)), - }); - } - - imgs.push(img); - - staging_bufs.push(staging_buffer); - } - - // Add start pipeline barrier - buf.pipeline_barrier( - PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER, - Dependencies::empty(), - imgs.iter().map(|li| Barrier::Image { - states: (Access::empty(), Layout::Undefined) - ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal), - target: &*li.img, - families: None, - range: SubresourceRange { - aspects: Aspects::COLOR, - level_start: 0, - level_count: None, - layer_start: 0, - layer_count: None, - }, - }), - ); - - // Record copy commands - for (li, sb) in imgs.iter().zip(staging_bufs.iter()) { - buf.copy_buffer_to_image( - &*sb.buf, - &*li.img, - Layout::TransferDstOptimal, - once(BufferImageCopy { - buffer_offset: 0, - buffer_width: (li.row_size / super::PIXEL_SIZE) as u32, - buffer_height: li.height, - image_layers: SubresourceLayers { - aspects: Aspects::COLOR, - level: 0, - layers: 0..1, - }, - image_offset: Offset { x: 0, y: 0, z: 0 }, - image_extent: gfx_hal::image::Extent { - width: li.width, - height: li.height, - depth: 1, - }, - }), - ); - } - buf.pipeline_barrier( - PipelineStage::TRANSFER..PipelineStage::BOTTOM_OF_PIPE, - Dependencies::empty(), - imgs.iter().map(|li| Barrier::Image { - states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal) - ..(Access::empty(), Layout::ShaderReadOnlyOptimal), - target: &*li.img, - families: None, - range: RESOURCES, - }), - ); - - buf.finish(); - - // Submit command buffer - { - let mut queue = self.queue.write().map_err(|_| LockPoisoned::Queue)?; - - queue.submit(IntoIter::new([&buf]), empty(), empty(), Some(&mut fence)); - } - - Ok(QueuedLoad { - staging_bufs, - fence, - buf, - block: TexturesBlock { - id: block_ref, - imgs, - descriptor_set: ManuallyDrop::new(descriptor_set), - }, - }) - } - - pub(crate) unsafe fn get_blank_image( - device: &mut DeviceT, - buf: &mut CommandBufferT, - queue_lock: &Arc<RwLock<QueueT>>, - staging_allocator: &mut DynamicAllocator, - tex_allocator: &mut DynamicAllocator, - staging_memory_type: MemoryTypeId, - obcpa: u64, - ) -> Result<LoadedImage<DynamicBlock>> { - let img_data = RgbaImage::from_pixel(1, 1, Rgba([0, 0, 0, 0])); - - let height = img_data.height(); - let width = img_data.width(); - let row_alignment_mask = obcpa as u32 - 1; - let initial_row_size = PIXEL_SIZE * img_data.width() as usize; - let row_size = - ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize; - - let (staging_buffer, img) = load_image( - device, - staging_allocator, - tex_allocator, - staging_memory_type, - obcpa, - img_data, - )?; - - buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); - - buf.pipeline_barrier( - PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER, - Dependencies::empty(), - once(Barrier::Image { - states: (Access::empty(), Layout::Undefined) - ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal), - target: &*img.img, - families: None, - range: SubresourceRange { - aspects: Aspects::COLOR, - level_start: 0, - level_count: None, - layer_start: 0, - layer_count: None, - }, - }), - ); - buf.copy_buffer_to_image( - &*staging_buffer.buf, - &*img.img, - Layout::TransferDstOptimal, - once(BufferImageCopy { - buffer_offset: 0, - buffer_width: (row_size / super::PIXEL_SIZE) as u32, - buffer_height: height, - image_layers: LAYERS, - image_offset: Offset { x: 0, y: 0, z: 0 }, - image_extent: Extent { - width: width, - height: height, - depth: 1, - }, - }), - ); - - buf.pipeline_barrier( - PipelineStage::TRANSFER..PipelineStage::BOTTOM_OF_PIPE, - Dependencies::empty(), - once(Barrier::Image { - states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal) - ..(Access::empty(), Layout::ShaderReadOnlyOptimal), - target: &*img.img, - families: None, - range: RESOURCES, - }), - ); - buf.finish(); - - let mut fence = device.create_fence(false).context("Error creating fence")?; - - { - let mut queue = queue_lock.write().map_err(|_| LockPoisoned::Queue)?; - - queue.submit( - IntoIter::new([buf as &CommandBufferT]), - empty(), - empty(), - Some(&mut fence), - ); - } - - device - .wait_for_fence(&fence, std::u64::MAX) - .context("Error waiting for copy")?; - - device.destroy_fence(fence); - - staging_buffer.deactivate(device, staging_allocator); - - Ok(img) - } -} +impl<'a, T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R, I> {} pub fn tex_size_info<T: LoadableImage>(img: &T, obcpa: hal::buffer::Offset) -> (usize, usize) { let initial_row_size = PIXEL_SIZE * img.width() as usize; @@ -391,7 +75,7 @@ pub fn tex_size_info<T: LoadableImage>(img: &T, obcpa: hal::buffer::Offset) -> ( (row_size, total_size as usize) } -fn create_image_view<T, I>( +pub fn create_image_view<T, I>( device: &mut DeviceT, allocator: &mut T, format: Format, @@ -435,7 +119,7 @@ where Ok((block, image_ref)) } -unsafe fn load_image<I: LoadableImage>( +pub unsafe fn load_image<I: LoadableImage>( device: &mut DeviceT, staging_allocator: &mut DynamicAllocator, tex_allocator: &mut DynamicAllocator, diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs index a23d633..2198fe4 100644 --- a/stockton-render/src/draw/texture/loader.rs +++ b/stockton-render/src/draw/texture/loader.rs @@ -2,14 +2,17 @@ use super::{ block::{LoadedImage, TexturesBlock}, - load::{QueuedLoad, TextureLoadError}, + load::{load_image, QueuedLoad, TextureLoadError, LAYERS, RESOURCES}, + repo::BLOCK_SIZE, resolver::TextureResolver, - LoadableImage, + LoadableImage, PIXEL_SIZE, }; use crate::{draw::utils::find_memory_type_id, error::LockPoisoned, types::*}; use std::{ + array::IntoIter, collections::VecDeque, + iter::{empty, once}, marker::PhantomData, mem::{drop, ManuallyDrop}, sync::{ @@ -23,12 +26,17 @@ use std::{ use anyhow::{Context, Result}; use arrayvec::ArrayVec; use hal::{ - format::Format, - memory::{Properties as MemProps, SparseFlags}, + command::{BufferImageCopy, CommandBufferFlags}, + format::{Aspects, Format}, + image::{Access, Extent, Layout, Offset, SubresourceLayers, SubresourceRange}, + memory::{Barrier, Dependencies, Properties as MemProps, SparseFlags}, + pso::{Descriptor, DescriptorSetWrite, ImageDescriptorType, PipelineStage, ShaderStageFlags}, queue::family::QueueFamilyId, MemoryTypeId, }; +use image::{Rgba, RgbaImage}; use log::*; +use rendy_descriptor::{DescriptorRanges, DescriptorSetLayoutBinding, DescriptorType}; use rendy_memory::DynamicConfig; use stockton_levels::prelude::HasTextures; use thiserror::Error; @@ -43,54 +51,54 @@ pub type BlockRef = usize; /// This is expected to load the textures, then send the loaded blocks back pub struct TextureLoader<T, R, I> { /// 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]>, + commands_queued: ArrayVec<[QueuedLoad<DynamicBlock>; NUM_SIMULTANEOUS_CMDS]>, /// The command buffers used and a fence to go with them - pub(crate) buffers: VecDeque<(FenceT, CommandBufferT)>, + buffers: VecDeque<(FenceT, CommandBufferT)>, /// The command pool buffers were allocated from - pub(crate) pool: ManuallyDrop<CommandPoolT>, + pool: ManuallyDrop<CommandPoolT>, /// The GPU we're submitting to - pub(crate) device: Arc<RwLock<DeviceT>>, + device: Arc<RwLock<DeviceT>>, /// The command queue being used - pub(crate) queue: Arc<RwLock<QueueT>>, + queue: Arc<RwLock<QueueT>>, /// The memory allocator being used for textures - pub(crate) tex_allocator: ManuallyDrop<DynamicAllocator>, + tex_allocator: ManuallyDrop<DynamicAllocator>, /// The memory allocator for staging memory - pub(crate) staging_allocator: ManuallyDrop<DynamicAllocator>, + staging_allocator: ManuallyDrop<DynamicAllocator>, /// Allocator for descriptor sets - pub(crate) descriptor_allocator: ManuallyDrop<DescriptorAllocator>, + descriptor_allocator: ManuallyDrop<DescriptorAllocator>, - pub(crate) ds_layout: Arc<RwLock<DescriptorSetLayoutT>>, + ds_layout: Arc<RwLock<DescriptorSetLayoutT>>, /// Type ID for staging memory - pub(crate) staging_memory_type: MemoryTypeId, + staging_memory_type: MemoryTypeId, /// From adapter, used for determining alignment - pub(crate) optimal_buffer_copy_pitch_alignment: hal::buffer::Offset, + optimal_buffer_copy_pitch_alignment: hal::buffer::Offset, /// The textures lump to get info from - pub(crate) textures: Arc<RwLock<T>>, + textures: Arc<RwLock<T>>, /// The resolver which gets image data for a given texture. - pub(crate) resolver: R, + resolver: R, /// The channel requests come in. /// Requests should reference a texture **block**, for example textures 8..16 is block 1. - pub(crate) request_channel: Receiver<LoaderRequest>, + request_channel: Receiver<LoaderRequest>, /// The channel blocks are returned to. - pub(crate) return_channel: Sender<TexturesBlock<DynamicBlock>>, + 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>>, + blank_image: ManuallyDrop<LoadedImage<DynamicBlock>>, - pub(crate) _li: PhantomData<I>, + _li: PhantomData<I>, } #[derive(Error, Debug)] @@ -100,7 +108,7 @@ pub enum TextureLoaderError { } impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R, I> { - pub fn loop_forever(mut self) -> Result<TextureLoaderRemains> { + pub fn loop_until_exit(mut self) -> Result<TextureLoaderRemains> { debug!("TextureLoader starting main loop"); let mut res = Ok(false); while res.is_ok() { @@ -331,6 +339,310 @@ impl<T: HasTextures, R: TextureResolver<I>, I: LoadableImage> TextureLoader<T, R }) } + unsafe fn attempt_queue_load(&mut self, block_ref: usize) -> Result<QueuedLoad<DynamicBlock>> { + let mut device = self + .device + .write() + .map_err(|_| LockPoisoned::Device) + .context("Error getting device lock")?; + + let textures = self + .textures + .read() + .map_err(|_| LockPoisoned::Map) + .context("Error getting map lock")?; + + // Get assets to use + let (mut fence, mut buf) = self + .buffers + .pop_front() + .ok_or(TextureLoadError::NoResources) + .context("Error getting resources to use")?; + + // Create descriptor set + let mut 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::Image { + ty: ImageDescriptorType::Sampled { + with_sampler: false, + }, + }, + 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, + ) + .context("Error creating descriptor set")?; + + v.pop().unwrap() + }; + + // Get a command buffer + buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); + + let mut imgs: ArrayVec<[_; BLOCK_SIZE]> = ArrayVec::new(); + let mut staging_bufs: ArrayVec<[_; BLOCK_SIZE]> = ArrayVec::new(); + + // 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 = textures.get_texture(tex_idx as u32); + if tex.is_none() { + // Write a blank descriptor + device.write_descriptor_set(DescriptorSetWrite { + set: descriptor_set.raw_mut(), + binding: 0, + array_offset: tex_idx % BLOCK_SIZE, + descriptors: once(Descriptor::Image( + &*self.blank_image.img_view, + Layout::ShaderReadOnlyOptimal, + )), + }); + device.write_descriptor_set(DescriptorSetWrite { + set: descriptor_set.raw_mut(), + binding: 1, + array_offset: tex_idx % BLOCK_SIZE, + descriptors: once(Descriptor::Sampler(&*self.blank_image.sampler)), + }); + + continue; + } + + let tex = tex.unwrap(); + + let img_data = self + .resolver + .resolve(tex) + .ok_or(TextureLoadError::ResolveFailed(tex_idx))?; + let array_offset = tex_idx % BLOCK_SIZE; + + let (staging_buffer, img) = load_image( + &mut device, + &mut self.staging_allocator, + &mut self.tex_allocator, + self.staging_memory_type, + self.optimal_buffer_copy_pitch_alignment, + img_data, + )?; + + // Write to descriptor set + { + device.write_descriptor_set(DescriptorSetWrite { + set: descriptor_set.raw_mut(), + binding: 0, + array_offset, + descriptors: once(Descriptor::Image( + &*img.img_view, + Layout::ShaderReadOnlyOptimal, + )), + }); + device.write_descriptor_set(DescriptorSetWrite { + set: descriptor_set.raw_mut(), + binding: 1, + array_offset, + descriptors: once(Descriptor::Sampler(&*img.sampler)), + }); + } + + imgs.push(img); + + staging_bufs.push(staging_buffer); + } + + // Add start pipeline barrier + buf.pipeline_barrier( + PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER, + Dependencies::empty(), + imgs.iter().map(|li| Barrier::Image { + states: (Access::empty(), Layout::Undefined) + ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal), + target: &*li.img, + families: None, + range: SubresourceRange { + aspects: Aspects::COLOR, + level_start: 0, + level_count: None, + layer_start: 0, + layer_count: None, + }, + }), + ); + + // Record copy commands + for (li, sb) in imgs.iter().zip(staging_bufs.iter()) { + buf.copy_buffer_to_image( + &*sb.buf, + &*li.img, + Layout::TransferDstOptimal, + once(BufferImageCopy { + buffer_offset: 0, + buffer_width: (li.row_size / super::PIXEL_SIZE) as u32, + buffer_height: li.height, + image_layers: SubresourceLayers { + aspects: Aspects::COLOR, + level: 0, + layers: 0..1, + }, + image_offset: Offset { x: 0, y: 0, z: 0 }, + image_extent: gfx_hal::image::Extent { + width: li.width, + height: li.height, + depth: 1, + }, + }), + ); + } + buf.pipeline_barrier( + PipelineStage::TRANSFER..PipelineStage::BOTTOM_OF_PIPE, + Dependencies::empty(), + imgs.iter().map(|li| Barrier::Image { + states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal) + ..(Access::empty(), Layout::ShaderReadOnlyOptimal), + target: &*li.img, + families: None, + range: RESOURCES, + }), + ); + + buf.finish(); + + // Submit command buffer + { + let mut queue = self.queue.write().map_err(|_| LockPoisoned::Queue)?; + + queue.submit(IntoIter::new([&buf]), empty(), empty(), Some(&mut fence)); + } + + Ok(QueuedLoad { + staging_bufs, + fence, + buf, + block: TexturesBlock { + id: block_ref, + imgs, + descriptor_set: ManuallyDrop::new(descriptor_set), + }, + }) + } + + unsafe fn get_blank_image( + device: &mut DeviceT, + buf: &mut CommandBufferT, + queue_lock: &Arc<RwLock<QueueT>>, + staging_allocator: &mut DynamicAllocator, + tex_allocator: &mut DynamicAllocator, + staging_memory_type: MemoryTypeId, + obcpa: u64, + ) -> Result<LoadedImage<DynamicBlock>> { + let img_data = RgbaImage::from_pixel(1, 1, Rgba([0, 0, 0, 0])); + + let height = img_data.height(); + let width = img_data.width(); + let row_alignment_mask = obcpa as u32 - 1; + let initial_row_size = PIXEL_SIZE * img_data.width() as usize; + let row_size = + ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize; + + let (staging_buffer, img) = load_image( + device, + staging_allocator, + tex_allocator, + staging_memory_type, + obcpa, + img_data, + )?; + + buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); + + buf.pipeline_barrier( + PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER, + Dependencies::empty(), + once(Barrier::Image { + states: (Access::empty(), Layout::Undefined) + ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal), + target: &*img.img, + families: None, + range: SubresourceRange { + aspects: Aspects::COLOR, + level_start: 0, + level_count: None, + layer_start: 0, + layer_count: None, + }, + }), + ); + buf.copy_buffer_to_image( + &*staging_buffer.buf, + &*img.img, + Layout::TransferDstOptimal, + once(BufferImageCopy { + buffer_offset: 0, + buffer_width: (row_size / super::PIXEL_SIZE) as u32, + buffer_height: height, + image_layers: LAYERS, + image_offset: Offset { x: 0, y: 0, z: 0 }, + image_extent: Extent { + width: width, + height: height, + depth: 1, + }, + }), + ); + + buf.pipeline_barrier( + PipelineStage::TRANSFER..PipelineStage::BOTTOM_OF_PIPE, + Dependencies::empty(), + once(Barrier::Image { + states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal) + ..(Access::empty(), Layout::ShaderReadOnlyOptimal), + target: &*img.img, + families: None, + range: RESOURCES, + }), + ); + buf.finish(); + + let mut fence = device.create_fence(false).context("Error creating fence")?; + + { + let mut queue = queue_lock.write().map_err(|_| LockPoisoned::Queue)?; + + queue.submit( + IntoIter::new([buf as &CommandBufferT]), + empty(), + empty(), + Some(&mut fence), + ); + } + + device + .wait_for_fence(&fence, std::u64::MAX) + .context("Error waiting for copy")?; + + device.destroy_fence(fence); + + staging_buffer.deactivate(device, staging_allocator); + + Ok(img) + } + /// Safely destroy all the vulkan stuff in this instance /// Note that this returns the memory allocators, from which should be freed any TextureBlocks /// All in-progress things are sent to return_channel. diff --git a/stockton-render/src/draw/texture/repo.rs b/stockton-render/src/draw/texture/repo.rs index c37da11..75cc650 100644 --- a/stockton-render/src/draw/texture/repo.rs +++ b/stockton-render/src/draw/texture/repo.rs @@ -116,7 +116,7 @@ impl<'a> TextureRepo<'a> { resolver, )?; - std::thread::spawn(move || loader.loop_forever()) + std::thread::spawn(move || loader.loop_until_exit()) }; Ok(TextureRepo { |