Reduce reported limits to allow us to expand all descriptor buffers

This commit is contained in:
baldurk
2025-06-16 14:34:49 +01:00
parent 799a9a8452
commit 71437e2800
6 changed files with 153 additions and 2 deletions
+3
View File
@@ -917,6 +917,9 @@ DECLARE_REFLECTION_STRUCT(DescriptorSetSlot);
constexpr uint64_t FixedOpaqueDescriptorCaptureSize = 16;
constexpr uint64_t MaxDescriptorSize = 256;
// used for calculating how much address space to reserve if it's small and we're worried about
// expanding descriptor buffers
constexpr uint32_t ExpectedMaxNumDescriptorBuffers = 100;
uint32_t DescriptorDataSize(const VkPhysicalDeviceDescriptorBufferPropertiesEXT &descSizes,
VkDescriptorType type);
+72 -2
View File
@@ -2187,8 +2187,9 @@ VkResult WrappedVulkan::FilterDeviceExtensionProperties(VkPhysicalDevice physDev
CHECK_PROP_SIZE(inputAttachmentDescriptorSize, MaxDescriptorSize);
CHECK_PROP_SIZE(accelerationStructureDescriptorSize, MaxDescriptorSize);
// we don't expect any world where descriptor buffer is available but descriptor indexing
// doesn't support robust update after bind, but require it anyway as we force robustness on
// we don't expect any world where descriptor buffer is available but descriptor
// indexing doesn't support robust update after bind, but require it anyway as we
// force robustness on
VkPhysicalDeviceDescriptorIndexingProperties descIndexingProps = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES,
};
@@ -2206,6 +2207,75 @@ VkResult WrappedVulkan::FilterDeviceExtensionProperties(VkPhysicalDevice physDev
return true;
}
// calculate the maximum descriptor size according to the spec
size_t maxResourceDescriptorSize = 0;
#define CALC_MAX_SIZE(prop) \
maxResourceDescriptorSize = RDCMAX(maxResourceDescriptorSize, descProps.prop);
CALC_MAX_SIZE(storageImageDescriptorSize);
CALC_MAX_SIZE(sampledImageDescriptorSize);
CALC_MAX_SIZE(robustUniformTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustUniformBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageBufferDescriptorSize);
CALC_MAX_SIZE(inputAttachmentDescriptorSize);
CALC_MAX_SIZE(accelerationStructureDescriptorSize);
// guess worst-case size of a descriptor set with 2 descriptors
VkDeviceSize reservedDescriptorSize =
AlignUp(maxResourceDescriptorSize * 2, descProps.descriptorBufferOffsetAlignment);
// finally we need to ensure we have enough room to hopefully expand every resource
// descriptor buffer a bit without blowing up available address space. we assume that
// making room for a certain number of buffers is more than enough - anyone making more
// than that is hopefully making buffers that are a much smaller fraction of the address space
// if the range is so small that we can't shrink the limit to give ourselves room and
// remain legal, that's a problem. We need to be able to expand each buffer by a bit
if(descProps.maxResourceDescriptorBufferRange - reservedDescriptorSize <
((1 << 20) - (1 << 15)) * maxResourceDescriptorSize)
{
if(!filterWarned)
{
RDCWARN(
"VkPhysicalDeviceDescriptorIndexingProperties buffer range of %llx is too "
"small for maxResourceDescriptorSize %zu, can't support capture of "
"VK_EXT_descriptor_buffer",
descProps.maxResourceDescriptorBufferRange, maxResourceDescriptorSize);
}
return true;
}
const VkDeviceSize addrSpaceSize =
RDCMIN(descProps.descriptorBufferAddressSpaceSize,
descProps.resourceDescriptorBufferAddressSpaceSize);
// an example set of close-to-problem limits here would be: 128MB (0x8000000) addr space
// with 64MB resource buffer range (0x4000000)
// the spec requires that the resource buffer range must be at least enough for ~1
// million (2^20-2^15 = 1015808) descriptors so as long as that's still satisfied if we
// reduce the max range by a bit, we're fine. In practice most implementations have
// plenty of address space and those that are more constrained have a max range that's
// power-of-two rather than the minimum ~1 million so we have plenty scope to remove.
// if the address space can't be shrunk by enough for 100 buffers to each have a couple
// of descriptors that's also a problem - this is a heuristic, and it could break if the
// user perfectly subdivided a shrunken address space into 101 buffers as then our
// expansion would cause things to explode. We don't expect that to be a problem though.
if(addrSpaceSize - ExpectedMaxNumDescriptorBuffers * reservedDescriptorSize < (1 << 27))
{
if(!filterWarned)
{
RDCWARN(
"VkPhysicalDeviceDescriptorIndexingProperties resource address space size of "
"%llx is too small for maxResourceDescriptorSize %zu, can't support capture of "
"VK_EXT_descriptor_buffer",
addrSpaceSize, maxResourceDescriptorSize);
}
return true;
}
// supported and all descriptor sizes are sensible
return false;
}
+1
View File
@@ -528,6 +528,7 @@ private:
bool m_NULLDescriptorPatternSaved = false;
bool m_IgnoreLayoutForDescriptors = false;
uint32_t m_ResourceDescriptorBufferReserveSize = 0;
std::unordered_map<ResourceId, ResourceId> m_InlineBuffers;
bool m_SeparateDepthStencil = false;
@@ -4341,6 +4341,24 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
RDCASSERT(m_DescriptorBufferProperties.samplerCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
uint32_t maxResourceDescriptorSize = 0;
#define CALC_MAX_SIZE(prop) \
maxResourceDescriptorSize = \
RDCMAX(maxResourceDescriptorSize, (uint32_t)m_DescriptorBufferProperties.prop);
CALC_MAX_SIZE(storageImageDescriptorSize);
CALC_MAX_SIZE(sampledImageDescriptorSize);
CALC_MAX_SIZE(robustUniformTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustUniformBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageBufferDescriptorSize);
CALC_MAX_SIZE(inputAttachmentDescriptorSize);
CALC_MAX_SIZE(accelerationStructureDescriptorSize);
m_ResourceDescriptorBufferReserveSize =
AlignUp(maxResourceDescriptorSize * 2,
(uint32_t)m_DescriptorBufferProperties.descriptorBufferOffsetAlignment);
m_IgnoreLayoutForDescriptors = descBufFeats->descriptorBufferImageLayoutIgnored != VK_FALSE;
}
@@ -5008,6 +5026,24 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
RDCASSERT(m_DescriptorBufferProperties.samplerCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
uint32_t maxResourceDescriptorSize = 0;
#define CALC_MAX_SIZE(prop) \
maxResourceDescriptorSize = \
RDCMAX(maxResourceDescriptorSize, (uint32_t)m_DescriptorBufferProperties.prop);
CALC_MAX_SIZE(storageImageDescriptorSize);
CALC_MAX_SIZE(sampledImageDescriptorSize);
CALC_MAX_SIZE(robustUniformTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustUniformBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageBufferDescriptorSize);
CALC_MAX_SIZE(inputAttachmentDescriptorSize);
CALC_MAX_SIZE(accelerationStructureDescriptorSize);
m_ResourceDescriptorBufferReserveSize =
AlignUp(maxResourceDescriptorSize * 2,
(uint32_t)m_DescriptorBufferProperties.descriptorBufferOffsetAlignment);
m_IgnoreLayoutForDescriptors = descBufFeatures->descriptorBufferImageLayoutIgnored != VK_FALSE;
VkPhysicalDeviceRobustness2FeaturesKHR *robustness2 =
@@ -897,6 +897,33 @@ void WrappedVulkan::vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevi
descBufferProperties->robustUniformTexelBufferDescriptorSize;
descBufferProperties->storageTexelBufferDescriptorSize =
descBufferProperties->robustStorageTexelBufferDescriptorSize;
// we also may need to shrink some range/address space limits to allow us to expand buffers. We
// checked that this should be valid at extension filter time
// calculate the maximum descriptor size according to the spec
size_t maxResourceDescriptorSize = 0;
#define CALC_MAX_SIZE(prop) \
maxResourceDescriptorSize = RDCMAX(maxResourceDescriptorSize, descBufferProperties->prop);
CALC_MAX_SIZE(storageImageDescriptorSize);
CALC_MAX_SIZE(sampledImageDescriptorSize);
CALC_MAX_SIZE(robustUniformTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageTexelBufferDescriptorSize);
CALC_MAX_SIZE(robustUniformBufferDescriptorSize);
CALC_MAX_SIZE(robustStorageBufferDescriptorSize);
CALC_MAX_SIZE(inputAttachmentDescriptorSize);
CALC_MAX_SIZE(accelerationStructureDescriptorSize);
VkDeviceSize reservedDescriptorSize = AlignUp(
maxResourceDescriptorSize * 2, descBufferProperties->descriptorBufferOffsetAlignment);
descBufferProperties->maxResourceDescriptorBufferRange -= reservedDescriptorSize;
descBufferProperties->descriptorBufferAddressSpaceSize -=
ExpectedMaxNumDescriptorBuffers * reservedDescriptorSize;
descBufferProperties->resourceDescriptorBufferAddressSpaceSize -=
ExpectedMaxNumDescriptorBuffers * reservedDescriptorSize;
}
}
@@ -1893,6 +1893,13 @@ bool WrappedVulkan::Serialise_vkCreateBuffer(SerialiserType &ser, VkDevice devic
VkBufferCreateInfo patched = CreateInfo;
// inflate all resource descriptor buffers by 2 descriptors, so that we have room for internal
// descriptors wherever they are bound
if(CreateInfo.usage & VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT)
{
patched.size += m_ResourceDescriptorBufferReserveSize;
}
byte *tempMem = GetTempMemory(GetNextPatchSize(patched.pNext));
UnwrapNextChain(m_State, "VkBufferCreateInfo", tempMem, (VkBaseInStructure *)&patched);
@@ -1977,6 +1984,13 @@ VkResult WrappedVulkan::vkCreateBuffer(VkDevice device, const VkBufferCreateInfo
if(IsCaptureMode(m_State))
adjusted_info.flags |= DefaultBufferCreateFlags();
// inflate all resource descriptor buffers by 2 descriptors, so that we have room for internal
// descriptors wherever they are bound
if(adjusted_info.usage & VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT)
{
adjusted_info.size += m_ResourceDescriptorBufferReserveSize;
}
SetBufferUsageFlags(&adjusted_info, adjusted_usage);
byte *tempMem = GetTempMemory(GetNextPatchSize(adjusted_info.pNext));