From ce1cfe5330611e4f5c2b056eb0609689ee2e7cea Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 14 Sep 2020 15:27:46 +0100 Subject: [PATCH] Provide more specific error on external-imported resources * When capturing some external memory driver implementations have completely disjoint memory type bits allowed for external and non-external resources. This means it is impossible to capture it as external and then replay it as non-external, leading to a broken capture. * This is warned about at capture time but easy to miss. Adding this error here is more likely to be seen and found. --- renderdoc/driver/vulkan/vk_core.h | 2 +- renderdoc/driver/vulkan/vk_info.cpp | 16 +++++++ renderdoc/driver/vulkan/vk_info.h | 2 + .../vulkan/wrappers/vk_resource_funcs.cpp | 43 ++++++++++++++----- 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index a915a8cf7..4d6f8a7b7 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -861,7 +861,7 @@ private: void FirstFrame(); bool CheckMemoryRequirements(const char *resourceName, ResourceId memId, - VkDeviceSize memoryOffset, VkMemoryRequirements mrq); + VkDeviceSize memoryOffset, VkMemoryRequirements mrq, bool external); void AddImplicitResolveResourceUsage(uint32_t subpass = 0); rdcarray GetImplicitRenderPassBarriers(uint32_t subpass = 0); diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 4466d192f..a7ea615b2 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -1091,6 +1091,13 @@ void VulkanCreationInfo::Buffer::Init(VulkanResourceManager *resourceMan, Vulkan usage = pCreateInfo->usage; size = pCreateInfo->size; gpuAddress = 0; + + external = false; + + if(FindNextStruct(pCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) + { + external = true; + } } void VulkanCreationInfo::BufferView::Init(VulkanResourceManager *resourceMan, @@ -1115,6 +1122,15 @@ void VulkanCreationInfo::Image::Init(VulkanResourceManager *resourceMan, VulkanC linear = pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR; + external = false; + + if(FindNextStruct(pCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV) || + FindNextStruct(pCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO) || + FindNextStruct(pCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID)) + { + external = true; + } + creationFlags = TextureCategory::NoFlags; if(pCreateInfo->usage & VK_IMAGE_USAGE_SAMPLED_BIT) diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 6b25438b3..24941e4ba 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -496,6 +496,7 @@ struct VulkanCreationInfo VkBufferUsageFlags usage; uint64_t size; uint64_t gpuAddress; + bool external; }; std::unordered_map m_Buffer; @@ -523,6 +524,7 @@ struct VulkanCreationInfo VkSampleCountFlagBits samples; bool linear; + bool external; bool cube; TextureCategory creationFlags; }; diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index f298ba4af..2a1e043ee 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -189,7 +189,8 @@ VkBindImageMemoryInfo *WrappedVulkan::UnwrapInfos(const VkBindImageMemoryInfo *i } bool WrappedVulkan::CheckMemoryRequirements(const char *resourceName, ResourceId memId, - VkDeviceSize memoryOffset, VkMemoryRequirements mrq) + VkDeviceSize memoryOffset, VkMemoryRequirements mrq, + bool external) { // verify that the memory meets basic requirements. If not, something changed and we should // bail loading this capture. This is a bit of an under-estimate since we just make sure @@ -211,6 +212,20 @@ bool WrappedVulkan::CheckMemoryRequirements(const char *resourceName, ResourceId bitsString += StringFormat::Fmt("%s%u", bitsString.empty() ? "" : ", ", i); } + if(external) + { + RDCERR( + "Trying to bind %s to memory %s which is type %u, " + "but only these types are allowed: %s\n" + "This resource was created with external memory bindings, which is not represented in " + "the capture.\n" + "Some drivers do not allow externally-imported resources to be bound to non-external " + "memory, meaning this cannot be replayed.", + resourceName, ToStr(memOrigId).c_str(), memInfo.memoryTypeIndex, bitsString.c_str()); + m_FailedReplayStatus = ReplayStatus::APIHardwareUnsupported; + return false; + } + RDCERR( "Trying to bind %s to memory %s which is type %u, " "but only these types are allowed: %s\n" @@ -1167,11 +1182,13 @@ bool WrappedVulkan::Serialise_vkBindBufferMemory(SerialiserType &ser, VkDevice d ResourceId resOrigId = GetResourceManager()->GetOriginalID(GetResID(buffer)); ResourceId memOrigId = GetResourceManager()->GetOriginalID(GetResID(memory)); + VulkanCreationInfo::Buffer &bufInfo = m_CreationInfo.m_Buffer[GetResID(buffer)]; + VkMemoryRequirements mrq = {}; ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), Unwrap(buffer), &mrq); bool ok = CheckMemoryRequirements(("Buffer " + ToStr(resOrigId)).c_str(), GetResID(memory), - memoryOffset, mrq); + memoryOffset, mrq, bufInfo.external); if(!ok) return false; @@ -1186,7 +1203,6 @@ bool WrappedVulkan::Serialise_vkBindBufferMemory(SerialiserType &ser, VkDevice d // for buffers created with device addresses, fetch it now as that's possible for both EXT and // KHR variants now. - VulkanCreationInfo::Buffer &bufInfo = m_CreationInfo.m_Buffer[GetResID(buffer)]; if(bufInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) { VkBufferDeviceAddressInfo getInfo = { @@ -1284,8 +1300,10 @@ bool WrappedVulkan::Serialise_vkBindImageMemory(SerialiserType &ser, VkDevice de VkMemoryRequirements mrq = {}; ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), Unwrap(image), &mrq); + VulkanCreationInfo::Image &imgInfo = m_CreationInfo.m_Image[GetResID(image)]; + bool ok = CheckMemoryRequirements(("Image " + ToStr(resOrigId)).c_str(), GetResID(memory), - memoryOffset, mrq); + memoryOffset, mrq, imgInfo.external); if(!ok) return false; @@ -1313,7 +1331,6 @@ bool WrappedVulkan::Serialise_vkBindImageMemory(SerialiserType &ser, VkDevice de AddResourceCurChunk(memOrigId); AddResourceCurChunk(resOrigId); - VulkanCreationInfo::Image &imgInfo = m_CreationInfo.m_Image[GetResID(image)]; m_CreationInfo.m_Memory[GetResID(memory)].BindMemory( memoryOffset, mrq.size, imgInfo.linear ? VulkanCreationInfo::Memory::Linear : VulkanCreationInfo::Memory::Tiled); @@ -2318,11 +2335,14 @@ bool WrappedVulkan::Serialise_vkBindBufferMemory2(SerialiserType &ser, VkDevice ResourceId resOrigId = GetResourceManager()->GetOriginalID(GetResID(bindInfo.buffer)); ResourceId memOrigId = GetResourceManager()->GetOriginalID(GetResID(bindInfo.memory)); + VulkanCreationInfo::Buffer &bufInfo = m_CreationInfo.m_Buffer[GetResID(bindInfo.buffer)]; + VkMemoryRequirements mrq = {}; ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), Unwrap(bindInfo.buffer), &mrq); - bool ok = CheckMemoryRequirements(("Buffer " + ToStr(resOrigId)).c_str(), - GetResID(bindInfo.memory), bindInfo.memoryOffset, mrq); + bool ok = + CheckMemoryRequirements(("Buffer " + ToStr(resOrigId)).c_str(), GetResID(bindInfo.memory), + bindInfo.memoryOffset, mrq, bufInfo.external); if(!ok) return false; @@ -2335,7 +2355,6 @@ bool WrappedVulkan::Serialise_vkBindBufferMemory2(SerialiserType &ser, VkDevice // for buffers created with device addresses, fetch it now as that's possible for both EXT and // KHR variants now. - VulkanCreationInfo::Buffer &bufInfo = m_CreationInfo.m_Buffer[GetResID(bindInfo.buffer)]; if(bufInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) { VkBufferDeviceAddressInfo getInfo = { @@ -2440,11 +2459,14 @@ bool WrappedVulkan::Serialise_vkBindImageMemory2(SerialiserType &ser, VkDevice d ResourceId resOrigId = GetResourceManager()->GetOriginalID(GetResID(bindInfo.image)); ResourceId memOrigId = GetResourceManager()->GetOriginalID(GetResID(bindInfo.memory)); + VulkanCreationInfo::Image &imgInfo = m_CreationInfo.m_Image[GetResID(bindInfo.image)]; + VkMemoryRequirements mrq = {}; ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), Unwrap(bindInfo.image), &mrq); - bool ok = CheckMemoryRequirements(("Image " + ToStr(resOrigId)).c_str(), - GetResID(bindInfo.memory), bindInfo.memoryOffset, mrq); + bool ok = + CheckMemoryRequirements(("Image " + ToStr(resOrigId)).c_str(), GetResID(bindInfo.memory), + bindInfo.memoryOffset, mrq, imgInfo.external); if(!ok) return false; @@ -2471,7 +2493,6 @@ bool WrappedVulkan::Serialise_vkBindImageMemory2(SerialiserType &ser, VkDevice d AddResourceCurChunk(memOrigId); AddResourceCurChunk(resOrigId); - VulkanCreationInfo::Image &imgInfo = m_CreationInfo.m_Image[GetResID(bindInfo.image)]; m_CreationInfo.m_Memory[GetResID(bindInfo.memory)].BindMemory( bindInfo.memoryOffset, mrq.size, imgInfo.linear ? VulkanCreationInfo::Memory::Linear : VulkanCreationInfo::Memory::Tiled);