I encountered this problem when releasing D3D12 resources. I didn't use ComPtr so I have to release everything manually. After enabling debug layer, I saw this error:
D3D12 ERROR: ID3D12CommandQueue::<final-release>: A Command Queue (0x000002EBE2F3C7A0:'Unnamed ID3D12CommandQueue Object') is being final-released while still in use by the GPU. This is invalid and can lead to application instability. [ EXECUTION ERROR #921: OBJECT_DELETED_WHILE_STILL_IN_USE]
I wanted to figure out which queue is it so I enabled debug device and used ReportLiveDeviceObjects trying to identify the queue. But it showed the same error. All my queues had names and ReportLiveDeviceObjects worked on other resources. After googling around, I found this page. It was a similar problem and it seemed it had something to do with finishing the unfinished frames.
Before I made any changes, my clean up code looks like this:
void Cleanup()
{
// wait for the gpu to finish all frames
for (int i = 0; i < FrameBufferCount; ++i)
{
frameIndex = i;
//fenceValue[i]++; //------------------------------------------> FIRST COMMENTED CODE SNIPPET
//commandQueue->Signal(fence[i], fenceValue[i]); //------------> SECOND COMMENTED CODE SNIPPET
WaitForPreviousFrame(i);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// FROM HERE ON, CODES HAVE NOTHING TO DO WITH THE QUESTION, THEY ARE HERE FOR THE SAKE OF COMPLETENESS
//////////////////////////////////////////////////////////////////////////////////////////////////////
// close the fence event
CloseHandle(fenceEvent);
// release gpu resources in the scene
mRenderer.Release();
mScene.Release();
// imgui stuff
ImGui_ImplDX12_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
SAFE_RELEASE(g_pd3dSrvDescHeap);
// direct input stuff
DIKeyboard->Unacquire();
DIMouse->Unacquire();
DirectInput->Release();
// other stuff ...
}
Obviously it didn't work that's why I googled the problem. After seeing what is proposed on that page, I added the first and the second commented code snippet. The problem was immediately solved. The error above completely disappeared. Then I tried to comment the first code snippet out and only use the second code snippet. It also worked. So I am wondering what happened.
1.Why do I have to signal it? Isn't WaitForPreviousFrame enough?
2.What does that answer on that page mean? What does operating system have anything to do with this?
For you information, the WaitForPreviousFrame function looks like this:
void WaitForPreviousFrame(int frameIndexOverride = -1)
{
HRESULT hr;
// swap the current rtv buffer index so we draw on the correct buffer
frameIndex = frameIndexOverride < 0 ? swapChain->GetCurrentBackBufferIndex() : frameIndexOverride;
// if the current fence value is still less than "fenceValue", then we know the GPU has not finished executing
// the command queue since it has not reached the "commandQueue->Signal(fence, fenceValue)" command
if (fence[frameIndex]->GetCompletedValue() < fenceValue[frameIndex])
{
// we have the fence create an event which is signaled once the fence's current value is "fenceValue"
hr = fence[frameIndex]->SetEventOnCompletion(fenceValue[frameIndex], fenceEvent);
if (FAILED(hr))
{
Running = false;
}
// We will wait until the fence has triggered the event that it's current value has reached "fenceValue". once it's value
// has reached "fenceValue", we know the command queue has finished executing
WaitForSingleObject(fenceEvent, INFINITE);
}
// increment fenceValue for next frame
fenceValue[frameIndex]++;
}