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;