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()