diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index bcbd7ef563a..d03066fbd5c 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -7,6 +7,8 @@ mod query; mod render; mod transfer; +use std::num::NonZeroU32; + pub use self::bundle::*; pub use self::compute::*; pub use self::draw::*; @@ -15,7 +17,9 @@ pub use self::render::*; pub use self::transfer::*; use crate::error::{ErrorFormatter, PrettyError}; +use crate::init_tracker::TextureInitRange; use crate::init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}; +use crate::track::TextureSelector; use crate::{ hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, @@ -69,9 +73,11 @@ pub struct BakedCommands { pub(crate) list: Vec, pub(crate) trackers: TrackerSet, buffer_memory_init_actions: Vec, + texture_memory_init_actions: Vec, } pub(crate) struct DestroyedBufferError(pub id::BufferId); +pub(crate) struct DestroyedTextureError(pub id::TextureId); impl BakedCommands { pub(crate) fn initialize_buffer_memory( @@ -80,6 +86,7 @@ impl BakedCommands { buffer_guard: &mut Storage, id::BufferId>, ) -> Result<(), DestroyedBufferError> { let mut ranges = Vec::new(); + // TODO: neighboring NeedsInitializedMemory ranges in init_actions are not collapsed! for buffer_use in self.buffer_memory_init_actions.drain(..) { let buffer = buffer_guard .get_mut(buffer_use.id) @@ -131,7 +138,94 @@ impl BakedCommands { } } } + Ok(()) + } + + pub(crate) fn initialize_texture_memory( + &mut self, + device_tracker: &mut TrackerSet, + texture_guard: &mut Storage, id::TextureId>, + ) -> Result<(), DestroyedTextureError> { + let mut ranges = Vec::new(); + for texture_use in self.texture_memory_init_actions.drain(..) { + let texture = texture_guard + .get_mut(texture_use.id) + .map_err(|_| DestroyedTextureError(texture_use.id))?; + let use_range = texture_use.range; + let affected_mip_trackers = texture + .initialization_status + .mips + .iter_mut() + .enumerate() + .skip(use_range.mip_range.start as usize) + .take((use_range.mip_range.end - use_range.mip_range.start) as usize); + + match texture_use.kind { + MemoryInitKind::ImplicitlyInitialized => { + for (_, mip_tracker) in affected_mip_trackers { + mip_tracker + .drain(use_range.layer_range.clone()) + .for_each(drop); + } + } + MemoryInitKind::NeedsInitializedMemory => { + ranges.clear(); + for (mip_level, mip_tracker) in affected_mip_trackers { + for layer_range in mip_tracker.drain(use_range.layer_range.clone()) { + // TODO: Don't treat every mip_level separately and collapse equal layer ranges! + ranges.push(TextureInitRange { + mip_range: mip_level as u32..(mip_level as u32 + 1), + layer_range, + }) + } + } + let raw_texture = texture + .raw + .as_ref() + .ok_or(DestroyedTextureError(texture_use.id))?; + + for range in &ranges { + // TODO: D24 formats are not allowed to support COPY_DST!! (and on the rest we don't enforce it) + // -> This would mean we need use clear passes whenever applicable and fall back to copies or even shader writes. Need to figure this out. + // --> Depending on the outcome we may decide to skip all this elaborate range collapsing anyways + + // Don't do use_replace since the texture may already no longer have a ref_count. + // However, we *know* that it is currently in use, so the tracker must already know about it. + let transition = device_tracker.textures.change_replace_tracked( + id::Valid(texture_use.id), + TextureSelector { + levels: range.mip_range.clone(), + layers: range.layer_range.clone(), + }, + hal::TextureUses::COPY_DST, + ); + unsafe { + self.encoder.transition_textures( + transition.map(|pending| pending.into_hal(texture)), + ); + self.encoder.clear_texture( + raw_texture, + &ranges + .iter() + .map(|r| wgt::ImageSubresourceRange { + aspect: wgt::TextureAspect::All, + base_mip_level: r.mip_range.start, + mip_level_count: NonZeroU32::new( + r.mip_range.end - r.mip_range.start, + ), + base_array_layer: r.layer_range.start, + array_layer_count: NonZeroU32::new( + r.layer_range.end - r.layer_range.start, + ), + }) + .collect::>(), + ); + } + } + } + } + } Ok(()) } } @@ -239,6 +333,7 @@ impl CommandBuffer { list: self.encoder.list, trackers: self.trackers, buffer_memory_init_actions: self.buffer_memory_init_actions, + texture_memory_init_actions: self.texture_memory_init_actions, } } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 8c25456782b..de7cc20685d 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -533,7 +533,7 @@ impl Global { let (compute_pipe_guard, mut token) = hub.compute_pipelines.read(&mut token); let (render_pipe_guard, mut token) = hub.render_pipelines.read(&mut token); let (mut buffer_guard, mut token) = hub.buffers.write(&mut token); - let (texture_guard, mut token) = hub.textures.write(&mut token); + let (mut texture_guard, mut token) = hub.textures.write(&mut token); let (texture_view_guard, mut token) = hub.texture_views.read(&mut token); let (sampler_guard, mut token) = hub.samplers.read(&mut token); let (query_set_guard, _) = hub.query_sets.read(&mut token); @@ -678,6 +678,9 @@ impl Global { baked .initialize_buffer_memory(&mut *trackers, &mut *buffer_guard) .map_err(|err| QueueSubmitError::DestroyedBuffer(err.0))?; + baked + .initialize_texture_memory(&mut *trackers, &mut *texture_guard) + .map_err(|err| QueueSubmitError::DestroyedTexture(err.0))?; //Note: stateless trackers are not merged: // device already knows these resources exist. CommandBuffer::insert_barriers( diff --git a/wgpu-core/src/init_tracker/texture.rs b/wgpu-core/src/init_tracker/texture.rs index 7be1e5856d9..eac20ca7f8f 100644 --- a/wgpu-core/src/init_tracker/texture.rs +++ b/wgpu-core/src/init_tracker/texture.rs @@ -29,7 +29,7 @@ pub(crate) type TextureLayerInitTracker = InitTracker; #[derive(Debug)] pub(crate) struct TextureInitTracker { - mips: ArrayVec, + pub mips: ArrayVec, } impl TextureInitTracker { @@ -73,8 +73,8 @@ impl TextureInitTracker { Some(TextureInitTrackerAction { id: action.id, range: TextureInitRange { - mip_range: mip_range_start as u32..mip_range_end as u32, - layer_range: layer_range_start..layer_range_end, + mip_range: mip_range_start as u32..mip_range_end as u32, + layer_range: layer_range_start..layer_range_end, }, kind: action.kind, }) diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index ec245d8ac3f..25bab363efa 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -331,8 +331,8 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn clear_texture( &mut self, - texture: &super::Texture, - ranges: &[wgt::ImageSubresourceRange], + _texture: &super::Texture, + _ranges: &[wgt::ImageSubresourceRange], ) { // TODO }