diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 0ccd2f46f..f7cb285d3 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -769,9 +769,11 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, const rdcarray *slotBinds = NULL; BindType bindType = BindType::Unknown; ShaderStageMask stageBits = ShaderStageMask::Unknown; + bool pushDescriptor = false; if(bindset < pipe.descriptorSets.count() && bind < pipe.descriptorSets[bindset].bindings.count()) { + pushDescriptor = pipe.descriptorSets[bindset].pushDescriptor; slotBinds = &pipe.descriptorSets[bindset].bindings[bind].binds; bindType = pipe.descriptorSets[bindset].bindings[bind].type; stageBits = pipe.descriptorSets[bindset].bindings[bind].stageFlags; @@ -817,6 +819,9 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, QString setname = QString::number(bindset); + if(pushDescriptor) + setname = tr("Push ") + setname; + QString slotname = QString::number(bind); if(shaderRes && !shaderRes->name.isEmpty()) slotname += lit(": ") + shaderRes->name; @@ -931,7 +936,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, if(!isbuf) { node = new RDTreeWidgetItem({ - QString(), bindset, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), + QString(), setname, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), QString(), }); @@ -945,7 +950,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, QFormatStr("Viewing bytes %1 - %2").arg(descriptorBind->byteOffset).arg(descriptorLen); node = new RDTreeWidgetItem({ - QString(), bindset, slotname, ToQStr(bindType), + QString(), setname, slotname, ToQStr(bindType), descriptorBind ? descriptorBind->resourceResourceId : ResourceId(), tr("%1 bytes").arg(len), range, QString(), }); @@ -966,7 +971,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, range = QFormatStr("bytes %1 - %2").arg(descriptorBind->byteOffset).arg(descriptorLen); node = new RDTreeWidgetItem({ - QString(), bindset, slotname, ToQStr(bindType), + QString(), setname, slotname, ToQStr(bindType), descriptorBind ? descriptorBind->resourceResourceId : ResourceId(), format, range, QString(), }); @@ -984,7 +989,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, if(descriptorBind == NULL || descriptorBind->samplerResourceId == ResourceId()) { node = new RDTreeWidgetItem({ - QString(), bindset, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), + QString(), setname, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), QString(), }); @@ -992,8 +997,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, } else { - node = - new RDTreeWidgetItem(makeSampler(QString::number(bindset), slotname, *descriptorBind)); + node = new RDTreeWidgetItem(makeSampler(setname, slotname, *descriptorBind)); if(!filledSlot) setEmptyRow(node); @@ -1014,7 +1018,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, if(descriptorBind == NULL || descriptorBind->resourceResourceId == ResourceId()) { node = new RDTreeWidgetItem({ - QString(), bindset, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), + QString(), setname, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), QString(), }); @@ -1055,7 +1059,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, dim += QFormatStr(", %1x MSAA").arg(samples); node = new RDTreeWidgetItem({ - QString(), bindset, slotname, typeName, descriptorBind->resourceResourceId, dim, + QString(), setname, slotname, typeName, descriptorBind->resourceResourceId, dim, format, QString(), }); @@ -1073,7 +1077,7 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, if(descriptorBind == NULL || descriptorBind->samplerResourceId == ResourceId()) { samplerNode = new RDTreeWidgetItem({ - QString(), bindset, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), + QString(), setname, slotname, ToQStr(bindType), ResourceId(), lit("-"), QString(), QString(), }); @@ -1151,8 +1155,11 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta BindType bindType = BindType::ConstantBuffer; ShaderStageMask stageBits = ShaderStageMask::Unknown; + bool pushDescriptor = false; + if(bindset < pipe.descriptorSets.count() && bind < pipe.descriptorSets[bindset].bindings.count()) { + pushDescriptor = pipe.descriptorSets[bindset].pushDescriptor; slotBinds = &pipe.descriptorSets[bindset].bindings[bind].binds; bindType = pipe.descriptorSets[bindset].bindings[bind].type; stageBits = pipe.descriptorSets[bindset].bindings[bind].stageFlags; @@ -1183,6 +1190,9 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta QString setname = QString::number(bindset); + if(pushDescriptor) + setname = tr("Push ") + setname; + QString slotname = QString::number(bind); if(cblock != NULL && !cblock->name.isEmpty()) slotname += lit(": ") + cblock->name; @@ -2581,6 +2591,9 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe:: QString setname = QString::number(bindMap.bindset); + if(set.pushDescriptor) + setname = tr("Push ") + setname; + QString slotname = QFormatStr("%1: %2").arg(bindMap.bind).arg(b.name); for(uint32_t a = 0; a < bind.descriptorCount; a++) @@ -2643,6 +2656,9 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe:: QString setname = QString::number(bindMap.bindset); + if(set.pushDescriptor) + setname = tr("Push ") + setname; + QString slotname = QFormatStr("%1: %2").arg(bindMap.bind).arg(b.name); for(uint32_t a = 0; a < bind.descriptorCount; a++) @@ -2756,6 +2772,9 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe:: QString setname = QString::number(bindMap.bindset); + if(set.pushDescriptor) + setname = tr("Push ") + setname; + QString slotname = QFormatStr("%1: %2").arg(bindMap.bind).arg(b.name); for(uint32_t a = 0; a < bind.descriptorCount; a++) diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index 894c820b3..45ca68819 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -218,7 +218,8 @@ struct DescriptorSet bool operator==(const DescriptorSet &o) const { return layoutResourceId == o.layoutResourceId && - descriptorSetResourceId == o.descriptorSetResourceId && bindings == o.bindings; + descriptorSetResourceId == o.descriptorSetResourceId && + pushDescriptor == o.pushDescriptor && bindings == o.bindings; } bool operator<(const DescriptorSet &o) const { @@ -226,6 +227,8 @@ struct DescriptorSet return layoutResourceId < o.layoutResourceId; if(!(descriptorSetResourceId == o.descriptorSetResourceId)) return descriptorSetResourceId < o.descriptorSetResourceId; + if(!(pushDescriptor == o.pushDescriptor)) + return pushDescriptor < o.pushDescriptor; if(!(bindings == o.bindings)) return bindings < o.bindings; return false; @@ -234,6 +237,8 @@ struct DescriptorSet ResourceId layoutResourceId; DOCUMENT("The :class:`ResourceId` of the descriptor set object."); ResourceId descriptorSetResourceId; + DOCUMENT("Indicates if this is a virtual 'push' descriptor set."); + bool pushDescriptor = false; DOCUMENT(R"(A list of :class:`VKDescriptorBinding` with the bindings within this set. This list is indexed by the binding, so it may be sparse (some entries do not contain any elements). diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 3c607b0c7..ff0a2268a 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -439,6 +439,7 @@ enum class VulkanChunk : uint32_t vkRegisterDeviceEventEXT, vkRegisterDisplayEventEXT, vkCmdIndirectSubCommand, + vkCmdPushDescriptorSetKHR, Max, }; diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 310da5fc4..a04a876c4 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -623,6 +623,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_KHR_MAINTENANCE1_SPEC_VERSION, }, + { + VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION, + }, { VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION, @@ -2226,6 +2229,11 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) return true; break; + case VulkanChunk::vkCmdPushDescriptorSetKHR: + return Serialise_vkCmdPushDescriptorSetKHR( + ser, VK_NULL_HANDLE, VK_PIPELINE_BIND_POINT_GRAPHICS, VK_NULL_HANDLE, 0, 0, NULL); + break; + default: { SystemChunk system = (SystemChunk)chunk; @@ -2865,7 +2873,6 @@ void WrappedVulkan::AddUsage(VulkanDrawcallTreeNode &drawNode, vectorGetOriginalID(descSets[bindset].descSet); ResourceId layoutId = GetResourceManager()->GetOriginalID(descset.layout); if(layout.bindings.empty()) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 3d9402a9c..2963a1419 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -186,6 +186,7 @@ class WrappedVulkan : public IFrameCapturer private: friend class VulkanReplay; friend class VulkanDebugManager; + friend struct VulkanRenderState; friend class VulkanShaderCache; struct ScopedDebugMessageSink @@ -473,6 +474,8 @@ private: std::vector > imgbarriers; + ResourceId pushDescriptorID[64]; + VulkanDrawcallTreeNode *draw; // the root draw to copy from when submitting uint32_t eventCount; // how many events are in this cmd buffer, for quick skipping uint32_t curEventID; // current event ID while reading or executing @@ -586,14 +589,18 @@ private: // need it on replay too struct DescriptorSetInfo { - ~DescriptorSetInfo() + ~DescriptorSetInfo() { clear(); } + ResourceId layout; + vector currentBindings; + + void clear() { + layout = ResourceId(); + for(size_t i = 0; i < currentBindings.size(); i++) delete[] currentBindings[i]; currentBindings.clear(); } - ResourceId layout; - vector currentBindings; }; // capture-side data @@ -1626,4 +1633,10 @@ public: // VK_AMD_shader_info VkResult vkGetShaderInfoAMD(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t *pInfoSize, void *pInfo); + + // VK_KHR_push_descriptor + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdPushDescriptorSetKHR, VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, + uint32_t set, uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites); }; diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index 3a712582c..d348c8f0d 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -300,7 +300,8 @@ CheckExt(VK_KHR_external_semaphore_win32); \ CheckExt(VK_KHR_external_semaphore_fd); \ CheckExt(VK_KHR_get_memory_requirements2); \ - CheckExt(VK_AMD_shader_info); + CheckExt(VK_AMD_shader_info); \ + CheckExt(VK_KHR_push_descriptor); #define HookInitVulkanInstanceExts() \ HookInitExtension(VK_KHR_surface, DestroySurfaceKHR); \ @@ -363,6 +364,7 @@ HookInitExtension(VK_KHR_get_memory_requirements2, GetImageMemoryRequirements2KHR); \ HookInitExtension(VK_KHR_get_memory_requirements2, GetImageSparseMemoryRequirements2KHR); \ HookInitExtension(VK_AMD_shader_info, GetShaderInfoAMD); \ + HookInitExtension(VK_KHR_push_descriptor, CmdPushDescriptorSetKHR); \ HookInitDevice_PlatformSpecific() #define DefineHooks() \ @@ -776,6 +778,9 @@ HookDefine6(VkResult, vkGetShaderInfoAMD, VkDevice, device, VkPipeline, pipeline, \ VkShaderStageFlagBits, shaderStage, VkShaderInfoTypeAMD, infoType, size_t *, \ pInfoSize, void *, pInfo); \ + HookDefine6(void, vkCmdPushDescriptorSetKHR, VkCommandBuffer, commandBuffer, \ + VkPipelineBindPoint, pipelineBindPoint, VkPipelineLayout, layout, uint32_t, set, \ + uint32_t, descriptorWriteCount, const VkWriteDescriptorSet *, pDescriptorWrites); \ HookDefine_PlatformSpecific() struct VkLayerInstanceDispatchTableExtended : VkLayerInstanceDispatchTable diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 78e2c5a24..5a567448c 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -30,6 +30,8 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo { dynamicCount = 0; + flags = pCreateInfo->flags; + // descriptor set layouts can be sparse, such that only three bindings exist // but they are at 0, 5 and 10. // We assume here that while the layouts may be sparse that's mostly to allow @@ -63,7 +65,7 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo } } -void DescSetLayout::CreateBindingsArray(vector &descBindings) +void DescSetLayout::CreateBindingsArray(std::vector &descBindings) const { descBindings.resize(bindings.size()); for(size_t i = 0; i < bindings.size(); i++) @@ -73,6 +75,33 @@ void DescSetLayout::CreateBindingsArray(vector &descBinding } } +void DescSetLayout::UpdateBindingsArray(const DescSetLayout &prevLayout, + std::vector &descBindings) const +{ + // if we have fewer bindings now, delete the orphaned bindings arrays + for(size_t i = bindings.size(); i < prevLayout.bindings.size(); i++) + SAFE_DELETE_ARRAY(descBindings[i]); + + // resize to the new number of bindings + descBindings.resize(bindings.size()); + + // re-allocate slots and move any previous bindings that overlapped over. + for(size_t i = 0; i < bindings.size(); i++) + { + // allocate new slot array + DescriptorSetSlot *newSlots = new DescriptorSetSlot[bindings[i].descriptorCount]; + + // copy over any previous bindings that overlapped + memcpy(newSlots, descBindings[i], + sizeof(DescriptorSetSlot) * + RDCMIN(prevLayout.bindings[i].descriptorCount, bindings[i].descriptorCount)); + + // delete old array, and assign the new one + SAFE_DELETE_ARRAY(descBindings[i]); + descBindings[i] = newSlots; + } +} + bool DescSetLayout::operator==(const DescSetLayout &other) const { // shortcut for equality to ourselves diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index d1a26421d..7b28f126e 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -35,7 +35,9 @@ struct DescSetLayout void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkDescriptorSetLayoutCreateInfo *pCreateInfo); - void CreateBindingsArray(vector &descBindings); + void CreateBindingsArray(std::vector &descBindings) const; + void UpdateBindingsArray(const DescSetLayout &prevLayout, + std::vector &descBindings) const; struct Binding { @@ -71,6 +73,7 @@ struct DescSetLayout vector bindings; uint32_t dynamicCount; + VkDescriptorSetLayoutCreateFlags flags; bool operator==(const DescSetLayout &other) const; bool operator!=(const DescSetLayout &other) const { return !(*this == other); } diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index e98eaddad..e54b30a5b 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -55,21 +55,30 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) VkInitialContents initialContents(type, VkInitialContents::DescriptorSet); - for(size_t i = 0; i < layout.bindings.size(); i++) - initialContents.numDescriptors += layout.bindings[i].descriptorCount; - - initialContents.descriptorSlots = new DescriptorSetSlot[initialContents.numDescriptors]; - RDCEraseMem(initialContents.descriptorSlots, - sizeof(DescriptorSetSlot) * initialContents.numDescriptors); - - uint32_t e = 0; - for(size_t i = 0; i < layout.bindings.size(); i++) + if((layout.flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) == 0) { - for(uint32_t b = 0; b < layout.bindings[i].descriptorCount; b++) + for(size_t i = 0; i < layout.bindings.size(); i++) + initialContents.numDescriptors += layout.bindings[i].descriptorCount; + + initialContents.descriptorSlots = new DescriptorSetSlot[initialContents.numDescriptors]; + RDCEraseMem(initialContents.descriptorSlots, + sizeof(DescriptorSetSlot) * initialContents.numDescriptors); + + uint32_t e = 0; + for(size_t i = 0; i < layout.bindings.size(); i++) { - initialContents.descriptorSlots[e++] = record->descInfo->descBindings[i][b]; + for(uint32_t b = 0; b < layout.bindings[i].descriptorCount; b++) + { + initialContents.descriptorSlots[e++] = record->descInfo->descBindings[i][b]; + } } } + else + { + RDCERR("Push descriptor set with initial contents! Should never have been marked dirty"); + initialContents.numDescriptors = 0; + initialContents.descriptorSlots = NULL; + } GetResourceManager()->SetInitialContents(id, initialContents); return true; @@ -565,6 +574,12 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, W const DescSetLayout &layout = m_CreationInfo.m_DescSetLayout[m_DescriptorSetState[liveid].layout]; + if(layout.flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) + { + RDCERR("Push descriptor set with initial contents!"); + return true; + } + VkInitialContents initialContents(type, VkInitialContents::DescriptorSet); initialContents.numDescriptors = (uint32_t)layout.bindings.size(); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index cf71d1907..ca2e08c34 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1194,7 +1194,18 @@ void VulkanReplay::SavePipelineState() ResourceId layoutId = m_pDriver->m_DescriptorSetState[src].layout; - dst.descriptorSetResourceId = rm->GetOriginalID(src); + // push descriptors don't have a real descriptor set backing them + if(c.m_DescSetLayout[layoutId].flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) + { + dst.descriptorSetResourceId = ResourceId(); + dst.pushDescriptor = true; + } + else + { + dst.descriptorSetResourceId = rm->GetOriginalID(src); + dst.pushDescriptor = false; + } + dst.layoutResourceId = rm->GetOriginalID(layoutId); dst.bindings.resize(m_pDriver->m_DescriptorSetState[src].currentBindings.size()); for(size_t b = 0; b < m_pDriver->m_DescriptorSetState[src].currentBindings.size(); b++) diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 8ab52811e..47c2dce91 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -833,6 +833,9 @@ VkResourceRecord::~VkResourceRecord() if(resType == eResDescriptorSetLayout || resType == eResDescriptorSet) SAFE_DELETE(descInfo); + + if(resType == eResPipelineLayout) + SAFE_DELETE(pipeLayoutInfo); } 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 279489e6c..a347b3020 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -919,6 +919,11 @@ struct DescriptorSetData map > bindFrameRefs; }; +struct PipelineLayoutData +{ + std::vector layouts; +}; + struct MemMapState { MemMapState() @@ -1062,6 +1067,7 @@ public: MemMapState *memMapState; // only for device memory 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 }; diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index 077dd4dc2..e9f50d748 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -246,11 +246,8 @@ void VulkanRenderState::BindPipeline(VkCommandBuffer cmd, PipelineBinding bindin } } - ObjDisp(cmd)->CmdBindDescriptorSets( - Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(layout), (uint32_t)i, 1, - UnwrapPtr(GetResourceManager()->GetCurrentHandle( - graphics.descSets[i].descSet)), - descLayout.dynamicCount, dynamicOffsets); + BindDescriptorSet(descLayout, cmd, layout, VK_PIPELINE_BIND_POINT_GRAPHICS, (uint32_t)i, + dynamicOffsets); if(graphics.descSets[i].offsets.size() < descLayout.dynamicCount) SAFE_DELETE_ARRAY(dynamicOffsets); @@ -315,11 +312,8 @@ void VulkanRenderState::BindPipeline(VkCommandBuffer cmd, PipelineBinding bindin } } - ObjDisp(cmd)->CmdBindDescriptorSets( - Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, Unwrap(layout), (uint32_t)i, 1, - UnwrapPtr(GetResourceManager()->GetCurrentHandle( - compute.descSets[i].descSet)), - descLayout.dynamicCount, dynamicOffsets); + BindDescriptorSet(descLayout, cmd, layout, VK_PIPELINE_BIND_POINT_COMPUTE, (uint32_t)i, + dynamicOffsets); if(compute.descSets[i].offsets.size() < descLayout.dynamicCount) SAFE_DELETE_ARRAY(dynamicOffsets); @@ -328,6 +322,102 @@ void VulkanRenderState::BindPipeline(VkCommandBuffer cmd, PipelineBinding bindin } } +void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCommandBuffer cmd, + VkPipelineLayout layout, VkPipelineBindPoint bindPoint, + uint32_t setIndex, uint32_t *dynamicOffsets) +{ + ResourceId descSet = (bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS) + ? graphics.descSets[setIndex].descSet + : compute.descSets[setIndex].descSet; + + if((descLayout.flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) == 0) + { + ObjDisp(cmd)->CmdBindDescriptorSets( + Unwrap(cmd), bindPoint, Unwrap(layout), (uint32_t)setIndex, 1, + UnwrapPtr(GetResourceManager()->GetCurrentHandle(descSet)), + descLayout.dynamicCount, dynamicOffsets); + } + else + { + // this isn't a real descriptor set, it's a push descriptor, so we need to push the + // current state. + std::vector writes; + + WrappedVulkan::DescriptorSetInfo &setInfo = m_pDriver->m_DescriptorSetState[descSet]; + + for(size_t b = 0; b < descLayout.bindings.size(); b++) + { + VkWriteDescriptorSet push = {}; + + // skip if this binding isn't used + if(descLayout.bindings[b].descriptorCount == 0) + continue; + + push.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + // push.dstSet; // unused for push descriptors + push.dstBinding = (uint32_t)b; + push.dstArrayElement = 0; + push.descriptorType = descLayout.bindings[b].descriptorType; + push.descriptorCount = descLayout.bindings[b].descriptorCount; + + DescriptorSetSlot *slots = setInfo.currentBindings[b]; + + if(push.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + push.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + VkBufferView *dst = new VkBufferView[push.descriptorCount]; + + for(uint32_t a = 0; a < push.descriptorCount; a++) + dst[a] = Unwrap(slots[a].texelBufferView); + + push.pTexelBufferView = dst; + } + else if(push.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + push.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + push.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + push.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + push.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + VkDescriptorImageInfo *dst = new VkDescriptorImageInfo[push.descriptorCount]; + + for(uint32_t a = 0; a < push.descriptorCount; a++) + { + dst[a] = slots[a].imageInfo; + dst[a].sampler = Unwrap(dst[a].sampler); + dst[a].imageView = Unwrap(dst[a].imageView); + } + + push.pImageInfo = dst; + } + else + { + VkDescriptorBufferInfo *dst = new VkDescriptorBufferInfo[push.descriptorCount]; + + for(uint32_t a = 0; a < push.descriptorCount; a++) + { + dst[a] = slots[a].bufferInfo; + dst[a].buffer = Unwrap(dst[a].buffer); + } + + push.pBufferInfo = dst; + } + + writes.push_back(push); + } + + ObjDisp(cmd)->CmdPushDescriptorSetKHR(Unwrap(cmd), bindPoint, Unwrap(layout), setIndex, + (uint32_t)writes.size(), writes.data()); + + // delete dynamically allocated arrays + for(VkWriteDescriptorSet &push : writes) + { + SAFE_DELETE_ARRAY(push.pImageInfo); + SAFE_DELETE_ARRAY(push.pBufferInfo); + SAFE_DELETE_ARRAY(push.pTexelBufferView); + } + } +} + void VulkanRenderState::EndRenderPass(VkCommandBuffer cmd) { ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); diff --git a/renderdoc/driver/vulkan/vk_state.h b/renderdoc/driver/vulkan/vk_state.h index 0b6529e89..4b24e506d 100644 --- a/renderdoc/driver/vulkan/vk_state.h +++ b/renderdoc/driver/vulkan/vk_state.h @@ -30,6 +30,7 @@ struct VulkanCreationInfo; class VulkanResourceManager; class WrappedVulkan; +struct DescSetLayout; struct VulkanRenderState { @@ -46,6 +47,10 @@ struct VulkanRenderState void EndRenderPass(VkCommandBuffer cmd); void BindPipeline(VkCommandBuffer cmd, PipelineBinding binding, bool subpass0); + void BindDescriptorSet(const DescSetLayout &descLayout, VkCommandBuffer cmd, + VkPipelineLayout layout, VkPipelineBindPoint bindPoint, uint32_t setIndex, + uint32_t *dynamicOffsets); + // dynamic state vector views; vector scissors; diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index 3014b6be4..778f069ec 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 == 1098, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1099, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(VulkanChunk) { @@ -130,6 +130,7 @@ std::string DoStringise(const VulkanChunk &el) STRINGISE_ENUM_CLASS(vkRegisterDeviceEventEXT); STRINGISE_ENUM_CLASS(vkRegisterDisplayEventEXT); STRINGISE_ENUM_CLASS_NAMED(vkCmdIndirectSubCommand, "Indirect sub-command"); + STRINGISE_ENUM_CLASS(vkCmdPushDescriptorSetKHR); STRINGISE_ENUM_CLASS_NAMED(Max, "Max Chunk"); } END_ENUM_STRINGISE() diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index c6a9bc0e8..0fef57ccb 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -594,6 +594,21 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman { m_LastCmdBufferID = CommandBuffer; + // when loading, allocate a new resource ID for each push descriptor slot in this command buffer + if(IsLoading(m_State)) + { + for(size_t i = 0; i < ARRAY_COUNT(BakedCmdBufferInfo::pushDescriptorID); i++) + m_BakedCmdBufferInfo[BakedCommandBuffer].pushDescriptorID[i] = + ResourceIDGen::GetNewUniqueID(); + } + + // clear/invalidate descriptor set state for this command buffer. + for(size_t i = 0; i < ARRAY_COUNT(BakedCmdBufferInfo::pushDescriptorID); i++) + { + m_DescriptorSetState[m_BakedCmdBufferInfo[BakedCommandBuffer].pushDescriptorID[i]] = + DescriptorSetInfo(); + } + m_BakedCmdBufferInfo[m_LastCmdBufferID].level = m_BakedCmdBufferInfo[BakedCommandBuffer].level = AllocateInfo.level; m_BakedCmdBufferInfo[m_LastCmdBufferID].beginFlags = @@ -2924,6 +2939,368 @@ void WrappedVulkan::vkCmdDebugMarkerInsertEXT(VkCommandBuffer commandBuffer, } } +template +bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetKHR(SerialiserType &ser, + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT(pipelineBindPoint); + SERIALISE_ELEMENT(layout); + SERIALISE_ELEMENT(set); + SERIALISE_ELEMENT(descriptorWriteCount); + SERIALISE_ELEMENT_ARRAY(pDescriptorWrites, descriptorWriteCount); + + 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 = + (pipelineBindPoint == 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 = + (pipelineBindPoint == 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) + { + // 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 + { + 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]; + } + } + } + } + + // now unwrap everything in-place to save on temp allocs. + VkWriteDescriptorSet *writes = (VkWriteDescriptorSet *)pDescriptorWrites; + + for(uint32_t i = 0; i < descriptorWriteCount; i++) + { + for(uint32_t d = 0; d < writes[i].descriptorCount; d++) + { + VkBufferView *pTexelBufferView = (VkBufferView *)writes[i].pTexelBufferView; + VkDescriptorBufferInfo *pBufferInfo = (VkDescriptorBufferInfo *)writes[i].pBufferInfo; + VkDescriptorImageInfo *pImageInfo = (VkDescriptorImageInfo *)writes[i].pImageInfo; + + if(pTexelBufferView) + pTexelBufferView[d] = Unwrap(pTexelBufferView[d]); + + if(pBufferInfo) + pBufferInfo[d].buffer = Unwrap(pBufferInfo[d].buffer); + + if(pImageInfo) + { + pImageInfo[d].imageView = Unwrap(pImageInfo[d].imageView); + pImageInfo[d].sampler = Unwrap(pImageInfo[d].sampler); + } + } + } + + ObjDisp(commandBuffer) + ->CmdPushDescriptorSetKHR(Unwrap(commandBuffer), pipelineBindPoint, Unwrap(layout), set, + descriptorWriteCount, pDescriptorWrites); + } + } + + return true; +} + +void WrappedVulkan::vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites) +{ + SCOPED_DBG_SINK(); + + { + // need to count up number of descriptor infos, to be able to alloc enough space + uint32_t numInfos = 0; + for(uint32_t i = 0; i < descriptorWriteCount; i++) + numInfos += pDescriptorWrites[i].descriptorCount; + + byte *memory = GetTempMemory(sizeof(VkDescriptorBufferInfo) * numInfos + + sizeof(VkWriteDescriptorSet) * descriptorWriteCount); + + RDCCOMPILE_ASSERT(sizeof(VkDescriptorBufferInfo) >= sizeof(VkDescriptorImageInfo), + "Descriptor structs sizes are unexpected, ensure largest size is used"); + + VkWriteDescriptorSet *unwrappedWrites = (VkWriteDescriptorSet *)memory; + VkDescriptorBufferInfo *nextDescriptors = + (VkDescriptorBufferInfo *)(unwrappedWrites + descriptorWriteCount); + + for(uint32_t i = 0; i < descriptorWriteCount; i++) + { + unwrappedWrites[i] = pDescriptorWrites[i]; + unwrappedWrites[i].dstSet = Unwrap(unwrappedWrites[i].dstSet); + + VkDescriptorBufferInfo *bufInfos = nextDescriptors; + VkDescriptorImageInfo *imInfos = (VkDescriptorImageInfo *)bufInfos; + VkBufferView *bufViews = (VkBufferView *)bufInfos; + nextDescriptors += pDescriptorWrites[i].descriptorCount; + + RDCCOMPILE_ASSERT(sizeof(VkDescriptorBufferInfo) >= sizeof(VkDescriptorImageInfo), + "Structure sizes mean not enough space is allocated for write data"); + RDCCOMPILE_ASSERT(sizeof(VkDescriptorBufferInfo) >= sizeof(VkBufferView), + "Structure sizes mean not enough space is allocated for write data"); + + // unwrap and assign the appropriate array + if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + unwrappedWrites[i].pTexelBufferView = (VkBufferView *)bufInfos; + for(uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) + bufViews[j] = Unwrap(pDescriptorWrites[i].pTexelBufferView[j]); + } + 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) + { + bool hasSampler = + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + bool hasImage = + (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); + + unwrappedWrites[i].pImageInfo = (VkDescriptorImageInfo *)bufInfos; + for(uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) + { + if(hasImage) + imInfos[j].imageView = Unwrap(pDescriptorWrites[i].pImageInfo[j].imageView); + if(hasSampler) + imInfos[j].sampler = Unwrap(pDescriptorWrites[i].pImageInfo[j].sampler); + imInfos[j].imageLayout = pDescriptorWrites[i].pImageInfo[j].imageLayout; + } + } + else + { + unwrappedWrites[i].pBufferInfo = bufInfos; + for(uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) + { + bufInfos[j].buffer = Unwrap(pDescriptorWrites[i].pBufferInfo[j].buffer); + bufInfos[j].offset = pDescriptorWrites[i].pBufferInfo[j].offset; + bufInfos[j].range = pDescriptorWrites[i].pBufferInfo[j].range; + } + } + } + + SERIALISE_TIME_CALL(ObjDisp(commandBuffer) + ->CmdPushDescriptorSetKHR(Unwrap(commandBuffer), pipelineBindPoint, + Unwrap(layout), set, descriptorWriteCount, + unwrappedWrites)); + } + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdPushDescriptorSetKHR); + Serialise_vkCmdPushDescriptorSetKHR(ser, commandBuffer, pipelineBindPoint, layout, set, + descriptorWriteCount, pDescriptorWrites); + + record->AddChunk(scope.Get()); + for(uint32_t i = 0; i < descriptorWriteCount; i++) + { + 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"); + } + + for(uint32_t d = 0; d < write.descriptorCount; d++) + { + if(write.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || + write.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + record->MarkResourceFrameReferenced(GetResID(write.pTexelBufferView[d]), eFrameRef_Read); + if(GetRecord(write.pTexelBufferView[d])->baseResource != ResourceId()) + record->MarkResourceFrameReferenced(GetRecord(write.pTexelBufferView[d])->baseResource, + ref); + } + else if(write.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + write.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + write.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + write.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + write.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) + { + // ignore descriptors not part of the write, by NULL'ing out those members + // as they might not even point to a valid object + if(write.descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) + { + record->MarkResourceFrameReferenced(GetResID(write.pImageInfo[d].imageView), + eFrameRef_Read); + if(GetRecord(write.pImageInfo[d].imageView)->baseResource != ResourceId()) + record->MarkResourceFrameReferenced( + GetRecord(write.pImageInfo[d].imageView)->baseResource, ref); + } + + if(write.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + write.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) + record->MarkResourceFrameReferenced(GetResID(write.pImageInfo[d].sampler), + eFrameRef_Read); + } + else + { + record->MarkResourceFrameReferenced(GetResID(write.pBufferInfo[d].buffer), eFrameRef_Read); + if(GetRecord(write.pBufferInfo[d].buffer)->baseResource != ResourceId()) + record->MarkResourceFrameReferenced( + GetRecord(write.pBufferInfo[d].buffer)->baseResource, ref); + } + } + } + } +} INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateCommandPool, VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool); @@ -3011,3 +3388,8 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdDebugMarkerEndEXT, VkCommandBuffer co INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdDebugMarkerInsertEXT, VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT *pMarker); + +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdPushDescriptorSetKHR, VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, + uint32_t set, uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites); diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index aae002be1..cfbbffa17 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -516,10 +516,15 @@ VkResult WrappedVulkan::vkAllocateDescriptorSets(VkDevice device, capframe = IsActiveCapturing(m_State); } - if(capframe) - GetResourceManager()->MarkPendingDirty(id); - else - GetResourceManager()->MarkDirtyResource(id); + // only mark descriptor set as dirty if it's not a push descriptor layout + if((layoutRecord->descInfo->layout->flags & + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) == 0) + { + if(capframe) + GetResourceManager()->MarkPendingDirty(id); + else + GetResourceManager()->MarkDirtyResource(id); + } record->descInfo = new DescriptorSetData(); record->descInfo->layout = layoutRecord->descInfo->layout; diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 6b8eca0e5..f20947dd9 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -1248,6 +1248,10 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi ObjDisp(physicalDevice) ->GetPhysicalDeviceFeatures(Unwrap(physicalDevice), &m_PhysicalDeviceData.features); + RDCASSERT(m_PhysicalDeviceData.props.limits.maxBoundDescriptorSets < + ARRAY_COUNT(BakedCmdBufferInfo::pushDescriptorID), + m_PhysicalDeviceData.props.limits.maxBoundDescriptorSets); + for(int i = VK_FORMAT_BEGIN_RANGE + 1; i < VK_FORMAT_END_RANGE; i++) ObjDisp(physicalDevice) ->GetPhysicalDeviceFormatProperties(Unwrap(physicalDevice), VkFormat(i), diff --git a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp index ad1907d22..73ad9c6c1 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp @@ -180,10 +180,14 @@ VkResult WrappedVulkan::vkCreatePipelineLayout(VkDevice device, VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pPipelineLayout); record->AddChunk(chunk); + record->pipeLayoutInfo = new PipelineLayoutData(); + for(uint32_t i = 0; i < pCreateInfo->setLayoutCount; i++) { VkResourceRecord *layoutrecord = GetRecord(pCreateInfo->pSetLayouts[i]); record->AddParent(layoutrecord); + + record->pipeLayoutInfo->layouts.push_back(*layoutrecord->descInfo->layout); } } else diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index d1e62282f..863be81af 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1765,10 +1765,11 @@ void DoSerialise(SerialiserType &ser, VKPipe::DescriptorSet &el) { SERIALISE_MEMBER(layoutResourceId); SERIALISE_MEMBER(descriptorSetResourceId); + SERIALISE_MEMBER(pushDescriptor); SERIALISE_MEMBER(bindings); - SIZE_CHECK(32); + SIZE_CHECK(40); } template