[D3D12] Command Allocator / Command List usage

Started by
0 comments, last by WFP 8 years, 2 months ago

Hey all,

In the MSDN docs, they describe the dynamic between ID3D12CommandAllocator and ID3D12CommandList.

Immediately after being created, command lists are in the recording state. You can also re-use an existing command list by calling ID3D12GraphicsCommandList::Reset, which also leaves the command list in the recording state. Unlike ID3D12CommandAllocator::Reset, you can call Reset while the command list is still being executed. A typical pattern is to submit a command list and then immediately reset it to reuse the allocated memory for another command list. Note that only one command list associated with each command allocator may be in a recording state at one time.

I understand that a command allocator is the heap for which commands in a command list are allocated. My assumption is that this is a sort of growing heap with a water mark that will remain at a certain size to avoid further allocations (this must be the case, since you don't define a size for the thing at creation time).

If true, it makes sense that a command allocator is resident physical memory which the command list records into. In the samples, it appears as though one a command allocator is created for each command list. This makes sense; however, according to the docs, it appears that a command allocator can be used on any command list so long as only one of them is in the recording state at one time.

Now, the part that confuses me is that it's okay to reset the command list and reuse it immediately, but it's not okay to reset the command allocator until the command list is finished on the GPU.

Command List Reset: I would venture to guess this preserves the contents of the original commands within the command allocator and starts a fresh record?

Command Allocator Reset: It seems as though this is literally destroying the contents of the heap, which may have command list data active on the GPU.

My big question is this: How does the memory ownership work between the command allocator and command list? Is the allocator doing implicit double (or more?) buffering on a command list reset? What's the actual difference between ID3D12CommandList::Reset and ID3D12CommandAllocator::Reset

Thanks!

Advertisement

It's OK to reset the command list immediately after submitting it as long as you use a different allocator or wait for a GPU signal that the submitted work has completed.


ID3D12CommandAllocator* pAlloc1, pAlloc2;
ID3D12GraphicsCommandList* pCmdList;

// later on
pCmdList->Reset(pAlloc1, nullptr);
// record some commands
pCommandQueue->ExecuteCommandLists(1, &pCmdList);
pCommandQueue->Signal(pFence, fenceValue);

// now you can reset the command list, but use pAlloc2 since pAlloc1 will still be executing
pCmdList->Reset(pAlloc2, nullptr);


After submitting the command list the second time (after recording into pAlloc2), you need to check the fence value set after the first submission to make sure it has completed before resetting with pAlloc1. You can use more allocators to avoid the likeliness of actually blocking on a fence very often if at all, but allocators only ever increase in size, so the largest batch of commands submitted to one is how much memory that allocator will consume until it's destroyed (COM destroyed through Release, not Reset).


Command Allocator Reset: It seems as though this is literally destroying the contents of the heap, which may have command list data active on the GPU.

Kind of. That's exactly why you'd want to ensure the job is done executing before resetting the command allocator, but it's likely more of a pointer reset to the beginning of the allocator's memory than any type of expensive deconstruction.


How does the memory ownership work between the command allocator and command list? Is the allocator doing implicit double (or more?) buffering on a command list reset?

The allocator owns the memory. The command list is your interface to write into that memory, but it doesn't actually own it. You've probably deduced from the previous parts of the post that the allocator does no additional buffering (double or otherwise), so again, that's why you want to ensure your work is done (fence) before resetting an allocator.

This topic is closed to new replies.

Advertisement