Skip to content

Commit

Permalink
Add test of SM6.7 bitfield reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
baldurk committed Jan 7, 2025
1 parent 2d86fe6 commit 980b6a8
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 12 deletions.
76 changes: 69 additions & 7 deletions util/test/demos/d3d12/d3d12_reflection_zoo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,42 @@ AppendStructuredBuffer<buf_struct> rwappend : register(u52);
ConsumeStructuredBuffer<buf_struct> rwconsume : register(u53);
RWStructuredBuffer<float2> 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<sm67_struct> rwstrbuf67 : register(u55);
#endif
float4 main(float4 pos : SV_Position) : SV_Target0
{
float4 ret = float4(0,0,0,0);
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 = {};
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion util/test/demos/d3d12/d3d12_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
141 changes: 137 additions & 4 deletions util/test/tests/D3D12/D3D12_Reflection_Zoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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]

Expand Down

0 comments on commit 980b6a8

Please sign in to comment.