From 0442c46affe55fa3274834e8a3c7392f050fcad2 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 23 Apr 2018 23:57:52 +0100 Subject: [PATCH] Implement VK_KHR_descriptor_update_template. Closes #934 --- renderdoc/driver/vulkan/vk_common.cpp | 94 ++++ renderdoc/driver/vulkan/vk_common.h | 18 +- renderdoc/driver/vulkan/vk_core.cpp | 17 + renderdoc/driver/vulkan/vk_core.h | 23 + renderdoc/driver/vulkan/vk_hookset_defs.h | 21 +- renderdoc/driver/vulkan/vk_info.cpp | 142 +++++ renderdoc/driver/vulkan/vk_info.h | 30 ++ renderdoc/driver/vulkan/vk_resources.cpp | 7 +- renderdoc/driver/vulkan/vk_resources.h | 23 +- renderdoc/driver/vulkan/vk_serialise.cpp | 61 +++ renderdoc/driver/vulkan/vk_stringise.cpp | 16 +- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 414 ++++++++++---- .../vulkan/wrappers/vk_descriptor_funcs.cpp | 508 ++++++++++++------ .../driver/vulkan/wrappers/vk_misc_funcs.cpp | 11 +- 14 files changed, 1113 insertions(+), 272 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index 1a84df995..9e85b1989 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -1683,3 +1683,97 @@ VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps) // not fixed yet qualcommLeakingUBOOffsets = m_Vendor == GPUVendor::Qualcomm; } + +FrameRefType GetRefType(VkDescriptorType descType) +{ + switch(descType) + { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: return eFrameRef_Read; break; + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: return eFrameRef_Write; break; + default: RDCERR("Unexpected descriptor type"); + } + + return eFrameRef_Read; +} + +void DescriptorSetSlot::RemoveBindRefs(VkResourceRecord *record) +{ + if(texelBufferView != VK_NULL_HANDLE) + { + record->RemoveBindFrameRef(GetResID(texelBufferView)); + + VkResourceRecord *viewRecord = GetRecord(texelBufferView); + if(viewRecord && viewRecord->baseResource != ResourceId()) + record->RemoveBindFrameRef(viewRecord->baseResource); + } + if(imageInfo.imageView != VK_NULL_HANDLE) + { + record->RemoveBindFrameRef(GetResID(imageInfo.imageView)); + + VkResourceRecord *viewRecord = GetRecord(imageInfo.imageView); + if(viewRecord) + { + record->RemoveBindFrameRef(viewRecord->baseResource); + if(viewRecord->baseResourceMem != ResourceId()) + record->RemoveBindFrameRef(viewRecord->baseResourceMem); + } + } + if(imageInfo.sampler != VK_NULL_HANDLE) + { + record->RemoveBindFrameRef(GetResID(imageInfo.sampler)); + } + if(bufferInfo.buffer != VK_NULL_HANDLE) + { + record->RemoveBindFrameRef(GetResID(bufferInfo.buffer)); + + VkResourceRecord *bufRecord = GetRecord(bufferInfo.buffer); + if(bufRecord && bufRecord->baseResource != ResourceId()) + record->RemoveBindFrameRef(bufRecord->baseResource); + } + + // NULL everything out now so that we don't accidentally reference an object + // that was removed already + texelBufferView = VK_NULL_HANDLE; + bufferInfo.buffer = VK_NULL_HANDLE; + imageInfo.imageView = VK_NULL_HANDLE; + imageInfo.sampler = VK_NULL_HANDLE; +} + +void DescriptorSetSlot::AddBindRefs(VkResourceRecord *record, FrameRefType ref) +{ + if(texelBufferView != VK_NULL_HANDLE) + { + record->AddBindFrameRef(GetResID(texelBufferView), eFrameRef_Read, + GetRecord(texelBufferView)->sparseInfo != NULL); + if(GetRecord(texelBufferView)->baseResource != ResourceId()) + record->AddBindFrameRef(GetRecord(texelBufferView)->baseResource, ref); + } + if(imageInfo.imageView != VK_NULL_HANDLE) + { + record->AddBindFrameRef(GetResID(imageInfo.imageView), eFrameRef_Read, + GetRecord(imageInfo.imageView)->sparseInfo != NULL); + record->AddBindFrameRef(GetRecord(imageInfo.imageView)->baseResource, ref); + if(GetRecord(imageInfo.imageView)->baseResourceMem != ResourceId()) + record->AddBindFrameRef(GetRecord(imageInfo.imageView)->baseResourceMem, eFrameRef_Read); + } + if(imageInfo.sampler != VK_NULL_HANDLE) + { + record->AddBindFrameRef(GetResID(imageInfo.sampler), eFrameRef_Read); + } + if(bufferInfo.buffer != VK_NULL_HANDLE) + { + record->AddBindFrameRef(GetResID(bufferInfo.buffer), eFrameRef_Read, + GetRecord(bufferInfo.buffer)->sparseInfo != NULL); + if(GetRecord(bufferInfo.buffer)->baseResource != ResourceId()) + record->AddBindFrameRef(GetRecord(bufferInfo.buffer)->baseResource, ref); + } +} diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index ff0a2268a..3c0fd3161 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -59,6 +59,7 @@ #include "api/replay/renderdoc_replay.h" #include "core/core.h" +#include "core/resource_manager.h" #include "official/vulkan.h" #include "serialise/serialiser.h" #include "vk_dispatchtables.h" @@ -316,6 +317,10 @@ struct MemoryAllocation // Writing is unambiguously during capture mode, so we don't have to check both in that case. #define IsReplayingAndReading() (ser.IsReading() && IsReplayMode(m_State)) +struct VkResourceRecord; + +FrameRefType GetRefType(VkDescriptorType descType); + // the possible contents of a descriptor set slot, // taken from the VkWriteDescriptorSet struct DescriptorSetSlot @@ -323,6 +328,9 @@ struct DescriptorSetSlot VkDescriptorBufferInfo bufferInfo; VkDescriptorImageInfo imageInfo; VkBufferView texelBufferView; + + void RemoveBindRefs(VkResourceRecord *record); + void AddBindRefs(VkResourceRecord *record, FrameRefType ref); }; DECLARE_REFLECTION_STRUCT(DescriptorSetSlot); @@ -440,6 +448,9 @@ enum class VulkanChunk : uint32_t vkRegisterDisplayEventEXT, vkCmdIndirectSubCommand, vkCmdPushDescriptorSetKHR, + vkCmdPushDescriptorSetWithTemplateKHR, + vkCreateDescriptorUpdateTemplateKHR, + vkUpdateDescriptorSetWithTemplateKHR, Max, }; @@ -476,7 +487,8 @@ DECLARE_REFLECTION_ENUM(VulkanChunk); SERIALISE_HANDLE(VkFramebuffer) \ SERIALISE_HANDLE(VkCommandPool) \ SERIALISE_HANDLE(VkSwapchainKHR) \ - SERIALISE_HANDLE(VkSurfaceKHR) + SERIALISE_HANDLE(VkSurfaceKHR) \ + SERIALISE_HANDLE(VkDescriptorUpdateTemplateKHR) #define SERIALISE_HANDLE(type) DECLARE_REFLECTION_STRUCT(type) @@ -581,6 +593,8 @@ DECLARE_REFLECTION_STRUCT(VkImageBlit); DECLARE_REFLECTION_STRUCT(VkImageResolve); DECLARE_REFLECTION_STRUCT(VkSwapchainCreateInfoKHR); DECLARE_REFLECTION_STRUCT(VkDebugMarkerMarkerInfoEXT); +DECLARE_REFLECTION_STRUCT(VkDescriptorUpdateTemplateEntryKHR); +DECLARE_REFLECTION_STRUCT(VkDescriptorUpdateTemplateCreateInfoKHR); DECLARE_DESERIALISE_TYPE(VkDeviceCreateInfo); DECLARE_DESERIALISE_TYPE(VkBufferCreateInfo); @@ -600,6 +614,7 @@ DECLARE_DESERIALISE_TYPE(VkComputePipelineCreateInfo); DECLARE_DESERIALISE_TYPE(VkDescriptorPoolCreateInfo); DECLARE_DESERIALISE_TYPE(VkWriteDescriptorSet); DECLARE_DESERIALISE_TYPE(VkDescriptorSetLayoutCreateInfo); +DECLARE_DESERIALISE_TYPE(VkDescriptorUpdateTemplateCreateInfoKHR); DECLARE_REFLECTION_ENUM(VkFlagWithNoBits); DECLARE_REFLECTION_ENUM(VkQueueFlagBits); @@ -664,3 +679,4 @@ DECLARE_REFLECTION_ENUM(VkSurfaceTransformFlagBitsKHR); DECLARE_REFLECTION_ENUM(VkCompositeAlphaFlagBitsKHR); DECLARE_REFLECTION_ENUM(VkColorSpaceKHR); DECLARE_REFLECTION_ENUM(VkPresentModeKHR); +DECLARE_REFLECTION_ENUM(VkDescriptorUpdateTemplateType); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index a04a876c4..92e28865d 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -573,6 +573,10 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION, }, + { + VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, + VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION, + }, #ifdef VK_KHR_display { VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_DISPLAY_SPEC_VERSION, @@ -2234,6 +2238,19 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) ser, VK_NULL_HANDLE, VK_PIPELINE_BIND_POINT_GRAPHICS, VK_NULL_HANDLE, 0, 0, NULL); break; + case VulkanChunk::vkCmdPushDescriptorSetWithTemplateKHR: + return Serialise_vkCmdPushDescriptorSetWithTemplateKHR(ser, VK_NULL_HANDLE, VK_NULL_HANDLE, + VK_NULL_HANDLE, 0, NULL); + break; + + case VulkanChunk::vkCreateDescriptorUpdateTemplateKHR: + return Serialise_vkCreateDescriptorUpdateTemplateKHR(ser, VK_NULL_HANDLE, NULL, NULL, NULL); + break; + case VulkanChunk::vkUpdateDescriptorSetWithTemplateKHR: + return Serialise_vkUpdateDescriptorSetWithTemplateKHR(ser, VK_NULL_HANDLE, VK_NULL_HANDLE, + VK_NULL_HANDLE, NULL); + break; + default: { SystemChunk system = (SystemChunk)chunk; diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 2963a1419..dcdb18f4c 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -1635,8 +1635,31 @@ public: VkShaderInfoTypeAMD infoType, size_t *pInfoSize, void *pInfo); // VK_KHR_push_descriptor + void ApplyPushDescriptorWrites(VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites); + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdPushDescriptorSetKHR, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdPushDescriptorSetWithTemplateKHR, + VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + VkPipelineLayout layout, uint32_t set, const void *pData); + + // VK_KHR_descriptor_update_template + IMPLEMENT_FUNCTION_SERIALISED(VkResult, vkCreateDescriptorUpdateTemplateKHR, VkDevice device, + const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkDestroyDescriptorUpdateTemplateKHR, VkDevice device, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + const VkAllocationCallbacks *pAllocator); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkUpdateDescriptorSetWithTemplateKHR, VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + const void *pData); }; diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index dc5047f86..682c037b6 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -307,7 +307,8 @@ CheckExt(KHR_external_semaphore_fd, VKXX); \ CheckExt(KHR_get_memory_requirements2, VK11); \ CheckExt(AMD_shader_info, VKXX); \ - CheckExt(KHR_push_descriptor, VKXX); + CheckExt(KHR_push_descriptor, VKXX); \ + CheckExt(KHR_descriptor_update_template, VK11); #define HookInitVulkanInstanceExts() \ HookInitExtension(KHR_surface, DestroySurfaceKHR); \ @@ -370,6 +371,11 @@ HookInitExtension(KHR_get_memory_requirements2, GetImageSparseMemoryRequirements2KHR); \ HookInitExtension(AMD_shader_info, GetShaderInfoAMD); \ HookInitExtension(KHR_push_descriptor, CmdPushDescriptorSetKHR); \ + HookInitExtension(KHR_descriptor_update_template, CreateDescriptorUpdateTemplateKHR); \ + HookInitExtension(KHR_descriptor_update_template, DestroyDescriptorUpdateTemplateKHR); \ + HookInitExtension(KHR_descriptor_update_template, UpdateDescriptorSetWithTemplateKHR); \ + HookInitExtension(KHR_push_descriptor &&KHR_descriptor_update_template, \ + CmdPushDescriptorSetWithTemplateKHR); \ HookInitDevice_PlatformSpecific() #define DefineHooks() \ @@ -786,6 +792,19 @@ HookDefine6(void, vkCmdPushDescriptorSetKHR, VkCommandBuffer, commandBuffer, \ VkPipelineBindPoint, pipelineBindPoint, VkPipelineLayout, layout, uint32_t, set, \ uint32_t, descriptorWriteCount, const VkWriteDescriptorSet *, pDescriptorWrites); \ + HookDefine4(VkResult, vkCreateDescriptorUpdateTemplateKHR, VkDevice, device, \ + const VkDescriptorUpdateTemplateCreateInfoKHR *, pCreateInfo, \ + const VkAllocationCallbacks *, pAllocator, VkDescriptorUpdateTemplateKHR *, \ + pDescriptorUpdateTemplate); \ + HookDefine3(void, vkDestroyDescriptorUpdateTemplateKHR, VkDevice, device, \ + VkDescriptorUpdateTemplateKHR, descriptorUpdateTemplate, \ + const VkAllocationCallbacks *, pAllocator); \ + HookDefine4(void, vkUpdateDescriptorSetWithTemplateKHR, VkDevice, device, VkDescriptorSet, \ + descriptorSet, VkDescriptorUpdateTemplateKHR, descriptorUpdateTemplate, \ + const void *, pData); \ + HookDefine5(void, vkCmdPushDescriptorSetWithTemplateKHR, VkCommandBuffer, commandBuffer, \ + VkDescriptorUpdateTemplateKHR, descriptorUpdateTemplate, VkPipelineLayout, layout, \ + uint32_t, set, const void *, pData); \ HookDefine_PlatformSpecific() struct VkLayerInstanceDispatchTableExtended : VkLayerInstanceDispatchTable diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 5a567448c..c473dac77 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -695,3 +695,145 @@ void VulkanCreationInfo::DescSetPool::CreateOverflow(VkDevice device, overflow.push_back(pool); } + +void DescUpdateTemplate::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, + const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo) +{ + updates.insert(updates.begin(), pCreateInfo->pDescriptorUpdateEntries, + pCreateInfo->pDescriptorUpdateEntries + pCreateInfo->descriptorUpdateEntryCount); + + dataByteSize = 0; + + texelBufferViewCount = 0; + bufferInfoCount = 0; + imageInfoCount = 0; + + for(const VkDescriptorUpdateTemplateEntryKHR &entry : updates) + { + uint32_t entrySize = 4; + + if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + entrySize = sizeof(VkBufferView); + + texelBufferViewCount += entry.descriptorCount; + } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + entrySize = sizeof(VkDescriptorImageInfo); + + imageInfoCount += entry.descriptorCount; + } + else + { + entrySize = sizeof(VkDescriptorBufferInfo); + + bufferInfoCount += entry.descriptorCount; + } + + dataByteSize = + RDCMAX(dataByteSize, entry.offset + entry.stride * entry.descriptorCount + entrySize); + } + + if(pCreateInfo->templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET) + { + if(IsCaptureMode(resourceMan->GetState())) + { + layout = *GetRecord(pCreateInfo->descriptorSetLayout)->descInfo->layout; + } + else + { + layout = info.m_DescSetLayout[GetResID(pCreateInfo->descriptorSetLayout)]; + } + } + else + { + if(IsCaptureMode(resourceMan->GetState())) + { + layout = GetRecord(pCreateInfo->pipelineLayout)->pipeLayoutInfo->layouts[pCreateInfo->set]; + } + else + { + const std::vector &descSetLayouts = + info.m_PipelineLayout[GetResID(pCreateInfo->pipelineLayout)].descSetLayouts; + + layout = info.m_DescSetLayout[descSetLayouts[pCreateInfo->set]]; + } + } +} + +void DescUpdateTemplate::Apply(const void *pData, DescUpdateTemplateApplication &application) +{ + application.bufView.reserve(texelBufferViewCount); + application.bufInfo.reserve(bufferInfoCount); + application.imgInfo.reserve(imageInfoCount); + + for(const VkDescriptorUpdateTemplateEntryKHR &entry : updates) + { + VkWriteDescriptorSet write = {}; + + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = VK_NULL_HANDLE; // set externally for non-push descriptor template updates. + write.dstBinding = entry.dstBinding; + write.dstArrayElement = entry.dstArrayElement; + write.descriptorType = entry.descriptorType; + write.descriptorCount = entry.descriptorCount; + + const byte *src = (const byte *)pData + entry.offset; + + if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + size_t idx = application.bufView.size(); + + application.bufView.resize(idx + entry.descriptorCount); + + for(uint32_t d = 0; d < entry.descriptorCount; d++) + { + memcpy(&application.bufView[idx + d], src, sizeof(VkBufferView)); + src += entry.stride; + } + + write.pTexelBufferView = &application.bufView[idx]; + } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + size_t idx = application.imgInfo.size(); + + application.imgInfo.resize(idx + entry.descriptorCount); + + for(uint32_t d = 0; d < entry.descriptorCount; d++) + { + memcpy(&application.imgInfo[idx + d], src, sizeof(VkDescriptorImageInfo)); + src += entry.stride; + } + + write.pImageInfo = &application.imgInfo[idx]; + } + else + { + size_t idx = application.bufInfo.size(); + + application.bufInfo.resize(idx + entry.descriptorCount); + + for(uint32_t d = 0; d < entry.descriptorCount; d++) + { + memcpy(&application.bufInfo[idx + d], src, sizeof(VkDescriptorBufferInfo)); + src += entry.stride; + } + + write.pBufferInfo = &application.bufInfo[idx]; + } + + application.writes.push_back(write); + } +} diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 7b28f126e..dd06c7efa 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -79,6 +79,35 @@ struct DescSetLayout bool operator!=(const DescSetLayout &other) const { return !(*this == other); } }; +struct DescUpdateTemplateApplication +{ + std::vector bufInfo; + std::vector imgInfo; + std::vector bufView; + + std::vector writes; +}; + +struct DescUpdateTemplate +{ + void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, + const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo); + + void Apply(const void *pData, DescUpdateTemplateApplication &application); + + DescSetLayout layout; + + VkPipelineBindPoint bindPoint; + + size_t dataByteSize; + + uint32_t texelBufferViewCount; + uint32_t bufferInfoCount; + uint32_t imageInfoCount; + + std::vector updates; +}; + struct VulkanCreationInfo { struct Pipeline @@ -390,4 +419,5 @@ struct VulkanCreationInfo map m_Names; map m_SwapChain; map m_DescSetLayout; + map m_DescUpdateTemplate; }; diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 47c2dce91..fb55ca159 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -50,9 +50,9 @@ WRAPPED_POOL_INST(WrappedVkDescriptorPool) WRAPPED_POOL_INST(WrappedVkDescriptorSet) WRAPPED_POOL_INST(WrappedVkFramebuffer) WRAPPED_POOL_INST(WrappedVkCommandPool) - WRAPPED_POOL_INST(WrappedVkSwapchainKHR) WRAPPED_POOL_INST(WrappedVkSurfaceKHR) +WRAPPED_POOL_INST(WrappedVkDescriptorUpdateTemplateKHR) byte VkResourceRecord::markerValue[32] = { 0xaa, 0xbb, 0xcc, 0xdd, 0x88, 0x77, 0x66, 0x55, 0x01, 0x23, 0x45, 0x67, 0x98, 0x76, 0x54, 0x32, @@ -121,6 +121,8 @@ VkResourceType IdentifyTypeByPtr(WrappedVkRes *ptr) return eResSwapchain; if(WrappedVkSurfaceKHR::IsAlloc(ptr)) return eResSurface; + if(WrappedVkDescriptorUpdateTemplateKHR::IsAlloc(ptr)) + return eResDescUpdateTemplate; RDCERR("Unknown type for ptr 0x%p", ptr); @@ -836,6 +838,9 @@ VkResourceRecord::~VkResourceRecord() if(resType == eResPipelineLayout) SAFE_DELETE(pipeLayoutInfo); + + if(resType == eResDescUpdateTemplate) + SAFE_DELETE(descTemplateInfo); } void SparseMapping::Update(uint32_t numBindings, const VkSparseImageMemoryBind *pBindings) diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index a347b3020..dda6075dd 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -67,9 +67,9 @@ enum VkResourceType eResEvent, eResQueryPool, eResSemaphore, - eResSwapchain, - eResSurface + eResSurface, + eResDescUpdateTemplate, }; DECLARE_REFLECTION_ENUM(VkResourceType); @@ -548,6 +548,19 @@ struct WrappedVkSurfaceKHR : WrappedVkNonDispRes TypeEnum = eResSurface, }; }; +struct WrappedVkDescriptorUpdateTemplateKHR : WrappedVkNonDispRes +{ + WrappedVkDescriptorUpdateTemplateKHR(VkDescriptorUpdateTemplateKHR obj, ResourceId objId) + : WrappedVkNonDispRes(obj, objId) + { + } + typedef VkDescriptorUpdateTemplateKHR InnerType; + ALLOCATE_WITH_WRAPPED_POOL(WrappedVkDescriptorUpdateTemplateKHR); + enum + { + TypeEnum = eResDescUpdateTemplate, + }; +}; // VkDisplayKHR and VkDisplayModeKHR are both UNWRAPPED because there's no need to wrap them. // The only thing we need to wrap VkSurfaceKHR for is to get back the window from it later. @@ -645,6 +658,7 @@ UNWRAP_NONDISP_HELPER(VkFramebuffer) UNWRAP_NONDISP_HELPER(VkCommandPool) UNWRAP_NONDISP_HELPER(VkSwapchainKHR) UNWRAP_NONDISP_HELPER(VkSurfaceKHR) +UNWRAP_NONDISP_HELPER(VkDescriptorUpdateTemplateKHR) // VkDisplayKHR and VkDisplayModeKHR are both UNWRAPPED because there's no need to wrap them. // The only thing we need to wrap VkSurfaceKHR for is to get back the window from it later. @@ -955,6 +969,8 @@ struct AttachmentInfo VkImageMemoryBarrier barrier; }; +struct DescUpdateTemplate; + struct VkResourceRecord : public ResourceRecord { public: @@ -1068,7 +1084,8 @@ public: CmdBufferRecordingInfo *cmdInfo; // only for command buffers AttachmentInfo *imageAttachments; // only for framebuffers and render passes PipelineLayoutData *pipeLayoutInfo; // only for pipeline layouts - DescriptorSetData *descInfo; // only for descriptor sets and descriptor set layouts + DescriptorSetData *descInfo; // only for descriptor sets and descriptor set layouts + DescUpdateTemplate *descTemplateInfo; // only for descriptor update templates }; VkResourceRecord *bakedCommands; diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index 457cd9b1b..eac1590d7 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -196,6 +196,14 @@ static void SerialiseNext(SerialiserType &ser, VkStructureType &sType, const voi } } +template +static void SerialiseNext(SerialiserType &ser, VkStructureType &sType, void *&pNext) +{ + const void *tmpNext = pNext; + SerialiseNext(ser, sType, tmpNext); + pNext = (void *)tmpNext; +} + template void DoSerialise(SerialiserType &ser, VkAllocationCallbacks &el) { @@ -1877,6 +1885,58 @@ void DoSerialise(SerialiserType &ser, ImageLayouts &el) SERIALISE_MEMBER(format); } +template +void DoSerialise(SerialiserType &ser, VkDescriptorUpdateTemplateEntryKHR &el) +{ + SERIALISE_MEMBER(dstBinding); + SERIALISE_MEMBER(dstArrayElement); + SERIALISE_MEMBER(descriptorCount); + SERIALISE_MEMBER(descriptorType); + SERIALISE_MEMBER(offset); + SERIALISE_MEMBER(stride); +} + +template +void DoSerialise(SerialiserType &ser, VkDescriptorUpdateTemplateCreateInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER_TYPED(VkFlagWithNoBits, flags); + SERIALISE_MEMBER(descriptorUpdateEntryCount); + SERIALISE_MEMBER_ARRAY(pDescriptorUpdateEntries, descriptorUpdateEntryCount); + SERIALISE_MEMBER(templateType); + + if(el.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET) + { + SERIALISE_MEMBER(descriptorSetLayout); + } + else + { + SERIALISE_MEMBER_EMPTY(descriptorSetLayout); + } + + if(el.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR) + { + SERIALISE_MEMBER(pipelineBindPoint); + SERIALISE_MEMBER(pipelineLayout); + SERIALISE_MEMBER(set); + } + else + { + SERIALISE_MEMBER_EMPTY(pipelineBindPoint); + SERIALISE_MEMBER_EMPTY(pipelineLayout); + SERIALISE_MEMBER_EMPTY(set); + } +} + +template <> +void Deserialise(const VkDescriptorUpdateTemplateCreateInfoKHR &el) +{ + RDCASSERT(el.pNext == NULL); // otherwise delete + delete[] el.pDescriptorUpdateEntries; +} + INSTANTIATE_SERIALISE_TYPE(VkOffset2D); INSTANTIATE_SERIALISE_TYPE(VkExtent2D); INSTANTIATE_SERIALISE_TYPE(VkMemoryType); @@ -1974,6 +2034,7 @@ INSTANTIATE_SERIALISE_TYPE(VkImageBlit); INSTANTIATE_SERIALISE_TYPE(VkImageResolve); INSTANTIATE_SERIALISE_TYPE(VkSwapchainCreateInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkDebugMarkerMarkerInfoEXT); +INSTANTIATE_SERIALISE_TYPE(VkDescriptorUpdateTemplateCreateInfoKHR); INSTANTIATE_SERIALISE_TYPE(DescriptorSetSlot); INSTANTIATE_SERIALISE_TYPE(ImageRegionState); diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index 778f069ec..c00e53660 100644 --- a/renderdoc/driver/vulkan/vk_stringise.cpp +++ b/renderdoc/driver/vulkan/vk_stringise.cpp @@ -28,7 +28,7 @@ template <> std::string DoStringise(const VulkanChunk &el) { - RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1099, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1102, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(VulkanChunk) { @@ -131,6 +131,9 @@ std::string DoStringise(const VulkanChunk &el) STRINGISE_ENUM_CLASS(vkRegisterDisplayEventEXT); STRINGISE_ENUM_CLASS_NAMED(vkCmdIndirectSubCommand, "Indirect sub-command"); STRINGISE_ENUM_CLASS(vkCmdPushDescriptorSetKHR); + STRINGISE_ENUM_CLASS(vkCmdPushDescriptorSetWithTemplateKHR); + STRINGISE_ENUM_CLASS(vkCreateDescriptorUpdateTemplateKHR); + STRINGISE_ENUM_CLASS(vkUpdateDescriptorSetWithTemplateKHR); STRINGISE_ENUM_CLASS_NAMED(Max, "Max Chunk"); } END_ENUM_STRINGISE() @@ -1672,6 +1675,17 @@ std::string DoStringise(const VkPresentModeKHR &el) END_ENUM_STRINGISE(); } +template <> +std::string DoStringise(const VkDescriptorUpdateTemplateType &el) +{ + BEGIN_ENUM_STRINGISE(VkDescriptorUpdateTemplateType); + { + STRINGISE_ENUM(VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET) + STRINGISE_ENUM(VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR) + } + END_ENUM_STRINGISE(); +} + template <> std::string DoStringise(const VkExtent3D &el) { diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 0fef57ccb..084c6349b 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -2939,6 +2939,98 @@ void WrappedVulkan::vkCmdDebugMarkerInsertEXT(VkCommandBuffer commandBuffer, } } +void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineLayout layout, uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites) +{ + ResourceId setId = m_BakedCmdBufferInfo[m_LastCmdBufferID].pushDescriptorID[set]; + + const std::vector &descSetLayouts = + m_CreationInfo.m_PipelineLayout[GetResID(layout)].descSetLayouts; + + const DescSetLayout &desclayout = m_CreationInfo.m_DescSetLayout[descSetLayouts[set]]; + + std::vector &bindings = m_DescriptorSetState[setId].currentBindings; + ResourceId prevLayout = m_DescriptorSetState[setId].layout; + + if(prevLayout == ResourceId()) + { + desclayout.CreateBindingsArray(bindings); + } + else if(prevLayout != descSetLayouts[set]) + { + desclayout.UpdateBindingsArray(m_CreationInfo.m_DescSetLayout[prevLayout], bindings); + } + + m_DescriptorSetState[setId].layout = descSetLayouts[set]; + + // update our local tracking + for(uint32_t i = 0; i < descriptorWriteCount; i++) + { + const VkWriteDescriptorSet &writeDesc = pDescriptorWrites[i]; + + RDCASSERT(writeDesc.dstBinding < bindings.size()); + + DescriptorSetSlot **bind = &bindings[writeDesc.dstBinding]; + const DescSetLayout::Binding *layoutBinding = &desclayout.bindings[writeDesc.dstBinding]; + uint32_t curIdx = writeDesc.dstArrayElement; + + if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) + { + // allow consecutive descriptor bind updates. See vkUpdateDescriptorSets for more + // explanation + if(curIdx >= layoutBinding->descriptorCount) + { + layoutBinding++; + bind++; + curIdx = 0; + } + + (*bind)[curIdx].texelBufferView = writeDesc.pTexelBufferView[d]; + } + } + else if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) + { + // allow consecutive descriptor bind updates. See vkUpdateDescriptorSets for more + // explanation + if(curIdx >= layoutBinding->descriptorCount) + { + layoutBinding++; + bind++; + curIdx = 0; + } + + (*bind)[curIdx].imageInfo = writeDesc.pImageInfo[d]; + } + } + else + { + for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) + { + // allow consecutive descriptor bind updates. See vkUpdateDescriptorSets for more + // explanation + if(curIdx >= layoutBinding->descriptorCount) + { + layoutBinding++; + bind++; + curIdx = 0; + } + + (*bind)[curIdx].bufferInfo = writeDesc.pBufferInfo[d]; + } + } + } +} + template bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetKHR(SerialiserType &ser, VkCommandBuffer commandBuffer, @@ -3014,92 +3106,7 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetKHR(SerialiserType &ser, // without worrying about overlap. We just need to check that we're in the record range so // that we don't pull in descriptor updates after the point in the command buffer we're // recording to - { - const std::vector &descSetLayouts = - m_CreationInfo.m_PipelineLayout[GetResID(layout)].descSetLayouts; - - const DescSetLayout &desclayout = m_CreationInfo.m_DescSetLayout[descSetLayouts[set]]; - - for(uint32_t i = 0; i < descriptorWriteCount; i++) - { - const VkWriteDescriptorSet &writeDesc = pDescriptorWrites[i]; - - // update our local tracking - std::vector &bindings = m_DescriptorSetState[setId].currentBindings; - ResourceId prevLayout = m_DescriptorSetState[setId].layout; - - if(prevLayout == ResourceId()) - { - desclayout.CreateBindingsArray(bindings); - } - else if(prevLayout != descSetLayouts[set]) - { - desclayout.UpdateBindingsArray(m_CreationInfo.m_DescSetLayout[prevLayout], bindings); - } - - m_DescriptorSetState[setId].layout = descSetLayouts[set]; - - RDCASSERT(writeDesc.dstBinding < bindings.size()); - - DescriptorSetSlot **bind = &bindings[writeDesc.dstBinding]; - const DescSetLayout::Binding *layoutBinding = &desclayout.bindings[writeDesc.dstBinding]; - uint32_t curIdx = writeDesc.dstArrayElement; - - if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || - writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) - { - for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) - { - // allow consecutive descriptor bind updates. See vkUpdateDescriptorSets for more - // explanation - if(curIdx >= layoutBinding->descriptorCount) - { - layoutBinding++; - bind++; - curIdx = 0; - } - - (*bind)[curIdx].texelBufferView = writeDesc.pTexelBufferView[d]; - } - } - else if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || - writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || - writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || - writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || - writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) - { - for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) - { - // allow consecutive descriptor bind updates. See vkUpdateDescriptorSets for more - // explanation - if(curIdx >= layoutBinding->descriptorCount) - { - layoutBinding++; - bind++; - curIdx = 0; - } - - (*bind)[curIdx].imageInfo = writeDesc.pImageInfo[d]; - } - } - else - { - for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) - { - // allow consecutive descriptor bind updates. See vkUpdateDescriptorSets for more - // explanation - if(curIdx >= layoutBinding->descriptorCount) - { - layoutBinding++; - bind++; - curIdx = 0; - } - - (*bind)[curIdx].bufferInfo = writeDesc.pBufferInfo[d]; - } - } - } - } + ApplyPushDescriptorWrites(layout, set, descriptorWriteCount, pDescriptorWrites); // now unwrap everything in-place to save on temp allocs. VkWriteDescriptorSet *writes = (VkWriteDescriptorSet *)pDescriptorWrites; @@ -3240,23 +3247,7 @@ void WrappedVulkan::vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, { const VkWriteDescriptorSet &write = pDescriptorWrites[i]; - FrameRefType ref = eFrameRef_Write; - - switch(write.descriptorType) - { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ref = eFrameRef_Read; break; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: ref = eFrameRef_Write; break; - default: RDCERR("Unexpected descriptor type"); - } + FrameRefType ref = GetRefType(write.descriptorType); for(uint32_t d = 0; d < write.descriptorCount; d++) { @@ -3301,6 +3292,218 @@ void WrappedVulkan::vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, } } } + +template +bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetWithTemplateKHR( + SerialiserType &ser, VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, + const void *pData) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT(descriptorUpdateTemplate); + SERIALISE_ELEMENT(layout); + SERIALISE_ELEMENT(set); + + // we can't serialise pData as-is, since we need to decode to ResourceId for references, etc. The + // sensible way to do this is to decode the data into a series of writes and serialise that. + DescUpdateTemplateApplication apply; + + if(IsCaptureMode(m_State)) + { + // decode while capturing. + GetRecord(descriptorUpdateTemplate)->descTemplateInfo->Apply(pData, apply); + } + + SERIALISE_ELEMENT(apply.writes).Named("Decoded Writes"); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + m_LastCmdBufferID = GetResourceManager()->GetOriginalID(GetResID(commandBuffer)); + + ResourceId setId = m_BakedCmdBufferInfo[m_LastCmdBufferID].pushDescriptorID[set]; + + if(IsActiveReplaying(m_State)) + { + if(InRerecordRange(m_LastCmdBufferID)) + { + commandBuffer = RerecordCmdBuf(m_LastCmdBufferID); + + if(IsPartialCmdBuf(m_LastCmdBufferID)) + { + std::vector &descsets = + (m_CreationInfo.m_DescUpdateTemplate[GetResID(descriptorUpdateTemplate)].bindPoint == + VK_PIPELINE_BIND_POINT_GRAPHICS) + ? m_RenderState.graphics.descSets + : m_RenderState.compute.descSets; + + // expand as necessary + if(descsets.size() < set + 1) + descsets.resize(set + 1); + + descsets[set].descSet = setId; + } + + // actual replay of the command will happen below + } + else + { + commandBuffer = VK_NULL_HANDLE; + } + } + else + { + // track while reading, as we need to track resource usage + std::vector &descsets = + (m_CreationInfo.m_DescUpdateTemplate[GetResID(descriptorUpdateTemplate)].bindPoint == + VK_PIPELINE_BIND_POINT_GRAPHICS) + ? m_BakedCmdBufferInfo[m_LastCmdBufferID].state.graphicsDescSets + : m_BakedCmdBufferInfo[m_LastCmdBufferID].state.computeDescSets; + + // expand as necessary + if(descsets.size() < set + 1) + descsets.resize(set + 1); + + // we use a 'special' ID for the push descriptor at this index, since there's no actual + // allocated object corresponding to it. + descsets[set].descSet = setId; + } + + if(commandBuffer != VK_NULL_HANDLE) + { + VkPipelineBindPoint bindPoint = + m_CreationInfo.m_DescUpdateTemplate[GetResID(descriptorUpdateTemplate)].bindPoint; + + // since we version push descriptors per-command buffer, we can safely update them always + // without worrying about overlap. We just need to check that we're in the record range so + // that we don't pull in descriptor updates after the point in the command buffer we're + // recording to + ApplyPushDescriptorWrites(layout, set, (uint32_t)apply.writes.size(), apply.writes.data()); + + ObjDisp(commandBuffer) + ->CmdPushDescriptorSetKHR(Unwrap(commandBuffer), bindPoint, Unwrap(layout), set, + (uint32_t)apply.writes.size(), apply.writes.data()); + } + } + + return true; +} + +void WrappedVulkan::vkCmdPushDescriptorSetWithTemplateKHR( + VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + VkPipelineLayout layout, uint32_t set, const void *pData) +{ + SCOPED_DBG_SINK(); + + // since it's relatively expensive to walk the memory, we gather frame references at the same time + // as unwrapping + std::vector > frameRefs; + + { + DescUpdateTemplate *tempInfo = GetRecord(descriptorUpdateTemplate)->descTemplateInfo; + + // allocate the whole blob of memory + byte *memory = GetTempMemory(tempInfo->dataByteSize); + + // iterate the entries, copy the descriptor data and unwrap + for(const VkDescriptorUpdateTemplateEntryKHR &entry : tempInfo->updates) + { + byte *dst = memory + entry.offset; + const byte *src = (const byte *)pData + entry.offset; + + FrameRefType ref = GetRefType(entry.descriptorType); + + if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + for(uint32_t d = 0; d < entry.descriptorCount; d++) + { + memcpy(dst, src, sizeof(VkBufferView)); + + VkBufferView *bufView = (VkBufferView *)dst; + + frameRefs.push_back(std::make_pair(GetResID(*bufView), eFrameRef_Read)); + if(GetRecord(*bufView)->baseResource != ResourceId()) + frameRefs.push_back(std::make_pair(GetRecord(*bufView)->baseResource, ref)); + + *bufView = Unwrap(*bufView); + } + } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + bool hasSampler = (entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + bool hasImage = (entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT); + + for(uint32_t d = 0; d < entry.descriptorCount; d++) + { + memcpy(dst, src, sizeof(VkDescriptorImageInfo)); + + VkDescriptorImageInfo *info = (VkDescriptorImageInfo *)dst; + + if(hasSampler) + { + frameRefs.push_back(std::make_pair(GetResID(info->sampler), eFrameRef_Read)); + info->sampler = Unwrap(info->sampler); + } + if(hasImage) + { + frameRefs.push_back(std::make_pair(GetResID(info->imageView), eFrameRef_Read)); + if(GetRecord(info->imageView)->baseResource != ResourceId()) + frameRefs.push_back(std::make_pair(GetRecord(info->imageView)->baseResource, ref)); + info->imageView = Unwrap(info->imageView); + } + } + } + else + { + for(uint32_t d = 0; d < entry.descriptorCount; d++) + { + memcpy(dst, src, sizeof(VkDescriptorBufferInfo)); + + VkDescriptorBufferInfo *info = (VkDescriptorBufferInfo *)dst; + + frameRefs.push_back(std::make_pair(GetResID(info->buffer), eFrameRef_Read)); + if(GetRecord(info->buffer)->baseResource != ResourceId()) + frameRefs.push_back(std::make_pair(GetRecord(info->buffer)->baseResource, ref)); + + info->buffer = Unwrap(info->buffer); + } + } + } + + SERIALISE_TIME_CALL(ObjDisp(commandBuffer) + ->CmdPushDescriptorSetWithTemplateKHR(Unwrap(commandBuffer), + Unwrap(descriptorUpdateTemplate), + Unwrap(layout), set, memory)); + } + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdPushDescriptorSetWithTemplateKHR); + Serialise_vkCmdPushDescriptorSetWithTemplateKHR(ser, commandBuffer, descriptorUpdateTemplate, + layout, set, pData); + + record->AddChunk(scope.Get()); + for(size_t i = 0; i < frameRefs.size(); i++) + record->MarkResourceFrameReferenced(frameRefs[i].first, frameRefs[i].second); + } +} + INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateCommandPool, VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool); @@ -3393,3 +3596,8 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdPushDescriptorSetKHR, VkCommandBuffer VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites); + +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdPushDescriptorSetWithTemplateKHR, + VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + VkPipelineLayout layout, uint32_t set, const void *pData); diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index cfbbffa17..d48f99bda 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -75,6 +75,18 @@ VkDescriptorSetAllocateInfo WrappedVulkan::UnwrapInfo(const VkDescriptorSetAlloc return ret; } +template <> +VkDescriptorUpdateTemplateCreateInfoKHR WrappedVulkan::UnwrapInfo( + const VkDescriptorUpdateTemplateCreateInfoKHR *info) +{ + VkDescriptorUpdateTemplateCreateInfoKHR ret = *info; + + ret.pipelineLayout = Unwrap(ret.pipelineLayout); + ret.descriptorSetLayout = Unwrap(ret.descriptorSetLayout); + + return ret; +} + template <> VkWriteDescriptorSet WrappedVulkan::UnwrapInfo(const VkWriteDescriptorSet *writeDesc) { @@ -977,33 +989,19 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, { for(uint32_t i = 0; i < writeCount; i++) { - VkResourceRecord *record = GetRecord(pDescriptorWrites[i].dstSet); + const VkWriteDescriptorSet &descWrite = pDescriptorWrites[i]; + + VkResourceRecord *record = GetRecord(descWrite.dstSet); RDCASSERT(record->descInfo && record->descInfo->layout); const DescSetLayout &layout = *record->descInfo->layout; - RDCASSERT(pDescriptorWrites[i].dstBinding < record->descInfo->descBindings.size()); + RDCASSERT(descWrite.dstBinding < record->descInfo->descBindings.size()); - DescriptorSetSlot **binding = &record->descInfo->descBindings[pDescriptorWrites[i].dstBinding]; + DescriptorSetSlot **binding = &record->descInfo->descBindings[descWrite.dstBinding]; - const DescSetLayout::Binding *layoutBinding = &layout.bindings[pDescriptorWrites[i].dstBinding]; + const DescSetLayout::Binding *layoutBinding = &layout.bindings[descWrite.dstBinding]; - FrameRefType ref = eFrameRef_Write; - - switch(layoutBinding->descriptorType) - { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ref = eFrameRef_Read; break; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: ref = eFrameRef_Write; break; - default: RDCERR("Unexpected descriptor type"); - } + FrameRefType ref = GetRefType(layoutBinding->descriptorType); // We need to handle the cases where these bindings are stale: // ie. image handle 0xf00baa is allocated @@ -1021,9 +1019,9 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, // This is handled by RemoveBindFrameRef silently dropping id == ResourceId() // start at the dstArrayElement - uint32_t curIdx = pDescriptorWrites[i].dstArrayElement; + uint32_t curIdx = descWrite.dstArrayElement; - for(uint32_t d = 0; d < pDescriptorWrites[i].descriptorCount; d++, curIdx++) + for(uint32_t d = 0; d < descWrite.descriptorCount; d++, curIdx++) { // roll over onto the next binding, on the assumption that it is the same // type and there is indeed a next binding at all. See spec language: @@ -1045,98 +1043,34 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, DescriptorSetSlot &bind = (*binding)[curIdx]; - if(bind.texelBufferView != VK_NULL_HANDLE) - { - record->RemoveBindFrameRef(GetResID(bind.texelBufferView)); + bind.RemoveBindRefs(record); - VkResourceRecord *viewRecord = GetRecord(bind.texelBufferView); - if(viewRecord && viewRecord->baseResource != ResourceId()) - record->RemoveBindFrameRef(viewRecord->baseResource); - } - if(bind.imageInfo.imageView != VK_NULL_HANDLE) + if(descWrite.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + descWrite.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { - record->RemoveBindFrameRef(GetResID(bind.imageInfo.imageView)); - - VkResourceRecord *viewRecord = GetRecord(bind.imageInfo.imageView); - if(viewRecord) - { - record->RemoveBindFrameRef(viewRecord->baseResource); - if(viewRecord->baseResourceMem != ResourceId()) - record->RemoveBindFrameRef(viewRecord->baseResourceMem); - } + bind.texelBufferView = descWrite.pTexelBufferView[d]; } - if(bind.imageInfo.sampler != VK_NULL_HANDLE) + else if(descWrite.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + descWrite.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + descWrite.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + descWrite.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + descWrite.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) { - record->RemoveBindFrameRef(GetResID(bind.imageInfo.sampler)); - } - if(bind.bufferInfo.buffer != VK_NULL_HANDLE) - { - record->RemoveBindFrameRef(GetResID(bind.bufferInfo.buffer)); - - VkResourceRecord *bufRecord = GetRecord(bind.bufferInfo.buffer); - if(bufRecord && bufRecord->baseResource != ResourceId()) - record->RemoveBindFrameRef(bufRecord->baseResource); - } - - // NULL everything out now so that we don't accidentally reference an object - // that was removed already - bind.texelBufferView = VK_NULL_HANDLE; - bind.bufferInfo.buffer = VK_NULL_HANDLE; - bind.imageInfo.imageView = VK_NULL_HANDLE; - bind.imageInfo.sampler = VK_NULL_HANDLE; - - if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || - pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) - { - bind.texelBufferView = pDescriptorWrites[i].pTexelBufferView[d]; - } - else if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || - pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || - pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || - pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || - pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) - { - bind.imageInfo = pDescriptorWrites[i].pImageInfo[d]; + bind.imageInfo = descWrite.pImageInfo[d]; // ignore descriptors not part of the write, by NULL'ing out those members // as they might not even point to a valid object - if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) + if(descWrite.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) bind.imageInfo.imageView = VK_NULL_HANDLE; - else if(pDescriptorWrites[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) + else if(descWrite.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) bind.imageInfo.sampler = VK_NULL_HANDLE; } else { - bind.bufferInfo = pDescriptorWrites[i].pBufferInfo[d]; + bind.bufferInfo = descWrite.pBufferInfo[d]; } - if(bind.texelBufferView != VK_NULL_HANDLE) - { - record->AddBindFrameRef(GetResID(bind.texelBufferView), eFrameRef_Read, - GetRecord(bind.texelBufferView)->sparseInfo != NULL); - if(GetRecord(bind.texelBufferView)->baseResource != ResourceId()) - record->AddBindFrameRef(GetRecord(bind.texelBufferView)->baseResource, ref); - } - if(bind.imageInfo.imageView != VK_NULL_HANDLE) - { - record->AddBindFrameRef(GetResID(bind.imageInfo.imageView), eFrameRef_Read, - GetRecord(bind.imageInfo.imageView)->sparseInfo != NULL); - record->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource, ref); - if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId()) - record->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem, - eFrameRef_Read); - } - if(bind.imageInfo.sampler != VK_NULL_HANDLE) - { - record->AddBindFrameRef(GetResID(bind.imageInfo.sampler), eFrameRef_Read); - } - if(bind.bufferInfo.buffer != VK_NULL_HANDLE) - { - record->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read, - GetRecord(bind.bufferInfo.buffer)->sparseInfo != NULL); - if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) - record->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref); - } + bind.AddBindRefs(record, ref); } } @@ -1167,23 +1101,7 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, const DescSetLayout::Binding *srclayoutBinding = &srclayout.bindings[pDescriptorCopies[i].srcBinding]; - FrameRefType ref = eFrameRef_Write; - - switch(dstlayoutBinding->descriptorType) - { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ref = eFrameRef_Read; break; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: ref = eFrameRef_Write; break; - default: RDCERR("Unexpected descriptor type"); - } + FrameRefType ref = GetRefType(dstlayoutBinding->descriptorType); // allow roll-over between consecutive bindings. See above in the plain write case for more // explanation @@ -1209,59 +1127,317 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, DescriptorSetSlot &bind = (*dstbinding)[curDstIdx]; - if(bind.texelBufferView != VK_NULL_HANDLE) - { - dstrecord->RemoveBindFrameRef(GetResID(bind.texelBufferView)); - if(GetRecord(bind.texelBufferView)->baseResource != ResourceId()) - dstrecord->RemoveBindFrameRef(GetRecord(bind.texelBufferView)->baseResource); - } - if(bind.imageInfo.imageView != VK_NULL_HANDLE) - { - dstrecord->RemoveBindFrameRef(GetResID(bind.imageInfo.imageView)); - dstrecord->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource); - if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId()) - dstrecord->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem); - } - if(bind.imageInfo.sampler != VK_NULL_HANDLE) - { - dstrecord->RemoveBindFrameRef(GetResID(bind.imageInfo.sampler)); - } - if(bind.bufferInfo.buffer != VK_NULL_HANDLE) - { - dstrecord->RemoveBindFrameRef(GetResID(bind.bufferInfo.buffer)); - if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) - dstrecord->RemoveBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource); - } - + bind.RemoveBindRefs(dstrecord); bind = (*srcbinding)[curSrcIdx]; + bind.AddBindRefs(dstrecord, ref); + } + } + } +} - if(bind.texelBufferView != VK_NULL_HANDLE) +template +bool WrappedVulkan::Serialise_vkCreateDescriptorUpdateTemplateKHR( + SerialiserType &ser, VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) +{ + SERIALISE_ELEMENT(device); + SERIALISE_ELEMENT_LOCAL(CreateInfo, *pCreateInfo); + SERIALISE_ELEMENT_OPT(pAllocator); + SERIALISE_ELEMENT_LOCAL(DescriptorUpdateTemplate, GetResID(*pDescriptorUpdateTemplate)) + .TypedAs("VkDescriptorUpdateTemplateKHR"); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + VkDescriptorUpdateTemplateKHR templ = VK_NULL_HANDLE; + + VkResult ret = ObjDisp(device)->CreateDescriptorUpdateTemplateKHR(Unwrap(device), &CreateInfo, + NULL, &templ); + + if(ret != VK_SUCCESS) + { + RDCERR("Failed on resource serialise-creation, VkResult: %s", ToStr(ret).c_str()); + return false; + } + else + { + ResourceId live = GetResourceManager()->WrapResource(Unwrap(device), templ); + GetResourceManager()->AddLiveResource(DescriptorUpdateTemplate, templ); + + m_CreationInfo.m_DescUpdateTemplate[live].Init(GetResourceManager(), m_CreationInfo, + &CreateInfo); + } + + AddResource(DescriptorUpdateTemplate, ResourceType::StateObject, "Descriptor Update Template"); + DerivedResource(device, DescriptorUpdateTemplate); + if(CreateInfo.pipelineLayout != VK_NULL_HANDLE) + DerivedResource(CreateInfo.pipelineLayout, DescriptorUpdateTemplate); + if(CreateInfo.descriptorSetLayout != VK_NULL_HANDLE) + DerivedResource(CreateInfo.descriptorSetLayout, DescriptorUpdateTemplate); + } + + return true; +} + +VkResult WrappedVulkan::vkCreateDescriptorUpdateTemplateKHR( + VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) +{ + VkDescriptorUpdateTemplateCreateInfoKHR unwrapped = UnwrapInfo(pCreateInfo); + VkResult ret; + SERIALISE_TIME_CALL(ret = ObjDisp(device)->CreateDescriptorUpdateTemplateKHR( + Unwrap(device), &unwrapped, pAllocator, pDescriptorUpdateTemplate)); + + if(ret == VK_SUCCESS) + { + ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), *pDescriptorUpdateTemplate); + + if(IsCaptureMode(m_State)) + { + Chunk *chunk = NULL; + + { + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCreateDescriptorUpdateTemplateKHR); + Serialise_vkCreateDescriptorUpdateTemplateKHR(ser, device, pCreateInfo, NULL, + pDescriptorUpdateTemplate); + + chunk = scope.Get(); + } + + VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pDescriptorUpdateTemplate); + record->AddChunk(chunk); + + record->descTemplateInfo = new DescUpdateTemplate(); + record->descTemplateInfo->Init(GetResourceManager(), m_CreationInfo, pCreateInfo); + } + else + { + GetResourceManager()->AddLiveResource(id, *pDescriptorUpdateTemplate); + + m_CreationInfo.m_DescUpdateTemplate[id].Init(GetResourceManager(), m_CreationInfo, pCreateInfo); + } + } + + return ret; +} + +template +bool WrappedVulkan::Serialise_vkUpdateDescriptorSetWithTemplateKHR( + SerialiserType &ser, VkDevice device, VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void *pData) +{ + SERIALISE_ELEMENT(device); + SERIALISE_ELEMENT(descriptorSet); + SERIALISE_ELEMENT(descriptorUpdateTemplate); + + // we can't serialise pData as-is, since we need to decode to ResourceId for references, etc. The + // sensible way to do this is to decode the data into a series of writes and serialise that. + DescUpdateTemplateApplication apply; + + if(IsCaptureMode(m_State)) + { + // decode while capturing. + GetRecord(descriptorUpdateTemplate)->descTemplateInfo->Apply(pData, apply); + } + + SERIALISE_ELEMENT(apply.writes).Named("Decoded Writes"); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + for(VkWriteDescriptorSet &writeDesc : apply.writes) + { + writeDesc.dstSet = descriptorSet; + ReplayDescriptorSetWrite(device, writeDesc); + } + } + + return true; +} + +// see vkUpdateDescriptorSets for more verbose comments, the concepts are the same here except we +// apply from a template & user memory instead of arrays of VkWriteDescriptorSet/VkCopyDescriptorSet +void WrappedVulkan::vkUpdateDescriptorSetWithTemplateKHR( + VkDevice device, VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void *pData) +{ + SCOPED_DBG_SINK(); + + DescUpdateTemplate *tempInfo = GetRecord(descriptorUpdateTemplate)->descTemplateInfo; + + { + // allocate the whole blob of memory + byte *memory = GetTempMemory(tempInfo->dataByteSize); + + // iterate the entries, copy the descriptor data and unwrap + for(const VkDescriptorUpdateTemplateEntryKHR &entry : tempInfo->updates) + { + byte *dst = memory + entry.offset; + const byte *src = (const byte *)pData + entry.offset; + + if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + for(uint32_t d = 0; d < entry.descriptorCount; d++) { - dstrecord->AddBindFrameRef(GetResID(bind.texelBufferView), eFrameRef_Read, - GetRecord(bind.texelBufferView)->sparseInfo != NULL); - if(GetRecord(bind.texelBufferView)->baseResource != ResourceId()) - dstrecord->AddBindFrameRef(GetRecord(bind.texelBufferView)->baseResource, ref); + memcpy(dst, src, sizeof(VkBufferView)); + + VkBufferView *bufView = (VkBufferView *)dst; + + *bufView = Unwrap(*bufView); + + dst += entry.stride; + src += entry.stride; } - if(bind.imageInfo.imageView != VK_NULL_HANDLE) + } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + bool hasSampler = (entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + bool hasImage = (entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT); + + for(uint32_t d = 0; d < entry.descriptorCount; d++) { - dstrecord->AddBindFrameRef(GetResID(bind.imageInfo.imageView), eFrameRef_Read, - GetRecord(bind.imageInfo.imageView)->sparseInfo != NULL); - dstrecord->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource, ref); - if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId()) - dstrecord->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem, - eFrameRef_Read); + memcpy(dst, src, sizeof(VkDescriptorImageInfo)); + + VkDescriptorImageInfo *info = (VkDescriptorImageInfo *)dst; + + if(hasSampler) + info->sampler = Unwrap(info->sampler); + if(hasImage) + info->imageView = Unwrap(info->imageView); + + dst += entry.stride; + src += entry.stride; } - if(bind.imageInfo.sampler != VK_NULL_HANDLE) + } + else + { + for(uint32_t d = 0; d < entry.descriptorCount; d++) { - dstrecord->AddBindFrameRef(GetResID(bind.imageInfo.sampler), ref); + memcpy(dst, src, sizeof(VkDescriptorBufferInfo)); + + VkDescriptorBufferInfo *info = (VkDescriptorBufferInfo *)dst; + + info->buffer = Unwrap(info->buffer); + + dst += entry.stride; + src += entry.stride; } - if(bind.bufferInfo.buffer != VK_NULL_HANDLE) + } + } + + SERIALISE_TIME_CALL(ObjDisp(device)->UpdateDescriptorSetWithTemplateKHR( + Unwrap(device), Unwrap(descriptorSet), Unwrap(descriptorUpdateTemplate), memory)); + } + + bool capframe = false; + { + SCOPED_LOCK(m_CapTransitionLock); + capframe = IsActiveCapturing(m_State); + } + + if(capframe) + { + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkUpdateDescriptorSetWithTemplateKHR); + Serialise_vkUpdateDescriptorSetWithTemplateKHR(ser, device, descriptorSet, + descriptorUpdateTemplate, pData); + + m_FrameCaptureRecord->AddChunk(scope.Get()); + + // mark the destination set and template as referenced + GetResourceManager()->MarkResourceFrameReferenced(GetResID(descriptorSet), eFrameRef_Write); + GetResourceManager()->MarkResourceFrameReferenced(GetResID(descriptorUpdateTemplate), + eFrameRef_Read); + } + + // need to track descriptor set contents whether capframing or idle + if(IsCaptureMode(m_State)) + { + for(const VkDescriptorUpdateTemplateEntryKHR &entry : tempInfo->updates) + { + VkResourceRecord *record = GetRecord(descriptorSet); + RDCASSERT(record->descInfo && record->descInfo->layout); + const DescSetLayout &layout = *record->descInfo->layout; + + RDCASSERT(entry.dstBinding < record->descInfo->descBindings.size()); + + DescriptorSetSlot **binding = &record->descInfo->descBindings[entry.dstBinding]; + + const DescSetLayout::Binding *layoutBinding = &layout.bindings[entry.dstBinding]; + + FrameRefType ref = GetRefType(layoutBinding->descriptorType); + + // start at the dstArrayElement + uint32_t curIdx = entry.dstArrayElement; + + for(uint32_t d = 0; d < entry.descriptorCount; d++, curIdx++) + { + // roll over onto the next binding, on the assumption that it is the same + // type and there is indeed a next binding at all. See spec language: + // + // If the dstBinding has fewer than descriptorCount array elements remaining starting from + // dstArrayElement, then the remainder will be used to update the subsequent binding - + // dstBinding+1 starting at array element zero. This behavior applies recursively, with the + // update affecting consecutive bindings as needed to update all descriptorCount + // descriptors. All consecutive bindings updated via a single VkWriteDescriptorSet structure + // must have identical descriptorType and stageFlags, and must all either use immutable + // samplers or must all not use immutable samplers. + + if(curIdx >= layoutBinding->descriptorCount) { - dstrecord->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read, - GetRecord(bind.bufferInfo.buffer)->sparseInfo != NULL); - if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) - dstrecord->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref); + layoutBinding++; + binding++; + curIdx = 0; } + + const byte *src = (const byte *)pData + entry.offset + entry.stride * d; + + DescriptorSetSlot &bind = (*binding)[curIdx]; + + bind.RemoveBindRefs(record); + + if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + bind.texelBufferView = *(VkBufferView *)src; + } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + bind.imageInfo = *(VkDescriptorImageInfo *)src; + + // ignore descriptors not part of the write, by NULL'ing out those members + // as they might not even point to a valid object + if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) + bind.imageInfo.imageView = VK_NULL_HANDLE; + else if(entry.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) + bind.imageInfo.sampler = VK_NULL_HANDLE; + } + else + { + bind.bufferInfo = *(VkDescriptorBufferInfo *)src; + } + + bind.AddBindRefs(record, ref); } } } @@ -1286,3 +1462,13 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkUpdateDescriptorSets, VkDevice device, const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies); + +INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateDescriptorUpdateTemplateKHR, VkDevice device, + const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate); + +INSTANTIATE_FUNCTION_SERIALISED(void, vkUpdateDescriptorSetWithTemplateKHR, VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + const void *pData); diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index 9add5e6af..fd692b2ce 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -110,6 +110,7 @@ DESTROY_IMPL(VkCommandPool, DestroyCommandPool) DESTROY_IMPL(VkQueryPool, DestroyQueryPool) DESTROY_IMPL(VkFramebuffer, DestroyFramebuffer) DESTROY_IMPL(VkRenderPass, DestroyRenderPass) +DESTROY_IMPL(VkDescriptorUpdateTemplateKHR, DestroyDescriptorUpdateTemplateKHR) #undef DESTROY_IMPL @@ -381,6 +382,13 @@ bool WrappedVulkan::ReleaseResource(WrappedVkRes *res) vt->DestroySemaphore(Unwrap(dev), real, NULL); break; } + case eResDescUpdateTemplate: + { + VkDescriptorUpdateTemplateKHR real = nondisp->real.As(); + GetResourceManager()->ReleaseWrappedResource(VkDescriptorUpdateTemplateKHR(handle)); + vt->DestroyDescriptorUpdateTemplateKHR(Unwrap(dev), real, NULL); + break; + } } return true; @@ -1141,6 +1149,8 @@ static VkResourceRecord *GetObjRecord(VkDebugReportObjectTypeEXT objType, uint64 case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT: return GetRecord((VkSurfaceKHR)object); case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: return GetRecord((VkSwapchainKHR)object); case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: return GetRecord((VkCommandPool)object); + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT: + return GetRecord((VkDescriptorUpdateTemplateKHR)object); case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT: case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT: case VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT: @@ -1149,7 +1159,6 @@ static VkResourceRecord *GetObjRecord(VkDebugReportObjectTypeEXT objType, uint64 case VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT: case VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT: case VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT: - case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT: case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT: case VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT: break; }