D3D12: Cleanup/refactoring of teardown process
This commit is contained in:
parent
759b77474d
commit
649b94338e
|
@ -715,7 +715,7 @@ void CreateRootSignatures()
|
|||
|
||||
void WaitForOutstandingRenderingToComplete()
|
||||
{
|
||||
command_list_mgr->ClearQueueAndWaitForCompletionOfInflightWork();
|
||||
command_list_mgr->ExecuteQueuedWork(true);
|
||||
}
|
||||
|
||||
void Close()
|
||||
|
@ -731,8 +731,6 @@ void Close()
|
|||
|
||||
D3D::CleanupPersistentD3DTextureResources();
|
||||
|
||||
command_list_mgr->ImmediatelyDestroyAllResourcesScheduledForDestruction();
|
||||
|
||||
SAFE_RELEASE(s_swap_chain);
|
||||
|
||||
command_list_mgr.reset();
|
||||
|
@ -816,15 +814,15 @@ unsigned int GetMaxTextureSize()
|
|||
|
||||
void Reset()
|
||||
{
|
||||
command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// release all back buffer references
|
||||
for (UINT i = 0; i < ARRAYSIZE(s_backbuf); i++)
|
||||
{
|
||||
SAFE_RELEASE(s_backbuf[i]);
|
||||
}
|
||||
|
||||
D3D::command_list_mgr->ImmediatelyDestroyAllResourcesScheduledForDestruction();
|
||||
// Block until all commands have finished.
|
||||
// This will also final-release all pending resources (including the backbuffer above)
|
||||
command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// resize swapchain buffers
|
||||
RECT client;
|
||||
|
|
|
@ -113,12 +113,10 @@ void D3DCommandListManager::ExecuteQueuedWork(bool wait_for_gpu_completion)
|
|||
m_queue_fence_value++;
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
CheckHR(m_queued_command_list->Close());
|
||||
m_queued_command_list->Close();
|
||||
m_queued_command_list->QueueExecute();
|
||||
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
|
||||
|
||||
m_queued_command_list->ProcessQueuedItems(wait_for_gpu_completion);
|
||||
m_queued_command_list->ProcessQueuedItems(wait_for_gpu_completion, wait_for_gpu_completion);
|
||||
#else
|
||||
CheckHR(m_backing_command_list->Close());
|
||||
|
||||
|
@ -145,7 +143,7 @@ void D3DCommandListManager::ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_cha
|
|||
m_queue_fence_value++;
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
CheckHR(m_queued_command_list->Close());
|
||||
m_queued_command_list->Close();
|
||||
m_queued_command_list->QueueExecute();
|
||||
m_queued_command_list->QueuePresent(swap_chain, sync_interval, flags);
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
|
||||
|
@ -170,6 +168,31 @@ void D3DCommandListManager::ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_cha
|
|||
SetInitialCommandListState();
|
||||
}
|
||||
|
||||
void D3DCommandListManager::DestroyAllPendingResources()
|
||||
{
|
||||
for (auto& destruction_list : m_deferred_destruction_lists)
|
||||
{
|
||||
for (auto& resource : destruction_list)
|
||||
resource->Release();
|
||||
|
||||
destruction_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ResetAllCommandAllocators()
|
||||
{
|
||||
for (auto& allocator_list : m_command_allocator_lists)
|
||||
{
|
||||
for (auto& allocator : allocator_list)
|
||||
allocator->Reset();
|
||||
}
|
||||
|
||||
// Move back to the start, using the first allocator of first list.
|
||||
m_current_command_allocator = 0;
|
||||
m_current_command_allocator_list = 0;
|
||||
m_current_deferred_destruction_list = 0;
|
||||
}
|
||||
|
||||
void D3DCommandListManager::WaitForGPUCompletion()
|
||||
{
|
||||
// Wait for GPU to finish all outstanding work.
|
||||
|
@ -186,13 +209,13 @@ void D3DCommandListManager::WaitForGPUCompletion()
|
|||
WaitOnCPUForFence(m_queue_frame_fence, m_queue_frame_fence_value);
|
||||
|
||||
// GPU is up to date with us. Therefore, it has finished with any pending resources.
|
||||
ImmediatelyDestroyAllResourcesScheduledForDestruction();
|
||||
DestroyAllPendingResources();
|
||||
|
||||
// Command allocators are also up-to-date, so reset these.
|
||||
ResetAllCommandAllocators();
|
||||
}
|
||||
|
||||
void D3DCommandListManager::PerformGpuRolloverChecks()
|
||||
void D3DCommandListManager::PerformGPURolloverChecks()
|
||||
{
|
||||
m_queue_frame_fence_value++;
|
||||
|
||||
|
@ -243,7 +266,7 @@ void D3DCommandListManager::MoveToNextCommandAllocator()
|
|||
|
||||
// Did we wrap around? Move to the next set of allocators.
|
||||
if (m_current_command_allocator == 0)
|
||||
PerformGpuRolloverChecks();
|
||||
PerformGPURolloverChecks();
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ResetCommandList()
|
||||
|
@ -264,52 +287,18 @@ void D3DCommandListManager::DestroyResourceAfterCurrentCommandListExecuted(ID3D1
|
|||
m_deferred_destruction_lists[m_current_deferred_destruction_list].push_back(resource);
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ImmediatelyDestroyAllResourcesScheduledForDestruction()
|
||||
{
|
||||
for (auto& destruction_list : m_deferred_destruction_lists)
|
||||
{
|
||||
for (auto& resource : destruction_list)
|
||||
resource->Release();
|
||||
|
||||
destruction_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ResetAllCommandAllocators()
|
||||
{
|
||||
for (auto& allocator_list : m_command_allocator_lists)
|
||||
{
|
||||
for (auto& allocator : allocator_list)
|
||||
allocator->Reset();
|
||||
}
|
||||
|
||||
// Move back to the start, using the first allocator of first list.
|
||||
m_current_command_allocator = 0;
|
||||
m_current_command_allocator_list = 0;
|
||||
m_current_deferred_destruction_list = 0;
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ClearQueueAndWaitForCompletionOfInflightWork()
|
||||
{
|
||||
// Wait for GPU to finish all outstanding work.
|
||||
m_queue_fence_value++;
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
m_queued_command_list->ClearQueue(); // Waits for currently-processing work to finish, then clears queue.
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
|
||||
m_queued_command_list->ProcessQueuedItems(true);
|
||||
#else
|
||||
CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value));
|
||||
#endif
|
||||
WaitOnCPUForFence(m_queue_fence, m_queue_fence_value);
|
||||
}
|
||||
|
||||
D3DCommandListManager::~D3DCommandListManager()
|
||||
{
|
||||
ImmediatelyDestroyAllResourcesScheduledForDestruction();
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
// Wait for background thread to exit.
|
||||
m_queued_command_list->Release();
|
||||
#endif
|
||||
|
||||
// The command list will still be open, close it before destroying.
|
||||
m_backing_command_list->Close();
|
||||
|
||||
DestroyAllPendingResources();
|
||||
|
||||
m_backing_command_list->Release();
|
||||
|
||||
for (auto& allocator_list : m_command_allocator_lists)
|
||||
|
|
|
@ -38,10 +38,7 @@ public:
|
|||
void ExecuteQueuedWork(bool wait_for_gpu_completion = false);
|
||||
void ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags);
|
||||
|
||||
void ClearQueueAndWaitForCompletionOfInflightWork();
|
||||
void DestroyResourceAfterCurrentCommandListExecuted(ID3D12Resource* resource);
|
||||
void ImmediatelyDestroyAllResourcesScheduledForDestruction();
|
||||
void ResetAllCommandAllocators();
|
||||
|
||||
void SetCommandListDirtyState(unsigned int command_list_state, bool dirty);
|
||||
bool GetCommandListDirtyState(COMMAND_LIST_STATE command_list_state) const;
|
||||
|
@ -63,9 +60,11 @@ public:
|
|||
void WaitOnCPUForFence(ID3D12Fence* fence, UINT64 fence_value);
|
||||
|
||||
private:
|
||||
|
||||
void DestroyAllPendingResources();
|
||||
void ResetAllCommandAllocators();
|
||||
void WaitForGPUCompletion();
|
||||
void PerformGpuRolloverChecks();
|
||||
|
||||
void PerformGPURolloverChecks();
|
||||
void MoveToNextCommandAllocator();
|
||||
void ResetCommandList();
|
||||
|
||||
|
|
|
@ -25,8 +25,6 @@ void ID3D12QueuedCommandList::BackgroundThreadFunction(ID3D12QueuedCommandList*
|
|||
while (true)
|
||||
{
|
||||
WaitForSingleObject(parent_queued_command_list->m_begin_execution_event, INFINITE);
|
||||
if (parent_queued_command_list->m_background_thread_exit.load())
|
||||
break;
|
||||
|
||||
byte* item = &queue_array[queue_array_front];
|
||||
|
||||
|
@ -341,6 +339,7 @@ void ID3D12QueuedCommandList::BackgroundThreadFunction(ID3D12QueuedCommandList*
|
|||
|
||||
bool eligible_to_move_to_front_of_queue = reinterpret_cast<D3DQueueItem*>(item)->Stop.eligible_to_move_to_front_of_queue;
|
||||
bool signal_stop_event = reinterpret_cast<D3DQueueItem*>(item)->Stop.signal_stop_event;
|
||||
bool terminate_worker_thread = reinterpret_cast<D3DQueueItem*>(item)->Stop.terminate_worker_thread;
|
||||
|
||||
item += BufferOffsetForQueueItemType<StopArguments>();
|
||||
|
||||
|
@ -354,6 +353,9 @@ void ID3D12QueuedCommandList::BackgroundThreadFunction(ID3D12QueuedCommandList*
|
|||
SetEvent(parent_queued_command_list->m_stop_execution_event);
|
||||
}
|
||||
|
||||
if (terminate_worker_thread)
|
||||
return;
|
||||
|
||||
goto exitLoop;
|
||||
}
|
||||
}
|
||||
|
@ -380,8 +382,8 @@ ID3D12QueuedCommandList::ID3D12QueuedCommandList(ID3D12GraphicsCommandList* back
|
|||
|
||||
ID3D12QueuedCommandList::~ID3D12QueuedCommandList()
|
||||
{
|
||||
m_background_thread_exit.store(true);
|
||||
ReleaseSemaphore(m_begin_execution_event, 1, nullptr);
|
||||
// Kick worker thread, and tell it to exit.
|
||||
ProcessQueuedItems(true, true, true);
|
||||
m_background_thread.join();
|
||||
|
||||
CloseHandle(m_begin_execution_event);
|
||||
|
@ -463,22 +465,14 @@ void ID3D12QueuedCommandList::QueuePresent(IDXGISwapChain* swap_chain, UINT sync
|
|||
CheckForOverflow();
|
||||
}
|
||||
|
||||
void ID3D12QueuedCommandList::ClearQueue()
|
||||
{
|
||||
// Drain semaphore to ensure no new previously queued work executes (though inflight work may continue).
|
||||
while (WaitForSingleObject(m_begin_execution_event, 0) != WAIT_TIMEOUT) { }
|
||||
|
||||
// Assume that any inflight queued work will complete within 100ms. This is a safe assumption.
|
||||
Sleep(100);
|
||||
}
|
||||
|
||||
void ID3D12QueuedCommandList::ProcessQueuedItems(bool eligible_to_move_to_front_of_queue, bool wait_for_stop)
|
||||
void ID3D12QueuedCommandList::ProcessQueuedItems(bool eligible_to_move_to_front_of_queue, bool wait_for_stop, bool terminate_worker_thread)
|
||||
{
|
||||
D3DQueueItem item = {};
|
||||
|
||||
item.Type = D3DQueueItemType::Stop;
|
||||
item.Stop.eligible_to_move_to_front_of_queue = eligible_to_move_to_front_of_queue;
|
||||
item.Stop.signal_stop_event = wait_for_stop;
|
||||
item.Stop.terminate_worker_thread = terminate_worker_thread;
|
||||
|
||||
*reinterpret_cast<D3DQueueItem*>(m_queue_array_back) = item;
|
||||
|
||||
|
@ -502,6 +496,7 @@ void ID3D12QueuedCommandList::ProcessQueuedItems(bool eligible_to_move_to_front_
|
|||
if (wait_for_stop)
|
||||
{
|
||||
WaitForSingleObject(m_stop_execution_event, INFINITE);
|
||||
ResetEvent(m_stop_execution_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -211,6 +211,7 @@ struct StopArguments
|
|||
{
|
||||
bool eligible_to_move_to_front_of_queue;
|
||||
bool signal_stop_event;
|
||||
bool terminate_worker_thread;
|
||||
};
|
||||
|
||||
struct D3DQueueItem
|
||||
|
@ -255,13 +256,12 @@ public:
|
|||
|
||||
ID3D12QueuedCommandList(ID3D12GraphicsCommandList* backing_command_list, ID3D12CommandQueue* backing_command_queue);
|
||||
|
||||
void ProcessQueuedItems(bool eligible_to_move_to_front_of_queue = false, bool wait_for_stop = false);
|
||||
void ProcessQueuedItems(bool eligible_to_move_to_front_of_queue = false, bool wait_for_stop = false, bool terminate_worker_thread = false);
|
||||
|
||||
void QueueExecute();
|
||||
void QueueFenceGpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value);
|
||||
void QueueFenceCpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value);
|
||||
void QueuePresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags);
|
||||
void ClearQueue();
|
||||
|
||||
// IUnknown methods
|
||||
|
||||
|
@ -621,7 +621,6 @@ private:
|
|||
byte* m_queue_array_back_at_start_of_frame = m_queue_array_back;
|
||||
|
||||
std::thread m_background_thread;
|
||||
std::atomic_bool m_background_thread_exit;
|
||||
|
||||
HANDLE m_begin_execution_event;
|
||||
HANDLE m_stop_execution_event;
|
||||
|
|
Loading…
Reference in New Issue