Fix D3D12 resource state transitions barriers

This commit is contained in:
Wojtek Figat
2021-06-08 14:12:31 +02:00
parent ab55c145f1
commit 9d9ecb3ba8
4 changed files with 78 additions and 56 deletions

View File

@@ -159,7 +159,7 @@ void GPUContextDX12::SetResourceState(ResourceOwnerDX12* resource, D3D12_RESOURC
if (ResourceStateDX12::IsTransitionNeeded(before, after))
{
AddTransitionBarrier(resource, before, after, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
state.SetSubresourceState(subresourceIndex, after);
state.SetResourceState(after);
}
}
else
@@ -175,8 +175,8 @@ void GPUContextDX12::SetResourceState(ResourceOwnerDX12* resource, D3D12_RESOURC
}
}
ASSERT(state.CheckResourceState(after));
state.SetResourceState(after);
}
state.SetResourceState(after);
}
else
{
@@ -286,7 +286,7 @@ void GPUContextDX12::flushSRVs()
return;
// Bind all required slots and mark them as not dirty
_srMaskDirtyCompute &= ~srMask;
//_srMaskDirtyCompute &= ~srMask; // TODO: this causes visual artifacts sometimes, maybe use binary SR-dirty flag for all slots?
}
else
{
@@ -295,7 +295,7 @@ void GPUContextDX12::flushSRVs()
return;
// Bind all required slots and mark them as not dirty
_srMaskDirtyGraphics &= ~srMask;
//_srMaskDirtyGraphics &= ~srMask; // TODO: this causes visual artifacts sometimes, maybe use binary SR-dirty flag for all slots?
}
// Count SRVs required to be bind to the pipeline (the index of the most significant bit that's set)
@@ -309,7 +309,7 @@ void GPUContextDX12::flushSRVs()
{
const auto handle = _srHandles[i];
const auto dimensions = (D3D12_SRV_DIMENSION)header.SrDimensions[i];
if (handle != nullptr && dimensions)
if (srMask & (1 << i) && handle != nullptr && dimensions)
{
ASSERT(handle->SrvDimension == dimensions);
srcDescriptorRangeStarts[i] = handle->SRV();
@@ -360,7 +360,8 @@ void GPUContextDX12::flushRTVs()
if (_rtDepth)
{
depthBuffer = _rtDepth->DSV();
SetResourceState(_rtDepth->GetResourceOwner(), D3D12_RESOURCE_STATE_DEPTH_WRITE, _rtDepth->SubresourceIndex);
auto states = _rtDepth->ReadOnlyDepthView ? D3D12_RESOURCE_STATE_DEPTH_READ : D3D12_RESOURCE_STATE_DEPTH_WRITE;
SetResourceState(_rtDepth->GetResourceOwner(), states, _rtDepth->SubresourceIndex);
}
else
{
@@ -507,28 +508,33 @@ void GPUContextDX12::onDrawCall()
SetResourceState(_ibHandle, D3D12_RESOURCE_STATE_INDEX_BUFFER);
}
// If SRV resource is not binded to RTV then transition it to the whole state (GPU-BASED VALIDATION complains about it)
for (uint32 i = 0; i < GPU_MAX_SR_BINDED; i++)
if (_currentState)
{
const auto handle = _srHandles[i];
if (handle != nullptr && handle->GetResourceOwner())
// If SRV resource is not binded to RTV then transition it to the whole state (GPU-BASED VALIDATION complains about it)
const uint32 srMask = _currentState->GetUsedSRsMask();
const uint32 srCount = Math::FloorLog2(srMask) + 1;
for (uint32 i = 0; i < srCount; i++)
{
const auto resourceOwner = handle->GetResourceOwner();
bool isRtv = false;
for (int32 j = 0; j < _rtCount; j++)
const auto handle = _srHandles[i];
if (srMask & (1 << i) && handle != nullptr && handle->GetResourceOwner())
{
if (_rtHandles[j] && _rtHandles[j]->GetResourceOwner() == resourceOwner)
const auto resourceOwner = handle->GetResourceOwner();
bool isRtv = false;
for (int32 j = 0; j < _rtCount; j++)
{
isRtv = true;
break;
if (_rtHandles[j] && _rtHandles[j]->GetResourceOwner() == resourceOwner)
{
isRtv = true;
break;
}
}
if (!isRtv)
{
D3D12_RESOURCE_STATES states = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
if (handle->IsDepthStencilResource())
states |= D3D12_RESOURCE_STATE_DEPTH_READ;
SetResourceState(handle->GetResourceOwner(), states);
}
}
if (!isRtv)
{
D3D12_RESOURCE_STATES states = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
if (handle->IsDepthStencilResource())
states |= D3D12_RESOURCE_STATE_DEPTH_READ;
SetResourceState(handle->GetResourceOwner(), states);
}
}
}
@@ -543,36 +549,39 @@ void GPUContextDX12::onDrawCall()
#if BUILD_DEBUG
// Additional verification of the state
for (int32 i = 0; i < _rtCount; i++)
if (_currentState)
{
const auto handle = _rtHandles[i];
if (handle != nullptr && handle->GetResourceOwner())
for (int32 i = 0; i < _rtCount; i++)
{
const auto& state = handle->GetResourceOwner()->State;
ASSERT((state.GetSubresourceState(handle->SubresourceIndex) & D3D12_RESOURCE_STATE_RENDER_TARGET) != 0);
}
}
const uint32 srMask = _currentState->GetUsedSRsMask();
const uint32 srCount = Math::FloorLog2(srMask) + 1;
for (uint32 i = 0; i < srCount; i++)
{
const auto handle = _srHandles[i];
if (handle != nullptr && handle->GetResourceOwner())
{
const auto& state = handle->GetResourceOwner()->State;
bool isRtv = false;
for (int32 j = 0; j < _rtCount; j++)
const auto handle = _rtHandles[i];
if (handle != nullptr && handle->GetResourceOwner())
{
if (_rtHandles[j] && _rtHandles[j]->GetResourceOwner() == handle->GetResourceOwner())
{
isRtv = true;
break;
}
const auto& state = handle->GetResourceOwner()->State;
ASSERT((state.GetSubresourceState(handle->SubresourceIndex) & D3D12_RESOURCE_STATE_RENDER_TARGET) != 0);
}
ASSERT((state.GetSubresourceState(handle->SubresourceIndex) & D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) != 0);
if (!isRtv)
}
const uint32 srMask = _currentState->GetUsedSRsMask();
const uint32 srCount = Math::FloorLog2(srMask) + 1;
for (uint32 i = 0; i < srCount; i++)
{
const auto handle = _srHandles[i];
if (srMask & (1 << i) && handle != nullptr && handle->GetResourceOwner())
{
ASSERT(state.AreAllSubresourcesSame());
const auto& state = handle->GetResourceOwner()->State;
bool isRtv = false;
for (int32 j = 0; j < _rtCount; j++)
{
if (_rtHandles[j] && _rtHandles[j]->GetResourceOwner() == handle->GetResourceOwner())
{
isRtv = true;
break;
}
}
ASSERT((state.GetSubresourceState(handle->SubresourceIndex) & D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) != 0);
if (!isRtv)
{
ASSERT(state.AreAllSubresourcesSame());
}
}
}
}
@@ -1069,10 +1078,10 @@ void GPUContextDX12::ClearState()
void GPUContextDX12::FlushState()
{
// Flush
flushCBs();
flushSRVs();
flushRTVs();
flushUAVs();
//flushCBs();
//flushSRVs();
//flushRTVs();
//flushUAVs();
flushRBs();
//flushPS();
}

View File

@@ -450,6 +450,8 @@ void GPUTextureDX12::initHandles()
srDesc.Texture2DArray.ResourceMinLODClamp = 0;
}
_handlesPerSlice[arrayIndex].SetSRV(srDesc);
if (isCubeMap)
_handlesPerSlice[arrayIndex].SrvDimension = D3D12_SRV_DIMENSION_TEXTURE2D; // Hack xD (to reproduce the problem comment this line and use Spot Light with a shadow)
}
if (useUAV)
{
@@ -688,6 +690,7 @@ void GPUTextureDX12::initHandles()
if (_desc.Flags & GPUTextureFlags::ReadOnlyDepthView)
{
_handleReadOnlyDepth.Init(this, _device, this, format, msaa);
_handleReadOnlyDepth.ReadOnlyDepthView = true;
if (useDSV)
{
if (isCubeMap)

View File

@@ -73,6 +73,7 @@ public:
public:
bool ReadOnlyDepthView = false;
void SetRTV(D3D12_RENDER_TARGET_VIEW_DESC& rtvDesc);
void SetSRV(D3D12_SHADER_RESOURCE_VIEW_DESC& srvDesc);
void SetDSV(D3D12_DEPTH_STENCIL_VIEW_DESC& dsvDesc);

View File

@@ -32,12 +32,21 @@ public:
/// <summary>
/// Returns true if resource state transition is needed in order to use resource in given state.
/// </summary>
/// <param name="currentState">The current resource state.</param>
/// <param name="targetState">the destination resource state.</param>
/// <param name="before">The current resource state.</param>
/// <param name="after">the destination resource state.</param>
/// <returns>True if need to perform a transition, otherwise false.</returns>
FORCE_INLINE static bool IsTransitionNeeded(D3D12_RESOURCE_STATES currentState, D3D12_RESOURCE_STATES targetState)
FORCE_INLINE static bool IsTransitionNeeded(D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES& after)
{
return currentState != targetState && ((currentState | targetState) != currentState || targetState == D3D12_RESOURCE_STATE_COMMON);
if (before == D3D12_RESOURCE_STATE_DEPTH_WRITE && after == D3D12_RESOURCE_STATE_DEPTH_READ)
return false;
if (after == D3D12_RESOURCE_STATE_COMMON)
return before != D3D12_RESOURCE_STATE_COMMON;
if (after == D3D12_RESOURCE_STATE_DEPTH_READ)
return ~(before & (D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)) == 0;
const D3D12_RESOURCE_STATES combined = before | after;
if ((combined & (D3D12_RESOURCE_STATE_GENERIC_READ | D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT)) == combined)
after = combined;
return before != after;
}
};