Serialise unique descriptor fetches on a per-resource basis

* ASs and samplers can only have one descriptor ever - we automatically fetch
  this at creation time when descriptor buffers are enabled. We also fetch all
  possible NULL descriptors at device creation and do not re-serialise them
  afterwards.
* Image views may have either 1 descriptor (if layouts are ignored) or N (one
  per layout). Buffers have N per offset/size and optionally format. These are
  tracked for uniqueness in the corresponding resource record to ensure we don't
  serialise infinite descriptors over time.
* For combined image/samplers since they are in a known format we serialise
  these as-if they are image view descriptors only (with some extra data that we
  ignore). The whole descriptor must still replay bitwise identical but we will
  only use the image view part of it.
This commit is contained in:
baldurk committed 2025-07-30 22:10:23 +01:00
1 parent 4ebfded137
commit efd60e5751
9 files changed
+598 -4

No files matched your search

+31
View File
@@ -5383,6 +5383,37 @@ WrappedVulkan::CommandBufferNode *WrappedVulkan::GetCommandBufferPartialSubmissi
return NULL;
}
size_t WrappedVulkan::DescriptorDataSize(VkDescriptorType type)
{
size_t ret = 0;
const VkPhysicalDeviceDescriptorBufferPropertiesEXT &descSizes = m_DescriptorBufferProperties;
switch(type)
{
case VK_DESCRIPTOR_TYPE_SAMPLER: ret = descSizes.samplerDescriptorSize; break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
ret = descSizes.combinedImageSamplerDescriptorSize;
break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ret = descSizes.inputAttachmentDescriptorSize; break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: ret = descSizes.sampledImageDescriptorSize; break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: ret = descSizes.storageImageDescriptorSize; break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
ret = descSizes.uniformTexelBufferDescriptorSize;
break;
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
ret = descSizes.storageTexelBufferDescriptorSize;
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: ret = descSizes.uniformBufferDescriptorSize; break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: ret = descSizes.storageBufferDescriptorSize; break;
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
ret = descSizes.accelerationStructureDescriptorSize;
break;
default: break;
}
return ret;
}
bool WrappedVulkan::IsPartialRenderPassActive()
{
for(const CommandBufferNode &cmdNode : m_Partial.partialStack)
+6
View File
@@ -447,9 +447,15 @@ private:
VkQueueFamilyProperties queueProps[16] = {};
};
VkPhysicalDeviceDescriptorBufferPropertiesEXT m_DescriptorBufferProperties;
size_t DescriptorDataSize(VkDescriptorType type);
Threading::CriticalSection m_ASLookupByAddrLock;
rdcflatmap<VkDeviceAddress, ResourceId> m_ASLookupByAddr;
bool m_NULLDescriptorPatternSaved = false;
bool m_IgnoreLayoutForDescriptors = false;
bool m_SeparateDepthStencil = false;
bool m_NULLDescriptorsAllowed = false;
bool m_ExtendedDynState = false;
+4
View File
@@ -3973,6 +3973,10 @@ VkResourceRecord::~VkResourceRecord()
if(resType == eResBuffer || resType == eResImage)
SAFE_DELETE(resInfo);
// for image views with descriptors, they have a duplicated resInfo
if(resType == eResImageView && resInfo && resInfo->parentResInfo != resInfo)
SAFE_DELETE(resInfo);
if(resType == eResInstance || resType == eResDevice || resType == eResPhysicalDevice)
SAFE_DELETE(instDevInfo);
+70
View File
@@ -1017,15 +1017,83 @@ struct AspectSparseTable
DECLARE_REFLECTION_STRUCT(AspectSparseTable);
struct DescriptorUniquenessKey
{
DescriptorUniquenessKey(VkImageLayout layout)
: layout(layout), offset(0), size(0), fmt(VK_FORMAT_UNDEFINED)
{
}
DescriptorUniquenessKey(uint64_t offset, uint64_t size, VkFormat fmt)
: layout(VK_IMAGE_LAYOUT_UNDEFINED), offset(offset), size(size), fmt(fmt)
{
}
bool operator==(const DescriptorUniquenessKey &key) const
{
return layout == key.layout && offset == key.offset && size == key.size && fmt == key.fmt;
}
VkImageLayout layout;
uint64_t offset, size;
VkFormat fmt;
};
namespace std
{
template <>
struct hash<DescriptorUniquenessKey>
{
std::size_t operator()(const DescriptorUniquenessKey &key) const
{
std::size_t hash = std::hash<uint32_t>()(key.layout);
hash ^= std::hash<uint64_t>()(key.offset) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= std::hash<uint64_t>()(key.size) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= std::hash<uint32_t>()(key.fmt) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
return hash;
}
};
};
// these structs are allocated for images and buffers, then pointed to (non-owning) by views
struct ResourceInfo
{
ResourceInfo() = default;
ResourceInfo(const ResourceInfo &other)
: banDedicated(other.banDedicated),
sparseAspect(other.sparseAspect),
dedicatedMemory(other.dedicatedMemory),
memreqs(other.memreqs),
imageInfo(other.imageInfo)
{
// this constructor is used to duplicate an image's resinfo in an image view when descriptor
// buffers are in use so that each view can have its own descriptor tracking.
// sparse table info deliberately not copied as it is mutable, and obviously the same for the descriptors
}
// commonly we expect only one aspect (COLOR is vastly likely and METADATA is rare) so have one
// directly accessible. If we have others (like separate DEPTH and STENCIL, or anything and
// METADATA) we put them in the array.
Sparse::PageTable sparseTable;
rdcarray<AspectSparseTable> altSparseAspects;
// for images this is a self pointer. For image views when we are using descriptor buffers we
// can't alias the resInfo in each view's record because each view needs to track its own
// descriptors - instead we point back to the image's resInfo here for sparse info. blech
ResourceInfo *parentResInfo;
// for buffers, or for images when layouts can affect descriptors, the set of descriptors which
// have already been serialised
Threading::CriticalSection descriptorLock;
std::unordered_set<DescriptorUniquenessKey> descriptors;
// return true if this is a new descriptor, false if we already had it
bool AddDescriptor(DescriptorUniquenessKey key)
{
SCOPED_LOCK(descriptorLock);
return descriptors.insert(key).second;
}
// for external images if we query both external and non-external and the sizes are different, we
// can't allow dedicated memory as it is required to precisely match in size.
bool banDedicated = false;
@@ -2329,6 +2397,8 @@ public:
bool storable = false;
bool dedicated = false;
bool hasBDA = false;
bool hasDescriptorSaved = false;
bool hasNULLDescriptorSaved = false;
void MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize offset, VkDeviceSize size,
FrameRefType refType);
@@ -199,6 +199,83 @@ VkCopyDescriptorSet WrappedVulkan::UnwrapInfo(const VkCopyDescriptorSet *copyDes
return ret;
}
template <>
VkDescriptorGetInfoEXT WrappedVulkan::UnwrapInfo(const VkDescriptorGetInfoEXT *pDescriptorInfo)
{
VkDescriptorGetInfoEXT ret = *pDescriptorInfo;
byte *memory = GetTempMemory(sizeof(VkDescriptorAddressInfoEXT) + GetNextPatchSize(ret.pNext));
RDCCOMPILE_ASSERT(sizeof(VkDescriptorAddressInfoEXT) >= sizeof(VkDescriptorImageInfo),
"Structure sizes mean not enough space is allocated for write data");
if(pDescriptorInfo->data.pUniformBuffer)
ret.data.pUniformBuffer = (VkDescriptorAddressInfoEXT *)memory;
byte *nextMem = memory + sizeof(VkDescriptorBufferInfo);
UnwrapNextChain(m_State, "VkDescriptorGetInfoEXT", nextMem, (VkBaseInStructure *)&ret);
switch(ret.type)
{
case VK_DESCRIPTOR_TYPE_SAMPLER:
{
VkSampler *samp = (VkSampler *)memory;
if(pDescriptorInfo->data.pSampler)
{
*samp = Unwrap(*pDescriptorInfo->data.pSampler);
}
break;
}
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
// ignore the sampler part
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
{
VkDescriptorImageInfo *img = (VkDescriptorImageInfo *)ret.data.pCombinedImageSampler;
if(pDescriptorInfo->data.pCombinedImageSampler)
{
img->imageView = Unwrap(pDescriptorInfo->data.pCombinedImageSampler->imageView);
img->sampler = Unwrap(pDescriptorInfo->data.pCombinedImageSampler->sampler);
img->imageLayout = pDescriptorInfo->data.pCombinedImageSampler->imageLayout;
}
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
{
// no unwrap, just copy
VkDescriptorAddressInfoEXT *buf = (VkDescriptorAddressInfoEXT *)ret.data.pUniformBuffer;
if(pDescriptorInfo->data.pUniformBuffer)
*buf = *pDescriptorInfo->data.pUniformBuffer;
break;
}
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
{
// no unwrap, just copy
ret.data.accelerationStructure = pDescriptorInfo->data.accelerationStructure;
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT:
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
case VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM:
case VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM:
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
case VK_DESCRIPTOR_TYPE_MAX_ENUM:
{
RDCERR("Invalid descriptor type %s", ToStr(ret.type).c_str());
break;
}
}
return ret;
}
template <typename SerialiserType>
bool WrappedVulkan::Serialise_vkCreateDescriptorPool(SerialiserType &ser, VkDevice device,
const VkDescriptorPoolCreateInfo *pCreateInfo,
@@ -1873,14 +1950,247 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate(
template <typename SerialiserType>
bool WrappedVulkan::Serialise_vkGetDescriptorEXT(SerialiserType &ser, VkDevice device,
const VkDescriptorGetInfoEXT *pDescriptorInfo,
size_t dataSize, void *pDescriptor)
size_t dataSize_, void *pDescriptor)
{
SERIALISE_ELEMENT(device);
SERIALISE_ELEMENT_LOCAL(DescriptorInfo, *pDescriptorInfo).Important();
SERIALISE_ELEMENT_LOCAL(dataSize, uint64_t(dataSize_));
SERIALISE_ELEMENT_ARRAY(pDescriptor, dataSize_);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
byte *tempMem = GetTempMemory(GetNextPatchSize(&DescriptorInfo));
VkDescriptorGetInfoEXT *unwrappedInfo = UnwrapStructAndChain(m_State, tempMem, &DescriptorInfo);
uint64_t curDataSize = DescriptorDataSize(DescriptorInfo.type);
if(dataSize != curDataSize)
{
SET_ERROR_RESULT(
m_FailedReplayResult, ResultCode::APIHardwareUnsupported,
"Descriptor of type %s changed size, it was %llu bytes during capture but is %llu bytes "
"during replay.\n"
"\n%s",
ToStr(DescriptorInfo.type).c_str(), dataSize, curDataSize,
GetPhysDeviceCompatString(false, false).c_str());
return false;
}
bytebuf replayDescriptor;
replayDescriptor.resize(dataSize);
// verify the descriptor is bitwise identical
ObjDisp(device)->GetDescriptorEXT(Unwrap(device), unwrappedInfo, (size_t)dataSize,
replayDescriptor.data());
if(memcmp(replayDescriptor.data(), pDescriptor, dataSize) != 0)
{
rdcstr bitDifferences;
uint32_t *capU32 = (uint32_t *)pDescriptor;
uint32_t *replayU32 = (uint32_t *)replayDescriptor.data();
bitDifferences = "Capture:\n";
for(uint32_t d = 0; d * 4 < dataSize; d++)
bitDifferences += StringFormat::Fmt("%08llx ", capU32[d]);
bitDifferences += "\n\n";
bitDifferences += "Replay:\n";
for(uint32_t d = 0; d * 4 < dataSize; d++)
bitDifferences += StringFormat::Fmt("%08llx ", replayU32[d]);
bitDifferences += "\n";
SET_ERROR_RESULT(m_FailedReplayResult, ResultCode::APIHardwareUnsupported,
"Descriptor of type %s changed bit pattern.\n"
"\n%s"
"\n%s",
ToStr(DescriptorInfo.type).c_str(), bitDifferences.c_str(),
GetPhysDeviceCompatString(false, false).c_str());
return false;
}
}
return true;
}
void WrappedVulkan::vkGetDescriptorEXT(VkDevice device, const VkDescriptorGetInfoEXT *pDescriptorInfo,
size_t dataSize, void *pDescriptor)
{
// the user *could* be querying straight into GPU upload memory which would be very bad to read
// back from. To avoid that, we read into our temporary memory then memcpy to user memory but only
// if we're actually going to process this.
// first determine where this should go, based on the 'primary' resource. For combined
// image/samplers, we pre-populated the sampler one so we treat them as-if they're just images
VkResourceRecord *dstRecord = NULL;
if(IsCaptureMode(m_State))
{
switch(pDescriptorInfo->type)
{
case VK_DESCRIPTOR_TYPE_SAMPLER:
{
if(pDescriptorInfo->data.pSampler)
{
dstRecord = GetRecord(*pDescriptorInfo->data.pSampler);
// don't need to worry about the race here, worst case we save an extra descriptor
if(dstRecord->hasDescriptorSaved)
dstRecord = NULL;
else
dstRecord->hasDescriptorSaved = true;
}
else
{
dstRecord = GetRecord(m_Device);
if(m_NULLDescriptorPatternSaved)
dstRecord = NULL;
}
break;
}
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
{
// sampled/storage/input attachment are identical in the union. Since the type forms part of
// our this logic can be done in common
if(pDescriptorInfo->data.pSampledImage &&
pDescriptorInfo->data.pSampledImage->imageView != VK_NULL_HANDLE)
{
dstRecord = GetRecord(pDescriptorInfo->data.pSampledImage->imageView);
DescriptorUniquenessKey descKey(
m_IgnoreLayoutForDescriptors
? VK_IMAGE_LAYOUT_UNDEFINED
: pDescriptorInfo->data.pCombinedImageSampler->imageLayout);
// this is internally locked
if(!dstRecord->resInfo->AddDescriptor(descKey))
dstRecord = NULL;
}
else if(pDescriptorInfo->data.pCombinedImageSampler &&
pDescriptorInfo->data.pCombinedImageSampler->imageView == VK_NULL_HANDLE &&
pDescriptorInfo->data.pCombinedImageSampler->sampler != VK_NULL_HANDLE)
{
dstRecord = GetRecord(pDescriptorInfo->data.pCombinedImageSampler->sampler);
// don't need to worry about the race here, worst case we save an extra descriptor
if(dstRecord->hasNULLDescriptorSaved)
dstRecord = NULL;
else
dstRecord->hasNULLDescriptorSaved = true;
}
else
{
dstRecord = GetRecord(m_Device);
if(m_NULLDescriptorPatternSaved)
dstRecord = NULL;
}
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
{
// uniform/storage are identical in the union. Since the type forms part of our this
// logic can be done in common
if(pDescriptorInfo->data.pUniformBuffer)
{
ResourceId id;
uint64_t offs = 0;
GetResIDFromAddr(pDescriptorInfo->data.pUniformBuffer->address, id, offs);
dstRecord = GetResourceManager()->GetResourceRecord(id);
VkFormat fmt = VK_FORMAT_UNDEFINED;
if(pDescriptorInfo->type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
pDescriptorInfo->type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
{
fmt = pDescriptorInfo->data.pUniformTexelBuffer->format;
}
DescriptorUniquenessKey descKey(offs, pDescriptorInfo->data.pUniformBuffer->range, fmt);
// this is internally locked
if(!dstRecord->resInfo->AddDescriptor(descKey))
dstRecord = NULL;
}
else
{
dstRecord = GetRecord(m_Device);
if(m_NULLDescriptorPatternSaved)
dstRecord = NULL;
}
break;
}
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
{
if(pDescriptorInfo->data.accelerationStructure)
{
ResourceId id;
{
SCOPED_LOCK(m_ASLookupByAddrLock);
id = m_ASLookupByAddr[pDescriptorInfo->data.accelerationStructure];
}
dstRecord = GetResourceManager()->GetResourceRecord(id);
// don't need to worry about the race here, worst case we save an extra descriptor
if(dstRecord->hasDescriptorSaved)
dstRecord = NULL;
else
dstRecord->hasDescriptorSaved = true;
}
else
{
dstRecord = GetRecord(m_Device);
if(m_NULLDescriptorPatternSaved)
dstRecord = NULL;
}
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
case VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM:
case VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM:
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT:
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
case VK_DESCRIPTOR_TYPE_MAX_ENUM:
RDCERR("Invalid descriptor type passed to vkGetDescriptorEXT");
break;
}
}
size_t localSize = 0;
if(dstRecord)
localSize = dataSize;
byte tempMem[256] = {};
VkDescriptorGetInfoEXT unwrappedInfo = UnwrapInfo(pDescriptorInfo);
SERIALISE_TIME_CALL(ObjDisp(device)->GetDescriptorEXT(Unwrap(device), &unwrappedInfo, dataSize,
dstRecord ? tempMem : pDescriptor));
// if we needed to serialise this descriptor
if(dstRecord)
{
// copy to the user's memory
memcpy(pDescriptor, tempMem, dataSize);
Chunk *chunk = NULL;
{
CACHE_THREAD_SERIALISER();
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkGetDescriptorEXT);
Serialise_vkGetDescriptorEXT(ser, device, pDescriptorInfo, dataSize, tempMem);
chunk = scope.Get();
}
dstRecord->AddChunk(chunk);
}
}
INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateDescriptorSetLayout, VkDevice device,
@@ -4291,6 +4291,53 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
if(m_EnabledExtensions.ext_EXT_descriptor_buffer && descBufFeats && descBufFeats->descriptorBuffer)
{
m_DescriptorBuffers = true;
// if any update after bind feature is enabled, check robustBufferAccessUpdateAfterBind
m_DescriptorBufferProperties = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT,
};
VkPhysicalDeviceProperties2 availBase = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
availBase.pNext = &m_DescriptorBufferProperties;
ObjDisp(physicalDevice)->GetPhysicalDeviceProperties2(Unwrap(physicalDevice), &availBase);
bool robustness = false;
// VkPhysicalDeviceFeatures2 takes priority
if(enabledFeatures2)
{
robustness = enabledFeatures2->features.robustBufferAccess != VK_FALSE;
}
else if(createInfo.pEnabledFeatures && createInfo.pEnabledFeatures->robustBufferAccess)
{
robustness = true;
}
// we should have forced on robustness
RDCASSERT(robustness);
m_DescriptorBufferProperties.uniformBufferDescriptorSize =
m_DescriptorBufferProperties.robustUniformBufferDescriptorSize;
m_DescriptorBufferProperties.storageBufferDescriptorSize =
m_DescriptorBufferProperties.robustStorageBufferDescriptorSize;
m_DescriptorBufferProperties.uniformTexelBufferDescriptorSize =
m_DescriptorBufferProperties.robustUniformTexelBufferDescriptorSize;
m_DescriptorBufferProperties.storageTexelBufferDescriptorSize =
m_DescriptorBufferProperties.robustStorageTexelBufferDescriptorSize;
// ensure our fixed-size is large enough for this driver.
RDCASSERT(m_DescriptorBufferProperties.accelerationStructureCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.bufferCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.imageCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.imageViewCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.samplerCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
m_IgnoreLayoutForDescriptors = descBufFeats->descriptorBufferImageLayoutIgnored != VK_FALSE;
}
// MoltenVK reports 0x3fffffff for this limit so just ignore that value if it comes up
@@ -4877,6 +4924,100 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
descBufFeatures->descriptorBuffer)
{
m_DescriptorBuffers = true;
// if any update after bind feature is enabled, check robustBufferAccessUpdateAfterBind
m_DescriptorBufferProperties = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT,
};
VkPhysicalDeviceProperties2 availBase = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
availBase.pNext = &m_DescriptorBufferProperties;
ObjDisp(physicalDevice)->GetPhysicalDeviceProperties2(Unwrap(physicalDevice), &availBase);
bool robustness = false;
// VkPhysicalDeviceFeatures2 takes priority
if(enabledFeatures2)
{
robustness = enabledFeatures2->features.robustBufferAccess != VK_FALSE;
}
else if(createInfo.pEnabledFeatures && createInfo.pEnabledFeatures->robustBufferAccess)
{
robustness = true;
}
// we should have forced on robustness
RDCASSERT(robustness);
m_DescriptorBufferProperties.uniformBufferDescriptorSize =
m_DescriptorBufferProperties.robustUniformBufferDescriptorSize;
m_DescriptorBufferProperties.storageBufferDescriptorSize =
m_DescriptorBufferProperties.robustStorageBufferDescriptorSize;
m_DescriptorBufferProperties.uniformTexelBufferDescriptorSize =
m_DescriptorBufferProperties.robustUniformTexelBufferDescriptorSize;
m_DescriptorBufferProperties.storageTexelBufferDescriptorSize =
m_DescriptorBufferProperties.robustStorageTexelBufferDescriptorSize;
// ensure our fixed-size is large enough for this driver.
RDCASSERT(m_DescriptorBufferProperties.accelerationStructureCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.bufferCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.imageCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.imageViewCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
RDCASSERT(m_DescriptorBufferProperties.samplerCaptureReplayDescriptorDataSize <=
FixedOpaqueDescriptorCaptureSize);
m_IgnoreLayoutForDescriptors = descBufFeatures->descriptorBufferImageLayoutIgnored != VK_FALSE;
VkPhysicalDeviceRobustness2FeaturesKHR *robustness2 =
(VkPhysicalDeviceRobustness2FeaturesKHR *)FindNextStruct(
&createInfo, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR);
// record all the NULL descriptors
if(IsCaptureMode(m_State) && robustness2 && robustness2->nullDescriptor)
{
VkResourceRecord *record = GetRecord(*pDevice);
RDCASSERT(record);
VkDescriptorGetInfoEXT getInfo = {
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
};
rdcarray<rdcpair<VkDescriptorType, size_t>> descriptorTypes = {
{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
m_DescriptorBufferProperties.sampledImageDescriptorSize},
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
m_DescriptorBufferProperties.storageImageDescriptorSize},
{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
m_DescriptorBufferProperties.robustUniformTexelBufferDescriptorSize},
{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
m_DescriptorBufferProperties.robustStorageTexelBufferDescriptorSize},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
m_DescriptorBufferProperties.robustUniformBufferDescriptorSize},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
m_DescriptorBufferProperties.robustStorageBufferDescriptorSize},
};
if(m_AccelerationStructures)
{
descriptorTypes.push_back(
{VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
m_DescriptorBufferProperties.accelerationStructureDescriptorSize});
}
byte dummy[256];
for(rdcpair<VkDescriptorType, size_t> typeAndSize : descriptorTypes)
{
getInfo.type = typeAndSize.first;
vkGetDescriptorEXT(*pDevice, &getInfo, typeAndSize.second, dummy);
}
}
m_NULLDescriptorPatternSaved = true;
}
m_PhysicalDeviceData.driverInfo =
@@ -731,6 +731,18 @@ VkResult WrappedVulkan::vkCreateSampler(VkDevice device, const VkSamplerCreateIn
VkResourceRecord *ycbcrRecord = GetRecord(ycbcr->conversion);
record->AddParent(ycbcrRecord);
}
if(m_DescriptorBuffers)
{
VkDescriptorGetInfoEXT getDesc = {
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
};
byte dummy[256];
getDesc.type = VK_DESCRIPTOR_TYPE_SAMPLER;
getDesc.data.pSampler = pSampler;
vkGetDescriptorEXT(device, &getDesc, m_DescriptorBufferProperties.samplerDescriptorSize,
dummy);
}
}
else
{
@@ -1118,7 +1118,9 @@ void WrappedVulkan::CaptureQueueSubmit(VkQueue queue,
for(auto refit = refs.sparseRefs.begin(); refit != refs.sparseRefs.end(); ++refit)
{
GetResourceManager()->MarkSparseMapReferenced((*refit)->resInfo);
// for these which are added as image views, step up to the image (if it's not an identity
// pointer) - see declaration of parentResInfo
GetResourceManager()->MarkSparseMapReferenced((*refit)->resInfo->parentResInfo);
}
UpdateImageStates(refs.bindImageStates);
@@ -2083,7 +2083,7 @@ VkResult WrappedVulkan::vkCreateBuffer(VkDevice device, const VkBufferCreateInfo
record->resInfo = NULL;
if(isSparse || isExternal)
if(isSparse || isExternal || m_DescriptorBuffers)
{
record->resInfo = new ResourceInfo();
@@ -2686,6 +2686,7 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo *
record->AddChunk(chunk);
record->resInfo = new ResourceInfo();
record->resInfo->parentResInfo = record->resInfo;
ResourceInfo &resInfo = *record->resInfo;
resInfo.imageInfo = ImageInfo(*pCreateInfo);
@@ -3067,7 +3068,15 @@ VkResult WrappedVulkan::vkCreateImageView(VkDevice device, const VkImageViewCrea
record->baseResource = imageRecord->GetResourceID();
record->baseResourceMem = imageRecord->baseResourceMem;
record->dedicated = imageRecord->dedicated;
record->resInfo = imageRecord->resInfo;
if(m_DescriptorBuffers)
{
record->resInfo = new ResourceInfo(*imageRecord->resInfo);
record->resInfo->parentResInfo = imageRecord->resInfo;
}
else
{
record->resInfo = imageRecord->resInfo;
}
record->viewRange = pCreateInfo->subresourceRange;
record->viewRange.setViewType(pCreateInfo->viewType);
}
@@ -3677,6 +3686,15 @@ VkResult WrappedVulkan::vkCreateAccelerationStructureKHR(
SCOPED_LOCK(m_ASLookupByAddrLock);
m_ASLookupByAddr[addr] = id;
}
VkDescriptorGetInfoEXT getDesc = {
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
};
byte dummy[256];
getDesc.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
getDesc.data.accelerationStructure = addr;
vkGetDescriptorEXT(device, &getDesc,
m_DescriptorBufferProperties.accelerationStructureDescriptorSize, dummy);
}
}
else