Actual cleanup of resources on submission

This commit is contained in:
Dzmitry Malyshau 2018-11-02 16:39:00 -04:00
parent 39186c9c7b
commit b03d7de335
2 changed files with 91 additions and 18 deletions

View File

@ -387,3 +387,7 @@ WGPUTextureViewId wgpu_texture_create_default_texture_view(WGPUTextureId texture
WGPUTextureViewId wgpu_texture_create_texture_view(WGPUTextureId texture_id, WGPUTextureViewId wgpu_texture_create_texture_view(WGPUTextureId texture_id,
const WGPUTextureViewDescriptor *desc); const WGPUTextureViewDescriptor *desc);
void wgpu_texture_destroy(WGPUDeviceId texture_id);
void wgpu_texture_view_destroy(WGPUTextureViewId _texture_view_id);

View File

@ -1,5 +1,5 @@
use {back, binding_model, command, conv, pipeline, resource}; use {back, binding_model, command, conv, pipeline, resource};
use registry::{HUB, Items, Registry}; use registry::{HUB, Items, ItemsGuard, Registry};
use track::{BufferTracker, TextureTracker}; use track::{BufferTracker, TextureTracker};
use { use {
CommandBuffer, LifeGuard, RefCount, Stored, SubmissionIndex, WeaklyStored, CommandBuffer, LifeGuard, RefCount, Stored, SubmissionIndex, WeaklyStored,
@ -32,46 +32,94 @@ pub(crate) struct FramebufferKey {
} }
impl Eq for FramebufferKey {} impl Eq for FramebufferKey {}
enum Resource { enum ResourceId {
Buffer(BufferId), Buffer(BufferId),
Texture(TextureId), Texture(TextureId),
} }
enum Resource<B: hal::Backend> {
Buffer(resource::Buffer<B>),
Texture(resource::Texture<B>),
}
struct ActiveFrame<B: hal::Backend> { struct ActiveFrame<B: hal::Backend> {
submission_index: SubmissionIndex, submission_index: SubmissionIndex,
fence: B::Fence, fence: B::Fence,
resources: Vec<Resource>, resources: Vec<Resource<B>>,
} }
struct DestroyedResources<B: hal::Backend> { struct DestroyedResources<B: hal::Backend> {
/// Resources that are destroyed by the user but still referenced by /// Resources that are destroyed by the user but still referenced by
/// other objects or command buffers. /// other objects or command buffers.
referenced: Vec<(Resource, RefCount)>, referenced: Vec<(ResourceId, RefCount)>,
/// Resources that are not referenced any more but still used by GPU. /// Resources that are not referenced any more but still used by GPU.
/// Grouped by frames associated with a fence and a submission index. /// Grouped by frames associated with a fence and a submission index.
active: Vec<ActiveFrame<B>>, active: Vec<ActiveFrame<B>>,
/// Resources that are neither referenced or used, just pending /// Resources that are neither referenced or used, just pending
/// actual deletion. /// actual deletion.
free: Vec<Resource>, free: Vec<Resource<B>>,
} }
unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {} unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {}
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {} unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
impl<B: hal::Backend> DestroyedResources<B> { impl<B: hal::Backend> DestroyedResources<B> {
fn add(&mut self, resource: Resource, life_guard: &LifeGuard) { fn add(&mut self, resource_id: ResourceId, life_guard: &LifeGuard) {
if life_guard.ref_count.load() == 1 { self.referenced.push((resource_id, life_guard.ref_count.clone()));
let sub_index = life_guard.submission_index.load(Ordering::Acquire); }
match self.active.iter_mut().find(|af| af.submission_index == sub_index) {
Some(frame) => { fn triage_referenced(
frame.resources.push(resource); &mut self,
} buffer_guard: &mut ItemsGuard<resource::Buffer<B>>,
None => { texture_guard: &mut ItemsGuard<resource::Texture<B>>,
self.free.push(resource); ) {
for i in (0 .. self.referenced.len()).rev() {
// one in resource itself, and one here in this list
let num_refs = self.referenced[i].1.load();
if num_refs <= 2 {
assert_eq!(num_refs, 2);
let resource_id = self.referenced.swap_remove(i).0;
let (submit_index, resource) = match resource_id {
ResourceId::Buffer(id) => {
let buf = buffer_guard.take(id);
let si = buf.life_guard.submission_index.load(Ordering::Acquire);
(si, Resource::Buffer(buf))
}
ResourceId::Texture(id) => {
let tex = texture_guard.take(id);
let si = tex.life_guard.submission_index.load(Ordering::Acquire);
(si, Resource::Texture(tex))
}
};
match self.active
.iter_mut()
.find(|af| af.submission_index == submit_index)
{
Some(af) => af.resources.push(resource),
None => self.free.push(resource),
}
}
}
}
fn cleanup(&mut self, raw: &B::Device) {
for i in (0 .. self.active.len()).rev() {
if raw.get_fence_status(&self.active[i].fence) {
let af = self.active.swap_remove(i);
self.free.extend(af.resources);
raw.destroy_fence(af.fence);
}
}
for resource in self.free.drain(..) {
match resource {
Resource::Buffer(buf) => {
raw.destroy_buffer(buf.raw);
}
Resource::Texture(tex) => {
raw.destroy_image(tex.raw);
} }
} }
} else {
self.referenced.push((resource, life_guard.ref_count.clone()));
} }
} }
} }
@ -311,7 +359,7 @@ pub extern "C" fn wgpu_texture_destroy(
.destroyed .destroyed
.lock() .lock()
.unwrap() .unwrap()
.add(Resource::Texture(texture_id), &texture.life_guard); .add(ResourceId::Texture(texture_id), &texture.life_guard);
} }
#[no_mangle] #[no_mangle]
@ -468,6 +516,9 @@ pub extern "C" fn wgpu_queue_submit(
// native command buffer of the previous chain instead of always creating // native command buffer of the previous chain instead of always creating
// a temporary one, since the chains are not finished. // a temporary one, since the chains are not finished.
//TODO: add used resources to the active frame
let mut resources = Vec::new();
// finish all the command buffers first // finish all the command buffers first
for &cmb_id in command_buffer_ids { for &cmb_id in command_buffer_ids {
let comb = command_buffer_guard.get_mut(cmb_id); let comb = command_buffer_guard.get_mut(cmb_id);
@ -476,6 +527,7 @@ pub extern "C" fn wgpu_queue_submit(
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT, hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
hal::command::CommandBufferInheritanceInfo::default(), hal::command::CommandBufferInheritanceInfo::default(),
); );
//TODO: fix the consume
CommandBuffer::insert_barriers( CommandBuffer::insert_barriers(
&mut transit, &mut transit,
buffer_tracker.consume(&comb.buffer_tracker), buffer_tracker.consume(&comb.buffer_tracker),
@ -490,6 +542,7 @@ pub extern "C" fn wgpu_queue_submit(
} }
// now prepare the GPU submission // now prepare the GPU submission
let fence = device.raw.create_fence(false);
{ {
let submission = hal::queue::RawSubmission { let submission = hal::queue::RawSubmission {
cmd_buffers: command_buffer_ids cmd_buffers: command_buffer_ids
@ -503,10 +556,26 @@ pub extern "C" fn wgpu_queue_submit(
unsafe { unsafe {
device.queue_group.queues[0] device.queue_group.queues[0]
.as_raw_mut() .as_raw_mut()
.submit_raw(submission, None); .submit_raw(submission, Some(&fence));
} }
} }
let old_submit_index = device.life_guard.submission_index.fetch_add(1, Ordering::Relaxed);
if let Ok(mut destroyed) = device.destroyed.lock() {
let mut buffer_guard = HUB.buffers.lock();
let mut texture_guard = HUB.textures.lock();
destroyed.triage_referenced(&mut buffer_guard, &mut texture_guard);
destroyed.cleanup(&device.raw);
destroyed.active.push(ActiveFrame {
submission_index: old_submit_index + 1,
fence,
resources,
});
}
// finally, return the command buffers to the allocator // finally, return the command buffers to the allocator
for &cmb_id in command_buffer_ids { for &cmb_id in command_buffer_ids {
let cmd_buf = command_buffer_guard.take(cmb_id); let cmd_buf = command_buffer_guard.take(cmb_id);