diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 8132c6a25..5002da8df 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -465,6 +465,10 @@ enum class VulkanChunk : uint32_t vkGetDeviceQueue2, vkCmdDrawIndirectCountKHR, vkCmdDrawIndexedIndirectCountKHR, + vkCreateRenderPass2KHR, + vkCmdBeginRenderPass2KHR, + vkCmdNextSubpass2KHR, + vkCmdEndRenderPass2KHR, Max, }; @@ -654,6 +658,13 @@ DECLARE_REFLECTION_STRUCT(VkProtectedSubmitInfo); DECLARE_REFLECTION_STRUCT(VkImageFormatListCreateInfoKHR); DECLARE_REFLECTION_STRUCT(VkImageViewASTCDecodeModeEXT); DECLARE_REFLECTION_STRUCT(VkShaderModuleValidationCacheCreateInfoEXT); +DECLARE_REFLECTION_STRUCT(VkAttachmentDescription2KHR); +DECLARE_REFLECTION_STRUCT(VkSubpassDescription2KHR); +DECLARE_REFLECTION_STRUCT(VkSubpassDependency2KHR); +DECLARE_REFLECTION_STRUCT(VkAttachmentReference2KHR); +DECLARE_REFLECTION_STRUCT(VkRenderPassCreateInfo2KHR); +DECLARE_REFLECTION_STRUCT(VkSubpassBeginInfoKHR); +DECLARE_REFLECTION_STRUCT(VkSubpassEndInfoKHR); DECLARE_REFLECTION_STRUCT(VkDispatchIndirectCommand); DECLARE_REFLECTION_STRUCT(VkDrawIndirectCommand); DECLARE_REFLECTION_STRUCT(VkDrawIndexedIndirectCommand); @@ -733,6 +744,9 @@ DECLARE_DESERIALISE_TYPE(VkDeviceGroupRenderPassBeginInfo); DECLARE_DESERIALISE_TYPE(VkMemoryAllocateFlagsInfo); DECLARE_DESERIALISE_TYPE(VkProtectedSubmitInfo); DECLARE_DESERIALISE_TYPE(VkImageFormatListCreateInfoKHR); +DECLARE_DESERIALISE_TYPE(VkRenderPassCreateInfo2KHR); +DECLARE_DESERIALISE_TYPE(VkSubpassBeginInfoKHR); +DECLARE_DESERIALISE_TYPE(VkSubpassEndInfoKHR); #if defined(VK_KHR_external_memory_win32) || defined(VK_NV_external_memory_win32) DECLARE_REFLECTION_STRUCT(VkImportMemoryWin32HandleInfoNV); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 2fa2cf0fa..112332af6 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -699,6 +699,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, VK_KHR_BIND_MEMORY_2_SPEC_VERSION, }, + { + VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION, + }, { VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION, }, @@ -2670,6 +2673,15 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) VK_NULL_HANDLE, 0, 0, 0); break; + case VulkanChunk::vkCreateRenderPass2KHR: + return Serialise_vkCreateRenderPass2KHR(ser, VK_NULL_HANDLE, NULL, NULL, NULL); + case VulkanChunk::vkCmdBeginRenderPass2KHR: + return Serialise_vkCmdBeginRenderPass2KHR(ser, VK_NULL_HANDLE, NULL, NULL); + case VulkanChunk::vkCmdNextSubpass2KHR: + return Serialise_vkCmdNextSubpass2KHR(ser, VK_NULL_HANDLE, NULL, NULL); + case VulkanChunk::vkCmdEndRenderPass2KHR: + return Serialise_vkCmdEndRenderPass2KHR(ser, VK_NULL_HANDLE, NULL); + default: { SystemChunk system = (SystemChunk)chunk; diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index cd6b4df1d..234e4213b 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -742,8 +742,6 @@ private: std::vector GetImplicitRenderPassBarriers(uint32_t subpass = 0); string MakeRenderPassOpString(bool store); - void MakeSubpassLoadRP(VkRenderPassCreateInfo &info, const VkRenderPassCreateInfo *origInfo, - uint32_t s); bool IsDrawInRenderPass(); @@ -1915,4 +1913,18 @@ public: // VK_KHR_shared_presentable_image VkResult vkGetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain); + + // VK_KHR_create_renderpass2 + IMPLEMENT_FUNCTION_SERIALISED(VkResult, vkCreateRenderPass2KHR, VkDevice device, + const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdBeginRenderPass2KHR, VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo *pRenderPassBegin, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo); + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdNextSubpass2KHR, VkCommandBuffer commandBuffer, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo, + const VkSubpassEndInfoKHR *pSubpassEndInfo); + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdEndRenderPass2KHR, VkCommandBuffer commandBuffer, + const VkSubpassEndInfoKHR *pSubpassEndInfo); +\ }; diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index 6f42e0d6e..3e6dc423e 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -351,7 +351,8 @@ CheckExt(MVK_moltenvk, VKXX); \ CheckExt(KHR_draw_indirect_count, VKXX); \ CheckExt(EXT_validation_cache, VKXX); \ - CheckExt(KHR_shared_presentable_image, VKXX); + CheckExt(KHR_shared_presentable_image, VKXX); \ + CheckExt(KHR_create_renderpass2, VKXX); #define HookInitVulkanInstanceExts() \ HookInitExtension(KHR_surface, DestroySurfaceKHR); \ @@ -468,6 +469,10 @@ HookInitExtension(EXT_validation_cache, MergeValidationCachesEXT); \ HookInitExtension(EXT_validation_cache, GetValidationCacheDataEXT); \ HookInitExtension(KHR_shared_presentable_image, GetSwapchainStatusKHR); \ + HookInitExtension(KHR_create_renderpass2, CreateRenderPass2KHR); \ + HookInitExtension(KHR_create_renderpass2, CmdBeginRenderPass2KHR); \ + HookInitExtension(KHR_create_renderpass2, CmdNextSubpass2KHR); \ + HookInitExtension(KHR_create_renderpass2, CmdEndRenderPass2KHR); \ HookInitDevice_PlatformSpecific() #define DefineHooks() \ @@ -994,6 +999,17 @@ HookDefine4(VkResult, vkGetValidationCacheDataEXT, VkDevice, device, VkValidationCacheEXT, \ validationCache, size_t *, pDataSize, void *, pData); \ HookDefine2(VkResult, vkGetSwapchainStatusKHR, VkDevice, device, VkSwapchainKHR, swapchain); \ + HookDefine4(VkResult, vkCreateRenderPass2KHR, VkDevice, device, \ + const VkRenderPassCreateInfo2KHR *, pCreateInfo, const VkAllocationCallbacks *, \ + pAllocator, VkRenderPass *, pRenderPass); \ + HookDefine3(void, vkCmdBeginRenderPass2KHR, VkCommandBuffer, commandBuffer, \ + const VkRenderPassBeginInfo *, pRenderPassBegin, const VkSubpassBeginInfoKHR *, \ + pSubpassBeginInfo); \ + HookDefine3(void, vkCmdNextSubpass2KHR, VkCommandBuffer, commandBuffer, \ + const VkSubpassBeginInfoKHR *, pSubpassBeginInfo, const VkSubpassEndInfoKHR *, \ + pSubpassEndInfo); \ + HookDefine2(void, vkCmdEndRenderPass2KHR, VkCommandBuffer, commandBuffer, \ + const VkSubpassEndInfoKHR *, pSubpassEndInfo); \ HookDefine_PlatformSpecific() struct VkLayerInstanceDispatchTableExtended : VkLayerInstanceDispatchTable diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index d236e68fd..684b4922e 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -503,9 +503,20 @@ void VulkanCreationInfo::RenderPass::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkRenderPassCreateInfo *pCreateInfo) { - attachments.reserve(pCreateInfo->attachmentCount); + attachments.resize(pCreateInfo->attachmentCount); for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) - attachments.push_back(pCreateInfo->pAttachments[i]); + { + Attachment &dst = attachments[i]; + dst.flags = pCreateInfo->pAttachments[i].flags; + dst.format = pCreateInfo->pAttachments[i].format; + dst.samples = pCreateInfo->pAttachments[i].samples; + dst.loadOp = pCreateInfo->pAttachments[i].loadOp; + dst.storeOp = pCreateInfo->pAttachments[i].storeOp; + dst.stencilLoadOp = pCreateInfo->pAttachments[i].stencilLoadOp; + dst.stencilStoreOp = pCreateInfo->pAttachments[i].stencilStoreOp; + dst.initialLayout = pCreateInfo->pAttachments[i].initialLayout; + dst.finalLayout = pCreateInfo->pAttachments[i].finalLayout; + } // VK_KHR_multiview const VkRenderPassMultiviewCreateInfo *multiview = @@ -559,6 +570,68 @@ void VulkanCreationInfo::RenderPass::Init(VulkanResourceManager *resourceMan, } } +void VulkanCreationInfo::RenderPass::Init(VulkanResourceManager *resourceMan, + VulkanCreationInfo &info, + const VkRenderPassCreateInfo2KHR *pCreateInfo) +{ + attachments.resize(pCreateInfo->attachmentCount); + for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) + { + Attachment &dst = attachments[i]; + dst.flags = pCreateInfo->pAttachments[i].flags; + dst.format = pCreateInfo->pAttachments[i].format; + dst.samples = pCreateInfo->pAttachments[i].samples; + dst.loadOp = pCreateInfo->pAttachments[i].loadOp; + dst.storeOp = pCreateInfo->pAttachments[i].storeOp; + dst.stencilLoadOp = pCreateInfo->pAttachments[i].stencilLoadOp; + dst.stencilStoreOp = pCreateInfo->pAttachments[i].stencilStoreOp; + dst.initialLayout = pCreateInfo->pAttachments[i].initialLayout; + dst.finalLayout = pCreateInfo->pAttachments[i].finalLayout; + } + + subpasses.resize(pCreateInfo->subpassCount); + for(uint32_t subp = 0; subp < pCreateInfo->subpassCount; subp++) + { + const VkSubpassDescription2KHR &src = pCreateInfo->pSubpasses[subp]; + Subpass &dst = subpasses[subp]; + + dst.inputAttachments.resize(src.inputAttachmentCount); + dst.inputLayouts.resize(src.inputAttachmentCount); + for(uint32_t i = 0; i < src.inputAttachmentCount; i++) + { + dst.inputAttachments[i] = src.pInputAttachments[i].attachment; + dst.inputLayouts[i] = src.pInputAttachments[i].layout; + } + + dst.colorAttachments.resize(src.colorAttachmentCount); + dst.resolveAttachments.resize(src.colorAttachmentCount); + dst.colorLayouts.resize(src.colorAttachmentCount); + for(uint32_t i = 0; i < src.colorAttachmentCount; i++) + { + dst.resolveAttachments[i] = + src.pResolveAttachments ? src.pResolveAttachments[i].attachment : ~0U; + dst.colorAttachments[i] = src.pColorAttachments[i].attachment; + dst.colorLayouts[i] = src.pColorAttachments[i].layout; + } + + dst.depthstencilAttachment = + (src.pDepthStencilAttachment != NULL && + src.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED + ? (int32_t)src.pDepthStencilAttachment->attachment + : -1); + dst.depthstencilLayout = (src.pDepthStencilAttachment != NULL && + src.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED + ? src.pDepthStencilAttachment->layout + : VK_IMAGE_LAYOUT_UNDEFINED); + + for(uint32_t i = 0; i < 32; i++) + { + if(src.viewMask & (1 << i)) + dst.multiviews.push_back(i); + } + } +} + void VulkanCreationInfo::Framebuffer::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkFramebufferCreateInfo *pCreateInfo) diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 9d22bcca5..10a74c02b 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -252,8 +252,23 @@ struct VulkanCreationInfo { void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkRenderPassCreateInfo *pCreateInfo); + void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, + const VkRenderPassCreateInfo2KHR *pCreateInfo); - vector attachments; + struct Attachment + { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; + }; + + vector attachments; struct Subpass { diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index be5c8c6cc..86bba6e2b 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -2560,6 +2560,159 @@ void DoSerialise(SerialiserType &ser, VkShaderModuleValidationCacheCreateInfoEXT // SERIALISE_MEMBER(validationCache); } +template +void DoSerialise(SerialiserType &ser, VkAttachmentDescription2KHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER_TYPED(VkAttachmentDescriptionFlagBits, flags); + SERIALISE_MEMBER(format); + SERIALISE_MEMBER(samples); + SERIALISE_MEMBER(loadOp); + SERIALISE_MEMBER(storeOp); + SERIALISE_MEMBER(stencilLoadOp); + SERIALISE_MEMBER(stencilStoreOp); + SERIALISE_MEMBER(initialLayout); + SERIALISE_MEMBER(finalLayout); +} + +template +void DoSerialise(SerialiserType &ser, VkAttachmentReference2KHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(attachment); + SERIALISE_MEMBER(layout); + SERIALISE_MEMBER(aspectMask); +} + +template +void DoSerialise(SerialiserType &ser, VkSubpassDescription2KHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER_TYPED(VkSubpassDescriptionFlagBits, flags); + SERIALISE_MEMBER(pipelineBindPoint); + SERIALISE_MEMBER(viewMask); + + SERIALISE_MEMBER(inputAttachmentCount); + SERIALISE_MEMBER_ARRAY(pInputAttachments, inputAttachmentCount); + + SERIALISE_MEMBER(colorAttachmentCount); + SERIALISE_MEMBER_ARRAY(pColorAttachments, colorAttachmentCount); + SERIALISE_MEMBER_ARRAY(pResolveAttachments, colorAttachmentCount); + + SERIALISE_MEMBER_OPT(pDepthStencilAttachment); + + SERIALISE_MEMBER(preserveAttachmentCount); + SERIALISE_MEMBER_ARRAY(pPreserveAttachments, preserveAttachmentCount); +} + +template +void DoSerialise(SerialiserType &ser, VkSubpassDependency2KHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(srcSubpass); + SERIALISE_MEMBER(dstSubpass); + SERIALISE_MEMBER_TYPED(VkPipelineStageFlagBits, srcStageMask); + SERIALISE_MEMBER_TYPED(VkPipelineStageFlagBits, dstStageMask); + SERIALISE_MEMBER_TYPED(VkAccessFlagBits, srcAccessMask); + SERIALISE_MEMBER_TYPED(VkAccessFlagBits, dstAccessMask); + SERIALISE_MEMBER_TYPED(VkDependencyFlagBits, dependencyFlags); + SERIALISE_MEMBER(viewOffset); +} + +template +void DoSerialise(SerialiserType &ser, VkRenderPassCreateInfo2KHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER_TYPED(VkFlagWithNoBits, flags); + SERIALISE_MEMBER(attachmentCount); + SERIALISE_MEMBER_ARRAY(pAttachments, attachmentCount); + SERIALISE_MEMBER(subpassCount); + SERIALISE_MEMBER_ARRAY(pSubpasses, subpassCount); + SERIALISE_MEMBER(dependencyCount); + SERIALISE_MEMBER_ARRAY(pDependencies, dependencyCount); + SERIALISE_MEMBER(correlatedViewMaskCount); + SERIALISE_MEMBER_ARRAY(pCorrelatedViewMasks, correlatedViewMaskCount); +} + +template <> +void Deserialise(const VkRenderPassCreateInfo2KHR &el) +{ + DeserialiseNext(el.pNext); + for(uint32_t i = 0; i < el.attachmentCount; i++) + { + DeserialiseNext(el.pAttachments[i].pNext); + } + delete[] el.pAttachments; + for(uint32_t i = 0; i < el.subpassCount; i++) + { + DeserialiseNext(el.pSubpasses[i].pNext); + + if(el.pSubpasses[i].pDepthStencilAttachment) + DeserialiseNext(el.pSubpasses[i].pDepthStencilAttachment->pNext); + + for(uint32_t j = 0; j < el.pSubpasses[i].colorAttachmentCount; j++) + { + DeserialiseNext(el.pSubpasses[i].pColorAttachments[j].pNext); + if(el.pSubpasses[i].pResolveAttachments) + DeserialiseNext(el.pSubpasses[i].pResolveAttachments[j].pNext); + } + + for(uint32_t j = 0; j < el.pSubpasses[i].inputAttachmentCount; j++) + DeserialiseNext(el.pSubpasses[i].pInputAttachments[j].pNext); + + delete el.pSubpasses[i].pDepthStencilAttachment; + delete[] el.pSubpasses[i].pInputAttachments; + delete[] el.pSubpasses[i].pColorAttachments; + delete[] el.pSubpasses[i].pResolveAttachments; + delete[] el.pSubpasses[i].pPreserveAttachments; + } + delete[] el.pSubpasses; + for(uint32_t i = 0; i < el.dependencyCount; i++) + { + DeserialiseNext(el.pDependencies[i].pNext); + } + delete[] el.pDependencies; + delete[] el.pCorrelatedViewMasks; +} + +template +void DoSerialise(SerialiserType &ser, VkSubpassBeginInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(contents); +} + +template <> +void Deserialise(const VkSubpassBeginInfoKHR &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkSubpassEndInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR); + SerialiseNext(ser, el.sType, el.pNext); +} + +template <> +void Deserialise(const VkSubpassEndInfoKHR &el) +{ + DeserialiseNext(el.pNext); +} + template void DoSerialise(SerialiserType &ser, VkDispatchIndirectCommand &el) { @@ -3177,6 +3330,9 @@ INSTANTIATE_SERIALISE_TYPE(VkProtectedSubmitInfo); INSTANTIATE_SERIALISE_TYPE(VkImageFormatListCreateInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkImageViewASTCDecodeModeEXT); INSTANTIATE_SERIALISE_TYPE(VkShaderModuleValidationCacheCreateInfoEXT); +INSTANTIATE_SERIALISE_TYPE(VkRenderPassCreateInfo2KHR); +INSTANTIATE_SERIALISE_TYPE(VkSubpassBeginInfoKHR); +INSTANTIATE_SERIALISE_TYPE(VkSubpassEndInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkDispatchIndirectCommand); INSTANTIATE_SERIALISE_TYPE(VkDrawIndirectCommand); INSTANTIATE_SERIALISE_TYPE(VkDrawIndexedIndirectCommand); diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index ccaa225ae..733e7da38 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 == 1118, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1122, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(VulkanChunk) { @@ -150,6 +150,10 @@ std::string DoStringise(const VulkanChunk &el) STRINGISE_ENUM_CLASS(vkGetDeviceQueue2); STRINGISE_ENUM_CLASS(vkCmdDrawIndirectCountKHR); STRINGISE_ENUM_CLASS(vkCmdDrawIndexedIndirectCountKHR); + STRINGISE_ENUM_CLASS(vkCreateRenderPass2KHR); + STRINGISE_ENUM_CLASS(vkCmdBeginRenderPass2KHR); + STRINGISE_ENUM_CLASS(vkCmdNextSubpass2KHR); + STRINGISE_ENUM_CLASS(vkCmdEndRenderPass2KHR); 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 496080024..0bfadc438 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -219,7 +219,7 @@ string WrappedVulkan::MakeRenderPassOpString(bool store) const VulkanCreationInfo::Framebuffer &fbinfo = m_CreationInfo.m_Framebuffer[m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer]; - const vector &atts = info.attachments; + const vector &atts = info.attachments; if(atts.empty()) { @@ -1352,6 +1352,389 @@ void WrappedVulkan::vkCmdEndRenderPass(VkCommandBuffer commandBuffer) } } +template +bool WrappedVulkan::Serialise_vkCmdBeginRenderPass2KHR(SerialiserType &ser, + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo *pRenderPassBegin, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT_LOCAL(RenderPassBegin, *pRenderPassBegin); + SERIALISE_ELEMENT_LOCAL(SubpassBegin, *pSubpassBeginInfo); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + VkRenderPassBeginInfo unwrappedInfo = RenderPassBegin; + unwrappedInfo.renderPass = Unwrap(unwrappedInfo.renderPass); + unwrappedInfo.framebuffer = Unwrap(unwrappedInfo.framebuffer); + + VkSubpassBeginInfoKHR unwrappedBeginInfo = SubpassBegin; + + byte *tempMem = GetTempMemory(GetNextPatchSize(unwrappedInfo.pNext) + + GetNextPatchSize(unwrappedBeginInfo.pNext)); + + UnwrapNextChain(m_State, "VkRenderPassBeginInfo", tempMem, (VkBaseInStructure *)&unwrappedInfo); + UnwrapNextChain(m_State, "VkSubpassBeginInfoKHR", tempMem, + (VkBaseInStructure *)&unwrappedBeginInfo); + + m_LastCmdBufferID = GetResourceManager()->GetOriginalID(GetResID(commandBuffer)); + + if(IsActiveReplaying(m_State)) + { + if(InRerecordRange(m_LastCmdBufferID)) + { + commandBuffer = RerecordCmdBuf(m_LastCmdBufferID); + + // always track this, for WrappedVulkan::IsDrawInRenderPass() + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass = 0; + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = + GetResID(RenderPassBegin.renderPass); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = + GetResID(RenderPassBegin.framebuffer); + + // only if we're partially recording do we update this state + if(ShouldUpdateRenderState(m_LastCmdBufferID, true)) + { + m_Partial[Primary].renderPassActive = true; + + m_RenderState.subpass = 0; + + m_RenderState.renderPass = GetResID(RenderPassBegin.renderPass); + m_RenderState.framebuffer = GetResID(RenderPassBegin.framebuffer); + m_RenderState.renderArea = RenderPassBegin.renderArea; + } + + ObjDisp(commandBuffer) + ->CmdBeginRenderPass2KHR(Unwrap(commandBuffer), &unwrappedInfo, &unwrappedBeginInfo); + + std::vector imgBarriers = GetImplicitRenderPassBarriers(); + + ResourceId cmd = GetResID(commandBuffer); + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), imgBarriers.data()); + } + } + else + { + ObjDisp(commandBuffer) + ->CmdBeginRenderPass2KHR(Unwrap(commandBuffer), &unwrappedInfo, &unwrappedBeginInfo); + + // track while reading, for fetching the right set of outputs in AddDrawcall + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass = 0; + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = GetResID(RenderPassBegin.renderPass); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = + GetResID(RenderPassBegin.framebuffer); + + std::vector imgBarriers = GetImplicitRenderPassBarriers(); + + ResourceId cmd = GetResID(commandBuffer); + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), imgBarriers.data()); + + AddEvent(); + DrawcallDescription draw; + draw.name = + StringFormat::Fmt("vkCmdBeginRenderPass2KHR(%s)", MakeRenderPassOpString(false).c_str()); + draw.flags |= DrawFlags::PassBoundary | DrawFlags::BeginPass; + + AddDrawcall(draw, true); + } + } + + return true; +} + +void WrappedVulkan::vkCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo *pRenderPassBegin, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo) +{ + SCOPED_DBG_SINK(); + + VkRenderPassBeginInfo unwrappedInfo = *pRenderPassBegin; + unwrappedInfo.renderPass = Unwrap(unwrappedInfo.renderPass); + unwrappedInfo.framebuffer = Unwrap(unwrappedInfo.framebuffer); + + VkSubpassBeginInfoKHR unwrappedBeginInfo = *pSubpassBeginInfo; + + byte *tempMem = GetTempMemory(GetNextPatchSize(unwrappedInfo.pNext) + + GetNextPatchSize(unwrappedBeginInfo.pNext)); + + UnwrapNextChain(m_State, "VkRenderPassBeginInfo", tempMem, (VkBaseInStructure *)&unwrappedInfo); + UnwrapNextChain(m_State, "VkSubpassBeginInfoKHR", tempMem, + (VkBaseInStructure *)&unwrappedBeginInfo); + + SERIALISE_TIME_CALL( + ObjDisp(commandBuffer) + ->CmdBeginRenderPass2KHR(Unwrap(commandBuffer), &unwrappedInfo, &unwrappedBeginInfo)); + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + ser.SetDrawChunk(); + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdBeginRenderPass2KHR); + Serialise_vkCmdBeginRenderPass2KHR(ser, commandBuffer, pRenderPassBegin, pSubpassBeginInfo); + + record->AddChunk(scope.Get()); + record->MarkResourceFrameReferenced(GetResID(pRenderPassBegin->renderPass), eFrameRef_Read); + + VkResourceRecord *fb = GetRecord(pRenderPassBegin->framebuffer); + + record->MarkResourceFrameReferenced(fb->GetResourceID(), eFrameRef_Read); + for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) + { + VkResourceRecord *att = fb->imageAttachments[i].record; + if(att == NULL) + break; + + record->MarkResourceFrameReferenced(att->baseResource, eFrameRef_Write); + if(att->baseResourceMem != ResourceId()) + record->MarkResourceFrameReferenced(att->baseResourceMem, eFrameRef_Read); + if(att->sparseInfo) + record->cmdInfo->sparse.insert(att->sparseInfo); + record->cmdInfo->dirtied.insert(att->baseResource); + } + + record->cmdInfo->framebuffer = fb; + } +} + +template +bool WrappedVulkan::Serialise_vkCmdNextSubpass2KHR(SerialiserType &ser, VkCommandBuffer commandBuffer, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo, + const VkSubpassEndInfoKHR *pSubpassEndInfo) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT_LOCAL(SubpassBegin, *pSubpassBeginInfo); + SERIALISE_ELEMENT_LOCAL(SubpassEnd, *pSubpassEndInfo); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + VkSubpassBeginInfoKHR unwrappedBeginInfo = SubpassBegin; + VkSubpassEndInfoKHR unwrappedEndInfo = SubpassEnd; + + byte *tempMem = GetTempMemory(GetNextPatchSize(unwrappedBeginInfo.pNext) + + GetNextPatchSize(unwrappedEndInfo.pNext)); + + UnwrapNextChain(m_State, "VkSubpassBeginInfoKHR", tempMem, + (VkBaseInStructure *)&unwrappedBeginInfo); + UnwrapNextChain(m_State, "VkSubpassEndInfoKHR", tempMem, (VkBaseInStructure *)&unwrappedEndInfo); + + m_LastCmdBufferID = GetResourceManager()->GetOriginalID(GetResID(commandBuffer)); + + if(IsActiveReplaying(m_State)) + { + // don't do anything if we're executing a single draw, NextSubpass is meaningless (and invalid + // on a partial render pass) + if(InRerecordRange(m_LastCmdBufferID) && m_FirstEventID != m_LastEventID) + { + commandBuffer = RerecordCmdBuf(m_LastCmdBufferID); + + // always track this, for WrappedVulkan::IsDrawInRenderPass() + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass++; + + if(ShouldUpdateRenderState(m_LastCmdBufferID, true)) + m_RenderState.subpass++; + + ObjDisp(commandBuffer) + ->CmdNextSubpass2KHR(Unwrap(commandBuffer), &unwrappedBeginInfo, &unwrappedEndInfo); + + std::vector imgBarriers = GetImplicitRenderPassBarriers(); + + ResourceId cmd = GetResID(commandBuffer); + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), imgBarriers.data()); + } + } + else + { + ObjDisp(commandBuffer) + ->CmdNextSubpass2KHR(Unwrap(commandBuffer), &unwrappedBeginInfo, &unwrappedEndInfo); + + // track while reading, for fetching the right set of outputs in AddDrawcall + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass++; + + std::vector imgBarriers = GetImplicitRenderPassBarriers(); + + ResourceId cmd = GetResID(commandBuffer); + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), &imgBarriers[0]); + + AddEvent(); + DrawcallDescription draw; + draw.name = StringFormat::Fmt("vkCmdNextSubpass2KHR() => %u", + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass); + draw.flags |= DrawFlags::PassBoundary | DrawFlags::BeginPass | DrawFlags::EndPass; + + AddDrawcall(draw, true); + } + } + + return true; +} + +void WrappedVulkan::vkCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo, + const VkSubpassEndInfoKHR *pSubpassEndInfo) +{ + SCOPED_DBG_SINK(); + + VkSubpassBeginInfoKHR unwrappedBeginInfo = *pSubpassBeginInfo; + VkSubpassEndInfoKHR unwrappedEndInfo = *pSubpassEndInfo; + + byte *tempMem = GetTempMemory(GetNextPatchSize(unwrappedBeginInfo.pNext) + + GetNextPatchSize(unwrappedEndInfo.pNext)); + + UnwrapNextChain(m_State, "VkSubpassBeginInfoKHR", tempMem, + (VkBaseInStructure *)&unwrappedBeginInfo); + UnwrapNextChain(m_State, "VkSubpassEndInfoKHR", tempMem, (VkBaseInStructure *)&unwrappedEndInfo); + + SERIALISE_TIME_CALL( + ObjDisp(commandBuffer) + ->CmdNextSubpass2KHR(Unwrap(commandBuffer), &unwrappedBeginInfo, &unwrappedEndInfo)); + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + ser.SetDrawChunk(); + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdNextSubpass2KHR); + Serialise_vkCmdNextSubpass2KHR(ser, commandBuffer, pSubpassBeginInfo, pSubpassEndInfo); + + record->AddChunk(scope.Get()); + } +} + +template +bool WrappedVulkan::Serialise_vkCmdEndRenderPass2KHR(SerialiserType &ser, + VkCommandBuffer commandBuffer, + const VkSubpassEndInfoKHR *pSubpassEndInfo) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT_LOCAL(SubpassEnd, *pSubpassEndInfo); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + VkSubpassEndInfoKHR unwrappedEndInfo = SubpassEnd; + + byte *tempMem = GetTempMemory(GetNextPatchSize(unwrappedEndInfo.pNext)); + + UnwrapNextChain(m_State, "VkSubpassEndInfoKHR", tempMem, (VkBaseInStructure *)&unwrappedEndInfo); + + m_LastCmdBufferID = GetResourceManager()->GetOriginalID(GetResID(commandBuffer)); + + if(IsActiveReplaying(m_State)) + { + if(InRerecordRange(m_LastCmdBufferID)) + { + commandBuffer = RerecordCmdBuf(m_LastCmdBufferID); + + // always track this, for WrappedVulkan::IsDrawInRenderPass() + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = ResourceId(); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = ResourceId(); + + if(ShouldUpdateRenderState(m_LastCmdBufferID, true)) + { + m_Partial[Primary].renderPassActive = false; + } + + ObjDisp(commandBuffer)->CmdEndRenderPass2KHR(Unwrap(commandBuffer), &unwrappedEndInfo); + + std::vector imgBarriers = GetImplicitRenderPassBarriers(~0U); + + ResourceId cmd = GetResID(commandBuffer); + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), imgBarriers.data()); + } + } + else + { + ObjDisp(commandBuffer)->CmdEndRenderPass2KHR(Unwrap(commandBuffer), &unwrappedEndInfo); + + std::vector imgBarriers = GetImplicitRenderPassBarriers(~0U); + + ResourceId cmd = GetResID(commandBuffer); + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), &imgBarriers[0]); + + AddEvent(); + DrawcallDescription draw; + draw.name = + StringFormat::Fmt("vkCmdEndRenderPass2KHR(%s)", MakeRenderPassOpString(true).c_str()); + draw.flags |= DrawFlags::PassBoundary | DrawFlags::EndPass; + + AddDrawcall(draw, true); + + // track while reading, reset this to empty so AddDrawcall sets no outputs, + // but only AFTER the above AddDrawcall (we want it grouped together) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = ResourceId(); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = ResourceId(); + } + } + + return true; +} + +void WrappedVulkan::vkCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, + const VkSubpassEndInfoKHR *pSubpassEndInfo) +{ + SCOPED_DBG_SINK(); + + VkSubpassEndInfoKHR unwrappedEndInfo = *pSubpassEndInfo; + + byte *tempMem = GetTempMemory(GetNextPatchSize(unwrappedEndInfo.pNext)); + + UnwrapNextChain(m_State, "VkSubpassEndInfoKHR", tempMem, (VkBaseInStructure *)&unwrappedEndInfo); + + SERIALISE_TIME_CALL( + ObjDisp(commandBuffer)->CmdEndRenderPass2KHR(Unwrap(commandBuffer), &unwrappedEndInfo)); + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + ser.SetDrawChunk(); + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdEndRenderPass2KHR); + Serialise_vkCmdEndRenderPass2KHR(ser, commandBuffer, pSubpassEndInfo); + + record->AddChunk(scope.Get()); + + VkResourceRecord *fb = record->cmdInfo->framebuffer; + + std::vector barriers; + + for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) + { + if(fb->imageAttachments[i].barrier.oldLayout == fb->imageAttachments[i].barrier.newLayout) + continue; + + barriers.push_back(fb->imageAttachments[i].barrier); + } + + // apply the implicit layout transitions here + { + SCOPED_LOCK(m_ImageLayoutsLock); + GetResourceManager()->RecordBarriers(GetRecord(commandBuffer)->cmdInfo->imgbarriers, + m_ImageLayouts, (uint32_t)barriers.size(), &barriers[0]); + } + } +} + template bool WrappedVulkan::Serialise_vkCmdBindPipeline(SerialiserType &ser, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, @@ -3915,6 +4298,15 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdNextSubpass, VkCommandBuffer commandB INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdEndRenderPass, VkCommandBuffer commandBuffer); +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdBeginRenderPass2KHR, VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo *pRenderPassBegin, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo); +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdNextSubpass2KHR, VkCommandBuffer commandBuffer, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo, + const VkSubpassEndInfoKHR *pSubpassEndInfo); +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdEndRenderPass2KHR, VkCommandBuffer commandBuffer, + const VkSubpassEndInfoKHR *pSubpassEndInfo); + INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdBindPipeline, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); @@ -4004,4 +4396,4 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdInsertDebugUtilsLabelEXT, VkCommandBu const VkDebugUtilsLabelEXT *pLabelInfo); INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetDeviceMask, VkCommandBuffer commandBuffer, - uint32_t deviceMask); + uint32_t deviceMask); \ No newline at end of file diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index abb8af365..2d12a2197 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -24,23 +24,8 @@ #include "../vk_core.h" -template <> -VkFramebufferCreateInfo WrappedVulkan::UnwrapInfo(const VkFramebufferCreateInfo *info) -{ - VkFramebufferCreateInfo ret = *info; - - VkImageView *unwrapped = GetTempArray(info->attachmentCount); - for(uint32_t i = 0; i < info->attachmentCount; i++) - unwrapped[i] = Unwrap(info->pAttachments[i]); - - ret.renderPass = Unwrap(ret.renderPass); - ret.pAttachments = unwrapped; - - return ret; -} - -void WrappedVulkan::MakeSubpassLoadRP(VkRenderPassCreateInfo &info, - const VkRenderPassCreateInfo *origInfo, uint32_t s) +template +static void MakeSubpassLoadRP(RPCreateInfo &info, const RPCreateInfo *origInfo, uint32_t s) { info.subpassCount = 1; info.pSubpasses = origInfo->pSubpasses + s; @@ -48,8 +33,14 @@ void WrappedVulkan::MakeSubpassLoadRP(VkRenderPassCreateInfo &info, // remove any dependencies info.dependencyCount = 0; - const VkSubpassDescription *sub = info.pSubpasses; - VkAttachmentDescription *att = (VkAttachmentDescription *)info.pAttachments; + // we use decltype here because this is templated to work for regular and create_renderpass2 + // structs + using SubpassInfo = typename std::remove_reference::type; + using AttachmentInfo = + std::remove_cv::type>::type; + + SubpassInfo *sub = info.pSubpasses; + AttachmentInfo *att = (AttachmentInfo *)info.pAttachments; // apply this subpass's attachment layouts to the initial and final layouts // so that this RP doesn't perform any layout transitions @@ -79,6 +70,21 @@ void WrappedVulkan::MakeSubpassLoadRP(VkRenderPassCreateInfo &info, } } +template <> +VkFramebufferCreateInfo WrappedVulkan::UnwrapInfo(const VkFramebufferCreateInfo *info) +{ + VkFramebufferCreateInfo ret = *info; + + VkImageView *unwrapped = GetTempArray(info->attachmentCount); + for(uint32_t i = 0; i < info->attachmentCount; i++) + unwrapped[i] = Unwrap(info->pAttachments[i]); + + ret.renderPass = Unwrap(ret.renderPass); + ret.pAttachments = unwrapped; + + return ret; +} + // note, for threading reasons we ensure to release the wrappers before // releasing the underlying object. Otherwise after releasing the vulkan object // that same handle could be returned by create on another thread, and we @@ -907,6 +913,221 @@ VkResult WrappedVulkan::vkCreateRenderPass(VkDevice device, const VkRenderPassCr return ret; } +template +bool WrappedVulkan::Serialise_vkCreateRenderPass2KHR(SerialiserType &ser, VkDevice device, + const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkRenderPass *pRenderPass) +{ + SERIALISE_ELEMENT(device); + SERIALISE_ELEMENT_LOCAL(CreateInfo, *pCreateInfo); + SERIALISE_ELEMENT_OPT(pAllocator); + SERIALISE_ELEMENT_LOCAL(RenderPass, GetResID(*pRenderPass)).TypedAs("VkRenderPass"); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + VkRenderPass rp = VK_NULL_HANDLE; + + VulkanCreationInfo::RenderPass rpinfo; + rpinfo.Init(GetResourceManager(), m_CreationInfo, &CreateInfo); + + // we want to store off the data so we can display it after the pass. + // override any user-specified DONT_CARE. + // Likewise we don't want to throw away data before we're ready, so change + // any load ops to LOAD instead of DONT_CARE (which is valid!). We of course + // leave any LOAD_OP_CLEAR alone. + VkAttachmentDescription2KHR *att = (VkAttachmentDescription2KHR *)CreateInfo.pAttachments; + for(uint32_t i = 0; i < CreateInfo.attachmentCount; i++) + { + att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + + if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE) + att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE) + att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + // renderpass can't start or end in presentable layout on replay + ReplacePresentableImageLayout(att[i].initialLayout); + ReplacePresentableImageLayout(att[i].finalLayout); + } + + VkResult ret = ObjDisp(device)->CreateRenderPass2KHR(Unwrap(device), &CreateInfo, NULL, &rp); + + if(ret != VK_SUCCESS) + { + RDCERR("Failed on resource serialise-creation, VkResult: %s", ToStr(ret).c_str()); + return false; + } + else + { + ResourceId live; + + if(GetResourceManager()->HasWrapper(ToTypedHandle(rp))) + { + live = GetResourceManager()->GetNonDispWrapper(rp)->id; + + // destroy this instance of the duplicate, as we must have matching create/destroy + // calls and there won't be a wrapped resource hanging around to destroy this one. + ObjDisp(device)->DestroyRenderPass(Unwrap(device), rp, NULL); + + // whenever the new ID is requested, return the old ID, via replacements. + GetResourceManager()->ReplaceResource(RenderPass, GetResourceManager()->GetOriginalID(live)); + } + else + { + live = GetResourceManager()->WrapResource(Unwrap(device), rp); + GetResourceManager()->AddLiveResource(RenderPass, rp); + + // make a version of the render pass that loads from its attachments, + // so it can be used for replaying a single draw after a render pass + // without doing a clear or a DONT_CARE load. + for(uint32_t i = 0; i < CreateInfo.attachmentCount; i++) + { + att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } + + VkRenderPassCreateInfo2KHR loadInfo = CreateInfo; + + rpinfo.loadRPs.resize(CreateInfo.subpassCount); + + // create a render pass for each subpass that maintains attachment layouts + for(uint32_t s = 0; s < CreateInfo.subpassCount; s++) + { + MakeSubpassLoadRP(loadInfo, &CreateInfo, s); + + ret = ObjDisp(device)->CreateRenderPass2KHR(Unwrap(device), &loadInfo, NULL, + &rpinfo.loadRPs[s]); + RDCASSERTEQUAL(ret, VK_SUCCESS); + + // handle the loadRP being a duplicate + if(GetResourceManager()->HasWrapper(ToTypedHandle(rpinfo.loadRPs[s]))) + { + // just fetch the existing wrapped object + rpinfo.loadRPs[s] = + (VkRenderPass)(uint64_t)GetResourceManager()->GetNonDispWrapper(rpinfo.loadRPs[s]); + + // destroy this instance of the duplicate, as we must have matching create/destroy + // calls and there won't be a wrapped resource hanging around to destroy this one. + ObjDisp(device)->DestroyRenderPass(Unwrap(device), rpinfo.loadRPs[s], NULL); + + // don't need to ReplaceResource as no IDs are involved + } + else + { + ResourceId loadRPid = + GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRPs[s]); + + // register as a live-only resource, so it is cleaned up properly + GetResourceManager()->AddLiveResource(loadRPid, rpinfo.loadRPs[s]); + } + } + + m_CreationInfo.m_RenderPass[live] = rpinfo; + } + } + + AddResource(RenderPass, ResourceType::RenderPass, "Render Pass"); + DerivedResource(device, RenderPass); + } + + return true; +} + +VkResult WrappedVulkan::vkCreateRenderPass2KHR(VkDevice device, + const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkRenderPass *pRenderPass) +{ + VkResult ret; + SERIALISE_TIME_CALL(ret = ObjDisp(device)->CreateRenderPass2KHR(Unwrap(device), pCreateInfo, + pAllocator, pRenderPass)); + + if(ret == VK_SUCCESS) + { + ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), *pRenderPass); + + if(IsCaptureMode(m_State)) + { + Chunk *chunk = NULL; + + { + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCreateRenderPass2KHR); + Serialise_vkCreateRenderPass2KHR(ser, device, pCreateInfo, NULL, pRenderPass); + + chunk = scope.Get(); + } + + VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pRenderPass); + record->AddChunk(chunk); + + // +1 for the terminal value + uint32_t arrayCount = pCreateInfo->attachmentCount + 1; + + record->imageAttachments = new AttachmentInfo[arrayCount]; + + RDCEraseMem(record->imageAttachments, sizeof(AttachmentInfo) * arrayCount); + + for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) + { + record->imageAttachments[i].record = NULL; + record->imageAttachments[i].barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + record->imageAttachments[i].barrier.oldLayout = pCreateInfo->pAttachments[i].initialLayout; + record->imageAttachments[i].barrier.newLayout = pCreateInfo->pAttachments[i].finalLayout; + } + } + else + { + GetResourceManager()->AddLiveResource(id, *pRenderPass); + + VulkanCreationInfo::RenderPass rpinfo; + rpinfo.Init(GetResourceManager(), m_CreationInfo, pCreateInfo); + + VkRenderPassCreateInfo2KHR info = *pCreateInfo; + + VkAttachmentDescription2KHR atts[16]; + RDCASSERT(ARRAY_COUNT(atts) >= (size_t)info.attachmentCount); + + // make a version of the render pass that loads from its attachments, + // so it can be used for replaying a single draw after a render pass + // without doing a clear or a DONT_CARE load. + for(uint32_t i = 0; i < info.attachmentCount; i++) + { + atts[i] = info.pAttachments[i]; + atts[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + atts[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } + + info.pAttachments = atts; + + rpinfo.loadRPs.resize(pCreateInfo->subpassCount); + + // create a render pass for each subpass that maintains attachment layouts + for(uint32_t s = 0; s < pCreateInfo->subpassCount; s++) + { + MakeSubpassLoadRP(info, pCreateInfo, s); + + ret = ObjDisp(device)->CreateRenderPass2KHR(Unwrap(device), &info, NULL, &rpinfo.loadRPs[s]); + RDCASSERTEQUAL(ret, VK_SUCCESS); + + ResourceId loadRPid = GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRPs[s]); + + // register as a live-only resource, so it is cleaned up properly + GetResourceManager()->AddLiveResource(loadRPid, rpinfo.loadRPs[s]); + } + + m_CreationInfo.m_RenderPass[id] = rpinfo; + } + } + + return ret; +} + template bool WrappedVulkan::Serialise_vkCreateQueryPool(SerialiserType &ser, VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, @@ -1706,6 +1927,10 @@ INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateRenderPass, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); +INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateRenderPass2KHR, VkDevice device, + const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); + INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateQueryPool, VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool);