diff --git a/util/test/demos/d3d12/d3d12_reflection_zoo.cpp b/util/test/demos/d3d12/d3d12_reflection_zoo.cpp index 017a884331..2f2c69101a 100644 --- a/util/test/demos/d3d12/d3d12_reflection_zoo.cpp +++ b/util/test/demos/d3d12/d3d12_reflection_zoo.cpp @@ -133,6 +133,42 @@ AppendStructuredBuffer rwappend : register(u52); ConsumeStructuredBuffer rwconsume : register(u53); RWStructuredBuffer rwstrbuf_f2 : register(u54); +#if SM67 +struct sm67_struct +{ + // ensure bitfield byte offsets are calculated properly by not starting at offset 0 + float x; + + uint a : 10; + uint b : 10; + uint c : 10; + uint d : 2; + + // calculate packing properly after a complete bitfield + float3 e; + + uint f : 14; + // similarly, packing properly after an incomplete bitfield + float3 g; + + // calculate bitfield rollover properly + uint h : 10; + uint i : 10; + uint j : 10; + uint k : 10; + uint l : 10; + + float m; + + // empty padding in bitfields and mixed types + uint n : 5; + uint : 5; + int o : 5; +}; + +RWStructuredBuffer rwstrbuf67 : register(u55); +#endif + float4 main(float4 pos : SV_Position) : SV_Target0 { float4 ret = float4(0,0,0,0); @@ -200,6 +236,11 @@ float4 main(float4 pos : SV_Position) : SV_Target0 #if ROV rov[pos.xy] = sqrt(rov[pos.xy]) + ret; #endif + +#if SM67 + sm67_struct dummy67 = (sm67_struct)0; + rwstrbuf67[indices.x] = dummy67; +#endif rwbytebuf.Store4(indices.y, asuint(ret)); @@ -234,7 +275,7 @@ float4 main(float4 pos : SV_Position) : SV_Target0 ID3DBlobPtr vs5blob = Compile(D3DFullscreenQuadVertex, "main", "vs_5_0"); ID3DBlobPtr vs6blob = m_DXILSupport ? Compile(D3DFullscreenQuadVertex, "main", "vs_6_0") : NULL; - ID3D12PipelineStatePtr dxbc, dxil; + ID3D12PipelineStatePtr dxbc, sm60, sm67; D3D12_STATIC_SAMPLER_DESC samp = { D3D12_FILTER_MIN_MAG_MIP_POINT, @@ -272,14 +313,20 @@ float4 main(float4 pos : SV_Position) : SV_Target0 D3D12PSOCreator creator = MakePSO().RootSig(sig).RTVs({DXGI_FORMAT_R8G8B8A8_UNORM_SRGB}).VS(vs5blob); - respixel = fmt::format("#define ROV {0}\n\n{1}", opts.ROVsSupported ? 1 : 0, respixel); + respixel = fmt::format("#define ROV {0}\n\n{1}\n", opts.ROVsSupported ? 1 : 0, respixel); ID3DBlobPtr dxbcBlob = Compile(respixel, "main", "ps_5_1"); dxbc = creator.VS(vs5blob).PS(dxbcBlob); if(m_DXILSupport) { - ID3DBlobPtr dxilBlob = Compile(respixel, "main", "ps_6_0"); - dxil = creator.VS(vs6blob).PS(dxilBlob); + ID3DBlobPtr sm60Blob = Compile(respixel, "main", "ps_6_0"); + sm60 = creator.VS(vs6blob).PS(sm60Blob); + + if(m_HighestShaderModel >= D3D_SHADER_MODEL_6_7) + { + ID3DBlobPtr sm67Blob = Compile("#define SM67 1\n" + respixel, "main", "ps_6_7"); + sm67 = creator.VS(vs6blob).PS(sm67Blob); + } } D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; @@ -575,6 +622,14 @@ float4 main(float4 pos : SV_Position) : SV_Target0 uavDesc.Buffer.StructureByteStride = 8; dev->CreateUnorderedAccessView(NULL, NULL, &uavDesc, cur); + cur.ptr = start.ptr + (200 + 55) * increment; + uavDesc.Buffer.StructureByteStride = 52; + dev->CreateUnorderedAccessView(NULL, NULL, &uavDesc, cur); + + cur.ptr = start.ptr + (200 + 56) * increment; + uavDesc.Buffer.StructureByteStride = 52; + dev->CreateUnorderedAccessView(NULL, NULL, &uavDesc, cur); + while(Running()) { ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); @@ -605,10 +660,17 @@ float4 main(float4 pos : SV_Position) : SV_Target0 cmd->SetPipelineState(dxbc); cmd->DrawInstanced(3, 1, 0, 0); - if(m_DXILSupport) + if(sm60) + { + setMarker(cmd, "SM6.0"); + cmd->SetPipelineState(sm60); + cmd->DrawInstanced(3, 1, 0, 0); + } + + if(sm67) { - setMarker(cmd, "DXIL"); - cmd->SetPipelineState(dxil); + setMarker(cmd, "SM6.7"); + cmd->SetPipelineState(sm67); cmd->DrawInstanced(3, 1, 0, 0); } diff --git a/util/test/demos/d3d12/d3d12_test.cpp b/util/test/demos/d3d12/d3d12_test.cpp index f9a66b0297..def069a261 100644 --- a/util/test/demos/d3d12/d3d12_test.cpp +++ b/util/test/demos/d3d12/d3d12_test.cpp @@ -400,7 +400,7 @@ void D3D12GraphicsTest::Prepare(int argc, char **argv) tmpdev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &opts6, sizeof(opts6)); tmpdev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &opts7, sizeof(opts7)); D3D12_FEATURE_DATA_SHADER_MODEL oShaderModel = {}; - oShaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_6; + oShaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_7; HRESULT hr = tmpdev->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &oShaderModel, sizeof(oShaderModel)); if(SUCCEEDED(hr)) diff --git a/util/test/tests/D3D12/D3D12_Reflection_Zoo.py b/util/test/tests/D3D12/D3D12_Reflection_Zoo.py index fbf1733661..b2cee7432c 100644 --- a/util/test/tests/D3D12/D3D12_Reflection_Zoo.py +++ b/util/test/tests/D3D12/D3D12_Reflection_Zoo.py @@ -27,10 +27,10 @@ def check_capture(self): rdtest.log.success("DXBC action is as expected") # Move to the DXIL action - action = self.find_action("DXIL") + action = self.find_action("SM6.0") if action is None: - rdtest.log.print("No DXIL action to test") + rdtest.log.print("No SM6.0 DXIL action to test") return self.controller.SetFrameEvent(action.next.eventId, False) @@ -44,7 +44,27 @@ def check_capture(self): self.check_event() - rdtest.log.success("DXIL action is as expected") + rdtest.log.success("SM6.0 DXIL action is as expected") + + # Move to the DXIL action + action = self.find_action("SM6.7") + + if action is None: + rdtest.log.print("No SM6.7 DXIL action to test") + return + + self.controller.SetFrameEvent(action.next.eventId, False) + + pipe: rd.PipeState = self.controller.GetPipelineState() + + disasm = self.controller.DisassembleShader(pipe.GetGraphicsPipelineObject(), pipe.GetShaderReflection(stage), + '') + + self.check('SM6.7' in disasm) + + self.check_event() + + rdtest.log.success("SM6.7 DXIL action is as expected") def check_event(self): pipe: rd.PipeState = self.controller.GetPipelineState() @@ -89,21 +109,122 @@ def buf_struct_check(type: rd.ShaderConstantType): self.check(type.members[0].type.rows == 1) self.check(type.members[0].type.columns == 1) self.check(type.members[0].type.elements == 1) + self.check(type.members[0].byteOffset == 0) + self.check(type.members[0].bitFieldOffset == 0) + self.check(type.members[0].bitFieldSize == 0) self.check(type.members[1].name == 'b') self.check(type.members[1].type.baseType == rd.VarType.Float) self.check(type.members[1].type.rows == 1) self.check(type.members[1].type.columns == 1) self.check(type.members[1].type.elements == 2) + self.check(type.members[1].byteOffset == 4) + self.check(type.members[1].bitFieldOffset == 0) + self.check(type.members[1].bitFieldSize == 0) self.check(type.members[2].name == 'c') self.check(type.members[2].type.name == 'nested') + self.check(type.members[2].byteOffset == 12) + self.check(type.members[2].bitFieldOffset == 0) + self.check(type.members[2].bitFieldSize == 0) self.check(len(type.members[2].type.members) == 1) self.check(type.members[2].type.members[0].name == 'x') self.check(type.members[2].type.members[0].type.baseType == rd.VarType.Float) self.check(type.members[2].type.members[0].type.rows == 2) self.check(type.members[2].type.members[0].type.columns == 3) self.check(type.members[2].type.members[0].type.RowMajor()) + self.check(type.members[2].type.members[0].byteOffset == 0) + self.check(type.members[2].type.members[0].bitFieldOffset == 0) + self.check(type.members[2].type.members[0].bitFieldSize == 0) + + return + + def sm67_struct_check(type: rd.ShaderConstantType): + self.check(type.name == 'sm67_struct') + self.check(len(type.members) == 17) + + # to simplify checks we only look at offsets and bitfield properties, + # assuming the base types are the same (except for deliberate int + # check_eqs on some bitfields) + self.check_eq(type.members[0].name, 'x') + self.check_eq(type.members[0].byteOffset, 0) + + self.check_eq(type.members[1].name, 'a') + self.check_eq(type.members[1].byteOffset, 4) + self.check_eq(type.members[1].bitFieldOffset, 0) + self.check_eq(type.members[1].bitFieldSize, 10) + + self.check_eq(type.members[2].name, 'b') + self.check_eq(type.members[2].byteOffset, 4) + self.check_eq(type.members[2].bitFieldOffset, 10) + self.check_eq(type.members[2].bitFieldSize, 10) + + self.check_eq(type.members[3].name, 'c') + self.check_eq(type.members[3].byteOffset, 4) + self.check_eq(type.members[3].bitFieldOffset, 20) + self.check_eq(type.members[3].bitFieldSize, 10) + + self.check_eq(type.members[4].name, 'd') + self.check_eq(type.members[4].byteOffset, 4) + self.check_eq(type.members[4].bitFieldOffset, 30) + self.check_eq(type.members[4].bitFieldSize, 2) + + self.check_eq(type.members[5].name, 'e') + self.check_eq(type.members[5].byteOffset, 8) + + self.check_eq(type.members[6].name, 'f') + self.check_eq(type.members[6].byteOffset, 20) + self.check_eq(type.members[6].bitFieldOffset, 0) + self.check_eq(type.members[6].bitFieldSize, 14) + + self.check_eq(type.members[7].name, 'g') + self.check_eq(type.members[7].byteOffset, 24) + + self.check_eq(type.members[8].name, 'h') + self.check_eq(type.members[8].byteOffset, 36) + self.check_eq(type.members[8].bitFieldOffset, 0) + self.check_eq(type.members[8].bitFieldSize, 10) + + self.check_eq(type.members[9].name, 'i') + self.check_eq(type.members[9].byteOffset, 36) + self.check_eq(type.members[9].bitFieldOffset, 10) + self.check_eq(type.members[9].bitFieldSize, 10) + + self.check_eq(type.members[10].name, 'j') + self.check_eq(type.members[10].byteOffset, 36) + self.check_eq(type.members[10].bitFieldOffset, 20) + self.check_eq(type.members[10].bitFieldSize, 10) + + self.check_eq(type.members[11].name, 'k') + self.check_eq(type.members[11].byteOffset, 40) + self.check_eq(type.members[11].bitFieldOffset, 0) + self.check_eq(type.members[11].bitFieldSize, 10) + + self.check_eq(type.members[12].name, 'l') + self.check_eq(type.members[12].byteOffset, 40) + self.check_eq(type.members[12].bitFieldOffset, 10) + self.check_eq(type.members[12].bitFieldSize, 10) + + self.check_eq(type.members[13].name, 'm') + self.check_eq(type.members[13].byteOffset, 44) + + self.check_eq(type.members[14].name, 'n') + self.check_eq(type.members[14].type.baseType, rd.VarType.UInt) + self.check_eq(type.members[14].byteOffset, 48) + self.check_eq(type.members[14].bitFieldOffset, 0) + self.check_eq(type.members[14].bitFieldSize, 5) + + self.check_eq(type.members[15].name, '') + self.check_eq(type.members[15].type.baseType, rd.VarType.UInt) + self.check_eq(type.members[15].byteOffset, 48) + self.check_eq(type.members[15].bitFieldOffset, 5) + self.check_eq(type.members[15].bitFieldSize, 5) + + self.check_eq(type.members[16].name, 'o') + self.check_eq(type.members[16].type.baseType, rd.VarType.SInt) + self.check_eq(type.members[16].byteOffset, 48) + self.check_eq(type.members[16].bitFieldOffset, 10) + self.check_eq(type.members[16].bitFieldSize, 5) return @@ -249,12 +370,24 @@ def buf_struct_check(type: rd.ShaderConstantType): structVarCheck=buf_struct_check), 'rwstrbuf_f2': checker(rd.TextureType.Buffer, rd.VarType.Float, 2, 54, 'float2', isTexture=False), + 'rwstrbuf67': + checker(rd.TextureType.Buffer, + rd.VarType.Unknown, + 0, + 55, + 'sm67_struct', + isTexture=False, + structVarCheck=sm67_struct_check), } # ROVs are optional, if it wasn't found then ignore that if '#define ROV 0' in debugInfo.files[0].contents: del rw_db['rov'] + # only check SM6.7 structured buffer with bitfields on SM6.7 + if '#define SM67 1' not in debugInfo.files[0].contents: + del rw_db['rwstrbuf67'] + access = [(a.type, a.index) for a in self.controller.GetDescriptorAccess()] for idx, s in enumerate(refl.samplers): @@ -295,7 +428,7 @@ def buf_struct_check(type: rd.ShaderConstantType): self.check(res.fixedBindNumber == check['register']) self.check(res.bindArraySize == check['regCount']) else: - raise rdtest.TestFailureException('Unrecognised read-only resource {}'.format(res.name)) + raise rdtest.TestFailureException(f"Unrecognised {'read-only' if res_readonly else 'read-write'} resource {res.name}") del res_db[res.name]