diff --git a/trinity/Tr2IndirectDrawBuffer.cpp b/trinity/Tr2IndirectDrawBuffer.cpp index 576e451f2..777ce633b 100644 --- a/trinity/Tr2IndirectDrawBuffer.cpp +++ b/trinity/Tr2IndirectDrawBuffer.cpp @@ -4,6 +4,9 @@ #include "Tr2IndirectDrawBuffer.h" #include "Tr2Renderer.h" #include "../trinityal/metal/Tr2ShaderProgramALMetal.h" +#if TRINITY_PLATFORM == TRINITY_DIRECTX12 +#include "../trinityal/dx12/Utilities.h" +#endif CCP_STATS_DECLARE( sceneExecuteIndirectCount, "Trinity/AL/sceneExecuteIndirectCount", true, CST_COUNTER_LOW, "Number of ExecuteIndirect calls." ); @@ -328,7 +331,7 @@ void Tr2IndirectDrawBuffer::CopyArguments() transition }; - renderContext.m_commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( renderContext.m_commandList, 1, &barrier ); } for( int i = 0; i <= copyIndex; i++ ) @@ -352,7 +355,7 @@ void Tr2IndirectDrawBuffer::CopyArguments() transition }; - renderContext.m_commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( renderContext.m_commandList, 1, &barrier ); } #endif } diff --git a/trinity/TriDevice12.cpp b/trinity/TriDevice12.cpp index 26425261c..a5ed773c6 100644 --- a/trinity/TriDevice12.cpp +++ b/trinity/TriDevice12.cpp @@ -212,13 +212,23 @@ void TriDevice::HandleRenderTick( Be::Time realTime, Be::Time simTime ) CCP_LOGERR( "[DRED] Last tracked GPU operations:" ); std::map contextStrings; - D3D12_AUTO_BREADCRUMB_NODE1 const* pNode = dredAutoBreadcrumbsOutput.pHeadAutoBreadcrumbNode; - while( pNode && pNode->pLastBreadcrumbValue ) + for( D3D12_AUTO_BREADCRUMB_NODE1 const* pNode = dredAutoBreadcrumbsOutput.pHeadAutoBreadcrumbNode; pNode; pNode = pNode->pNext ) { + if( !pNode->pLastBreadcrumbValue ) + { + continue; + } UINT lastCompletedOp = *pNode->pLastBreadcrumbValue; - if( lastCompletedOp != (int)pNode->BreadcrumbCount && lastCompletedOp != 0 ) + // Only lists in flight at removal time; 0 = never started, BreadcrumbCount = fully retired + if( lastCompletedOp != pNode->BreadcrumbCount && lastCompletedOp != 0 ) { - CCP_LOGERR( "[DRED] Commandlist completed %d of %d commands", lastCompletedOp, pNode->BreadcrumbCount ); + CCP_LOGERR( "[DRED] Commandlist '%s' (%p) on queue '%s' completed %d of %d commands (%d contexts)", + pNode->pCommandListDebugNameA ? pNode->pCommandListDebugNameA : "", + pNode->pCommandList, + pNode->pCommandQueueDebugNameA ? pNode->pCommandQueueDebugNameA : "", + lastCompletedOp, + pNode->BreadcrumbCount, + pNode->BreadcrumbContextsCount ); UINT firstOp = lastCompletedOp > 100 ? lastCompletedOp - 100 : 0; UINT lastOp = std::min( lastCompletedOp + 20, UINT( pNode->BreadcrumbCount ) - 1 ); @@ -227,7 +237,10 @@ void TriDevice::HandleRenderTick( Be::Time realTime, Be::Time simTime ) for( UINT breadcrumbContext = 0; breadcrumbContext < pNode->BreadcrumbContextsCount; ++breadcrumbContext ) { const D3D12_DRED_BREADCRUMB_CONTEXT& context = pNode->pBreadcrumbContexts[breadcrumbContext]; - contextStrings[context.BreadcrumbIndex] = context.pContextString; + if( context.BreadcrumbIndex >= firstOp && context.BreadcrumbIndex <= lastOp ) + { + contextStrings[context.BreadcrumbIndex] = context.pContextString; + } } for( UINT op = firstOp; op <= lastOp; ++op ) @@ -241,28 +254,36 @@ void TriDevice::HandleRenderTick( Be::Time realTime, Be::Time simTime ) contextString = it->second; } - char const* opName = DredBreadcrumbOpName( breadcrumbOp ); - CCP_LOGERR( "\tOp: %d, %s%ls%s", op, opName, contextString.c_str(), ( op + 1 == lastCompletedOp ) ? " - Last completed" : "" ); + // Markers with a context string are our own annotations, not GPU work + char const* opName = breadcrumbOp == D3D12_AUTO_BREADCRUMB_OP_SETMARKER && !contextString.empty() ? "[Trinity]" : DredBreadcrumbOpName( breadcrumbOp ); + char const* status = op == lastCompletedOp ? " - IN FLIGHT" : ( op + 1 == lastCompletedOp ) ? " - Last completed" : + ""; + CCP_LOGERR( "\tOp: %d, %s %ls%s", op, opName, contextString.c_str(), status ); } } - pNode = pNode->pNext; } } if( SUCCEEDED( pDred->GetPageFaultAllocationOutput1( &dredPageFaultOutput ) ) ) { - for( auto node = dredPageFaultOutput.pHeadExistingAllocationNode; node != nullptr; node = node->pNext ) - { - if( node->ObjectNameW ) + CCP_LOGERR( "[DRED] Page fault VA: 0x%016llX", dredPageFaultOutput.PageFaultVA ); + // Engine names are ANSI (WKPDID_D3DDebugObjectName), so DRED fills ObjectNameA; ObjectNameW only holds names set via SetName + auto logAllocationNode = []( const char* prefix, const D3D12_DRED_ALLOCATION_NODE1* node ) { + if( node->ObjectNameA ) { - CCP_LOGERR( "Page Fault Allocation on: %ls", node->ObjectNameW ); + CCP_LOGERR( "%s: %s (type %d)", prefix, node->ObjectNameA, node->AllocationType ); } + else + { + CCP_LOGERR( "%s: %ls (type %d)", prefix, node->ObjectNameW ? node->ObjectNameW : L"", node->AllocationType ); + } + }; + for( auto node = dredPageFaultOutput.pHeadExistingAllocationNode; node != nullptr; node = node->pNext ) + { + logAllocationNode( "Page Fault Allocation on", node ); } for( auto node = dredPageFaultOutput.pHeadRecentFreedAllocationNode; node != nullptr; node = node->pNext ) { - if( node->ObjectNameW ) - { - CCP_LOGERR( "Page Fault Free on: %ls", node->ObjectNameW ); - } + logAllocationNode( "Page Fault Free on", node ); } } } diff --git a/trinityal/Tr2RenderContextEnum.cpp b/trinityal/Tr2RenderContextEnum.cpp index 8e756c70e..b30a89962 100644 --- a/trinityal/Tr2RenderContextEnum.cpp +++ b/trinityal/Tr2RenderContextEnum.cpp @@ -6,6 +6,7 @@ #include "ALLog.h" bool g_requestDebugMarkers = false; +bool g_dredBreadcrumbsEnabled = false; bool g_skipNvidiaStreamline = false; bool g_brokenMacOSNvidiaDrivers = false; diff --git a/trinityal/dx12/Tr2PrimaryRenderContextDx12.cpp b/trinityal/dx12/Tr2PrimaryRenderContextDx12.cpp index 72eeecf9d..7cd2567ed 100644 --- a/trinityal/dx12/Tr2PrimaryRenderContextDx12.cpp +++ b/trinityal/dx12/Tr2PrimaryRenderContextDx12.cpp @@ -16,6 +16,7 @@ extern bool g_requestDeviceDebugLayer; extern bool g_requestDebugMarkers; extern bool g_requestDred; +extern bool g_dredBreadcrumbsEnabled; bool g_gatherPipelineStatistics = false; extern ICrashReporter* TrinityALCrashes; @@ -45,6 +46,9 @@ bool EnableDred() // Turn on auto-breadcrumbs and page fault reporting. pDredSettings->SetAutoBreadcrumbsEnablement( D3D12_DRED_ENABLEMENT_FORCED_ON ); pDredSettings->SetPageFaultEnablement( D3D12_DRED_ENABLEMENT_FORCED_ON ); + // Capture SetMarker/BeginEvent strings alongside the breadcrumb ops + pDredSettings->SetBreadcrumbContextEnablement( D3D12_DRED_ENABLEMENT_FORCED_ON ); + g_dredBreadcrumbsEnabled = true; return true; } return false; @@ -410,6 +414,7 @@ ALResult Tr2PrimaryRenderContextAL::CreateDevice( desc.NodeMask = 0; CR_RETURN_HR( CreateCommandQueue( device, &desc, commandQueue ) ); + TrinityALImpl::SetDebugName( commandQueue, "PrimaryDirectQueue" ); const bool isWindowless = ( focusWindow == 0 ) && presentationParameters.software; diff --git a/trinityal/dx12/Tr2RenderContextDx12.cpp b/trinityal/dx12/Tr2RenderContextDx12.cpp index e13747566..dff1c56f9 100644 --- a/trinityal/dx12/Tr2RenderContextDx12.cpp +++ b/trinityal/dx12/Tr2RenderContextDx12.cpp @@ -17,6 +17,7 @@ #include "util/AmdExtDevice.h" extern bool g_requestDebugMarkers; +extern bool g_dredBreadcrumbsEnabled; CCP_STATS_DECLARE( primitiveCount, "Trinity/AL/primitiveCount", true, CST_COUNTER_HIGH, "Primitive count in DrawPrimitive calls." ); CCP_STATS_DECLARE( vertexCount, "Trinity/AL/vertexCount", true, CST_COUNTER_HIGH, "Vertex count in DrawPrimitive calls." ); @@ -139,6 +140,7 @@ ALResult Tr2RenderContextAL::CreateDx12( ID3D12CommandAllocator* commandAllocato commandAllocator, nullptr, IID_PPV_ARGS( &m_commandList ) ) ); + TrinityALImpl::SetDebugName( m_commandList, "Tr2RenderContext CommandList" ); CR_RETURN_HR( m_commandList->Close() ); m_commandList.QueryInterface( &m_commandList2 ); @@ -1576,6 +1578,10 @@ void Tr2RenderContextAL::AddGpuMarker( const char* marker ) { crashTracker->PutMarker( m_commandList2, marker ); } + if( g_dredBreadcrumbsEnabled ) + { + TrinityALImpl::SetDredMarker( m_commandList, marker ); + } } void Tr2RenderContextAL::PushGpuMarker( const char* marker ) @@ -1724,7 +1730,7 @@ void Tr2RenderContextAL::FlushBarriersDx12() { if( !m_barriers.empty() ) { - m_commandList->ResourceBarrier( UINT( m_barriers.size() ), m_barriers.data() ); + TrinityALImpl::ResourceBarrier( m_commandList, UINT( m_barriers.size() ), m_barriers.data() ); m_barriers.clear(); } } @@ -1771,7 +1777,7 @@ void Tr2RenderContextAL::FlushBarriersDx12( size_t count, ID3D12Resource** resou } if( barrierCount ) { - m_commandList->ResourceBarrier( UINT( barrierCount ), barriers ); + TrinityALImpl::ResourceBarrier( m_commandList, UINT( barrierCount ), barriers ); } } else @@ -1797,7 +1803,7 @@ void Tr2RenderContextAL::FlushBarriersDx12( size_t count, ID3D12Resource** resou } if( !barriers.empty() ) { - m_commandList->ResourceBarrier( UINT( barriers.size() ), barriers.data() ); + TrinityALImpl::ResourceBarrier( m_commandList, UINT( barriers.size() ), barriers.data() ); } } } diff --git a/trinityal/dx12/Tr2RtTopLevelAccelerationStructureALDx12.cpp b/trinityal/dx12/Tr2RtTopLevelAccelerationStructureALDx12.cpp index 459186ef1..4039266c4 100644 --- a/trinityal/dx12/Tr2RtTopLevelAccelerationStructureALDx12.cpp +++ b/trinityal/dx12/Tr2RtTopLevelAccelerationStructureALDx12.cpp @@ -78,7 +78,7 @@ ALResult Tr2RtTopLevelAccelerationStructureAL::Create( const size_t count, const uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; uavBarrier.UAV.pResource = nullptr; uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - renderContext.m_commandList->ResourceBarrier( 1, &uavBarrier ); + TrinityALImpl::ResourceBarrier( renderContext.m_commandList, 1, &uavBarrier ); size_t capacity = Align( count, 128 ); @@ -165,7 +165,7 @@ ALResult Tr2RtTopLevelAccelerationStructureAL::Create( const size_t count, const topLevelUavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; topLevelUavBarrier.UAV.pResource = buffer.TrinityALImpl_GetObject()->GetGpuResource(); topLevelUavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - renderContext.m_commandList->ResourceBarrier( 1, &topLevelUavBarrier ); + TrinityALImpl::ResourceBarrier( renderContext.m_commandList, 1, &topLevelUavBarrier ); return S_OK; } @@ -195,7 +195,7 @@ ALResult Tr2RtTopLevelAccelerationStructureAL::Update( const size_t count, const uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; uavBarrier.UAV.pResource = nullptr; uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - renderContext.m_commandList->ResourceBarrier( 1, &uavBarrier ); + TrinityALImpl::ResourceBarrier( renderContext.m_commandList, 1, &uavBarrier ); CComPtr uploadBuffer; auto completed = m_owner->GetRenderedFrameNumber(); @@ -256,7 +256,7 @@ ALResult Tr2RtTopLevelAccelerationStructureAL::Update( const size_t count, const topLevelUavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; topLevelUavBarrier.UAV.pResource = m_buffer.TrinityALImpl_GetObject()->GetGpuResource(); topLevelUavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - renderContext.m_commandList->ResourceBarrier( 1, &topLevelUavBarrier ); + TrinityALImpl::ResourceBarrier( renderContext.m_commandList, 1, &topLevelUavBarrier ); return S_OK; } diff --git a/trinityal/dx12/Tr2TextureALDx12.cpp b/trinityal/dx12/Tr2TextureALDx12.cpp index c51a92174..ac9dd816a 100644 --- a/trinityal/dx12/Tr2TextureALDx12.cpp +++ b/trinityal/dx12/Tr2TextureALDx12.cpp @@ -260,17 +260,17 @@ struct Tr2TextureAL::MipMapGenerator else { auto restore = TrinityALImpl::Transition( m_staging, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST ); - commandList->ResourceBarrier( 1, &restore ); + TrinityALImpl::ResourceBarrier( commandList, 1, &restore ); } staging = m_staging; // Copy the resource to staging auto from = TrinityALImpl::Transition( resource, resourceState, D3D12_RESOURCE_STATE_COPY_SOURCE ); - commandList->ResourceBarrier( 1, &from ); + TrinityALImpl::ResourceBarrier( commandList, 1, &from ); commandList->CopyResource( staging, resource ); auto to = TrinityALImpl::Transition( staging, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ); - commandList->ResourceBarrier( 1, &to ); + TrinityALImpl::ResourceBarrier( commandList, 1, &to ); } else { @@ -279,7 +279,7 @@ struct Tr2TextureAL::MipMapGenerator if( ( resourceState & D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ) == 0 ) { auto barrier = TrinityALImpl::Transition( staging, resourceState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); } else { @@ -390,7 +390,7 @@ struct Tr2TextureAL::MipMapGenerator srv2uavDescs[i].Transition.Subresource = mip + ( i * desc.MipLevels ); uav2srvDescs[i].Transition.Subresource = mip + ( i * desc.MipLevels ); } - commandList->ResourceBarrier( desc.DepthOrArraySize, srv2uavDescs.data() ); + TrinityALImpl::ResourceBarrier( commandList, desc.DepthOrArraySize, srv2uavDescs.data() ); // Bind the mip subresources commandList->SetComputeRootDescriptorTable( TrinityALImpl::GenerateMipsResources::TargetTexture, uavH ); @@ -412,10 +412,10 @@ struct Tr2TextureAL::MipMapGenerator ( mipHeight + TrinityALImpl::GenerateMipsResources::ThreadGroupSize - 1 ) / TrinityALImpl::GenerateMipsResources::ThreadGroupSize, desc.DepthOrArraySize ); - commandList->ResourceBarrier( 1, &barrierUAV ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrierUAV ); // Transition the mip to an SRV - commandList->ResourceBarrier( desc.DepthOrArraySize, uav2srvDescs.data() ); + TrinityALImpl::ResourceBarrier( commandList, desc.DepthOrArraySize, uav2srvDescs.data() ); // Offset the descriptor heap handles uavH.ptr += descriptorSize; @@ -430,18 +430,18 @@ struct Tr2TextureAL::MipMapGenerator TrinityALImpl::Transition( resource, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST ) }; - commandList->ResourceBarrier( 2, barriers ); + TrinityALImpl::ResourceBarrier( commandList, 2, barriers ); // Copy the entire resource back commandList->CopyResource( resource, staging ); // Transition the target resource back to pixel shader resource auto barrier = TrinityALImpl::Transition( resource, D3D12_RESOURCE_STATE_COPY_DEST, resourceState ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); } else if( ( resourceState & D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ) == 0 ) { auto barrier = TrinityALImpl::Transition( resource, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, resourceState ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); } m_device.DirtyDescriptorCache(); @@ -477,27 +477,27 @@ struct Tr2TextureAL::MipMapGenerator else { auto restore = TrinityALImpl::Transition( m_resourceCopy, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST ); - commandList->ResourceBarrier( 1, &restore ); + TrinityALImpl::ResourceBarrier( commandList, 1, &restore ); } // Copy the resource data auto barrier = TrinityALImpl::Transition( resource, resourceState, D3D12_RESOURCE_STATE_COPY_SOURCE ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); commandList->CopyResource( m_resourceCopy, resource ); barrier = TrinityALImpl::Transition( m_resourceCopy, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); // Generate the mips GenerateMips_UnorderedAccessPath( m_resourceCopy, DXGI_FORMAT_R8G8B8A8_UNORM, commandList, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ); // Direct copy back barrier = TrinityALImpl::Transition( m_resourceCopy, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_SOURCE ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); barrier = TrinityALImpl::Transition( resource, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); commandList->CopyResource( resource, m_resourceCopy ); barrier = TrinityALImpl::Transition( resource, D3D12_RESOURCE_STATE_COPY_DEST, resourceState ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); return S_OK; } @@ -550,33 +550,33 @@ struct Tr2TextureAL::MipMapGenerator else { auto restore = TrinityALImpl::Transition( m_bgrAliasCopy, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST ); - commandList->ResourceBarrier( 1, &restore ); + TrinityALImpl::ResourceBarrier( commandList, 1, &restore ); } // Copy the resource data auto barrier = TrinityALImpl::AliasBarrier( nullptr, m_bgrAliasCopy ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); barrier = TrinityALImpl::Transition( resource, resourceState, D3D12_RESOURCE_STATE_COPY_SOURCE ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); commandList->CopyResource( m_bgrAliasCopy, resource ); // Generate the mips barrier = TrinityALImpl::AliasBarrier( m_bgrAliasCopy, m_bgrResourceCopy ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); barrier = TrinityALImpl::Transition( m_bgrResourceCopy, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); FORWARD_HR( GenerateMips_UnorderedAccessPath( m_bgrResourceCopy, DXGI_FORMAT_R8G8B8A8_UNORM, commandList, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ) ); // Direct copy back barrier = TrinityALImpl::AliasBarrier( m_bgrResourceCopy, m_bgrAliasCopy ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); barrier = TrinityALImpl::Transition( m_bgrAliasCopy, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); barrier = TrinityALImpl::Transition( resource, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); commandList->CopyResource( resource, m_bgrAliasCopy ); barrier = TrinityALImpl::Transition( resource, D3D12_RESOURCE_STATE_COPY_DEST, resourceState ); - commandList->ResourceBarrier( 1, &barrier ); + TrinityALImpl::ResourceBarrier( commandList, 1, &barrier ); return S_OK; } diff --git a/trinityal/dx12/Utilities.cpp b/trinityal/dx12/Utilities.cpp index 479be6763..692c90eae 100644 --- a/trinityal/dx12/Utilities.cpp +++ b/trinityal/dx12/Utilities.cpp @@ -8,6 +8,8 @@ #include "ALResult.h" #include "ALLog.h" +extern bool g_dredBreadcrumbsEnabled; + namespace { @@ -1384,6 +1386,126 @@ D3D12_RESOURCE_BARRIER AliasBarrier( return desc; } +// DRED breadcrumb contexts are only captured from PIX3-blob markers (Metadata=2, +// WinPixEventRuntime encoding); legacy ANSI/unicode markers are ignored +void SetDredMarker( ID3D12GraphicsCommandList* commandList, const char* text ) +{ + constexpr UINT64 PIXEvent_SetMarker_NoArgs = 0x008; + UINT64 blob[64]; + blob[0] = PIXEvent_SetMarker_NoArgs << 10; // timestamp 0, event type + blob[1] = 0xFF000000; // ARGB color + blob[2] = ( UINT64( 8 ) << 55 ) | ( UINT64( 1 ) << 54 ); // string info: copy chunk 8, isANSI + size_t lenBytes = strlen( text ) + 1; + size_t qwords = std::min( ( lenBytes + 7 ) / 8, size_t( 60 ) ); + memset( &blob[3], 0, qwords * 8 ); + memcpy( &blob[3], text, std::min( lenBytes, qwords * 8 - 1 ) ); + commandList->SetMarker( 2, blob, UINT( ( 3 + qwords ) * 8 ) ); +} + +namespace +{ +// snprintf returns the untruncated length; clamp so pos never passes the terminator +size_t AdvanceFormatPos( size_t pos, int written, size_t size ) +{ + return written < 0 || pos + size_t( written ) >= size ? size - 1 : pos + size_t( written ); +} + +const char* FormatResourceStates( char* buf, size_t size, D3D12_RESOURCE_STATES states ) +{ + if( states == D3D12_RESOURCE_STATE_COMMON ) + { + return "COMMON"; + } + if( states == D3D12_RESOURCE_STATE_GENERIC_READ ) + { + return "GENERIC_READ"; + } + static const struct + { + D3D12_RESOURCE_STATES bit; + const char* name; + } s_stateNames[] = { + { D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, "VB_CB" }, + { D3D12_RESOURCE_STATE_INDEX_BUFFER, "IB" }, + { D3D12_RESOURCE_STATE_RENDER_TARGET, "RT" }, + { D3D12_RESOURCE_STATE_UNORDERED_ACCESS, "UAV" }, + { D3D12_RESOURCE_STATE_DEPTH_WRITE, "DEPTH_W" }, + { D3D12_RESOURCE_STATE_DEPTH_READ, "DEPTH_R" }, + { D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, "SRV_NONPX" }, + { D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, "SRV_PX" }, + { D3D12_RESOURCE_STATE_STREAM_OUT, "STREAM_OUT" }, + { D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT, "INDIRECT" }, + { D3D12_RESOURCE_STATE_COPY_DEST, "COPY_DST" }, + { D3D12_RESOURCE_STATE_COPY_SOURCE, "COPY_SRC" }, + { D3D12_RESOURCE_STATE_RESOLVE_DEST, "RESOLVE_DST" }, + { D3D12_RESOURCE_STATE_RESOLVE_SOURCE, "RESOLVE_SRC" }, + { D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, "RTAS" }, + }; + size_t pos = 0; + UINT remaining = UINT( states ); + for( const auto& state : s_stateNames ) + { + if( ( remaining & UINT( state.bit ) ) == UINT( state.bit ) ) + { + pos = AdvanceFormatPos( pos, snprintf( buf + pos, size - pos, "%s%s", pos ? "|" : "", state.name ), size ); + remaining &= ~UINT( state.bit ); + } + } + if( remaining ) + { + snprintf( buf + pos, size - pos, "%s0x%x", pos ? "|" : "", remaining ); + } + return buf; +} + +// Recorded immediately before each ResourceBarrier so the DRED breadcrumb context +// identifies which resources/states the otherwise anonymous RESOURCEBARRIER op contains +void EmitBarrierBreadcrumb( ID3D12GraphicsCommandList* commandList, const D3D12_RESOURCE_BARRIER* barriers, size_t count ) +{ + if( !g_dredBreadcrumbsEnabled ) + { + return; + } + char buf[512]; + size_t pos = AdvanceFormatPos( 0, snprintf( buf, sizeof( buf ), "[Barrier]" ), sizeof( buf ) ); + for( size_t i = 0; i < count && pos < sizeof( buf ) - 1; ++i ) + { + const auto& barrier = barriers[i]; + ID3D12Resource* resource = barrier.Type == D3D12_RESOURCE_BARRIER_TYPE_UAV ? barrier.UAV.pResource : barrier.Type == D3D12_RESOURCE_BARRIER_TYPE_ALIASING ? barrier.Aliasing.pResourceAfter : + barrier.Transition.pResource; + char name[128]; + UINT nameSize = sizeof( name ) - 1; + if( !resource || FAILED( resource->GetPrivateData( WKPDID_D3DDebugObjectName, &nameSize, name ) ) || nameSize >= sizeof( name ) ) + { + nameSize = UINT( snprintf( name, sizeof( name ), "%p", resource ) ); + } + name[nameSize] = 0; + if( barrier.Type == D3D12_RESOURCE_BARRIER_TYPE_TRANSITION ) + { + char before[96], after[96]; + const char* beforeStates = FormatResourceStates( before, sizeof( before ), barrier.Transition.StateBefore ); + const char* afterStates = FormatResourceStates( after, sizeof( after ), barrier.Transition.StateAfter ); + pos = AdvanceFormatPos( pos, snprintf( buf + pos, sizeof( buf ) - pos, " %s(%s->%s)", name, beforeStates, afterStates ), sizeof( buf ) ); + } + else if( barrier.Type == D3D12_RESOURCE_BARRIER_TYPE_UAV ) + { + pos = AdvanceFormatPos( pos, snprintf( buf + pos, sizeof( buf ) - pos, " UAV(%s)", name ), sizeof( buf ) ); + } + else + { + pos = AdvanceFormatPos( pos, snprintf( buf + pos, sizeof( buf ) - pos, " Alias(%s)", name ), sizeof( buf ) ); + } + } + SetDredMarker( commandList, buf ); +} +} + +void ResourceBarrier( ID3D12GraphicsCommandList* commandList, UINT count, const D3D12_RESOURCE_BARRIER* barriers ) +{ + EmitBarrierBreadcrumb( commandList, barriers, count ); + commandList->ResourceBarrier( count, barriers ); +} + D3D12_HEAP_PROPERTIES HeapDesc( D3D12_HEAP_TYPE type ) { D3D12_HEAP_PROPERTIES heap = { type, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0 }; diff --git a/trinityal/dx12/Utilities.h b/trinityal/dx12/Utilities.h index efa37b3c5..9b01aa4f8 100644 --- a/trinityal/dx12/Utilities.h +++ b/trinityal/dx12/Utilities.h @@ -20,6 +20,10 @@ D3D12_RESOURCE_BARRIER AliasBarrier( ID3D12Resource* before, ID3D12Resource* after ); +void SetDredMarker( ID3D12GraphicsCommandList* commandList, const char* text ); + +void ResourceBarrier( ID3D12GraphicsCommandList* commandList, UINT count, const D3D12_RESOURCE_BARRIER* barriers ); + D3D12_HEAP_PROPERTIES HeapDesc( D3D12_HEAP_TYPE type ); void MemcpySubresource(