-
Notifications
You must be signed in to change notification settings - Fork 434
Resource Barriers
When you are rendering or running a compute shader, many threads of work are executed on the GPU which in most cases is massively parallel hardware. In order to ensure all pending work (like rendering to a texture) is completed before you use the results in another operation, you have two choices:
- You can insert a fence, submit the command-list, and wait for the GPU to stall
- You can insert a resource barrier into the command-list which indicates the point at which one state moves to the next.
For example, when uploading textures you first copy the data a 'upload heap' source (which requires the source texture to be in D3D12_RESOURCE_STATE_COPY_SOURCE
, and the VRAM texture resource be in D3D12_RESOURCE_STATE_COPY_DEST
), then you want to render that just-loaded texture (which typically requires the VRAM texture resource to be in D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
).
A number of DirectX Tool Kit for DX12 classes include support these state transition resource barriers. For example, the ResourceUploadBatch lets you automatically queue a transition like the one in the example above:
ResourceUploadBatch resourceUpload(device);
resourceUpload.Begin();
resourceUpload.Upload(texture.Get(), 0, &textureData, 1);
resourceUpload.Transition(
texture.Get(),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
auto uploadResourcesFinished = resourceUpload.End(m_deviceResources->GetCommandQueue());
uploadResourcesFinished.wait();
In fact, this is done automatically by the DDSTextureLoader / WICTextureLoader since this is the most common use case.
There are similar Transition methods available for GeometricPrimitive and Model when utilizing static vertex buffers & index buffers.
The easiest way to create your own resource barriers is to utilize a D3DX12 helper. Here's a case where you want to transition from being a source of a copy to something used by a compute shader:
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(texture, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
commandList->ResourceBarrier(1, &barrier);
If to simplify code flow you decide to track state with a variable, you may find the DirectXHelpers TransitionResource method useful.
TransitionResource(commandList, texture, m_txtState, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
...
TransitionResource(commandList, texture, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, m_txtState);
If you need to execute a number of resource barriers at once, it's best to insert them in a batch. This allows the driver to decide how to handle it based on the GPU architecture. For example, here we have two barriers submitting at once:
D3D12_RESOURCE_BARRIER barriers[2];
barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition(uavBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
barriers[1] = CD3DX12_RESOURCE_BARRIER::Transition(texture,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
commandList->ResourceBarrier(_countof(barriers), barriers);
If you have a set of barriers you apply and then reverse, you may find DirectXHelpers's ScopedBarrier class useful:
{
D3D12_RESOURCE_BARRIER barriers[2];
barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition(uavBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
barriers[1] = CD3DX12_RESOURCE_BARRIER::Transition(texture,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
ScopedBarrier rb(commandList, barriers);
...
// At the end of the scope, the same barrier with all the states swapped is executed
}
Using Resource Barriers to Synchronize Resource States in Direct3D 12
All content and source code for this package are subject to the terms of the MIT License.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
- Universal Windows Platform apps
- Windows desktop apps
- Windows 11
- Windows 10
- Xbox One
- Xbox Series X|S
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- MinGW 12.2, 13.2
- CMake 3.20