From 220b26aa5933f90e4d0ac9f965e33d933c1bd522 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 6 Jan 2023 13:18:57 +0000 Subject: [PATCH] Handle collisions with existing UAVs in root signature when patching * When debugging a pixel or doing quad overdraw we replace the pixel shader and patch in our own UAV. Previously we were moving other UAVs out of the way that were visible to the pixel shader, but this fails if a UAV is visible to all stages and used in a vertex stage. * Now instead for pixel shader inputs we pick a free space and use it. For quad overdraw we pick an arbitrary high space to hopefully use the precompiled shader, and if it's somehow not free we recompile the shader with a free space. --- renderdoc/data/hlsl/hlsl_cbuffers.h | 4 + renderdoc/data/hlsl/quadoverdraw.hlsl | 10 + renderdoc/driver/d3d12/d3d12_debug.cpp | 41 ++-- renderdoc/driver/d3d12/d3d12_debug.h | 5 +- renderdoc/driver/d3d12/d3d12_overlay.cpp | 39 +++- renderdoc/driver/d3d12/d3d12_replay.h | 3 +- renderdoc/driver/d3d12/d3d12_shader_cache.cpp | 2 +- renderdoc/driver/d3d12/d3d12_shaderdebug.cpp | 30 +-- renderdoc/renderdoc.vcxproj | 2 +- util/test/demos/d3d12/d3d12_vertex_uav.cpp | 181 ++++++++++++++++++ util/test/tests/D3D12/D3D12_Vertex_UAV.py | 74 +++++++ 11 files changed, 351 insertions(+), 40 deletions(-) create mode 100644 util/test/demos/d3d12/d3d12_vertex_uav.cpp create mode 100644 util/test/tests/D3D12/D3D12_Vertex_UAV.py diff --git a/renderdoc/data/hlsl/hlsl_cbuffers.h b/renderdoc/data/hlsl/hlsl_cbuffers.h index 860190f79..dab094d32 100644 --- a/renderdoc/data/hlsl/hlsl_cbuffers.h +++ b/renderdoc/data/hlsl/hlsl_cbuffers.h @@ -259,6 +259,10 @@ cbuffer DebugSampleOperation REG(b0) #define FLT_EPSILON 1.192092896e-07f #endif +// we pick a space that hopefully no-one else will use +// must match the define in quadoverdraw.hlsl +#define QUADOVERDRAW_UAV_SPACE 105202922 + // histogram/minmax is calculated in blocks of NxN each with MxM tiles. // e.g. a tile is 32x32 pixels, then this is arranged in blocks of 32x32 tiles. // 1 compute thread = 1 tile, 1 compute group = 1 block diff --git a/renderdoc/data/hlsl/quadoverdraw.hlsl b/renderdoc/data/hlsl/quadoverdraw.hlsl index fbedd682e..2cf9511d2 100644 --- a/renderdoc/data/hlsl/quadoverdraw.hlsl +++ b/renderdoc/data/hlsl/quadoverdraw.hlsl @@ -29,7 +29,17 @@ // https://github.com/selfshadow/demos/blob/master/QuadShading/QuadShading.fx //////////////////////////////////////////////////////////////////////////////////////////// +#if !defined(UAV_SPACE) && defined(D3D12) +// must match the define in hlsl_cbuffers.h +#define UAV_SPACE space105202922 +#endif + +#if defined(D3D12) +RWTexture2DArray overdrawUAV : register(u0, UAV_SPACE); +#else RWTexture2DArray overdrawUAV : register(u0); +#endif + Texture2DArray overdrawSRV : register(t0); [earlydepthstencil] void RENDERDOC_QuadOverdrawPS(float4 vpos diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index 00943df71..fbf09a7dd 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -1949,8 +1949,10 @@ void D3D12Replay::OverlayRendering::Init(WrappedID3D12Device *device, D3D12Debug rdcstr hlsl = GetEmbeddedResource(quadoverdraw_hlsl); + hlsl = "#define D3D12 1\n\n" + hlsl; + shaderCache->GetShaderBlob(hlsl.c_str(), "RENDERDOC_QuadOverdrawPS", - D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_5_0", &QuadOverdrawWritePS); + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_5_1", &QuadOverdrawWritePS); // only create DXIL shaders if DXIL was used by the application, since dxc/dxcompiler is really // flakey. @@ -2480,15 +2482,17 @@ void D3D12Replay::HistogramMinMax::Release() SAFE_RELEASE(MinMaxTileBuffer); } -void MoveRootSignatureElementsToRegisterSpace(D3D12RootSignature &sig, uint32_t registerSpace, - D3D12DescriptorType type, - D3D12_SHADER_VISIBILITY visibility) +uint32_t GetFreeRegSpace(const D3D12RootSignature &sig, const uint32_t registerSpace, + D3D12DescriptorType type, D3D12_SHADER_VISIBILITY visibility) { // This function is used when root signature elements need to be added to a specific register // space, such as for debug overlays. We can't remove elements from the root signature entirely - // because then then the root signature indices wouldn't match up as expected. Instead move them - // into the specified register space so that another register space (commonly space0) can be used - // for other purposes. + // because then then the root signature indices wouldn't match up as expected. Instead we see if a + // given desired register space is unused (which can be referenced in pre-compiled shaders), and + // if not return an unused space for use instead. + uint32_t maxSpace = 0; + bool usedDesiredSpace = false; + size_t numParams = sig.Parameters.size(); for(size_t i = 0; i < numParams; i++) { @@ -2504,32 +2508,43 @@ void MoveRootSignatureElementsToRegisterSpace(D3D12RootSignature &sig, uint32_t D3D12_DESCRIPTOR_RANGE_TYPE rangeType = sig.Parameters[i].ranges[r].RangeType; if(rangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV && type == D3D12DescriptorType::CBV) { - sig.Parameters[i].ranges[r].RegisterSpace += registerSpace; + maxSpace = RDCMAX(maxSpace, sig.Parameters[i].ranges[r].RegisterSpace); + usedDesiredSpace |= (sig.Parameters[i].ranges[r].RegisterSpace == registerSpace); } else if(rangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV && type == D3D12DescriptorType::SRV) { - sig.Parameters[i].ranges[r].RegisterSpace += registerSpace; + maxSpace = RDCMAX(maxSpace, sig.Parameters[i].ranges[r].RegisterSpace); + usedDesiredSpace |= (sig.Parameters[i].ranges[r].RegisterSpace == registerSpace); } else if(rangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV && type == D3D12DescriptorType::UAV) { - sig.Parameters[i].ranges[r].RegisterSpace += registerSpace; + maxSpace = RDCMAX(maxSpace, sig.Parameters[i].ranges[r].RegisterSpace); + usedDesiredSpace |= (sig.Parameters[i].ranges[r].RegisterSpace == registerSpace); } } } else if(rootType == D3D12_ROOT_PARAMETER_TYPE_CBV && type == D3D12DescriptorType::CBV) { - sig.Parameters[i].Descriptor.RegisterSpace += registerSpace; + maxSpace = RDCMAX(maxSpace, sig.Parameters[i].Descriptor.RegisterSpace); + usedDesiredSpace |= (sig.Parameters[i].Descriptor.RegisterSpace == registerSpace); } else if(rootType == D3D12_ROOT_PARAMETER_TYPE_SRV && type == D3D12DescriptorType::SRV) { - sig.Parameters[i].Descriptor.RegisterSpace += registerSpace; + maxSpace = RDCMAX(maxSpace, sig.Parameters[i].Descriptor.RegisterSpace); + usedDesiredSpace |= (sig.Parameters[i].Descriptor.RegisterSpace == registerSpace); } else if(rootType == D3D12_ROOT_PARAMETER_TYPE_UAV && type == D3D12DescriptorType::UAV) { - sig.Parameters[i].Descriptor.RegisterSpace += registerSpace; + maxSpace = RDCMAX(maxSpace, sig.Parameters[i].Descriptor.RegisterSpace); + usedDesiredSpace |= (sig.Parameters[i].Descriptor.RegisterSpace == registerSpace); } } } + + if(usedDesiredSpace) + return maxSpace + 1; + + return registerSpace; } void AddDebugDescriptorsToRenderState(WrappedID3D12Device *pDevice, D3D12RenderState &rs, diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 2427ae477..c63ea4b95 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -253,9 +253,8 @@ private: rdcarray m_DiscardBuffers; }; -void MoveRootSignatureElementsToRegisterSpace(D3D12RootSignature &sig, uint32_t registerSpace, - D3D12DescriptorType type, - D3D12_SHADER_VISIBILITY visibility); +uint32_t GetFreeRegSpace(const D3D12RootSignature &sig, const uint32_t registerSpace, + D3D12DescriptorType type, D3D12_SHADER_VISIBILITY visibility); void AddDebugDescriptorsToRenderState(WrappedID3D12Device *pDevice, D3D12RenderState &rs, const rdcarray &handles, diff --git a/renderdoc/driver/d3d12/d3d12_overlay.cpp b/renderdoc/driver/d3d12/d3d12_overlay.cpp index 8ee0c68dc..c5c9257ce 100644 --- a/renderdoc/driver/d3d12/d3d12_overlay.cpp +++ b/renderdoc/driver/d3d12/d3d12_overlay.cpp @@ -87,15 +87,20 @@ struct D3D12QuadOverdrawCallback : public D3D12ActionCallback D3D12RootSignature modsig = sig->sig; - UINT regSpace = modsig.maxSpaceIndex + 1; - MoveRootSignatureElementsToRegisterSpace(modsig, regSpace, D3D12DescriptorType::UAV, - D3D12_SHADER_VISIBILITY_PIXEL); + uint32_t regSpace = GetFreeRegSpace(modsig, QUADOVERDRAW_UAV_SPACE, D3D12DescriptorType::UAV, + D3D12_SHADER_VISIBILITY_PIXEL); + + if(regSpace != QUADOVERDRAW_UAV_SPACE) + { + RDCLOG("Register space %u wasn't available for use, recompiling shaders", + QUADOVERDRAW_UAV_SPACE); + } D3D12_DESCRIPTOR_RANGE1 range; range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; range.NumDescriptors = 1; range.BaseShaderRegister = 0; - range.RegisterSpace = 0; + range.RegisterSpace = regSpace; range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; range.OffsetInDescriptorsFromTableStart = 0; @@ -147,7 +152,7 @@ struct D3D12QuadOverdrawCallback : public D3D12ActionCallback // dxil is stricter about pipeline signatures matching. On D3D11 there's an error but all // drivers handle a PS that reads no VS outputs and only screenspace SV_Position and // SV_Coverage. On D3D12 we need to patch to generate a new PS - m_pDevice->GetReplay()->PatchQuadWritePS(pipeDesc, dxil); + m_pDevice->GetReplay()->PatchQuadWritePS(pipeDesc, regSpace, dxil); if(pipeDesc.PS.BytecodeLength == 0) { m_pDevice->AddDebugMessage( @@ -296,13 +301,35 @@ static void SetRTVDesc(D3D12_RENDER_TARGET_VIEW_DESC &rtDesc, const D3D12_RESOUR } } -void D3D12Replay::PatchQuadWritePS(D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &pipeDesc, bool dxil) +void D3D12Replay::PatchQuadWritePS(D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &pipeDesc, + uint32_t regSpace, bool dxil) { pipeDesc.PS.pShaderBytecode = NULL; pipeDesc.PS.BytecodeLength = 0; ID3DBlob *quadWriteBlob = dxil ? m_Overlay.QuadOverdrawWriteDXILPS : m_Overlay.QuadOverdrawWritePS; + if(regSpace != QUADOVERDRAW_UAV_SPACE) + { + rdcstr hlsl = GetEmbeddedResource(quadoverdraw_hlsl); + + hlsl = + "#define D3D12 1\n\n" + StringFormat::Fmt("#define UAV_SPACE space%u\n\n", regSpace) + hlsl; + + if(dxil) + { + m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_QuadOverdrawPS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_6_0", + &quadWriteBlob); + } + else + { + m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_QuadOverdrawPS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_5_1", + &quadWriteBlob); + } + } + if(!quadWriteBlob) { RDCERR("Compiled quad overdraw write %s blob isn't available", dxil ? "DXIL" : "DXBC"); diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index b78088882..6aa8b6751 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -256,7 +256,8 @@ public: bool IsRenderOutput(ResourceId id) { return GetRenderOutputSubresource(id).mip != ~0U; } void FileChanged() {} AMDCounters *GetAMDCounters() { return m_pAMDCounters; } - void PatchQuadWritePS(D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &pipeDesc, bool dxil); + void PatchQuadWritePS(D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &pipeDesc, uint32_t regSpace, + bool dxil); private: void FillRootElements(uint32_t eventId, const D3D12RenderState::RootSignature &rootSig, diff --git a/renderdoc/driver/d3d12/d3d12_shader_cache.cpp b/renderdoc/driver/d3d12/d3d12_shader_cache.cpp index bc2bb1fe8..9a7c992b7 100644 --- a/renderdoc/driver/d3d12/d3d12_shader_cache.cpp +++ b/renderdoc/driver/d3d12/d3d12_shader_cache.cpp @@ -517,7 +517,7 @@ rdcstr D3D12ShaderCache::GetShaderBlob(const char *source, const char *entry, } } - if(m_CacheShaders) + if(m_CacheShaders && byteBlob) { m_ShaderCache[hash] = byteBlob; byteBlob->AddRef(); diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index dc2a7a96c..bbf98970b 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -2055,14 +2055,25 @@ struct PSInitialData )"; + WrappedID3D12RootSignature *sig = + m_pDevice->GetResourceManager()->GetCurrentAs(rs.graphics.rootsig); + + // Need to be able to add a descriptor table with our UAV without hitting the 64 DWORD limit + RDCASSERT(sig->sig.dwordLength < 64); + D3D12RootSignature modsig = sig->sig; + + UINT regSpace = GetFreeRegSpace(modsig, 0, D3D12DescriptorType::UAV, D3D12_SHADER_VISIBILITY_PIXEL); + // If this event uses MSAA, then at least one render target must be preserved to get // multisampling info. leave u0 alone and start with register u1 - extractHlsl += "RWStructuredBuffer PSInitialBuffer : register(u1);\n\n"; + extractHlsl += StringFormat::Fmt( + "RWStructuredBuffer PSInitialBuffer : register(u1, space%u);\n\n", regSpace); if(!evalSampleCacheData.empty()) { // float4 is wasteful in some cases but it's easier than using byte buffers and manual packing - extractHlsl += "RWBuffer PSEvalBuffer : register(u2);\n\n"; + extractHlsl += + StringFormat::Fmt("RWBuffer PSEvalBuffer : register(u2, space%u);\n\n", regSpace); } if(usePrimitiveID) @@ -2188,7 +2199,7 @@ void ExtractInputsPS(PSInput IN, ID3DBlob *psBlob = NULL; UINT flags = D3DCOMPILE_WARNINGS_ARE_ERRORS; if(m_pDevice->GetShaderCache()->GetShaderBlob(extractHlsl.c_str(), "ExtractInputsPS", flags, {}, - "ps_5_0", &psBlob) != "") + "ps_5_1", &psBlob) != "") { RDCERR("Failed to create shader to extract inputs"); return new ShaderDebugTrace; @@ -2293,23 +2304,12 @@ void ExtractInputsPS(PSInput IN, m_pDevice->CreateUnorderedAccessView(pMsaaEvalBuffer, NULL, &uavDesc, msaaClearUav); } - WrappedID3D12RootSignature *sig = - m_pDevice->GetResourceManager()->GetCurrentAs(rs.graphics.rootsig); - - // Need to be able to add a descriptor table with our UAV without hitting the 64 DWORD limit - RDCASSERT(sig->sig.dwordLength < 64); - D3D12RootSignature modsig = sig->sig; - - UINT regSpace = modsig.maxSpaceIndex + 1; - MoveRootSignatureElementsToRegisterSpace(modsig, regSpace, D3D12DescriptorType::UAV, - D3D12_SHADER_VISIBILITY_PIXEL); - // Create the descriptor table for our UAV D3D12_DESCRIPTOR_RANGE1 descRange; descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; descRange.NumDescriptors = pMsaaEvalBuffer ? 2 : 1; descRange.BaseShaderRegister = 1; - descRange.RegisterSpace = 0; + descRange.RegisterSpace = regSpace; descRange.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; descRange.OffsetInDescriptorsFromTableStart = 0; diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 00f5843f6..ce4a4fecb 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -820,7 +820,7 @@ namespace DXCEnumerateAndCheck { - + diff --git a/util/test/demos/d3d12/d3d12_vertex_uav.cpp b/util/test/demos/d3d12/d3d12_vertex_uav.cpp new file mode 100644 index 000000000..0f990917d --- /dev/null +++ b/util/test/demos/d3d12/d3d12_vertex_uav.cpp @@ -0,0 +1,181 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "d3d12_test.h" + +RD_TEST(D3D12_Vertex_UAV, D3D12GraphicsTest) +{ + static constexpr const char *Description = + "Runs some tests with a vertex shader visible UAV to test that root signature patching for " + "any PS UAVs works correctly"; + + std::string vertex = R"EOSHADER( + +#ifndef SPACE +#define SPACE space0 +#endif + +#if SM >= 51 +RWByteAddressBuffer testUAV : register(u0, SPACE); +RWByteAddressBuffer testUAV2 : register(u1, SPACE); +#else +RWByteAddressBuffer testUAV : register(u0); +RWByteAddressBuffer testUAV2 : register(u1); +#endif + +struct v2f +{ + float4 pos : SV_POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +v2f main(uint vid : SV_VertexID) +{ + float2 positions[] = { + float2(-1.0f, 1.0f), + float2( 1.0f, 1.0f), + float2(-1.0f, -1.0f), + float2( 1.0f, -1.0f), + }; + + float a = asfloat(testUAV.Load(16)); + float b = asfloat(testUAV2.Load(16)); + + v2f ret; + ret.pos = float4(positions[vid] * float2(a, b), 0, 1); + ret.col = float4(a, b, 0, 1); + ret.uv = float2(a, b); + return ret; +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + ID3D12ResourcePtr vb = MakeBuffer().Data(DefaultTri); + + ID3D12RootSignaturePtr sig = MakeSig({ + uavParam(D3D12_SHADER_VISIBILITY_ALL, 0, 0), uavParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 1), + }); + + // 105202922 is the magic space renderdoc tries to use to avoid collisions + ID3D12RootSignaturePtr collidesig = MakeSig({ + uavParam(D3D12_SHADER_VISIBILITY_ALL, 105202922, 0), + uavParam(D3D12_SHADER_VISIBILITY_VERTEX, 105202922, 1), + }); + + ID3D12PipelineStatePtr pso[3]; + ID3D12PipelineStatePtr collidepso[3]; + + std::string smstring[] = {"5_0", "5_1", "6_0"}; + int smval[] = {50, 51, 60}; + for(int i = 0; i < 3; i++) + { + if(smval[i] == 60 && !m_DXILSupport) + continue; + + std::string sm = smstring[i]; + + std::string header = "#define SM " + std::to_string(smval[i]) + "\n\n"; + ID3DBlobPtr vsblob = Compile(header + vertex, "main", "vs_" + sm); + header += "#define SPACE space105202922\n\n"; + ID3DBlobPtr collidevsblob = Compile(header + vertex, "main", "vs_" + sm); + ID3DBlobPtr psblob = Compile(D3DDefaultPixel, "main", "ps_" + sm); + + pso[i] = MakePSO().RootSig(sig).InputLayout().VS(vsblob).PS(psblob); + + if(smval[i] >= 51) + collidepso[i] = MakePSO().RootSig(collidesig).InputLayout().VS(collidevsblob).PS(psblob); + } + + ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + + ID3D12ResourcePtr uav = MakeBuffer().Data(DefaultTri).UAV(); + + ResourceBarrier(uav, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + while(Running()) + { + ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); + + Reset(cmd); + + ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + D3D12_CPU_DESCRIPTOR_HANDLE rtv = + MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0); + + ClearRenderTargetView(cmd, rtv, {0.2f, 0.2f, 0.2f, 1.0f}); + + cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + IASetVertexBuffer(cmd, vb, sizeof(DefaultA2V), 0); + + RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f}); + RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight}); + + OMSetRenderTargets(cmd, {rtv}, {}); + + for(int i = 0; i < 3; i++) + { + if(pso[i] == NULL) + continue; + + setMarker(cmd, "Normal_" + smstring[i]); + cmd->SetPipelineState(pso[i]); + cmd->SetGraphicsRootSignature(sig); + cmd->SetGraphicsRootUnorderedAccessView(0, uav->GetGPUVirtualAddress()); + cmd->SetGraphicsRootUnorderedAccessView(1, uav->GetGPUVirtualAddress()); + cmd->DrawInstanced(3, 1, 0, 0); + + if(collidepso[i] == NULL) + continue; + + setMarker(cmd, "Collide_" + smstring[i]); + cmd->SetPipelineState(collidepso[i]); + cmd->SetGraphicsRootSignature(collidesig); + cmd->SetGraphicsRootUnorderedAccessView(0, uav->GetGPUVirtualAddress()); + cmd->SetGraphicsRootUnorderedAccessView(1, uav->GetGPUVirtualAddress()); + cmd->DrawInstanced(3, 1, 0, 0); + } + + FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + cmd->Close(); + + Submit({cmd}); + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/tests/D3D12/D3D12_Vertex_UAV.py b/util/test/tests/D3D12/D3D12_Vertex_UAV.py new file mode 100644 index 000000000..bbc52dbb2 --- /dev/null +++ b/util/test/tests/D3D12/D3D12_Vertex_UAV.py @@ -0,0 +1,74 @@ +import rdtest +import renderdoc as rd + + +class D3D12_Vertex_UAV(rdtest.TestCase): + demos_test_name = 'D3D12_Vertex_UAV' + + def check_capture(self): + out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) + + quad_seen = [] + + for pass_name in ["Normal", "Collide"]: + for base_event_name in ["5_0", "5_1", "6_0"]: + name = pass_name + "_" + base_event_name + marker = self.find_action(name) + + if marker is None: + continue + + rdtest.log.print("Checking quad overdraw on {}".format(name)) + + self.controller.SetFrameEvent(marker.next.eventId, True) + + pipe: rd.PipeState = self.controller.GetPipelineState() + + tex = rd.TextureDisplay() + tex.resourceId = pipe.GetOutputTargets()[0].resourceId + + tex.overlay = rd.DebugOverlay.QuadOverdrawPass + out.SetTextureDisplay(tex) + + out.Display() + + overlay_id: rd.ResourceId = out.GetDebugOverlayTexID() + + picked = self.controller.PickPixel(overlay_id, 5, 5, rd.Subresource(0,0,0), rd.CompType.Float).floatValue + + if any([p != picked[0] for p in picked]): + raise rdtest.TestFailureException("Quad overdraw isn't correct: {}".format(picked)) + + quad_seen.append(picked[0]) + + rdtest.log.success("Quad overdraw is good on {}".format(name)) + + if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable: + rdtest.log.print("Skipping undebuggable shader.") + continue + + # Debug the shader + trace = self.controller.DebugPixel(50, 50, rd.ReplayController.NoPreference, + rd.ReplayController.NoPreference) + if trace.debugger is None: + raise rdtest.TestFailureException("Pixel shader at {} could not be debugged.".format(name)) + self.controller.FreeTrace(trace) + + cycles, variables = self.process_trace(trace) + + output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0) + + debugged = self.evaluate_source_var(output, variables) + + self.controller.FreeTrace(trace) + + if not rdtest.value_compare(debugged.value.f32v[0:4], [1.0, 1.0, 0.0, 1.0]): + raise rdtest.TestFailureException("Pixel shader at {} did not debug correctly.".format(name)) + + rdtest.log.success("Shader debugging at {} was successful".format(name)) + + quad_seen = sorted(quad_seen) + if quad_seen != [float(a) for a in range(1, len(quad_seen) + 1)]: + raise rdtest.TestFailureException("Quad overdraw values are inconsistent: {}".format(quad_seen)) + + out.Shutdown()