From 0253dbcc70c17f5810f3ad7a64142871365b5eb8 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 16 Nov 2018 15:13:36 +0000 Subject: [PATCH] During capture report worst-case mem requirements for external images * On some implementations, external images have lower memory requirements than an identical non-external image. To account for the replay being non-external we create both and pick the worst when reporting memory requirements to the app, so that it allocates enough for us on replay. --- renderdoc/driver/vulkan/vk_common.cpp | 6 +- renderdoc/driver/vulkan/vk_common.h | 26 +++ renderdoc/driver/vulkan/vk_initstate.cpp | 4 +- renderdoc/driver/vulkan/vk_manager.cpp | 2 +- renderdoc/driver/vulkan/vk_manager.h | 2 +- renderdoc/driver/vulkan/vk_resources.cpp | 6 +- renderdoc/driver/vulkan/vk_resources.h | 12 +- .../driver/vulkan/vk_sparse_initstate.cpp | 10 +- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 36 ++-- .../vulkan/wrappers/vk_descriptor_funcs.cpp | 2 +- .../driver/vulkan/wrappers/vk_draw_funcs.cpp | 88 +++++----- .../driver/vulkan/wrappers/vk_get_funcs.cpp | 28 ++- .../driver/vulkan/wrappers/vk_queue_funcs.cpp | 8 +- .../vulkan/wrappers/vk_resource_funcs.cpp | 164 ++++++++++++++---- 14 files changed, 276 insertions(+), 118 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index f4b7df51a..9d6aac18e 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -2333,14 +2333,14 @@ void DescriptorSetSlot::AddBindRefs(VkResourceRecord *record, FrameRefType ref) if(texelBufferView != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(texelBufferView), eFrameRef_Read, - GetRecord(texelBufferView)->sparseInfo != NULL); + GetRecord(texelBufferView)->resInfo != NULL); if(GetRecord(texelBufferView)->baseResource != ResourceId()) record->AddBindFrameRef(GetRecord(texelBufferView)->baseResource, ref); } if(imageInfo.imageView != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(imageInfo.imageView), eFrameRef_Read, - GetRecord(imageInfo.imageView)->sparseInfo != NULL); + GetRecord(imageInfo.imageView)->resInfo != NULL); record->AddBindFrameRef(GetRecord(imageInfo.imageView)->baseResource, ref); if(GetRecord(imageInfo.imageView)->baseResourceMem != ResourceId()) record->AddBindFrameRef(GetRecord(imageInfo.imageView)->baseResourceMem, eFrameRef_Read); @@ -2352,7 +2352,7 @@ void DescriptorSetSlot::AddBindRefs(VkResourceRecord *record, FrameRefType ref) if(bufferInfo.buffer != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(bufferInfo.buffer), eFrameRef_Read, - GetRecord(bufferInfo.buffer)->sparseInfo != NULL); + GetRecord(bufferInfo.buffer)->resInfo != NULL); if(GetRecord(bufferInfo.buffer)->baseResource != ResourceId()) record->AddBindFrameRef(GetRecord(bufferInfo.buffer)->baseResource, ref); } diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 54146e04e..1755c02c7 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -268,6 +268,32 @@ VkBaseInStructure *FindNextStruct(VkStruct *haystack, VkStructureType needle) return NULL; } +template +bool RemoveNextStruct(VkStruct *haystack, VkStructureType needle) +{ + // start from the haystack, and iterate + VkBaseInStructure *root = (VkBaseInStructure *)haystack; + while(root && root->pNext) + { + // at each point, if the *next* struct is the needle, then point our next pointer at whatever + // its was - either the next in the chain or NULL if it was at the end. Then we can return true + // because we removed the struct (we assume no duplicates). + // Note that this can't remove the first struct in the chain but that's expected, we only want + // to remove extension structs. + if(root->pNext->sType == needle) + { + root->pNext = root->pNext->pNext; + return true; + } + + // move to the next struct + root = (VkBaseInStructure *)root->pNext; + } + + // struct wasn't found, bail + return false; +} + enum class MemoryScope : uint8_t { InitialContents, diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 67cf37180..f6c29c5ae 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -88,7 +88,7 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) WrappedVkBuffer *buffer = (WrappedVkBuffer *)res; // buffers are only dirty if they are sparse - RDCASSERT(buffer->record->sparseInfo); + RDCASSERT(buffer->record->resInfo && buffer->record->resInfo->IsSparse()); return Prepare_SparseInitialState(buffer); } @@ -98,7 +98,7 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) WrappedVkImage *im = (WrappedVkImage *)res; - if(im->record->sparseInfo) + if(im->record->resInfo && im->record->resInfo->IsSparse()) { // if the image is sparse we have to do a different kind of initial state prepare, // to serialise out the page mapping. The fetching of memory is also different diff --git a/renderdoc/driver/vulkan/vk_manager.cpp b/renderdoc/driver/vulkan/vk_manager.cpp index 46b24a497..32d4a7135 100644 --- a/renderdoc/driver/vulkan/vk_manager.cpp +++ b/renderdoc/driver/vulkan/vk_manager.cpp @@ -354,7 +354,7 @@ template void VulkanResourceManager::SerialiseImageStates(WriteSerialiser &ser, std::map &states, std::vector &barriers); -void VulkanResourceManager::MarkSparseMapReferenced(SparseMapping *sparse) +void VulkanResourceManager::MarkSparseMapReferenced(ResourceInfo *sparse) { if(sparse == NULL) { diff --git a/renderdoc/driver/vulkan/vk_manager.h b/renderdoc/driver/vulkan/vk_manager.h index 75b8ac777..74b378771 100644 --- a/renderdoc/driver/vulkan/vk_manager.h +++ b/renderdoc/driver/vulkan/vk_manager.h @@ -404,7 +404,7 @@ public: } // helper for sparse mappings - void MarkSparseMapReferenced(SparseMapping *sparse); + void MarkSparseMapReferenced(ResourceInfo *sparse); void SetInternalResource(ResourceId id); diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 45f6e9c4a..691026f88 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -832,7 +832,7 @@ VkResourceRecord::~VkResourceRecord() // bufferviews and imageviews have non-owning pointers to the sparseinfo struct if(resType == eResBuffer || resType == eResImage) - SAFE_DELETE(sparseInfo); + SAFE_DELETE(resInfo); if(resType == eResInstance || resType == eResDevice) SAFE_DELETE(instDevInfo); @@ -868,7 +868,7 @@ VkResourceRecord::~VkResourceRecord() SAFE_DELETE(descTemplateInfo); } -void SparseMapping::Update(uint32_t numBindings, const VkSparseImageMemoryBind *pBindings) +void ResourceInfo::Update(uint32_t numBindings, const VkSparseImageMemoryBind *pBindings) { // update image page table mappings @@ -906,7 +906,7 @@ void SparseMapping::Update(uint32_t numBindings, const VkSparseImageMemoryBind * } } -void SparseMapping::Update(uint32_t numBindings, const VkSparseMemoryBind *pBindings) +void ResourceInfo::Update(uint32_t numBindings, const VkSparseMemoryBind *pBindings) { // update opaque mappings diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 2876d91db..a4c7b2f2a 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -877,9 +877,10 @@ struct SwapchainInfo uint32_t lastPresent; }; -struct SparseMapping +// these structs are allocated for images and buffers, then pointed to (non-owning) by views +struct ResourceInfo { - SparseMapping() + ResourceInfo() { RDCEraseEl(imgdim); RDCEraseEl(pagedim); @@ -889,6 +890,8 @@ struct SparseMapping // for buffers or non-sparse-resident images (bound with opaque mappings) vector opaquemappings; + VkMemoryRequirements memreqs; + // for sparse resident images: // total image size (in pages) VkExtent3D imgdim; @@ -898,6 +901,7 @@ struct SparseMapping // in order of width first, then height, then depth pair *pages[NUM_VK_IMAGE_ASPECTS]; + bool IsSparse() const { return pages[0] != NULL; } void Update(uint32_t numBindings, const VkSparseMemoryBind *pBindings); void Update(uint32_t numBindings, const VkSparseImageMemoryBind *pBindings); }; @@ -914,7 +918,7 @@ struct CmdBufferRecordingInfo // sparse resources referenced by this command buffer (at submit time // need to go through the sparse mapping and reference all memory) - set sparse; + set sparse; // a list of all resources dirtied by this command buffer set dirtied; @@ -1099,7 +1103,7 @@ public: void *ptrunion; // for initialisation to NULL VkPhysicalDeviceMemoryProperties *memProps; // only for physical devices InstanceDeviceInfo *instDevInfo; // only for logical devices or instances - SparseMapping *sparseInfo; // only for buffers, images, and views of them + ResourceInfo *resInfo; // only for buffers, images, and views of them SwapchainInfo *swapInfo; // only for swapchains MemMapState *memMapState; // only for device memory CmdBufferRecordingInfo *cmdInfo; // only for command buffers diff --git a/renderdoc/driver/vulkan/vk_sparse_initstate.cpp b/renderdoc/driver/vulkan/vk_sparse_initstate.cpp index a5f4bbea3..159c92b15 100644 --- a/renderdoc/driver/vulkan/vk_sparse_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_sparse_initstate.cpp @@ -82,10 +82,10 @@ bool WrappedVulkan::Prepare_SparseInitialState(WrappedVkBuffer *buf) map boundMems; // value will be filled out later once all memories are added - for(size_t i = 0; i < buf->record->sparseInfo->opaquemappings.size(); i++) - boundMems[buf->record->sparseInfo->opaquemappings[i].memory] = 0; + for(size_t i = 0; i < buf->record->resInfo->opaquemappings.size(); i++) + boundMems[buf->record->resInfo->opaquemappings[i].memory] = 0; - uint32_t numElems = (uint32_t)buf->record->sparseInfo->opaquemappings.size(); + uint32_t numElems = (uint32_t)buf->record->resInfo->opaquemappings.size(); VkInitialContents initContents; @@ -97,7 +97,7 @@ bool WrappedVulkan::Prepare_SparseInitialState(WrappedVkBuffer *buf) initContents.sparseBuffer.numUniqueMems = (uint32_t)boundMems.size(); initContents.sparseBuffer.memDataOffs = new MemIDOffset[boundMems.size()]; - memcpy(initContents.sparseBuffer.binds, &buf->record->sparseInfo->opaquemappings[0], + memcpy(initContents.sparseBuffer.binds, &buf->record->resInfo->opaquemappings[0], sizeof(VkSparseMemoryBind) * numElems); VkDevice d = GetDev(); @@ -201,7 +201,7 @@ bool WrappedVulkan::Prepare_SparseInitialState(WrappedVkImage *im) { ResourceId id = im->id; - SparseMapping *sparse = im->record->sparseInfo; + ResourceInfo *sparse = im->record->resInfo; // VKTODOLOW this is a bit conservative, as we save the whole memory object rather than just the // bound range. diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 8e30be21e..0fe546ee1 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -1165,8 +1165,8 @@ void WrappedVulkan::vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, 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); + if(att->resInfo) + record->cmdInfo->sparse.insert(att->resInfo); record->cmdInfo->dirtied.insert(att->baseResource); } @@ -1508,8 +1508,8 @@ void WrappedVulkan::vkCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, 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); + if(att->resInfo) + record->cmdInfo->sparse.insert(att->resInfo); record->cmdInfo->dirtied.insert(att->baseResource); } @@ -2136,8 +2136,8 @@ void WrappedVulkan::vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32 { record->MarkResourceFrameReferenced(GetResID(pBuffers[i]), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(pBuffers[i])->baseResource, eFrameRef_Read); - if(GetRecord(pBuffers[i])->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(pBuffers[i])->sparseInfo); + if(GetRecord(pBuffers[i])->resInfo) + record->cmdInfo->sparse.insert(GetRecord(pBuffers[i])->resInfo); } } } @@ -2213,8 +2213,8 @@ void WrappedVulkan::vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer record->AddChunk(scope.Get()); record->MarkResourceFrameReferenced(GetResID(buffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(buffer)->baseResource, eFrameRef_Read); - if(GetRecord(buffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(buffer)->sparseInfo); + if(GetRecord(buffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(buffer)->resInfo); } } @@ -2286,8 +2286,8 @@ void WrappedVulkan::vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer de record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); if(buf->baseResource != ResourceId()) record->cmdInfo->dirtied.insert(buf->baseResource); - if(buf->sparseInfo) - record->cmdInfo->sparse.insert(buf->sparseInfo); + if(buf->resInfo) + record->cmdInfo->sparse.insert(buf->resInfo); } } @@ -2355,8 +2355,8 @@ void WrappedVulkan::vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dest record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); if(buf->baseResource != ResourceId()) record->cmdInfo->dirtied.insert(buf->baseResource); - if(buf->sparseInfo) - record->cmdInfo->sparse.insert(buf->sparseInfo); + if(buf->resInfo) + record->cmdInfo->sparse.insert(buf->resInfo); } } @@ -2728,8 +2728,8 @@ void WrappedVulkan::vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQ record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); if(buf->baseResource != ResourceId()) record->cmdInfo->dirtied.insert(buf->baseResource); - if(buf->sparseInfo) - record->cmdInfo->sparse.insert(buf->sparseInfo); + if(buf->resInfo) + record->cmdInfo->sparse.insert(buf->resInfo); } } @@ -4023,8 +4023,8 @@ void WrappedVulkan::vkCmdWriteBufferMarkerAMD(VkCommandBuffer commandBuffer, record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); if(buf->baseResource != ResourceId()) record->cmdInfo->dirtied.insert(buf->baseResource); - if(buf->sparseInfo) - record->cmdInfo->sparse.insert(buf->sparseInfo); + if(buf->resInfo) + record->cmdInfo->sparse.insert(buf->resInfo); } } @@ -4381,8 +4381,8 @@ void WrappedVulkan::vkCmdBindTransformFeedbackBuffersEXT(VkCommandBuffer command { record->MarkResourceFrameReferenced(GetResID(pBuffers[i]), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(pBuffers[i])->baseResource, eFrameRef_Read); - if(GetRecord(pBuffers[i])->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(pBuffers[i])->sparseInfo); + if(GetRecord(pBuffers[i])->resInfo) + record->cmdInfo->sparse.insert(GetRecord(pBuffers[i])->resInfo); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index 6c765a048..0a935023d 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -965,7 +965,7 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, { VkResourceRecord *record = GetResourceManager()->GetResourceRecord(refit->first); - GetResourceManager()->MarkSparseMapReferenced(record->sparseInfo); + GetResourceManager()->MarkSparseMapReferenced(record->resInfo); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp index 17fb225bd..86a7cb136 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp @@ -740,8 +740,8 @@ void WrappedVulkan::vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer bu record->MarkResourceFrameReferenced(GetResID(buffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(buffer)->baseResource, eFrameRef_Read); - if(GetRecord(buffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(buffer)->sparseInfo); + if(GetRecord(buffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(buffer)->resInfo); } } @@ -1119,8 +1119,8 @@ void WrappedVulkan::vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBu record->MarkResourceFrameReferenced(GetResID(buffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(buffer)->baseResource, eFrameRef_Read); - if(GetRecord(buffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(buffer)->sparseInfo); + if(GetRecord(buffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(buffer)->resInfo); } } @@ -1290,8 +1290,8 @@ void WrappedVulkan::vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffe record->MarkResourceFrameReferenced(GetResID(buffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(buffer)->baseResource, eFrameRef_Read); - if(GetRecord(buffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(buffer)->sparseInfo); + if(GetRecord(buffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(buffer)->resInfo); } } @@ -1414,10 +1414,10 @@ void WrappedVulkan::vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcIma record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); - if(GetRecord(srcImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); - if(GetRecord(destImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); + if(GetRecord(srcImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->resInfo); + if(GetRecord(destImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->resInfo); } } @@ -1538,10 +1538,10 @@ void WrappedVulkan::vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage src record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); - if(GetRecord(srcImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); - if(GetRecord(destImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); + if(GetRecord(srcImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->resInfo); + if(GetRecord(destImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->resInfo); } } @@ -1660,10 +1660,10 @@ void WrappedVulkan::vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcIma record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); - if(GetRecord(srcImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); - if(GetRecord(destImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); + if(GetRecord(srcImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->resInfo); + if(GetRecord(destImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->resInfo); } } @@ -1773,10 +1773,10 @@ void WrappedVulkan::vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuff record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); - if(GetRecord(srcBuffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(srcBuffer)->sparseInfo); - if(GetRecord(destImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); + if(GetRecord(srcBuffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(srcBuffer)->resInfo); + if(GetRecord(destImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->resInfo); } } @@ -1892,10 +1892,10 @@ void WrappedVulkan::vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImag record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); if(buf->baseResource != ResourceId()) record->cmdInfo->dirtied.insert(buf->baseResource); - if(GetRecord(srcImage)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); - if(buf->sparseInfo) - record->cmdInfo->sparse.insert(buf->sparseInfo); + if(GetRecord(srcImage)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->resInfo); + if(buf->resInfo) + record->cmdInfo->sparse.insert(buf->resInfo); } } @@ -2014,10 +2014,10 @@ void WrappedVulkan::vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcB record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); if(buf->baseResource != ResourceId()) record->cmdInfo->dirtied.insert(buf->baseResource); - if(GetRecord(srcBuffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(srcBuffer)->sparseInfo); - if(buf->sparseInfo) - record->cmdInfo->sparse.insert(buf->sparseInfo); + if(GetRecord(srcBuffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(srcBuffer)->resInfo); + if(buf->resInfo) + record->cmdInfo->sparse.insert(buf->resInfo); } } @@ -2121,8 +2121,8 @@ void WrappedVulkan::vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage record->AddChunk(scope.Get()); record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Read); - if(GetRecord(image)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(image)->sparseInfo); + if(GetRecord(image)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(image)->resInfo); } } @@ -2228,8 +2228,8 @@ void WrappedVulkan::vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, V record->AddChunk(scope.Get()); record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Read); - if(GetRecord(image)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(image)->sparseInfo); + if(GetRecord(image)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(image)->resInfo); } } @@ -2780,13 +2780,13 @@ void WrappedVulkan::vkCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkB record->MarkResourceFrameReferenced(GetResID(buffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(buffer)->baseResource, eFrameRef_Read); - if(GetRecord(buffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(buffer)->sparseInfo); + if(GetRecord(buffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(buffer)->resInfo); record->MarkResourceFrameReferenced(GetResID(countBuffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(countBuffer)->baseResource, eFrameRef_Read); - if(GetRecord(countBuffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(countBuffer)->sparseInfo); + if(GetRecord(countBuffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(countBuffer)->resInfo); } } @@ -3100,13 +3100,13 @@ void WrappedVulkan::vkCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuff record->MarkResourceFrameReferenced(GetResID(buffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(buffer)->baseResource, eFrameRef_Read); - if(GetRecord(buffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(buffer)->sparseInfo); + if(GetRecord(buffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(buffer)->resInfo); record->MarkResourceFrameReferenced(GetResID(countBuffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(countBuffer)->baseResource, eFrameRef_Read); - if(GetRecord(countBuffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(countBuffer)->sparseInfo); + if(GetRecord(countBuffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(countBuffer)->resInfo); } } @@ -3233,8 +3233,8 @@ void WrappedVulkan::vkCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, record->MarkResourceFrameReferenced(GetResID(counterBuffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(counterBuffer)->baseResource, eFrameRef_Read); - if(GetRecord(counterBuffer)->sparseInfo) - record->cmdInfo->sparse.insert(GetRecord(counterBuffer)->sparseInfo); + if(GetRecord(counterBuffer)->resInfo) + record->cmdInfo->sparse.insert(GetRecord(counterBuffer)->resInfo); } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp index f5feb6f08..5b9dbc4ef 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp @@ -222,7 +222,13 @@ void WrappedVulkan::vkGetImageSubresourceLayout(VkDevice device, VkImage image, void WrappedVulkan::vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) { - ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), Unwrap(buffer), pMemoryRequirements); + // if we have cached memory requirements, use them. These were fetched at create time (which is + // still valid, they don't change over the lifetime of the resource) and may be slightly more + // pessimistic for the case of external memory bound resources. See vkCreateBuffer/vkCreateImage + if(IsCaptureMode(m_State) && GetRecord(buffer)->resInfo) + *pMemoryRequirements = GetRecord(buffer)->resInfo->memreqs; + else + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), Unwrap(buffer), pMemoryRequirements); // don't do remapping here on replay. if(IsReplayMode(m_State)) @@ -243,7 +249,13 @@ void WrappedVulkan::vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buff void WrappedVulkan::vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) { - ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), Unwrap(image), pMemoryRequirements); + // if we have cached memory requirements, use them. These were fetched at create time (which is + // still valid, they don't change over the lifetime of the resource) and may be slightly more + // pessimistic for the case of external memory bound resources. See vkCreateBuffer/vkCreateImage + if(IsCaptureMode(m_State) && GetRecord(image)->resInfo) + *pMemoryRequirements = GetRecord(image)->resInfo->memreqs; + else + ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), Unwrap(image), pMemoryRequirements); // don't do remapping here on replay. if(IsReplayMode(m_State)) @@ -301,6 +313,12 @@ void WrappedVulkan::vkGetBufferMemoryRequirements2(VkDevice device, unwrappedInfo.buffer = Unwrap(unwrappedInfo.buffer); ObjDisp(device)->GetBufferMemoryRequirements2(Unwrap(device), &unwrappedInfo, pMemoryRequirements); + // if we have cached memory requirements, use them. These were fetched at create time (which is + // still valid, they don't change over the lifetime of the resource) and may be slightly more + // pessimistic for the case of external memory bound resources. See vkCreateBuffer/vkCreateImage + if(IsCaptureMode(m_State) && GetRecord(pInfo->buffer)->resInfo) + pMemoryRequirements->memoryRequirements = GetRecord(pInfo->buffer)->resInfo->memreqs; + // don't do remapping here on replay. if(IsReplayMode(m_State)) return; @@ -325,6 +343,12 @@ void WrappedVulkan::vkGetImageMemoryRequirements2(VkDevice device, unwrappedInfo.image = Unwrap(unwrappedInfo.image); ObjDisp(device)->GetImageMemoryRequirements2(Unwrap(device), &unwrappedInfo, pMemoryRequirements); + // if we have cached memory requirements, use them. These were fetched at create time (which is + // still valid, they don't change over the lifetime of the resource) and may be slightly more + // pessimistic for the case of external memory bound resources. See vkCreateBuffer/vkCreateImage + if(IsCaptureMode(m_State) && GetRecord(pInfo->image)->resInfo) + pMemoryRequirements->memoryRequirements = GetRecord(pInfo->image)->resInfo->memreqs; + // don't do remapping here on replay. if(IsReplayMode(m_State)) return; diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index 0a84338ca..c9ee46ed4 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -840,7 +840,7 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount, { VkResourceRecord *sparserecord = GetResourceManager()->GetResourceRecord(refit->first); - GetResourceManager()->MarkSparseMapReferenced(sparserecord->sparseInfo); + GetResourceManager()->MarkSparseMapReferenced(sparserecord->resInfo); } } } @@ -1250,19 +1250,19 @@ VkResult WrappedVulkan::vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, for(uint32_t buf = 0; buf < pBindInfo[i].bufferBindCount; buf++) { const VkSparseBufferMemoryBindInfo &bind = pBindInfo[i].pBufferBinds[buf]; - GetRecord(bind.buffer)->sparseInfo->Update(bind.bindCount, bind.pBinds); + GetRecord(bind.buffer)->resInfo->Update(bind.bindCount, bind.pBinds); } for(uint32_t op = 0; op < pBindInfo[i].imageOpaqueBindCount; op++) { const VkSparseImageOpaqueMemoryBindInfo &bind = pBindInfo[i].pImageOpaqueBinds[op]; - GetRecord(bind.image)->sparseInfo->Update(bind.bindCount, bind.pBinds); + GetRecord(bind.image)->resInfo->Update(bind.bindCount, bind.pBinds); } for(uint32_t op = 0; op < pBindInfo[i].imageBindCount; op++) { const VkSparseImageMemoryBindInfo &bind = pBindInfo[i].pImageBinds[op]; - GetRecord(bind.image)->sparseInfo->Update(bind.bindCount, bind.pBinds); + GetRecord(bind.image)->resInfo->Update(bind.bindCount, bind.pBinds); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index 5a85d1fcd..0bb3deddf 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -1090,14 +1090,17 @@ VkResult WrappedVulkan::vkCreateBuffer(VkDevice device, const VkBufferCreateInfo VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pBuffer); record->AddChunk(chunk); - if(pCreateInfo->flags & - (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT)) - { - record->sparseInfo = new SparseMapping(); + bool isSparse = (pCreateInfo->flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | + VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT)) != 0; + bool isExternal = FindNextStruct(&adjusted_info, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO) != NULL; + + if(isSparse) + { // buffers are always bound opaquely and in arbitrary divisions, sparse residency // only means not all the buffer needs to be bound, which is not that interesting for - // our purposes + // our purposes. We just need to make sure sparse buffers are dirty. bool capframe = false; @@ -1111,6 +1114,58 @@ VkResult WrappedVulkan::vkCreateBuffer(VkDevice device, const VkBufferCreateInfo else GetResourceManager()->MarkDirtyResource(id); } + + if(isSparse || isExternal) + { + record->resInfo = new ResourceInfo(); + + // pre-populate memory requirements + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), Unwrap(*pBuffer), + &record->resInfo->memreqs); + + // for external buffers, try creating a non-external version and take the worst case of + // memory requirements, in case the non-external one (as we will replay it) needs more + // memory or a stricter alignment + if(isExternal) + { + bool removed = + RemoveNextStruct(&adjusted_info, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO); + + RDCASSERTMSG("Couldn't find next struct indicating external memory", removed); + + VkBuffer tmpbuf = VK_NULL_HANDLE; + VkResult vkr = ObjDisp(device)->CreateBuffer(Unwrap(device), &adjusted_info, NULL, &tmpbuf); + + if(vkr == VK_SUCCESS && tmpbuf != VK_NULL_HANDLE) + { + VkMemoryRequirements mrq = {}; + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), tmpbuf, &mrq); + + if(mrq.size > 0) + { + RDCDEBUG("External buffer requires %llu bytes at %llu alignment, in %x memory types", + record->resInfo->memreqs.size, record->resInfo->memreqs.alignment, + record->resInfo->memreqs.memoryTypeBits); + RDCDEBUG( + "Non-external version requires %llu bytes at %llu alignment, in %x memory types", + mrq.size, mrq.alignment, mrq.memoryTypeBits); + + record->resInfo->memreqs.size = RDCMAX(record->resInfo->memreqs.size, mrq.size); + record->resInfo->memreqs.alignment = + RDCMAX(record->resInfo->memreqs.size, mrq.alignment); + record->resInfo->memreqs.memoryTypeBits &= mrq.memoryTypeBits; + } + } + else + { + RDCERR("Failed to create temporary non-external buffer to find memory requirements: %s", + ToStr(vkr).c_str()); + } + + if(tmpbuf != VK_NULL_HANDLE) + ObjDisp(device)->DestroyBuffer(Unwrap(device), tmpbuf, NULL); + } + } } else { @@ -1216,7 +1271,7 @@ VkResult WrappedVulkan::vkCreateBufferView(VkDevice device, const VkBufferViewCr // store the base resource record->baseResource = bufferRecord->baseResource; - record->sparseInfo = bufferRecord->sparseInfo; + record->resInfo = bufferRecord->resInfo; } else { @@ -1466,28 +1521,79 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo * next = next->pNext; } - bool capframe = false; - - { - SCOPED_LOCK(m_CapTransitionLock); - capframe = IsActiveCapturing(m_State); - } - // sparse and external images are considered dirty from creation. For sparse images this is // so that we can serialise the tracked page table, for external images this is so we can be // sure to fetch their contents even if we don't see any writes. if(isSparse || isExternal) { + record->resInfo = new ResourceInfo(); + + bool capframe = false; + + { + SCOPED_LOCK(m_CapTransitionLock); + capframe = IsActiveCapturing(m_State); + } + if(capframe) GetResourceManager()->MarkPendingDirty(id); else GetResourceManager()->MarkDirtyResource(id); + + // pre-populate memory requirements + ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), Unwrap(*pImage), + &record->resInfo->memreqs); + + // for external images, try creating a non-external version and take the worst case of + // memory requirements, in case the non-external one (as we will replay it) needs more + // memory or a stricter alignment + if(isExternal) + { + bool removed = false; + removed |= RemoveNextStruct(&createInfo_adjusted, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV); + removed |= RemoveNextStruct(&createInfo_adjusted, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO); + + RDCASSERTMSG("Couldn't find next struct indicating external memory", removed); + + VkImage tmpimg = VK_NULL_HANDLE; + VkResult vkr = + ObjDisp(device)->CreateImage(Unwrap(device), &createInfo_adjusted, NULL, &tmpimg); + + if(vkr == VK_SUCCESS && tmpimg != VK_NULL_HANDLE) + { + VkMemoryRequirements mrq = {}; + ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), tmpimg, &mrq); + + if(mrq.size > 0) + { + RDCDEBUG("External image requires %llu bytes at %llu alignment, in %x memory types", + record->resInfo->memreqs.size, record->resInfo->memreqs.alignment, + record->resInfo->memreqs.memoryTypeBits); + RDCDEBUG( + "Non-external version requires %llu bytes at %llu alignment, in %x memory types", + mrq.size, mrq.alignment, mrq.memoryTypeBits); + + record->resInfo->memreqs.size = RDCMAX(record->resInfo->memreqs.size, mrq.size); + record->resInfo->memreqs.alignment = + RDCMAX(record->resInfo->memreqs.size, mrq.alignment); + record->resInfo->memreqs.memoryTypeBits &= mrq.memoryTypeBits; + } + } + else + { + RDCERR("Failed to create temporary non-external image to find memory requirements: %s", + ToStr(vkr).c_str()); + } + + if(tmpimg != VK_NULL_HANDLE) + ObjDisp(device)->DestroyImage(Unwrap(device), tmpimg, NULL); + } } if(isSparse) { - record->sparseInfo = new SparseMapping(); - if(pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) { // must record image and page dimension, and create page tables @@ -1498,24 +1604,22 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo * RDCASSERT(numreqs > 0); - record->sparseInfo->pagedim = reqs[0].formatProperties.imageGranularity; - record->sparseInfo->imgdim = pCreateInfo->extent; - record->sparseInfo->imgdim.width /= record->sparseInfo->pagedim.width; - record->sparseInfo->imgdim.height /= record->sparseInfo->pagedim.height; - record->sparseInfo->imgdim.depth /= record->sparseInfo->pagedim.depth; + record->resInfo->pagedim = reqs[0].formatProperties.imageGranularity; + record->resInfo->imgdim = pCreateInfo->extent; + record->resInfo->imgdim.width /= record->resInfo->pagedim.width; + record->resInfo->imgdim.height /= record->resInfo->pagedim.height; + record->resInfo->imgdim.depth /= record->resInfo->pagedim.depth; - uint32_t numpages = record->sparseInfo->imgdim.width * record->sparseInfo->imgdim.height * - record->sparseInfo->imgdim.depth; + uint32_t numpages = record->resInfo->imgdim.width * record->resInfo->imgdim.height * + record->resInfo->imgdim.depth; for(uint32_t i = 0; i < numreqs; i++) { // assume all page sizes are the same for all aspects - RDCASSERT(record->sparseInfo->pagedim.width == - reqs[i].formatProperties.imageGranularity.width && - record->sparseInfo->pagedim.height == - reqs[i].formatProperties.imageGranularity.height && - record->sparseInfo->pagedim.depth == - reqs[i].formatProperties.imageGranularity.depth); + RDCASSERT( + record->resInfo->pagedim.width == reqs[i].formatProperties.imageGranularity.width && + record->resInfo->pagedim.height == reqs[i].formatProperties.imageGranularity.height && + record->resInfo->pagedim.depth == reqs[i].formatProperties.imageGranularity.depth); int a = 0; for(a = 0; a < NUM_VK_IMAGE_ASPECTS; a++) @@ -1524,7 +1628,7 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo * break; } - record->sparseInfo->pages[a] = new pair[numpages]; + record->resInfo->pages[a] = new pair[numpages]; } } else @@ -1673,7 +1777,7 @@ VkResult WrappedVulkan::vkCreateImageView(VkDevice device, const VkImageViewCrea // to their memory, which we will also need so we store that separately record->baseResource = imageRecord->GetResourceID(); record->baseResourceMem = imageRecord->baseResource; - record->sparseInfo = imageRecord->sparseInfo; + record->resInfo = imageRecord->resInfo; record->viewRange = pCreateInfo->subresourceRange; } else