diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 9a2292f202..16ffc7b70c 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -17,7 +17,7 @@ pub use self::transfer::*; use crate::{ hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, - memory_init_tracker::MemoryInitTrackerAction, + memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, resource::{Buffer, Texture}, track::{BufferState, ResourceTracker, TextureState, TrackerSet}, Label, Stored, @@ -63,10 +63,76 @@ impl CommandEncoder { } } -pub struct BackedCommands { +pub struct BakedCommands { pub(crate) encoder: A::CommandEncoder, pub(crate) list: Vec, pub(crate) trackers: TrackerSet, + buffer_memory_init_actions: Vec>, +} + +pub(crate) struct DestroyedBufferError(pub id::BufferId); + +impl BakedCommands { + pub(crate) fn initialize_buffer_memory( + &mut self, + device_tracker: &mut TrackerSet, + buffer_guard: &mut Storage, id::BufferId>, + ) -> Result<(), DestroyedBufferError> { + let mut ranges = Vec::new(); + for buffer_use in self.buffer_memory_init_actions.drain(..) { + let buffer = buffer_guard + .get_mut(buffer_use.id) + .map_err(|_| DestroyedBufferError(buffer_use.id))?; + + let uninitialized_ranges = buffer.initialization_status.drain(buffer_use.range.clone()); + match buffer_use.kind { + MemoryInitKind::ImplicitlyInitialized => { + uninitialized_ranges.for_each(drop); + } + MemoryInitKind::NeedsInitializedMemory => { + ranges.clear(); + ranges.extend(uninitialized_ranges); + // Collapse touching ranges. We can't do this any earlier since we only now gathered ranges from several different command buffers! + ranges.sort_by(|a, b| a.start.cmp(&b.start)); + for i in (1..ranges.len()).rev() { + assert!(ranges[i - 1].end <= ranges[i].start); // The memory init tracker made sure of this! + if ranges[i].start == ranges[i - 1].end { + ranges[i - 1].end = ranges[i].end; + ranges.swap_remove(i); // Ordering not important at this point + } + } + + // Don't do use_replace since the buffer 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.buffers.change_replace_tracked( + id::Valid(buffer_use.id), + (), + hal::BufferUses::COPY_DST, + ); + let raw_buf = buffer + .raw + .as_ref() + .ok_or(DestroyedBufferError(buffer_use.id))?; + + unsafe { + self.encoder + .transition_buffers(transition.map(|pending| pending.into_hal(buffer))); + } + + for range in ranges.iter() { + assert!(range.start % 4 == 0, "Buffer {:?} has an uninitialized range with a start not aligned to 4 (start was {})", raw_buf, range.start); + assert!(range.end % 4 == 0, "Buffer {:?} has an uninitialized range with an end not aligned to 4 (end was {})", raw_buf, range.end); + + unsafe { + self.encoder.fill_buffer(raw_buf, range.clone(), 0); + } + } + } + } + } + + Ok(()) + } } pub struct CommandBuffer { @@ -75,7 +141,7 @@ pub struct CommandBuffer { pub(crate) device_id: Stored, pub(crate) trackers: TrackerSet, pub(crate) used_swap_chains: SmallVec<[Stored; 1]>, - pub(crate) buffer_memory_init_actions: Vec>, + buffer_memory_init_actions: Vec>, limits: wgt::Limits, support_fill_buffer_texture: bool, #[cfg(feature = "trace")] @@ -164,11 +230,12 @@ impl CommandBuffer { } } - pub(crate) fn into_baked(self) -> BackedCommands { - BackedCommands { + pub(crate) fn into_baked(self) -> BakedCommands { + BakedCommands { encoder: self.encoder.raw, list: self.encoder.list, trackers: self.trackers, + buffer_memory_init_actions: self.buffer_memory_init_actions, } } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 577a6fd7e7..342a9ea685 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -7,17 +7,16 @@ use crate::{ }, conv, device::{DeviceError, WaitIdleError}, - hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, + hub::{Global, GlobalIdentityHandlerFactory, HalApi, Token}, id, - memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, - resource::{Buffer, BufferAccessError, BufferMapState}, - FastHashMap, FastHashSet, + resource::{BufferAccessError, BufferMapState}, + FastHashSet, }; use hal::{CommandEncoder as _, Device as _, Queue as _}; use parking_lot::Mutex; use smallvec::SmallVec; -use std::{iter, mem, num::NonZeroU32, ops::Range, ptr}; +use std::{iter, mem, num::NonZeroU32, ptr}; use thiserror::Error; /// Number of command buffers that we generate from the same pool @@ -177,39 +176,6 @@ impl PendingWrites { } } -#[derive(Default)] -struct RequiredBufferInits { - map: FastHashMap>>, -} - -impl RequiredBufferInits { - fn add( - &mut self, - buffer_memory_init_actions: &[MemoryInitTrackerAction], - buffer_guard: &mut Storage, id::BufferId>, - ) -> Result<(), QueueSubmitError> { - for buffer_use in buffer_memory_init_actions.iter() { - let buffer = buffer_guard - .get_mut(buffer_use.id) - .map_err(|_| QueueSubmitError::DestroyedBuffer(buffer_use.id))?; - - let uninitialized_ranges = buffer.initialization_status.drain(buffer_use.range.clone()); - match buffer_use.kind { - MemoryInitKind::ImplicitlyInitialized => { - uninitialized_ranges.for_each(drop); - } - MemoryInitKind::NeedsInitializedMemory => { - self.map - .entry(buffer_use.id) - .or_default() - .extend(uninitialized_ranges); - } - } - } - Ok(()) - } -} - impl super::Device { fn prepare_stage(&mut self, size: wgt::BufferAddress) -> Result, DeviceError> { profiling::scope!("prepare_stage"); @@ -222,58 +188,6 @@ impl super::Device { let buffer = unsafe { self.raw.create_buffer(&stage_desc)? }; Ok(StagingData { buffer }) } - - fn initialize_buffer_memory( - &mut self, - mut required_buffer_inits: RequiredBufferInits, - buffer_guard: &mut Storage, id::BufferId>, - ) -> Result<(), QueueSubmitError> { - self.pending_writes - .dst_buffers - .extend(required_buffer_inits.map.keys()); - - let encoder = self.pending_writes.activate(); - let mut trackers = self.trackers.lock(); - - for (buffer_id, mut ranges) in required_buffer_inits.map.drain() { - // Collapse touching ranges. We can't do this any earlier since we only now gathered ranges from several different command buffers! - ranges.sort_by(|a, b| a.start.cmp(&b.start)); - for i in (1..ranges.len()).rev() { - assert!(ranges[i - 1].end <= ranges[i].start); // The memory init tracker made sure of this! - if ranges[i].start == ranges[i - 1].end { - ranges[i - 1].end = ranges[i].end; - ranges.swap_remove(i); // Ordering not important at this point - } - } - - // Don't do use_replace since the buffer 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 = trackers.buffers.change_replace_tracked( - id::Valid(buffer_id), - (), - hal::BufferUses::COPY_DST, - ); - let buffer = buffer_guard.get(buffer_id).unwrap(); - let raw_buf = buffer - .raw - .as_ref() - .ok_or(QueueSubmitError::DestroyedBuffer(buffer_id))?; - unsafe { - encoder.transition_buffers(transition.map(|pending| pending.into_hal(buffer))); - } - - for range in ranges { - assert!(range.start % 4 == 0, "Buffer {:?} has an uninitialized range with a start not aligned to 4 (start was {})", raw_buf, range.start); - assert!(range.end % 4 == 0, "Buffer {:?} has an uninitialized range with an end not aligned to 4 (end was {})", raw_buf, range.end); - - unsafe { - encoder.fill_buffer(raw_buf, range, 0); - } - } - } - - Ok(()) - } } #[derive(Clone, Debug, Error)] @@ -624,7 +538,6 @@ impl Global { let (sampler_guard, mut token) = hub.samplers.read(&mut token); let (query_set_guard, _) = hub.query_sets.read(&mut token); - let mut required_buffer_inits = RequiredBufferInits::default(); //Note: locking the trackers has to be done after the storages let mut trackers = device.trackers.lock(); @@ -653,8 +566,6 @@ impl Global { continue; } - required_buffer_inits - .add(&cmdbuf.buffer_memory_init_actions, &mut *buffer_guard)?; // optimize the tracked states cmdbuf.trackers.optimize(); @@ -756,7 +667,6 @@ impl Global { } let mut baked = cmdbuf.into_baked(); - // execute resource transitions unsafe { baked @@ -765,6 +675,9 @@ impl Global { .map_err(DeviceError::from)? }; log::trace!("Stitching command buffer {:?} before submission", cmb_id); + baked + .initialize_buffer_memory(&mut *trackers, &mut *buffer_guard) + .map_err(|err| QueueSubmitError::DestroyedBuffer(err.0))?; //Note: stateless trackers are not merged: // device already knows these resources exist. CommandBuffer::insert_barriers( @@ -775,6 +688,7 @@ impl Global { &*buffer_guard, &*texture_guard, ); + let transit = unsafe { baked.encoder.end_encoding().unwrap() }; baked.list.insert(0, transit); active_executions.push(EncoderInFlight { @@ -784,11 +698,6 @@ impl Global { } log::trace!("Device after submission {}: {:#?}", submit_index, trackers); - drop(trackers); - if !required_buffer_inits.map.is_empty() { - device - .initialize_buffer_memory(required_buffer_inits, &mut *buffer_guard)?; - } } let super::Device { diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index abbe61528c..8903194827 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1085,7 +1085,6 @@ impl crate::Context for Context { if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause { log::warn!("Shader translation error for stage {:?}: {}", stage, error); log::warn!("Please report it to https://github.com/gfx-rs/naga"); - log::warn!("Try enabling `wgpu/cross` feature as a workaround."); } self.handle_error( &device.error_sink, @@ -1136,7 +1135,6 @@ impl crate::Context for Context { error ); log::warn!("Please report it to https://github.com/gfx-rs/naga"); - log::warn!("Try enabling `wgpu/cross` feature as a workaround."); } self.handle_error( &device.error_sink,