mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Handle immutable/static samplers on Vulkan and D3D12
* On vulkan immutable samplers mostly work as-is because they have a descriptor set space even if they may not be written dynamically. We just set a flag so the replay API is aware they're compile-time constant. * On D3D12 we follow the path of root constants and other non-descriptor backed bindings, by creating virtual descriptor store in the root signature where the static samplers are created.
This commit is contained in:
@@ -1089,6 +1089,50 @@ rdcstr PIX3DecodeEventString(const UINT64 *pData, UINT64 &color)
|
||||
return formatString;
|
||||
}
|
||||
|
||||
D3D12_SAMPLER_DESC2 ConvertStaticSampler(const D3D12_STATIC_SAMPLER_DESC1 &samp)
|
||||
{
|
||||
D3D12_SAMPLER_DESC2 desc;
|
||||
desc.Filter = samp.Filter;
|
||||
desc.AddressU = samp.AddressU;
|
||||
desc.AddressV = samp.AddressV;
|
||||
desc.AddressW = samp.AddressW;
|
||||
desc.MipLODBias = samp.MipLODBias;
|
||||
desc.MaxAnisotropy = samp.MaxAnisotropy;
|
||||
desc.ComparisonFunc = samp.ComparisonFunc;
|
||||
switch(samp.BorderColor)
|
||||
{
|
||||
default:
|
||||
case D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK:
|
||||
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] =
|
||||
desc.FloatBorderColor[3] = 0.0f;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK:
|
||||
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] = 0.0f;
|
||||
desc.FloatBorderColor[3] = 1.0f;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE:
|
||||
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] =
|
||||
desc.FloatBorderColor[3] = 1.0f;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK_UINT:
|
||||
desc.UintBorderColor[0] = desc.UintBorderColor[1] = desc.UintBorderColor[2] = 0;
|
||||
desc.UintBorderColor[3] = 1;
|
||||
// this flag is optional in D3D, add it here to ensure we can check it elsewhere
|
||||
desc.Flags |= D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE_UINT:
|
||||
desc.UintBorderColor[0] = desc.UintBorderColor[1] = desc.UintBorderColor[2] =
|
||||
desc.UintBorderColor[3] = 1;
|
||||
// this flag is optional in D3D, add it here to ensure we can check it elsewhere
|
||||
desc.Flags |= D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR;
|
||||
break;
|
||||
}
|
||||
desc.MinLOD = samp.MinLOD;
|
||||
desc.MaxLOD = samp.MaxLOD;
|
||||
desc.Flags = samp.Flags;
|
||||
return desc;
|
||||
}
|
||||
|
||||
D3D12_DEPTH_STENCILOP_DESC1 Upconvert(const D3D12_DEPTH_STENCILOP_DESC &face)
|
||||
{
|
||||
D3D12_DEPTH_STENCILOP_DESC1 ret = {};
|
||||
|
||||
@@ -233,6 +233,7 @@ struct BarrierSet
|
||||
|
||||
D3D12_DEPTH_STENCIL_DESC2 Upconvert(const D3D12_DEPTH_STENCIL_DESC1 &desc);
|
||||
D3D12_RASTERIZER_DESC2 Upconvert(const D3D12_RASTERIZER_DESC &desc);
|
||||
D3D12_SAMPLER_DESC2 ConvertStaticSampler(const D3D12_STATIC_SAMPLER_DESC1 &samp);
|
||||
|
||||
ShaderStageMask ConvertVisibility(D3D12_SHADER_VISIBILITY ShaderVisibility);
|
||||
UINT GetNumSubresources(ID3D12Device *dev, const D3D12_RESOURCE_DESC *desc);
|
||||
|
||||
@@ -2346,6 +2346,12 @@ rdcarray<Descriptor> D3D12Replay::GetDescriptors(ResourceId descriptorStore,
|
||||
|
||||
ID3D12DeviceChild *res = rm->GetCurrentAs<ID3D12DeviceChild>(descriptorStore);
|
||||
|
||||
if(WrappedID3D12RootSignature::IsAlloc(res))
|
||||
{
|
||||
// root signature descriptor storage is for static samplers
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(WrappedID3D12PipelineState::IsAlloc(res))
|
||||
{
|
||||
const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
|
||||
@@ -2502,6 +2508,32 @@ rdcarray<SamplerDescriptor> D3D12Replay::GetSamplerDescriptors(ResourceId descri
|
||||
|
||||
ID3D12DeviceChild *res = rm->GetCurrentAs<ID3D12DeviceChild>(descriptorStore);
|
||||
|
||||
if(WrappedID3D12RootSignature::IsAlloc(res))
|
||||
{
|
||||
WrappedID3D12RootSignature *sig = (WrappedID3D12RootSignature *)res;
|
||||
size_t dst = 0;
|
||||
for(const DescriptorRange &r : ranges)
|
||||
{
|
||||
uint32_t staticIdx = r.offset;
|
||||
|
||||
for(uint32_t i = 0; i < r.count; i++)
|
||||
{
|
||||
if(staticIdx >= sig->sig.StaticSamplers.size())
|
||||
{
|
||||
// silently drop out of bounds descriptor reads
|
||||
}
|
||||
else
|
||||
{
|
||||
FillSamplerDescriptor(ret[dst], ConvertStaticSampler(sig->sig.StaticSamplers[staticIdx]));
|
||||
ret[dst].creationTimeConstant = true;
|
||||
}
|
||||
dst++;
|
||||
staticIdx++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(WrappedID3D12PipelineState::IsAlloc(res))
|
||||
{
|
||||
// root constants, not sampler data
|
||||
@@ -2577,6 +2609,20 @@ rdcarray<DescriptorAccess> D3D12Replay::GetDescriptorAccess()
|
||||
|
||||
for(DescriptorAccess &access : ret)
|
||||
{
|
||||
const D3D12RenderState::RootSignature &rootSig = pipe->IsGraphics() ? rs.graphics : rs.compute;
|
||||
|
||||
uint32_t rootIndex = (uint32_t)access.byteSize;
|
||||
access.byteSize = 1;
|
||||
|
||||
// access off the end of the root signature list indicates a static sampler. We virtualise
|
||||
// this as root signature descriptor storage
|
||||
if(access.type == DescriptorType::Sampler && rootIndex >= rootSig.sigelems.size())
|
||||
{
|
||||
access.descriptorStore = rm->GetOriginalID(rootSig.rootsig);
|
||||
// the access byteOffset is the index of the static sampler
|
||||
continue;
|
||||
}
|
||||
|
||||
if(access.type == DescriptorType::Sampler)
|
||||
access.descriptorStore =
|
||||
samplerHeap ? rm->GetOriginalID(samplerHeap->GetResourceID()) : ResourceId();
|
||||
@@ -2584,10 +2630,7 @@ rdcarray<DescriptorAccess> D3D12Replay::GetDescriptorAccess()
|
||||
access.descriptorStore =
|
||||
resourceHeap ? rm->GetOriginalID(resourceHeap->GetResourceID()) : ResourceId();
|
||||
|
||||
uint32_t rootIndex = (uint32_t)access.byteSize;
|
||||
const D3D12RenderState::SignatureElement &rootEl =
|
||||
pipe->IsGraphics() ? rs.graphics.sigelems[rootIndex] : rs.compute.sigelems[rootIndex];
|
||||
access.byteSize = 1;
|
||||
const D3D12RenderState::SignatureElement &rootEl = rootSig.sigelems[rootIndex];
|
||||
|
||||
// this indicates a root parameter
|
||||
if(access.byteOffset == ~0U)
|
||||
@@ -2598,7 +2641,6 @@ rdcarray<DescriptorAccess> D3D12Replay::GetDescriptorAccess()
|
||||
// other types of virtual constants to handle we can use the pipeline state directly
|
||||
access.descriptorStore = rm->GetOriginalID(pipe->GetResourceID());
|
||||
access.byteOffset = rootIndex;
|
||||
access.byteSize = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -713,6 +713,21 @@ rdcpair<uint32_t, uint32_t> FindMatchingRootParameter(const D3D12RootSignature *
|
||||
}
|
||||
}
|
||||
|
||||
// if not found above, and looking for samplers, look at static samplers next
|
||||
if(rangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER)
|
||||
{
|
||||
// indicate that we're looking up static samplers
|
||||
uint32_t numRoots = (uint32_t)sig->Parameters.size();
|
||||
for(uint32_t samp = 0; samp < sig->StaticSamplers.size(); samp++)
|
||||
{
|
||||
if(sig->StaticSamplers[samp].RegisterSpace == space &&
|
||||
sig->StaticSamplers[samp].ShaderRegister == bind)
|
||||
{
|
||||
return {numRoots, samp};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {~0U, 0};
|
||||
}
|
||||
|
||||
|
||||
@@ -619,43 +619,7 @@ D3D12Descriptor D3D12DebugAPIWrapper::FindDescriptor(DXBCBytecode::OperandType t
|
||||
{
|
||||
if(samp.RegisterSpace == slot.registerSpace && samp.ShaderRegister == slot.shaderRegister)
|
||||
{
|
||||
D3D12_SAMPLER_DESC2 desc;
|
||||
|
||||
desc.Filter = samp.Filter;
|
||||
desc.AddressU = samp.AddressU;
|
||||
desc.AddressV = samp.AddressV;
|
||||
desc.AddressW = samp.AddressW;
|
||||
desc.MipLODBias = samp.MipLODBias;
|
||||
desc.MaxAnisotropy = samp.MaxAnisotropy;
|
||||
desc.ComparisonFunc = samp.ComparisonFunc;
|
||||
switch(samp.BorderColor)
|
||||
{
|
||||
default:
|
||||
case D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK:
|
||||
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] =
|
||||
desc.FloatBorderColor[3] = 0.0f;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK:
|
||||
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] = 0.0f;
|
||||
desc.FloatBorderColor[3] = 1.0f;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE:
|
||||
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] =
|
||||
desc.FloatBorderColor[3] = 1.0f;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK_UINT:
|
||||
desc.UintBorderColor[0] = desc.UintBorderColor[1] = desc.UintBorderColor[2] = 0;
|
||||
desc.UintBorderColor[3] = 1;
|
||||
break;
|
||||
case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE_UINT:
|
||||
desc.UintBorderColor[0] = desc.UintBorderColor[1] = desc.UintBorderColor[2] =
|
||||
desc.UintBorderColor[3] = 1;
|
||||
break;
|
||||
}
|
||||
desc.MinLOD = samp.MinLOD;
|
||||
desc.MaxLOD = samp.MaxLOD;
|
||||
desc.Flags = samp.Flags;
|
||||
|
||||
D3D12_SAMPLER_DESC2 desc = ConvertStaticSampler(samp);
|
||||
descriptor.Init(&desc);
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@@ -716,6 +716,9 @@ struct DescriptorSetSlot
|
||||
|
||||
// used for buffers and inline blocks. We could steal some bits here if we needed them since 48
|
||||
// bits would be plenty for a long time.
|
||||
//
|
||||
// Immutable samplers set this to 1 to indicate for replay purposes that the sampler came from an
|
||||
// immutable binding when looking purely at the descriptor without knowing its layout
|
||||
VkDeviceSize offset;
|
||||
|
||||
// resource IDs are kept separate rather than overlapping/union'ing with other types. This
|
||||
|
||||
@@ -453,6 +453,8 @@ void DescSetLayout::CreateBindingsArray(BindingStorage &bindingStorage, uint32_t
|
||||
// samplers set the type from the layout. That way even if the descriptor is never
|
||||
// written we still process immutable samplers properly.
|
||||
bindingStorage.binds[i][a].type = convert(bindings[i].layoutDescType);
|
||||
|
||||
bindingStorage.binds[i][a].offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2516,6 +2516,10 @@ void VulkanReplay::FillSamplerDescriptor(SamplerDescriptor &dstel, const Descrip
|
||||
dstel.unnormalized = sampl.unnormalizedCoordinates;
|
||||
dstel.seamlessCubemaps = sampl.seamless;
|
||||
|
||||
// immutable samplers set the offset to non-zero so that we can check it here without knowing what
|
||||
// layout this descriptor binding came from
|
||||
dstel.creationTimeConstant = srcel.offset != 0;
|
||||
|
||||
if(sampl.ycbcr != ResourceId())
|
||||
{
|
||||
const VulkanCreationInfo::YCbCrSampler &ycbcr = c.m_YCbCrSampler[sampl.ycbcr];
|
||||
|
||||
Reference in New Issue
Block a user