From d3ef145c87e403b2c45c40821c8529056683966b Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 19 Jun 2020 10:49:08 +0100 Subject: [PATCH] Patch VkRenderPassMultiviewCreateInfo when making single-subpass RPs --- renderdoc/driver/vulkan/vk_common.h | 1 + renderdoc/driver/vulkan/vk_next_chains.cpp | 184 ++++++++++++++++++ .../driver/vulkan/wrappers/vk_misc_funcs.cpp | 48 +++++ 3 files changed, 233 insertions(+) diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index a5713b88b..4378ba6d7 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -286,6 +286,7 @@ enum VkFlagWithNoBits size_t GetNextPatchSize(const void *next); void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem, VkBaseInStructure *infoStruct); +void CopyNextChainForPatching(const char *structName, byte *&tempMem, VkBaseInStructure *infoStruct); template const VkBaseInStructure *FindNextStruct(const VkStruct *haystack, VkStructureType needle) diff --git a/renderdoc/driver/vulkan/vk_next_chains.cpp b/renderdoc/driver/vulkan/vk_next_chains.cpp index c949199ad..bc29db045 100644 --- a/renderdoc/driver/vulkan/vk_next_chains.cpp +++ b/renderdoc/driver/vulkan/vk_next_chains.cpp @@ -982,6 +982,7 @@ void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem, break; \ } +#undef UNWRAP_STRUCT_INNER #define UNWRAP_STRUCT_INNER(StructType, StructName, ...) \ { \ const StructName *in = (const StructName *)nextInput; \ @@ -1562,3 +1563,186 @@ void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem, nextInput = nextInput->pNext; } } + +void CopyNextChainForPatching(const char *structName, byte *&tempMem, VkBaseInStructure *infoStruct) +{ + VkBaseInStructure *nextChainTail = infoStruct; + const VkBaseInStructure *nextInput = (const VkBaseInStructure *)infoStruct->pNext; + +// simplified version of UnwrapNextChain which just copies everything. Useful for when we need to +// shallow duplicate a next chain (e.g. because we'll copy and patch one struct) + +#undef COPY_STRUCT_CAPTURE_ONLY +#define COPY_STRUCT_CAPTURE_ONLY(StructType, StructName) \ + case StructType: \ + CopyNextChainedStruct(sizeof(StructName), tempMem, nextInput, nextChainTail); \ + break; + +#undef COPY_STRUCT +#define COPY_STRUCT(StructType, StructName) \ + case StructType: \ + CopyNextChainedStruct(sizeof(StructName), tempMem, nextInput, nextChainTail); \ + break; + +#undef UNWRAP_STRUCT_INNER +#define UNWRAP_STRUCT_INNER(StructType, StructName, ...) \ + case StructType: \ + CopyNextChainedStruct(sizeof(StructName), tempMem, nextInput, nextChainTail); \ + break; + +#undef UNWRAP_STRUCT +#define UNWRAP_STRUCT(StructType, StructName, ...) \ + case StructType: \ + CopyNextChainedStruct(sizeof(StructName), tempMem, nextInput, nextChainTail); \ + break; + +#undef UNWRAP_STRUCT_CAPTURE_ONLY +#define UNWRAP_STRUCT_CAPTURE_ONLY(StructType, StructName, ...) \ + case StructType: \ + CopyNextChainedStruct(sizeof(StructName), tempMem, nextInput, nextChainTail); \ + break; + + nextChainTail->pNext = NULL; + while(nextInput) + { + switch(nextInput->sType) + { + PROCESS_SIMPLE_STRUCTS(); + + // complex structs to handle - require multiple allocations + case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO: + CopyNextChainedStruct(sizeof(VkBindSparseInfo), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO: + CopyNextChainedStruct(sizeof(VkDescriptorSetAllocateInfo), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO: + CopyNextChainedStruct(sizeof(VkDescriptorSetLayoutCreateInfo), tempMem, nextInput, + nextChainTail); + break; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: + CopyNextChainedStruct(sizeof(VkDeviceGroupDeviceCreateInfo), tempMem, nextInput, + nextChainTail); + break; + case VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO: + CopyNextChainedStruct(sizeof(VkFramebufferCreateInfo), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO: + CopyNextChainedStruct(sizeof(VkGraphicsPipelineCreateInfo), tempMem, nextInput, + nextChainTail); + break; + case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO: + CopyNextChainedStruct(sizeof(VkComputePipelineCreateInfo), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO: + CopyNextChainedStruct(sizeof(VkPipelineLayoutCreateInfo), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_PRESENT_INFO_KHR: + CopyNextChainedStruct(sizeof(VkPresentInfoKHR), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: + CopyNextChainedStruct(sizeof(VkRenderPassAttachmentBeginInfo), tempMem, nextInput, + nextChainTail); + break; + case VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO: + CopyNextChainedStruct(sizeof(VkSemaphoreWaitInfo), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_SUBMIT_INFO: + CopyNextChainedStruct(sizeof(VkSubmitInfo), tempMem, nextInput, nextChainTail); + break; + case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: + CopyNextChainedStruct(sizeof(VkWriteDescriptorSet), tempMem, nextInput, nextChainTail); + break; + +// NV win32 external memory extensions +#if ENABLED(RDOC_WIN32) + // Structs that can be copied into place + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV, + VkImportMemoryWin32HandleInfoNV); + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV, + VkExportMemoryWin32HandleInfoNV); + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR, + VkImportMemoryWin32HandleInfoKHR); + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR, + VkExportMemoryWin32HandleInfoKHR); + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR, + VkMemoryWin32HandlePropertiesKHR); + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR, + VkExportSemaphoreWin32HandleInfoKHR); + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR, + VkD3D12FenceSubmitInfoKHR); + COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR, + VkExportFenceWin32HandleInfoKHR); + + UNWRAP_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR, + VkMemoryGetWin32HandleInfoKHR, UnwrapInPlace(out->memory)); + UNWRAP_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR, + VkImportSemaphoreWin32HandleInfoKHR, + UnwrapInPlace(out->semaphore)); + UNWRAP_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR, + VkSemaphoreGetWin32HandleInfoKHR, UnwrapInPlace(out->semaphore)); + UNWRAP_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR, + VkImportFenceWin32HandleInfoKHR, UnwrapInPlace(out->fence)); + UNWRAP_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR, + VkFenceGetWin32HandleInfoKHR, UnwrapInPlace(out->fence)); + + case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV: + case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR: + CopyNextChainedStruct(sizeof(VkWin32KeyedMutexAcquireReleaseInfoKHR), tempMem, nextInput, + nextChainTail); + break; +#else + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV: + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV: + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR: + case VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR: + case VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR: + case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV: + case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR: + { + RDCERR("Support for win32 external memory extensions not compiled in"); + nextChainTail->pNext = nextInput; + break; + } +#endif + + case VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT: + case VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT: + case VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT: + case VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT: + case VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT: + { + // could be implemented but would need extra work or doesn't make sense right now + RDCERR("Struct %s not handled in %s pNext chain", ToStr(nextInput->sType).c_str(), + structName); + nextChainTail->pNext = nextInput; + break; + } + + UNHANDLED_STRUCTS() + { + RDCERR("Unhandled struct %s in %s pNext chain", ToStr(nextInput->sType).c_str(), + structName); + nextChainTail->pNext = nextInput; + break; + } + + case VK_STRUCTURE_TYPE_MAX_ENUM: + { + RDCERR("Invalid value %x in %s pNext chain", nextInput->sType, structName); + nextChainTail->pNext = nextInput; + break; + } + } + + nextInput = nextInput->pNext; + } +} diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index e8f24135f..1fc8c625e 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -53,6 +53,33 @@ static void MakeSubpassLoadRP(RPCreateInfo &info, const RPCreateInfo *origInfo, info.subpassCount = 1; info.pSubpasses = origInfo->pSubpasses + s; + // VK_KHR_multiview + const VkRenderPassMultiviewCreateInfo *multiview = + (const VkRenderPassMultiviewCreateInfo *)FindNextStruct( + origInfo, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO); + + static VkRenderPassMultiviewCreateInfo patched; + + if(multiview) + { + // remove from the chain, the caller ensured we have a mutable chain so we won't be trashing the + // pNext chain we'll look up for any subsequent subpasses + RemoveNextStruct(&info, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO); + patched = *multiview; + + // keep the view mask for our target subpass + patched.subpassCount = 1; + patched.pViewMasks = patched.pViewMasks + s; + + // view offsets are not allowed for self-dependencies, and we remove all other dependencies. + patched.dependencyCount = 0; + patched.pViewOffsets = NULL; + + // add onto the chain + patched.pNext = info.pNext; + info.pNext = &patched; + } + // remove any non-self dependencies info.dependencyCount = 0; for(uint32_t i = 0; i < origInfo->dependencyCount; i++) @@ -932,6 +959,11 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(SerialiserType &ser, VkDevice d VkRenderPassCreateInfo loadInfo = CreateInfo; + { + byte *tempMem = GetTempMemory(GetNextPatchSize(loadInfo.pNext)); + CopyNextChainForPatching("VkRenderPassCreateInfo", tempMem, (VkBaseInStructure *)&loadInfo); + } + rpinfo.loadRPs.resize(CreateInfo.subpassCount); // create a render pass for each subpass that maintains attachment layouts @@ -1037,6 +1069,11 @@ VkResult WrappedVulkan::vkCreateRenderPass(VkDevice device, const VkRenderPassCr info.pDependencies = deps.data(); + { + byte *tempMem = GetTempMemory(GetNextPatchSize(info.pNext)); + CopyNextChainForPatching("VkRenderPassCreateInfo", tempMem, (VkBaseInStructure *)&info); + } + rpinfo.loadRPs.resize(pCreateInfo->subpassCount); // create a render pass for each subpass that maintains attachment layouts @@ -1152,6 +1189,12 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass2(SerialiserType &ser, VkDevice VkRenderPassCreateInfo2 loadInfo = CreateInfo; + { + byte *tempMem = GetTempMemory(GetNextPatchSize(loadInfo.pNext)); + CopyNextChainForPatching("VkRenderPassCreateInfo2", tempMem, + (VkBaseInStructure *)&loadInfo); + } + rpinfo.loadRPs.resize(CreateInfo.subpassCount); // create a render pass for each subpass that maintains attachment layouts @@ -1258,6 +1301,11 @@ VkResult WrappedVulkan::vkCreateRenderPass2(VkDevice device, info.pDependencies = deps.data(); + { + byte *tempMem = GetTempMemory(GetNextPatchSize(info.pNext)); + CopyNextChainForPatching("VkRenderPassCreateInfo2", tempMem, (VkBaseInStructure *)&info); + } + rpinfo.loadRPs.resize(pCreateInfo->subpassCount); // create a render pass for each subpass that maintains attachment layouts