mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
buffers are now zero initialized for mappings
queue_write_buffer marks as initialized
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1807,6 +1807,7 @@ dependencies = [
|
||||
"loom",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"ron",
|
||||
"serde",
|
||||
|
||||
@@ -38,6 +38,7 @@ gpu-descriptor = { version = "0.1", features = ["tracing"] }
|
||||
|
||||
hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "2fd74dbe1562a3eef05b11dcd300c1c9c9bc12a8" }
|
||||
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "2fd74dbe1562a3eef05b11dcd300c1c9c9bc12a8" }
|
||||
range-alloc = {git = "https://github.com/gfx-rs/gfx", rev = "2fd74dbe1562a3eef05b11dcd300c1c9c9bc12a8"}
|
||||
|
||||
[target.'cfg(all(not(target_arch = "wasm32"), all(unix, not(target_os = "ios"), not(target_os = "macos"))))'.dependencies]
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "2fd74dbe1562a3eef05b11dcd300c1c9c9bc12a8", features = ["naga"] }
|
||||
|
||||
@@ -196,6 +196,30 @@ fn map_buffer<B: hal::Backend>(
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
let writes_are_synced = buffer.sync_mapped_writes.is_some() || block.is_coherent();
|
||||
|
||||
// Zero out uninitialized parts of the mapping. (Spec dictates all resources behave as if they were initialized with zero)
|
||||
// Note that going through a `fill_buffer` command may be faster but we don't have the chance of interacting with the queue
|
||||
// between map intent (map_buffer_async or immediately) and this call.
|
||||
let uninitialized_ranges: Vec<Range<BufferAddress>> =
|
||||
buffer.uninitialized_ranges_in_range(Range {
|
||||
start: offset,
|
||||
end: offset + size,
|
||||
});
|
||||
for range in uninitialized_ranges {
|
||||
unsafe {
|
||||
ptr::write_bytes(
|
||||
ptr.as_ptr().offset(range.start as isize),
|
||||
0,
|
||||
(range.end - range.start) as usize,
|
||||
)
|
||||
};
|
||||
// (technically the buffer is only initialized when we're done unmapping but we know it can't be used otherwise meanwhile)
|
||||
if writes_are_synced {
|
||||
buffer.mark_initialized(range);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ptr)
|
||||
}
|
||||
|
||||
@@ -534,6 +558,13 @@ impl<B: GfxBackend> Device<B> {
|
||||
.allocate(&self.raw, requirements, mem_usage)?;
|
||||
block.bind_buffer(&self.raw, &mut buffer)?;
|
||||
|
||||
let mut uninitialized_ranges = range_alloc::RangeAllocator::new(Range {
|
||||
start: 0,
|
||||
end: desc.size,
|
||||
});
|
||||
// Mark buffer as uninitialized
|
||||
let _ = uninitialized_ranges.allocate_range(desc.size);
|
||||
|
||||
Ok(resource::Buffer {
|
||||
raw: Some((buffer, block)),
|
||||
device_id: Stored {
|
||||
@@ -542,7 +573,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
},
|
||||
usage: desc.usage,
|
||||
size: desc.size,
|
||||
full_range: (),
|
||||
uninitialized_ranges,
|
||||
sync_mapped_writes: None,
|
||||
map_state: resource::BufferMapState::Idle,
|
||||
life_guard: LifeGuard::new(desc.label.borrow_or_default()),
|
||||
|
||||
@@ -191,7 +191,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let device = device_guard
|
||||
.get_mut(queue_id)
|
||||
.map_err(|_| DeviceError::Invalid)?;
|
||||
let (buffer_guard, _) = hub.buffers.read(&mut token);
|
||||
let (mut buffer_guard, _) = hub.buffers.write(&mut token);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref trace) = device.trace {
|
||||
@@ -271,6 +271,21 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device.pending_writes.consume(stage);
|
||||
device.pending_writes.dst_buffers.insert(buffer_id);
|
||||
|
||||
// Ensure the overwritten bytes are marked as initialized so they don't need to be nulled prior to mapping or binding.
|
||||
{
|
||||
let dst = buffer_guard.get_mut(buffer_id).unwrap();
|
||||
for range in dst
|
||||
.uninitialized_ranges_in_range::<Vec<std::ops::Range<wgt::BufferAddress>>>(
|
||||
std::ops::Range {
|
||||
start: buffer_offset,
|
||||
end: buffer_offset + data_size,
|
||||
},
|
||||
)
|
||||
{
|
||||
dst.mark_initialized(range);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -160,12 +160,42 @@ pub struct Buffer<B: hal::Backend> {
|
||||
pub(crate) device_id: Stored<DeviceId>,
|
||||
pub(crate) usage: wgt::BufferUsage,
|
||||
pub(crate) size: wgt::BufferAddress,
|
||||
pub(crate) full_range: (),
|
||||
// An allocated range in this allocator means that the range in question is NOT yet initialized.
|
||||
pub(crate) uninitialized_ranges: range_alloc::RangeAllocator<wgt::BufferAddress>,
|
||||
pub(crate) sync_mapped_writes: Option<hal::memory::Segment>,
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
pub(crate) map_state: BufferMapState<B>,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> Buffer<B> {
|
||||
pub(crate) fn uninitialized_ranges_in_range<
|
||||
'a,
|
||||
R: std::iter::FromIterator<Range<wgt::BufferAddress>>,
|
||||
>(
|
||||
&self,
|
||||
range: Range<wgt::BufferAddress>,
|
||||
) -> R {
|
||||
self.uninitialized_ranges
|
||||
.allocated_ranges()
|
||||
.filter_map(|r: Range<wgt::BufferAddress>| {
|
||||
if r.end > range.start && r.start < range.end {
|
||||
Some(Range {
|
||||
start: range.start.max(r.start),
|
||||
end: range.end.min(r.end),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<R>()
|
||||
}
|
||||
|
||||
// Range must be continuous previously uninitialized section.
|
||||
pub(crate) fn mark_initialized(&mut self, range: Range<wgt::BufferAddress>) {
|
||||
self.uninitialized_ranges.free_range(range);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateBufferError {
|
||||
#[error(transparent)]
|
||||
|
||||
Reference in New Issue
Block a user