Add UAV slots dimensions to cache for D3D12 validation

This commit is contained in:
Wojtek Figat
2021-06-08 15:18:04 +02:00
parent e0b5558399
commit b300793009
9 changed files with 50 additions and 40 deletions

View File

@@ -28,6 +28,7 @@ public:
GPUBufferViewDX12() GPUBufferViewDX12()
{ {
SrvDimension = D3D12_SRV_DIMENSION_BUFFER; SrvDimension = D3D12_SRV_DIMENSION_BUFFER;
UavDimension = D3D12_UAV_DIMENSION_BUFFER;
} }
/// <summary> /// <summary>

View File

@@ -70,8 +70,6 @@ GPUContextDX12::GPUContextDX12(GPUDeviceDX12* device, D3D12_COMMAND_LIST_TYPE ty
, _rbBufferSize(0) , _rbBufferSize(0)
, _srMaskDirtyGraphics(0) , _srMaskDirtyGraphics(0)
, _srMaskDirtyCompute(0) , _srMaskDirtyCompute(0)
, _uaMaskDirtyGraphics(0)
, _uaMaskDirtyCompute(0)
, _isCompute(0) , _isCompute(0)
, _rtDirtyFlag(0) , _rtDirtyFlag(0)
, _psDirtyFlag(0) , _psDirtyFlag(0)
@@ -208,8 +206,6 @@ void GPUContextDX12::Reset()
_rtDepth = nullptr; _rtDepth = nullptr;
_srMaskDirtyGraphics = 0; _srMaskDirtyGraphics = 0;
_srMaskDirtyCompute = 0; _srMaskDirtyCompute = 0;
_uaMaskDirtyGraphics = 0;
_uaMaskDirtyCompute = 0;
_psDirtyFlag = false; _psDirtyFlag = false;
_isCompute = false; _isCompute = false;
_currentCompute = nullptr; _currentCompute = nullptr;
@@ -309,7 +305,7 @@ void GPUContextDX12::flushSRVs()
{ {
const auto handle = _srHandles[i]; const auto handle = _srHandles[i];
const auto dimensions = (D3D12_SRV_DIMENSION)header.SrDimensions[i]; const auto dimensions = (D3D12_SRV_DIMENSION)header.SrDimensions[i];
if (srMask & (1 << i) && handle != nullptr && dimensions) if (srMask & (1 << i) && handle != nullptr)
{ {
ASSERT(handle->SrvDimension == dimensions); ASSERT(handle->SrvDimension == dimensions);
srcDescriptorRangeStarts[i] = handle->SRV(); srcDescriptorRangeStarts[i] = handle->SRV();
@@ -379,35 +375,30 @@ void GPUContextDX12::flushUAVs()
if (_isCompute) if (_isCompute)
{ {
// Skip if no compute shader binded or it doesn't use shader resources // Skip if no compute shader binded or it doesn't use shader resources
if (_uaMaskDirtyCompute == 0 || _currentCompute == nullptr || (uaMask = _currentCompute->GetBindings().UsedUAsMask) == 0) if ((uaMask = _currentCompute->GetBindings().UsedUAsMask) == 0)
return; return;
// Bind all dirty slots and all used slots
uaMask |= _uaMaskDirtyCompute;
_uaMaskDirtyCompute = 0;
} }
else else
{ {
// Skip if no state binded or it doesn't use shader resources // Skip if no state binded or it doesn't use shader resources
if (_uaMaskDirtyGraphics == 0 || _currentState == nullptr || (uaMask = _currentState->GetUsedUAsMask()) == 0) if (_currentState == nullptr || (uaMask = _currentState->GetUsedUAsMask()) == 0)
return; return;
// Bind all dirty slots and all used slots
uaMask |= _uaMaskDirtyGraphics;
_uaMaskDirtyGraphics = 0;
} }
// Count UAVs required to be bind to the pipeline (the index of the most significant bit that's set) // Count UAVs required to be bind to the pipeline (the index of the most significant bit that's set)
const uint32 uaCount = Math::FloorLog2(uaMask) + 1; const uint32 uaCount = Math::FloorLog2(uaMask) + 1;
ASSERT(uaCount <= GPU_MAX_UA_BINDED); ASSERT(uaCount <= GPU_MAX_UA_BINDED + 1);
// Fill table with source descriptors // Fill table with source descriptors
D3D12_CPU_DESCRIPTOR_HANDLE srcDescriptorRangeStarts[GPU_MAX_UA_BINDED]; DxShaderHeader& header = _currentCompute ? ((GPUShaderProgramCSDX12*)_currentCompute)->Header : _currentState->Header;
D3D12_CPU_DESCRIPTOR_HANDLE srcDescriptorRangeStarts[GPU_MAX_UA_BINDED + 1];
for (uint32 i = 0; i < uaCount; i++) for (uint32 i = 0; i < uaCount; i++)
{ {
const auto handle = _uaHandles[i]; const auto handle = _uaHandles[i];
if (handle != nullptr) const auto dimensions = (D3D12_UAV_DIMENSION)header.UaDimensions[i];
if (uaMask & (1 << i) && handle != nullptr)
{ {
ASSERT(handle->UavDimension == dimensions);
srcDescriptorRangeStarts[i] = handle->UAV(); srcDescriptorRangeStarts[i] = handle->UAV();
SetResourceState(handle->GetResourceOwner(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS); SetResourceState(handle->GetResourceOwner(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
} }
@@ -752,15 +743,8 @@ void GPUContextDX12::SetRenderTarget(GPUTextureView* rt, GPUBuffer* uaOutput)
// Set render target normally // Set render target normally
SetRenderTarget(nullptr, rt); SetRenderTarget(nullptr, rt);
// Bind UAV output to the last slot // Bind UAV output to the 2nd slot (after render target to match DX11 binding model)
const int32 slot = ARRAY_COUNT(_uaHandles) - 1; _uaHandles[1] = uaOutputDX12;
IShaderResourceDX12** lastSlot = &_uaHandles[slot];
if (*lastSlot != uaOutputDX12)
{
*lastSlot = uaOutputDX12;
_srMaskDirtyGraphics |= 1 << slot;
_srMaskDirtyCompute |= 1 << slot;
}
} }
void GPUContextDX12::ResetSR() void GPUContextDX12::ResetSR()
@@ -824,13 +808,7 @@ void GPUContextDX12::BindSR(int32 slot, GPUResourceView* view)
void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view) void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view)
{ {
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED); ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
auto handle = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr; _uaHandles[slot] = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
if (_uaHandles[slot] != handle || !handle)
{
_uaMaskDirtyGraphics |= 1 << slot;
_uaMaskDirtyCompute |= 1 << slot;
_uaHandles[slot] = handle;
}
} }
void GPUContextDX12::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets) void GPUContextDX12::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets)

View File

@@ -47,9 +47,6 @@ private:
uint32 _srMaskDirtyGraphics; uint32 _srMaskDirtyGraphics;
uint32 _srMaskDirtyCompute; uint32 _srMaskDirtyCompute;
uint32 _uaMaskDirtyGraphics;
uint32 _uaMaskDirtyCompute;
int32 _isCompute : 1; int32 _isCompute : 1;
int32 _rtDirtyFlag : 1; int32 _rtDirtyFlag : 1;
int32 _psDirtyFlag : 1; int32 _psDirtyFlag : 1;
@@ -58,7 +55,7 @@ private:
GPUTextureViewDX12* _rtDepth; GPUTextureViewDX12* _rtDepth;
GPUTextureViewDX12* _rtHandles[GPU_MAX_RT_BINDED]; GPUTextureViewDX12* _rtHandles[GPU_MAX_RT_BINDED];
IShaderResourceDX12* _srHandles[GPU_MAX_SR_BINDED]; IShaderResourceDX12* _srHandles[GPU_MAX_SR_BINDED];
IShaderResourceDX12* _uaHandles[GPU_MAX_UA_BINDED + 1]; IShaderResourceDX12* _uaHandles[GPU_MAX_UA_BINDED];
GPUBufferDX12* _ibHandle; GPUBufferDX12* _ibHandle;
GPUBufferDX12* _vbHandles[GPU_MAX_VB_BINDED]; GPUBufferDX12* _vbHandles[GPU_MAX_VB_BINDED];
D3D12_INDEX_BUFFER_VIEW _ibView; D3D12_INDEX_BUFFER_VIEW _ibView;

View File

@@ -467,12 +467,11 @@ bool GPUDeviceDX12::Init()
{ {
D3D12_DESCRIPTOR_RANGE& range = r[1]; D3D12_DESCRIPTOR_RANGE& range = r[1];
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
range.NumDescriptors = GPU_MAX_UA_BINDED + 1; // the last (additional) UAV register is used as a UAV output (hidden internally) range.NumDescriptors = GPU_MAX_UA_BINDED;
range.BaseShaderRegister = 0; range.BaseShaderRegister = 0;
range.RegisterSpace = 0; range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
} }
static_assert(GPU_MAX_UA_BINDED == 2, "DX12 backend uses hardcoded single UAV register slot. Update code to support more.");
// Root parameters // Root parameters
D3D12_ROOT_PARAMETER rootParameters[4]; D3D12_ROOT_PARAMETER rootParameters[4];

View File

@@ -139,6 +139,10 @@ bool GPUPipelineStateDX12::Init(const Description& desc)
for (uint32 i = 0; i < srCount; i++) \ for (uint32 i = 0; i < srCount; i++) \
if (shader->Header.SrDimensions[i]) \ if (shader->Header.SrDimensions[i]) \
Header.SrDimensions[i] = shader->Header.SrDimensions[i]; \ Header.SrDimensions[i] = shader->Header.SrDimensions[i]; \
auto uaCount = Math::FloorLog2(shader->GetBindings().UsedUAsMask) + 1; \
for (uint32 i = 0; i < uaCount; i++) \
if (shader->Header.UaDimensions[i]) \
Header.UaDimensions[i] = shader->Header.UaDimensions[i]; \
} }
INIT_SHADER_STAGE(HS, GPUShaderProgramHSDX12); INIT_SHADER_STAGE(HS, GPUShaderProgramHSDX12);
INIT_SHADER_STAGE(DS, GPUShaderProgramDSDX12); INIT_SHADER_STAGE(DS, GPUShaderProgramDSDX12);

View File

@@ -280,6 +280,7 @@ void GPUTextureViewDX12::SetDSV(D3D12_DEPTH_STENCIL_VIEW_DESC& dsvDesc)
void GPUTextureViewDX12::SetUAV(D3D12_UNORDERED_ACCESS_VIEW_DESC& uavDesc, ID3D12Resource* counterResource) void GPUTextureViewDX12::SetUAV(D3D12_UNORDERED_ACCESS_VIEW_DESC& uavDesc, ID3D12Resource* counterResource)
{ {
UavDimension = uavDesc.ViewDimension;
_uav.CreateUAV(_device, _owner->GetResource(), &uavDesc, counterResource); _uav.CreateUAV(_device, _owner->GetResource(), &uavDesc, counterResource);
} }

View File

@@ -33,6 +33,7 @@ public:
int32 SubresourceIndex; int32 SubresourceIndex;
D3D12_SRV_DIMENSION SrvDimension = D3D12_SRV_DIMENSION_UNKNOWN; D3D12_SRV_DIMENSION SrvDimension = D3D12_SRV_DIMENSION_UNKNOWN;
D3D12_UAV_DIMENSION UavDimension = D3D12_UAV_DIMENSION_UNKNOWN;
public: public:

View File

@@ -13,6 +13,11 @@ struct DxShaderHeader
/// </summary> /// </summary>
byte SrDimensions[32]; byte SrDimensions[32];
/// <summary>
/// The UAV dimensions per-slot.
/// </summary>
byte UaDimensions[4];
// .. rest is just a actual data array // .. rest is just a actual data array
}; };

View File

@@ -379,6 +379,30 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
case D3D_SIT_UAV_CONSUME_STRUCTURED: case D3D_SIT_UAV_CONSUME_STRUCTURED:
case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER:
bindings.UsedUAsMask |= 1 << resDesc.BindPoint; bindings.UsedUAsMask |= 1 << resDesc.BindPoint;
switch (resDesc.Dimension)
{
case D3D_SRV_DIMENSION_BUFFER:
header.UaDimensions[resDesc.BindPoint] = 1; // D3D12_UAV_DIMENSION_BUFFER;
break;
case D3D_SRV_DIMENSION_TEXTURE1D:
header.UaDimensions[resDesc.BindPoint] = 2; // D3D12_UAV_DIMENSION_TEXTURE1D;
break;
case D3D_SRV_DIMENSION_TEXTURE1DARRAY:
header.UaDimensions[resDesc.BindPoint] = 3; // D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
break;
case D3D_SRV_DIMENSION_TEXTURE2D:
header.UaDimensions[resDesc.BindPoint] = 4; // D3D12_UAV_DIMENSION_TEXTURE2D;
break;
case D3D_SRV_DIMENSION_TEXTURE2DARRAY:
header.UaDimensions[resDesc.BindPoint] = 5; // D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
break;
case D3D_SRV_DIMENSION_TEXTURE3D:
header.UaDimensions[resDesc.BindPoint] = 8; // D3D12_UAV_DIMENSION_TEXTURE3D;
break;
default:
LOG(Error, "Unknown UAV resource {2} of type {0} at slot {1}", resDesc.Dimension, resDesc.BindPoint, String(resDesc.Name));
return true;
}
break; break;
} }
} }