diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index b425c5bd2..9437e384f 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -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) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 707a01fcf..552f00237 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -447,9 +447,15 @@ private: VkQueueFamilyProperties queueProps[16] = {}; }; + VkPhysicalDeviceDescriptorBufferPropertiesEXT m_DescriptorBufferProperties; + size_t DescriptorDataSize(VkDescriptorType type); + Threading::CriticalSection m_ASLookupByAddrLock; rdcflatmap m_ASLookupByAddr; + bool m_NULLDescriptorPatternSaved = false; + bool m_IgnoreLayoutForDescriptors = false; + bool m_SeparateDepthStencil = false; bool m_NULLDescriptorsAllowed = false; bool m_ExtendedDynState = false; diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index c61f2063f..5d317cab1 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -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); diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 9b93ec3fc..16f2844fb 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -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 +{ + std::size_t operator()(const DescriptorUniquenessKey &key) const + { + std::size_t hash = std::hash()(key.layout); + hash ^= std::hash()(key.offset) + 0x9e3779b9 + (hash << 6) + (hash >> 2); + hash ^= std::hash()(key.size) + 0x9e3779b9 + (hash << 6) + (hash >> 2); + hash ^= std::hash()(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 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 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); diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index 7060a5de4..4ac31876f 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -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 bool WrappedVulkan::Serialise_vkCreateDescriptorPool(SerialiserType &ser, VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, @@ -1873,14 +1950,247 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( template 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, diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 46c88ca5d..1de93a240 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -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> 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 typeAndSize : descriptorTypes) + { + getInfo.type = typeAndSize.first; + + vkGetDescriptorEXT(*pDevice, &getInfo, typeAndSize.second, dummy); + } + } + + m_NULLDescriptorPatternSaved = true; } m_PhysicalDeviceData.driverInfo = diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index 48c0f5d35..6b201a926 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -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 { diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index 9e4bbc803..2602c60aa 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -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); diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index 74b6437f0..c58bed248 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -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