If you are good at fencing you will be good at DX12
A fence is an UINT64 that can be used to synchronize the CPU with the GPU queues and also the GPU queue with each other.
Create a Fence
Create it with the ID3D12Device::CreateFence() method. It takes a the start value (integer), option flags and the pointer to return the fence in.
Get the value of a fence
To get the value of the fence use ID3D12Fence::GetCompletedValue()
CPU: Set the value
Use ID3D12Fence::Signal () to set the fence value on the CPU.
GPU: Set the value
You use ID3D12CommandQueue::Signal() and when the GPU reaches that point in the queue it will change the fence value.
Do things when a fence changes to a value
Use ID3D12Fence::SetEventOnCompletion() to select a event object and the value of the fence for the event to be signalled.
Make a GPU queue wait on another GPU queue
If you have more then one queue, for example Direct and a Copy one, use ID3D12CommandQueue::Wait() to make it wait for a fence. It will wait until the fence value is the same or exceed the value given as a wait parameter.
When a resource is used it needs to be in the correct state. It's state is changed with ID3D12GraphicsCommandList::ResourceBarrier(). To describe each change a D3D12_RESOURCE_BARRIER() structure is used. The function takes an array of structures so try to batch barriers to be done at the same time. Avoid doing redundant transitions. There are three types of barrier descriptions.
This barrier tells the GPU to transition a resource or subresources from one state to another. One must give both the state the it have now (before) and the one it it should change to (after). In the structure one needs to fill in the resource and the subresource index. It is possible to use D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES (0xffffffff) to change all subresources in the resource at the same time.
Always use the most contrained state possible on a resource so avoid COMMON and GENERIC_READ. COMMON is needed for CPU access to textures and GENERIC_READ for upload heaps.
Split resource barriers
A split barrier is made up of two barrier with one set with the flag FLAG_BEGIN_ONLY and the next with FLAG_END_ONLY. The other parameters need to be the same to the both commands and the resource will by in a no-access condition between the two barriers. It is possible to do other work between the barriers. The transition might complete before the end flag and then the cost of the transition is more or less free.
Used to change the usage of tiled resources.
With this one can make sure that all Read/Write operations is finished after this barrier is done.