mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
Early buffer destruction logic
This commit is contained in:
parent
0a7d81351c
commit
c4c8e3b224
@ -150,7 +150,7 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
self.device_create_texture::<B>(device, &desc, id).unwrap();
|
||||
}
|
||||
A::DestroyTexture(id) => {
|
||||
self.texture_drop::<B>(id);
|
||||
self.texture_drop::<B>(id, true);
|
||||
}
|
||||
A::CreateTextureView {
|
||||
id,
|
||||
|
@ -5,7 +5,7 @@
|
||||
#[cfg(feature = "trace")]
|
||||
use crate::device::trace;
|
||||
use crate::{
|
||||
device::DeviceError,
|
||||
device::{queue::TempResource, DeviceError},
|
||||
hub::{GfxBackend, GlobalIdentityHandlerFactory, Hub, Token},
|
||||
id, resource,
|
||||
track::TrackerSet,
|
||||
@ -241,10 +241,16 @@ impl<B: hal::Backend> LifetimeTracker<B> {
|
||||
index: SubmissionIndex,
|
||||
fence: B::Fence,
|
||||
new_suspects: &SuspectedResources,
|
||||
temp_buffers: impl Iterator<Item = (B::Buffer, MemoryBlock<B>)>,
|
||||
temp_resources: impl Iterator<Item = (TempResource<B>, MemoryBlock<B>)>,
|
||||
) {
|
||||
let mut last_resources = NonReferencedResources::new();
|
||||
last_resources.buffers.extend(temp_buffers);
|
||||
for (res, memory) in temp_resources {
|
||||
match res {
|
||||
TempResource::Buffer(raw) => last_resources.buffers.push((raw, memory)),
|
||||
//TempResource::Image(raw) => last_resources.images.push((raw, memory)),
|
||||
}
|
||||
}
|
||||
|
||||
self.suspected_resources.buffers.extend(
|
||||
self.future_suspected_buffers
|
||||
.drain(..)
|
||||
@ -256,6 +262,7 @@ impl<B: hal::Backend> LifetimeTracker<B> {
|
||||
.map(|stored| stored.value),
|
||||
);
|
||||
self.suspected_resources.extend(new_suspects);
|
||||
|
||||
self.active.alloc().init(ActiveSubmission {
|
||||
index,
|
||||
fence,
|
||||
@ -336,6 +343,23 @@ impl<B: hal::Backend> LifetimeTracker<B> {
|
||||
descriptor_allocator_mutex.lock().cleanup(device);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn schedule_resource_destruction(
|
||||
&mut self,
|
||||
temp_resource: TempResource<B>,
|
||||
memory: MemoryBlock<B>,
|
||||
last_submit_index: SubmissionIndex,
|
||||
) {
|
||||
let resources = self
|
||||
.active
|
||||
.iter_mut()
|
||||
.find(|a| a.index == last_submit_index)
|
||||
.map_or(&mut self.free_resources, |a| &mut a.last_resources);
|
||||
match temp_resource {
|
||||
TempResource::Buffer(raw) => resources.buffers.push((raw, memory)),
|
||||
//TempResource::Image(raw) => resources.images.push((raw, memory)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: GfxBackend> LifetimeTracker<B> {
|
||||
|
@ -1219,7 +1219,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
//TODO: lock pending writes separately, keep the device read-only
|
||||
let (mut device_guard, mut token) = hub.devices.write(&mut token);
|
||||
|
||||
tracing::info!("Buffer {:?} is destroyed", buffer_id);
|
||||
let (mut buffer_guard, _) = hub.buffers.write(&mut token);
|
||||
@ -1227,18 +1228,35 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
.get_mut(buffer_id)
|
||||
.map_err(|_| resource::DestroyError::Invalid)?;
|
||||
|
||||
let device = &device_guard[buffer.device_id.value];
|
||||
let device = &mut device_guard[buffer.device_id.value];
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref trace) = device.trace {
|
||||
trace.lock().add(trace::Action::FreeBuffer(buffer_id));
|
||||
}
|
||||
|
||||
let _ = device; //TODO: schedule buffer destruction
|
||||
let (raw, memory) = buffer
|
||||
.raw
|
||||
.take()
|
||||
.ok_or(resource::DestroyError::AlreadyDestroyed)?;
|
||||
let temp = queue::TempResource::Buffer(raw);
|
||||
|
||||
if device.pending_writes.dst_buffers.contains(&buffer_id) {
|
||||
device.pending_writes.temp_resources.push((temp, memory));
|
||||
} else {
|
||||
let last_submit_index = buffer.life_guard.submission_index.load(Ordering::Acquire);
|
||||
drop(buffer_guard);
|
||||
device.lock_life(&mut token).schedule_resource_destruction(
|
||||
temp,
|
||||
memory,
|
||||
last_submit_index,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn buffer_drop<B: GfxBackend>(&self, buffer_id: id::BufferId, now: bool) {
|
||||
pub fn buffer_drop<B: GfxBackend>(&self, buffer_id: id::BufferId, wait: bool) {
|
||||
span!(_guard, INFO, "Buffer::drop");
|
||||
|
||||
let hub = B::hub(self);
|
||||
@ -1263,25 +1281,26 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
let device = &device_guard[device_id];
|
||||
if now {
|
||||
let mut life_lock = device_guard[device_id].lock_life(&mut token);
|
||||
|
||||
if device.pending_writes.dst_buffers.contains(&buffer_id) {
|
||||
life_lock.future_suspected_buffers.push(Stored {
|
||||
value: id::Valid(buffer_id),
|
||||
ref_count,
|
||||
});
|
||||
} else {
|
||||
drop(ref_count);
|
||||
device
|
||||
.lock_life(&mut token)
|
||||
life_lock
|
||||
.suspected_resources
|
||||
.buffers
|
||||
.push(id::Valid(buffer_id));
|
||||
}
|
||||
|
||||
if wait {
|
||||
match device.wait_for_submit(last_submit_index, &mut token) {
|
||||
Ok(()) => (),
|
||||
Err(e) => tracing::error!("Failed to wait for buffer {:?}: {:?}", buffer_id, e),
|
||||
}
|
||||
} else {
|
||||
device
|
||||
.lock_life(&mut token)
|
||||
.future_suspected_buffers
|
||||
.push(Stored {
|
||||
value: id::Valid(buffer_id),
|
||||
ref_count,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1338,19 +1357,21 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
.register_error(id_in, &mut Token::root())
|
||||
}
|
||||
|
||||
pub fn texture_drop<B: GfxBackend>(&self, texture_id: id::TextureId) {
|
||||
pub fn texture_drop<B: GfxBackend>(&self, texture_id: id::TextureId, wait: bool) {
|
||||
span!(_guard, INFO, "Texture::drop");
|
||||
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
|
||||
let (ref_count, device_id) = {
|
||||
let (ref_count, last_submit_index, device_id) = {
|
||||
let (mut texture_guard, _) = hub.textures.write(&mut token);
|
||||
match texture_guard.get_mut(texture_id) {
|
||||
Ok(texture) => (
|
||||
texture.life_guard.ref_count.take().unwrap(),
|
||||
texture.device_id.value,
|
||||
),
|
||||
Ok(texture) => {
|
||||
let ref_count = texture.life_guard.ref_count.take().unwrap();
|
||||
let last_submit_index =
|
||||
texture.life_guard.submission_index.load(Ordering::Acquire);
|
||||
(ref_count, last_submit_index, texture.device_id.value)
|
||||
}
|
||||
Err(InvalidId) => {
|
||||
hub.textures
|
||||
.unregister_locked(texture_id, &mut *texture_guard);
|
||||
@ -1360,13 +1381,28 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
};
|
||||
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
device_guard[device_id]
|
||||
.lock_life(&mut token)
|
||||
.future_suspected_textures
|
||||
.push(Stored {
|
||||
let device = &device_guard[device_id];
|
||||
let mut life_lock = device_guard[device_id].lock_life(&mut token);
|
||||
|
||||
if device.pending_writes.dst_textures.contains(&texture_id) {
|
||||
life_lock.future_suspected_textures.push(Stored {
|
||||
value: id::Valid(texture_id),
|
||||
ref_count,
|
||||
});
|
||||
} else {
|
||||
drop(ref_count);
|
||||
life_lock
|
||||
.suspected_resources
|
||||
.textures
|
||||
.push(id::Valid(texture_id));
|
||||
}
|
||||
|
||||
if wait {
|
||||
match device.wait_for_submit(last_submit_index, &mut token) {
|
||||
Ok(()) => (),
|
||||
Err(e) => tracing::error!("Failed to wait for texture {:?}: {:?}", texture_id, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn texture_create_view<B: GfxBackend>(
|
||||
@ -3797,7 +3833,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
device
|
||||
.pending_writes
|
||||
.consume_temp(stage_buffer, stage_memory);
|
||||
.consume_temp(queue::TempResource::Buffer(stage_buffer), stage_memory);
|
||||
}
|
||||
resource::BufferMapState::Idle => {
|
||||
return Err(resource::BufferAccessError::NotMapped);
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Token},
|
||||
id,
|
||||
resource::{BufferAccessError, BufferMapState, BufferUse, TextureUse},
|
||||
span,
|
||||
span, FastHashSet,
|
||||
};
|
||||
|
||||
use gfx_memory::{Block, Heaps, MemoryBlock};
|
||||
@ -29,17 +29,27 @@ struct StagingData<B: hal::Backend> {
|
||||
cmdbuf: B::CommandBuffer,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug)]
|
||||
pub enum TempResource<B: hal::Backend> {
|
||||
Buffer(B::Buffer),
|
||||
//Image(B::Image),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PendingWrites<B: hal::Backend> {
|
||||
pub command_buffer: Option<B::CommandBuffer>,
|
||||
pub temp_buffers: Vec<(B::Buffer, MemoryBlock<B>)>,
|
||||
pub temp_resources: Vec<(TempResource<B>, MemoryBlock<B>)>,
|
||||
pub dst_buffers: FastHashSet<id::BufferId>,
|
||||
pub dst_textures: FastHashSet<id::TextureId>,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> PendingWrites<B> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
command_buffer: None,
|
||||
temp_buffers: Vec::new(),
|
||||
temp_resources: Vec::new(),
|
||||
dst_buffers: FastHashSet::default(),
|
||||
dst_textures: FastHashSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,22 +62,38 @@ impl<B: hal::Backend> PendingWrites<B> {
|
||||
if let Some(raw) = self.command_buffer {
|
||||
cmd_allocator.discard_internal(raw);
|
||||
}
|
||||
for (buffer, memory) in self.temp_buffers {
|
||||
for (resource, memory) in self.temp_resources {
|
||||
mem_allocator.free(device, memory);
|
||||
unsafe {
|
||||
device.destroy_buffer(buffer);
|
||||
match resource {
|
||||
TempResource::Buffer(buffer) => unsafe {
|
||||
device.destroy_buffer(buffer);
|
||||
},
|
||||
/*TempResource::Image(image) => unsafe {
|
||||
device.destroy_image(image);
|
||||
},*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume_temp(&mut self, buffer: B::Buffer, memory: MemoryBlock<B>) {
|
||||
self.temp_buffers.push((buffer, memory));
|
||||
pub fn consume_temp(&mut self, resource: TempResource<B>, memory: MemoryBlock<B>) {
|
||||
self.temp_resources.push((resource, memory));
|
||||
}
|
||||
|
||||
fn consume(&mut self, stage: StagingData<B>) {
|
||||
self.temp_buffers.push((stage.buffer, stage.memory));
|
||||
self.temp_resources
|
||||
.push((TempResource::Buffer(stage.buffer), stage.memory));
|
||||
self.command_buffer = Some(stage.cmdbuf);
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn finish(&mut self) -> Option<B::CommandBuffer> {
|
||||
self.dst_buffers.clear();
|
||||
self.dst_textures.clear();
|
||||
self.command_buffer.take().map(|mut cmd_buf| unsafe {
|
||||
cmd_buf.finish();
|
||||
cmd_buf
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> super::Device<B> {
|
||||
@ -260,6 +286,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
|
||||
device.pending_writes.consume(stage);
|
||||
device.pending_writes.dst_buffers.insert(buffer_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -418,6 +445,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
|
||||
device.pending_writes.consume(stage);
|
||||
device
|
||||
.pending_writes
|
||||
.dst_textures
|
||||
.insert(destination.texture);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -437,15 +468,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let device = device_guard
|
||||
.get_mut(queue_id)
|
||||
.map_err(|_| DeviceError::Invalid)?;
|
||||
let pending_write_command_buffer =
|
||||
device
|
||||
.pending_writes
|
||||
.command_buffer
|
||||
.take()
|
||||
.map(|mut comb_raw| unsafe {
|
||||
comb_raw.finish();
|
||||
comb_raw
|
||||
});
|
||||
let pending_write_command_buffer = device.pending_writes.finish();
|
||||
device.temp_suspected.clear();
|
||||
device.active_submission_index += 1;
|
||||
let submit_index = device.active_submission_index;
|
||||
@ -615,7 +638,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
submit_index,
|
||||
fence,
|
||||
&device.temp_suspected,
|
||||
device.pending_writes.temp_buffers.drain(..),
|
||||
device.pending_writes.temp_resources.drain(..),
|
||||
);
|
||||
|
||||
// finally, return the command buffers to the allocator
|
||||
|
@ -232,6 +232,8 @@ macro_rules! span {
|
||||
/// Fast hash map used internally.
|
||||
type FastHashMap<K, V> =
|
||||
std::collections::HashMap<K, V, std::hash::BuildHasherDefault<fxhash::FxHasher>>;
|
||||
/// Fast hash set used internally.
|
||||
type FastHashSet<K> = std::collections::HashSet<K, std::hash::BuildHasherDefault<fxhash::FxHasher>>;
|
||||
|
||||
#[test]
|
||||
fn test_default_limits() {
|
||||
|
Loading…
Reference in New Issue
Block a user