Metal: Resolve premature memory release

After previous changes to allow command buffers to not require
execution and completion in submission order,
guarantees for releasing freed buffers back to the memory pool
within the frame life time had changed.

This could mean a released buffer could be returned to the
memory pool prematurely, if a subsequent command buffer
completes before a previously submitted one, flagging a resource as no
longer in use by the GPU, while it still may be in use by the orignal
command buffer.

This PR defers final reference count release for buffers
being actively used until the following call to GPU_render_step,
to ensure that buffers freed will be available for the lifetime of
the frame, covering all command submissions, rather than just
within the lifetime of the command buffer submission within which a
buffer was freed.

Authored by Apple: Michael Parkin-White

Pull Request: https://projects.blender.org/blender/blender/pulls/114329
This commit is contained in:
Jason Fielder
2023-10-31 16:45:12 +01:00
committed by Clément Foucault
parent 5974a4482a
commit a96aabc6f6
3 changed files with 12 additions and 1 deletions

View File

@@ -156,7 +156,6 @@ void MTLBackend::render_step()
MTLContext::get_global_memory_manager()->get_current_safe_list();
if (cmd_free_buffer_list->should_flush()) {
MTLContext::get_global_memory_manager()->begin_new_safe_list();
cmd_free_buffer_list->decrement_reference();
}
}

View File

@@ -418,6 +418,9 @@ class MTLBufferPool {
std::atomic<MTLSafeFreeList *> current_free_list_;
std::atomic<int64_t> allocations_in_pool_;
/* Previous list, to be released after one full frame. */
MTLSafeFreeList *prev_free_buffer_list_ = nullptr;
public:
void init(id<MTLDevice> device);
~MTLBufferPool();

View File

@@ -425,8 +425,17 @@ MTLSafeFreeList *MTLBufferPool::get_current_safe_list()
void MTLBufferPool::begin_new_safe_list()
{
safelist_lock_.lock();
MTLSafeFreeList *previous_list = prev_free_buffer_list_;
MTLSafeFreeList *active_list = get_current_safe_list();
current_free_list_ = new MTLSafeFreeList();
prev_free_buffer_list_ = active_list;
safelist_lock_.unlock();
/* Release final reference for previous list.
* Note: Outside of lock as this function itself locks. */
if (previous_list) {
previous_list->decrement_reference();
}
}
void MTLBufferPool::ensure_buffer_pool(MTLResourceOptions options)