mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-11-07 14:35:48 +00:00
Implement bindless feedback for samplers on D3D12. Closes #3387
This commit is contained in:
4 files changed
+125
-32
No files matched your search
@@ -112,7 +112,8 @@ static bool AnnotateDXBCShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
|
||||
|
||||
for(const Operand &operand : op.operands)
|
||||
{
|
||||
if(operand.type != TYPE_RESOURCE && operand.type != TYPE_UNORDERED_ACCESS_VIEW)
|
||||
if(operand.type != TYPE_RESOURCE && operand.type != TYPE_UNORDERED_ACCESS_VIEW &&
|
||||
operand.type != TYPE_SAMPLER)
|
||||
continue;
|
||||
|
||||
const Declaration *decl =
|
||||
@@ -187,9 +188,6 @@ static bool AnnotateDXBCShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
|
||||
// atomic or the slot
|
||||
editor.InsertOperation(
|
||||
i++, oper(OPCODE_ATOMIC_OR, {uav(u), temp(t).swizzle(0), imm(magicFeedbackValue)}));
|
||||
|
||||
// only one resource operand per instruction
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,10 +247,10 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
|
||||
Attribute::NoUnwind | Attribute::ReadNone);
|
||||
|
||||
// while we're iterating through the metadata to add our UAV, we'll also note the shader-local
|
||||
// register IDs of each SRV/UAV with slots, and record the base slot in this array for easy access
|
||||
// later when annotating dx.op.createHandle calls. We also need to know the base register because
|
||||
// the index dxc provides is register-relative
|
||||
rdcarray<rdcpair<uint32_t, uint32_t>> srvBaseSlots, uavBaseSlots;
|
||||
// register IDs of each SRV/UAV/Sampler with slots, and record the base slot in this array for
|
||||
// easy access later when annotating dx.op.createHandle calls. We also need to know the base
|
||||
// register because the index dxc provides is register-relative
|
||||
rdcarray<rdcpair<uint32_t, uint32_t>> srvBaseSlots, uavBaseSlots, sampBaseSlots;
|
||||
|
||||
// declare the resource, this happens purely in metadata but we need to store the slot
|
||||
uint32_t regSlot = 0;
|
||||
@@ -272,6 +270,7 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
|
||||
|
||||
Metadata *srvs = reslist->children[0];
|
||||
Metadata *uavs = reslist->children[1];
|
||||
Metadata *samps = reslist->children[3];
|
||||
// if there isn't a UAV list, create an empty one so we can add our own
|
||||
if(!uavs)
|
||||
uavs = reslist->children[1] = editor.CreateMetadata();
|
||||
@@ -329,6 +328,56 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
|
||||
srvBaseSlots[id] = {feedbackSlot, key.bind};
|
||||
}
|
||||
|
||||
key.type = DXBCBytecode::TYPE_SAMPLER;
|
||||
|
||||
for(size_t i = 0; samps && i < samps->children.size(); i++)
|
||||
{
|
||||
// each Sampler child should have a fixed format
|
||||
const Metadata *samp = samps->children[i];
|
||||
const Constant *slot = cast<Constant>(samp->children[(size_t)ResField::ID]->value);
|
||||
const Constant *sampSpace = cast<Constant>(samp->children[(size_t)ResField::Space]->value);
|
||||
const Constant *reg = cast<Constant>(samp->children[(size_t)ResField::RegBase]->value);
|
||||
|
||||
if(!slot)
|
||||
{
|
||||
RDCWARN("Unexpected non-constant slot ID in sampler");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!sampSpace)
|
||||
{
|
||||
RDCWARN("Unexpected non-constant register space in sampler");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!reg)
|
||||
{
|
||||
RDCWARN("Unexpected non-constant register base in sampler");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t id = slot->getU32();
|
||||
key.space = sampSpace->getU32();
|
||||
key.bind = reg->getU32();
|
||||
|
||||
// ensure every valid ID has an index, even if it's 0
|
||||
sampBaseSlots.resize_for_index(id);
|
||||
|
||||
auto it = slots.find(key);
|
||||
|
||||
// not annotated
|
||||
if(it == slots.end())
|
||||
continue;
|
||||
|
||||
uint32_t feedbackSlot = it->second.slot;
|
||||
|
||||
// we assume all feedback slots are non-zero, so that a 0 base slot can be used as an
|
||||
// identifier for 'this resource isn't annotated'
|
||||
RDCASSERT(feedbackSlot > 0);
|
||||
|
||||
sampBaseSlots[id] = {feedbackSlot, key.bind};
|
||||
}
|
||||
|
||||
key.type = DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW;
|
||||
|
||||
for(size_t i = 0; i < uavs->children.size(); i++)
|
||||
@@ -616,6 +665,8 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
|
||||
slotInfo = srvBaseSlots[id];
|
||||
else if(kind == HandleKind::UAV && id < uavBaseSlots.size())
|
||||
slotInfo = uavBaseSlots[id];
|
||||
else if(kind == HandleKind::Sampler && id < sampBaseSlots.size())
|
||||
slotInfo = sampBaseSlots[id];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -658,10 +709,14 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
|
||||
}
|
||||
|
||||
HandleKind kind = (HandleKind)kindArg->getU32();
|
||||
if(kind != HandleKind::SRV && kind != HandleKind::UAV)
|
||||
if(kind == HandleKind::SRV)
|
||||
key.type = DXBCBytecode::TYPE_RESOURCE;
|
||||
else if(kind == HandleKind::UAV)
|
||||
key.type = DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW;
|
||||
else if(kind == HandleKind::Sampler)
|
||||
key.type = DXBCBytecode::TYPE_SAMPLER;
|
||||
else
|
||||
continue;
|
||||
key.type = kind == HandleKind::UAV ? DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW
|
||||
: DXBCBytecode::TYPE_RESOURCE;
|
||||
key.space = spaceArg->getU32();
|
||||
key.bind = regArg->getU32();
|
||||
}
|
||||
@@ -942,6 +997,32 @@ static bool AddArraySlots(WrappedID3D12PipelineState::ShaderEntry *shad, uint32_
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < refl.samplers.size(); i++)
|
||||
{
|
||||
const ShaderSampler &s = refl.samplers[i];
|
||||
if(s.bindArraySize > 1)
|
||||
{
|
||||
D3D12FeedbackKey key;
|
||||
key.stage = refl.stage;
|
||||
key.type = DXBCBytecode::TYPE_SAMPLER;
|
||||
key.space = s.fixedBindSetOrSpace;
|
||||
key.bind = s.fixedBindNumber;
|
||||
|
||||
DescriptorAccess access;
|
||||
access.stage = refl.stage;
|
||||
access.type = DescriptorType::Sampler;
|
||||
access.index = i & 0xffff;
|
||||
// descriptor storage side will be calculated later when finalising this with the root
|
||||
// signature information.
|
||||
|
||||
slots[key].numDescriptors = RDCMIN(maxDescriptors, s.bindArraySize);
|
||||
slots[key].access = access;
|
||||
slots[key].slot = numSlots;
|
||||
numSlots += slots[key].numDescriptors;
|
||||
dynamicUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < refl.readWriteResources.size(); i++)
|
||||
{
|
||||
const ShaderResource &rw = refl.readWriteResources[i];
|
||||
@@ -1504,7 +1585,7 @@ bool D3D12Replay::FetchShaderFeedback(uint32_t eventId)
|
||||
D3D12_DESCRIPTOR_RANGE_TYPE rangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
if(IsConstantBlockDescriptor(access.type))
|
||||
rangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
|
||||
else if(IsConstantBlockDescriptor(access.type))
|
||||
else if(IsSamplerDescriptor(access.type))
|
||||
rangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
|
||||
else if(IsReadOnlyDescriptor(access.type))
|
||||
rangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
|
||||
@@ -90,6 +90,8 @@ Texture2D<float4> texArray1[32] : register(t0, space1);
|
||||
Texture2D<float4> texArray2[32] : register(t40, space1);
|
||||
Texture2D<float4> texArray3[32] : register(t80, space1);
|
||||
|
||||
SamplerState sArray1[32] : register(s0, space1);
|
||||
|
||||
struct alias1
|
||||
{
|
||||
float4 Color;
|
||||
@@ -126,9 +128,9 @@ float4 main(v2f IN) : SV_Target0
|
||||
|
||||
if(t.tex == 0)
|
||||
{
|
||||
ret *= texArray1[t.binding].SampleLevel(s, uv.xy, 0);
|
||||
ret *= texArray1[t.binding+1].SampleLevel(s, uv.xy, 0);
|
||||
ret *= texArray1[t.binding+2].SampleLevel(s, uv.xy, 0);
|
||||
ret *= texArray1[t.binding].SampleLevel(sArray1[t.binding], uv.xy, 0);
|
||||
ret *= texArray1[t.binding+1].SampleLevel(sArray1[t.binding+1], uv.xy, 0);
|
||||
ret *= texArray1[t.binding+2].SampleLevel(sArray1[t.binding+2], uv.xy, 0);
|
||||
}
|
||||
else if(t.tex == 1)
|
||||
{
|
||||
@@ -219,9 +221,9 @@ float4 main(v2f IN) : SV_Target0
|
||||
}
|
||||
else if(t.tex == 1)
|
||||
{
|
||||
SamplerState s1 = SamplerDescriptorHeap[4];
|
||||
SamplerState s2 = SamplerDescriptorHeap[5];
|
||||
SamplerState s3 = SamplerDescriptorHeap[6];
|
||||
SamplerState s1 = SamplerDescriptorHeap[19];
|
||||
SamplerState s2 = SamplerDescriptorHeap[20];
|
||||
SamplerState s3 = SamplerDescriptorHeap[21];
|
||||
Texture2D<float4> tex1 = ResourceDescriptorHeap[40+t.binding];
|
||||
Texture2D<float4> tex2 = ResourceDescriptorHeap[40+t.binding+10];
|
||||
ConstantBuffer<CBuffer> cbv = ResourceDescriptorHeap[9];
|
||||
@@ -232,7 +234,7 @@ float4 main(v2f IN) : SV_Target0
|
||||
}
|
||||
else if(t.tex == 2)
|
||||
{
|
||||
SamplerState s = SamplerDescriptorHeap[7];
|
||||
SamplerState s = SamplerDescriptorHeap[25];
|
||||
Texture2D<float4> tex = ResourceDescriptorHeap[80+t.binding];
|
||||
ret *= tex.SampleLevel(s, uv.xy, 0);
|
||||
}
|
||||
@@ -302,6 +304,7 @@ float4 main(v2f IN) : SV_Target0
|
||||
tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 0, 20, 0),
|
||||
tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 150, 0),
|
||||
tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 15, 32, 150),
|
||||
tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0, 32, 0),
|
||||
},
|
||||
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, 1, &staticSamp);
|
||||
ID3D12PipelineStatePtr graphicspso[4];
|
||||
@@ -479,7 +482,7 @@ float4 main(v2f IN) : SV_Target0
|
||||
D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
UINT increment = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE samplerStart = m_Sampler->GetCPUDescriptorHandleForHeapStart();
|
||||
for(int i = 0; i < 8; ++i)
|
||||
for(int i = 0; i < 128; ++i)
|
||||
dev->CreateSampler(&samplerDesc, {samplerStart.ptr + increment * i});
|
||||
|
||||
while(Running())
|
||||
@@ -525,6 +528,7 @@ float4 main(v2f IN) : SV_Target0
|
||||
{
|
||||
cmd->SetGraphicsRootDescriptorTable(0, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart());
|
||||
cmd->SetGraphicsRootDescriptorTable(1, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart());
|
||||
cmd->SetGraphicsRootDescriptorTable(3, m_Sampler->GetGPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
||||
RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f});
|
||||
|
||||
@@ -499,7 +499,7 @@ void D3D12GraphicsTest::PostDeviceCreate()
|
||||
|
||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
|
||||
desc.NumDescriptors = 8;
|
||||
desc.NumDescriptors = 128;
|
||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||
|
||||
CHECK_HR(dev->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&m_Sampler));
|
||||
|
||||
@@ -77,6 +77,10 @@ class D3D12_Descriptor_Indexing(rdtest.TestCase):
|
||||
'loc': (1, 80),
|
||||
'elems': [19, 23]
|
||||
},
|
||||
(rd.DescriptorCategory.Sampler, 1): {
|
||||
'loc': (1, 0),
|
||||
'elems': [19, 20, 21]
|
||||
},
|
||||
}
|
||||
|
||||
ro = pipe.GetReadOnlyResources(rd.ShaderStage.Pixel)
|
||||
@@ -84,23 +88,26 @@ class D3D12_Descriptor_Indexing(rdtest.TestCase):
|
||||
rw = pipe.GetReadWriteResources(rd.ShaderStage.Pixel)
|
||||
|
||||
self.check_eq(len(ro), 2 + 8)
|
||||
self.check_eq(len(samp), 1)
|
||||
self.check_eq(len(samp), 1 + 3)
|
||||
self.check_eq(len(rw), 0)
|
||||
|
||||
refl = pipe.GetShaderReflection(rd.ShaderStage.Pixel)
|
||||
|
||||
for a in samp + ro:
|
||||
idx = (rd.CategoryForDescriptorType(a.access.type), a.access.index)
|
||||
if a.access.type == rd.DescriptorType.Sampler: # static sampler
|
||||
if a.access.type == rd.DescriptorType.Sampler and a.access.index == 0: # static sampler
|
||||
# descriptor store should not be a heap, but we don't verify exactly where it comes from
|
||||
self.check(a.access.descriptorStore not in d3d12pipe.descriptorHeaps)
|
||||
self.check_eq(a.access.index, 0)
|
||||
continue
|
||||
|
||||
heapName = "ResourceDescriptorHeap"
|
||||
if rd.IsReadOnlyDescriptor(a.access.type):
|
||||
res = refl.readOnlyResources[a.access.index]
|
||||
elif rd.IsReadWriteDescriptor(a.access.type):
|
||||
res = refl.readOnlyResources[a.access.index]
|
||||
else:
|
||||
res = refl.readWriteResources[a.access.index]
|
||||
res = refl.samplers[a.access.index]
|
||||
heapName = "SamplerDescriptorHeap"
|
||||
|
||||
if idx not in bind_info.keys():
|
||||
raise rdtest.TestFailureException(
|
||||
@@ -121,12 +128,13 @@ class D3D12_Descriptor_Indexing(rdtest.TestCase):
|
||||
loc = self.controller.GetDescriptorLocations(a.access.descriptorStore,
|
||||
[rd.DescriptorRange(a.access)])[0]
|
||||
if loc.fixedBindNumber != bind_info[idx]['loc'][1] + a.access.arrayElement:
|
||||
raise rdtest.TestFailureException("Location {} not expected for space,reg {} array element {}".format(
|
||||
loc.fixedBindNumber, bind_info[idx]['loc'], a.access.arrayElement))
|
||||
if loc.logicalBindName != "ResourceDescriptorHeap[{}]".format(bind_info[idx]['loc'][1] +
|
||||
a.access.arrayElement):
|
||||
raise rdtest.TestFailureException("Location {} not expected for space,reg {} array element {}".format(
|
||||
loc.logicalBindName, bind_info[idx]['loc'], a.access.arrayElement))
|
||||
raise rdtest.TestFailureException(
|
||||
"Location {} not expected for {} at space,reg {} array element {}".format(
|
||||
loc.fixedBindNumber, str(a.access.type), bind_info[idx]['loc'], a.access.arrayElement))
|
||||
if loc.logicalBindName != "{}[{}]".format(heapName, bind_info[idx]['loc'][1] + a.access.arrayElement):
|
||||
raise rdtest.TestFailureException(
|
||||
"Location {} not expected for space,reg {} array element {}".format(
|
||||
loc.logicalBindName, bind_info[idx]['loc'], a.access.arrayElement))
|
||||
|
||||
bind_info[idx]['elems'].remove(a.access.arrayElement)
|
||||
|
||||
@@ -152,7 +160,7 @@ class D3D12_Descriptor_Indexing(rdtest.TestCase):
|
||||
# - UAV resources
|
||||
bind_info = {
|
||||
rd.DescriptorCategory.ConstantBlock: [9],
|
||||
rd.DescriptorCategory.Sampler: [0, 1, 2, 4, 5, 6, 7],
|
||||
rd.DescriptorCategory.Sampler: [0, 1, 2, 19, 20, 21, 25],
|
||||
rd.DescriptorCategory.ReadOnlyResource: [8, 12, 19, 20, 21, 49, 59, 6, 99, 103, 156, 162],
|
||||
rd.DescriptorCategory.ReadWriteResource: [10],
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user