From d1b4b5cba5571e3d380372db37348ab675f479d0 Mon Sep 17 00:00:00 2001 From: Brandon Jones Date: Fri, 14 Jun 2019 15:14:12 +0000 Subject: [PATCH] Allow D3D12 Implicit State Transitions When transitioning from the COMMON state, an explicit ResourceBarrier call is unnecessary and can be handled implicitly by the driver. This acts as an optimization because no synchronization waits are required when transitioning from the COMMON state. Bug: dawn:167 Change-Id: Ifd45236dc51c339de8b9945e6f4e2a00934f3676 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7920 Commit-Queue: Brandon Jones Reviewed-by: Corentin Wallez --- src/dawn_native/d3d12/BufferD3D12.cpp | 24 ++++++++++++++++++++ src/dawn_native/d3d12/CommandBufferD3D12.cpp | 4 ++-- src/dawn_native/d3d12/TextureD3D12.cpp | 22 ++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/dawn_native/d3d12/BufferD3D12.cpp b/src/dawn_native/d3d12/BufferD3D12.cpp index 6ee3636abc..bfc7e7e36a 100644 --- a/src/dawn_native/d3d12/BufferD3D12.cpp +++ b/src/dawn_native/d3d12/BufferD3D12.cpp @@ -130,6 +130,30 @@ namespace dawn_native { namespace d3d12 { D3D12_RESOURCE_STATES lastState = D3D12BufferUsage(mLastUsage); D3D12_RESOURCE_STATES newState = D3D12BufferUsage(newUsage); + + // The COMMON state represents a state where no write operations can be pending, which makes + // it possible to transition to some states without synchronizaton (i.e. without an explicit + // ResourceBarrier call). This can be to 1) a single write state, or 2) multiple read + // states. + // + // Destination states used in Dawn that qualify for implicit transition for a buffer: + // COPY_SOURCE, VERTEX_AND_CONSTANT_BUFFER, INDEX_BUFFER, COPY_DEST, UNORDERED_ACCESS + // https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#implicit-state-transitions + { + static constexpr D3D12_RESOURCE_STATES kD3D12BufferReadOnlyStates = + D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | + D3D12_RESOURCE_STATE_INDEX_BUFFER; + + if (lastState == D3D12_RESOURCE_STATE_COMMON) { + bool singleWriteState = ((newState == D3D12_RESOURCE_STATE_COPY_DEST) || + (newState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS)); + bool readOnlyState = newState == (newState & kD3D12BufferReadOnlyStates); + if (singleWriteState ^ readOnlyState) { + return false; + } + } + } + barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier->Transition.pResource = mResource.Get(); diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index 98afe265b1..fd2b4e6808 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -436,8 +436,8 @@ namespace dawn_native { namespace d3d12 { if (ToBackend(usages.buffers[i]) ->CreateD3D12ResourceBarrierIfNeeded(&barrier, usages.bufferUsages[i])) { barriers.push_back(barrier); - ToBackend(usages.buffers[i])->SetUsage(usages.bufferUsages[i]); } + ToBackend(usages.buffers[i])->SetUsage(usages.bufferUsages[i]); } for (size_t i = 0; i < usages.textures.size(); ++i) { @@ -445,8 +445,8 @@ namespace dawn_native { namespace d3d12 { if (ToBackend(usages.textures[i]) ->CreateD3D12ResourceBarrierIfNeeded(&barrier, usages.textureUsages[i])) { barriers.push_back(barrier); - ToBackend(usages.textures[i])->SetUsage(usages.textureUsages[i]); } + ToBackend(usages.textures[i])->SetUsage(usages.textureUsages[i]); } if (barriers.size()) { diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index a8153b55f9..ccf86854eb 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -186,6 +186,28 @@ namespace dawn_native { namespace d3d12 { return false; } + // The COMMON state represents a state where no write operations can be pending, and where + // all pixels are uncompressed. This makes it possible to transition to some states without + // synchronization (i.e. without an explicit ResourceBarrier call). This can be to 1) a + // single write state, or 2) multiple read states. + // + // Destination states that qualify for an implicit transition for a non-simulataneous-access + // texture: NON_PIXEL_SHADER_RESOURCE, PIXEL_SHADER_RESOURCE, COPY_SRC, COPY_DEST + // https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#implicit-state-transitions + { + static constexpr D3D12_RESOURCE_STATES kD3D12TextureReadOnlyStates = + D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + + if (mLastState == D3D12_RESOURCE_STATE_COMMON) { + bool singleWriteState = (newState == D3D12_RESOURCE_STATE_COPY_DEST); + bool readOnlyState = newState == (newState & kD3D12TextureReadOnlyStates); + if (singleWriteState ^ readOnlyState) { + return false; + } + } + } + barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier->Transition.pResource = mResourcePtr;