From 3e4cac498595502b63e31d5dd5397e40895031b9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 5 Jan 2021 16:18:58 +0000 Subject: [PATCH] Respect dedicated memory allocations during capture, use those buffers * In addition for memory allocations for images we prevent the memory from getting write references propagated to it, as this can cause initial states to be generated in captures after the first when we convert write references into dirty states. --- renderdoc/driver/vulkan/vk_initstate.cpp | 2 +- renderdoc/driver/vulkan/vk_resources.cpp | 16 +++- renderdoc/driver/vulkan/vk_resources.h | 2 + .../vulkan/wrappers/vk_resource_funcs.cpp | 85 +++++++++++++++---- 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 673dc1be8..643c175f6 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -1810,7 +1810,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten VkDeviceSize dstBufSize = RDCMIN(initial.mem.size, m_CreationInfo.m_Memory[id].wholeMemBufSize); if(dstBuf == VK_NULL_HANDLE) { - RDCERR("Whole memory buffer not present for %s", ToStr(id).c_str()); + RDCERR("Whole memory buffer not present for %s", ToStr(orig).c_str()); return; } diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index dd3b35828..67fdc0f0d 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -3824,8 +3824,12 @@ void VkResourceRecord::MarkImageFrameReferenced(VkResourceRecord *img, const Ima { ResourceId id = img->GetResourceID(); - // mark backing memory - MarkResourceFrameReferenced(img->baseResource, refType); + // mark backing memory. For dedicated images we always treat the memory as read only so + // we don't try and include its initial contents. + if(img->dedicated) + MarkResourceFrameReferenced(img->baseResource, eFrameRef_Read); + else + MarkResourceFrameReferenced(img->baseResource, refType); if(img->resInfo && img->resInfo->IsSparse()) cmdInfo->sparse.insert(img->resInfo); @@ -3849,8 +3853,12 @@ void VkResourceRecord::MarkImageViewFrameReferenced(VkResourceRecord *view, cons // mark image view as read MarkResourceFrameReferenced(view->GetResourceID(), eFrameRef_Read); - // mark memory backing image - MarkResourceFrameReferenced(mem, refType); + // mark memory backing image. For dedicated images we always treat the memory as read only so + // we don't try and include its initial contents. + if(view->dedicated) + MarkResourceFrameReferenced(mem, eFrameRef_Read); + else + MarkResourceFrameReferenced(mem, refType); ImageSubresourceRange imgRange; imgRange.aspectMask = view->viewRange.aspectMask; diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index edde7bbd4..87bf4b4ff 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -1112,6 +1112,7 @@ struct MemMapState { VkBuffer wholeMemBuf = VK_NULL_HANDLE; VkDeviceSize mapOffset = 0, mapSize = 0; + bool dedicated = false; bool needRefData = false; bool mapFlushed = false; bool mapCoherent = false; @@ -2160,6 +2161,7 @@ public: VkDeviceSize memSize; VkResourceType resType; bool storable = false; + bool dedicated = false; void MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize offset, VkDeviceSize size, FrameRefType refType); diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index e18870fe3..52230e16b 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -478,6 +478,12 @@ VkResult WrappedVulkan::vkAllocateMemory(VkDevice device, const VkMemoryAllocate { ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), *pMemory); + VkMemoryDedicatedAllocateInfo *dedicated = (VkMemoryDedicatedAllocateInfo *)FindNextStruct( + pAllocateInfo, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + VkDedicatedAllocationMemoryAllocateInfoNV *dedicatedNV = + (VkDedicatedAllocationMemoryAllocateInfoNV *)FindNextStruct( + pAllocateInfo, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV); + // create a buffer with the whole memory range bound, for copying to and from // conveniently (for initial state data) VkBuffer wholeMemBuf = VK_NULL_HANDLE; @@ -504,20 +510,51 @@ VkResult WrappedVulkan::vkAllocateMemory(VkDevice device, const VkMemoryAllocate bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; } - ret = ObjDisp(device)->CreateBuffer(Unwrap(device), &bufInfo, NULL, &wholeMemBuf); - RDCASSERTEQUAL(ret, VK_SUCCESS); + VkDeviceSize memSize = info.allocationSize; + ResourceId bufid; - // we already validated above that the memory size is aligned/etc as necessary so we can - // create a buffer of the whole size, but just to keep the validation layers happy let's check - // the requirements here again. - VkMemoryRequirements mrq = {}; - ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), wholeMemBuf, &mrq); + if(dedicated) + { + // either set the buffer that's dedicated, or if this is dedicated image memory set NULL + wholeMemBuf = dedicated->buffer; - RDCASSERTEQUAL(mrq.size, info.allocationSize); + VkDeviceSize bufSize = m_CreationInfo.m_Buffer[GetResID(dedicated->buffer)].size; + if(memSize > bufSize) + { + RDCDEBUG("Truncating memory size %llu to dedicated buffer size %llu for %s", memSize, + bufSize, ToStr(id).c_str()); + memSize = bufSize; + } + } + else if(dedicatedNV) + { + wholeMemBuf = dedicatedNV->buffer; - ResourceId bufid = GetResourceManager()->WrapResource(Unwrap(device), wholeMemBuf); + VkDeviceSize bufSize = m_CreationInfo.m_Buffer[GetResID(dedicatedNV->buffer)].size; + if(memSize > bufSize) + { + RDCDEBUG("Truncating memory size %llu to dedicated buffer size %llu for %s", memSize, + bufSize, ToStr(id).c_str()); + memSize = bufSize; + } + } + else + { + ret = ObjDisp(device)->CreateBuffer(Unwrap(device), &bufInfo, NULL, &wholeMemBuf); + RDCASSERTEQUAL(ret, VK_SUCCESS); - ObjDisp(device)->BindBufferMemory(Unwrap(device), Unwrap(wholeMemBuf), Unwrap(*pMemory), 0); + // we already validated above that the memory size is aligned/etc as necessary so we can + // create a buffer of the whole size, but just to keep the validation layers happy let's check + // the requirements here again. + VkMemoryRequirements mrq = {}; + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), wholeMemBuf, &mrq); + + RDCASSERTEQUAL(mrq.size, info.allocationSize); + + bufid = GetResourceManager()->WrapResource(Unwrap(device), wholeMemBuf); + + ObjDisp(device)->BindBufferMemory(Unwrap(device), Unwrap(wholeMemBuf), Unwrap(*pMemory), 0); + } if(IsCaptureMode(m_State)) { @@ -571,13 +608,14 @@ VkResult WrappedVulkan::vkAllocateMemory(VkDevice device, const VkMemoryAllocate record->AddChunk(chunk); - record->Length = info.allocationSize; + record->Length = memSize; uint32_t memProps = m_PhysicalDeviceData.memProps.memoryTypes[info.memoryTypeIndex].propertyFlags; record->memMapState = new MemMapState(); record->memMapState->wholeMemBuf = wholeMemBuf; + record->memMapState->dedicated = dedicated != NULL || dedicatedNV != NULL; // if memory is not host visible, so not mappable, don't create map state at all if((memProps & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) @@ -603,8 +641,11 @@ VkResult WrappedVulkan::vkAllocateMemory(VkDevice device, const VkMemoryAllocate m_CreationInfo.m_Memory[id].Init(GetResourceManager(), m_CreationInfo, &info); - // register as a live-only resource, so it is cleaned up properly - GetResourceManager()->AddLiveResource(bufid, wholeMemBuf); + if(dedicated == NULL && dedicatedNV == NULL) + { + // register as a live-only resource, so it is cleaned up properly + GetResourceManager()->AddLiveResource(bufid, wholeMemBuf); + } m_CreationInfo.m_Memory[id].wholeMemBuf = wholeMemBuf; } @@ -651,7 +692,8 @@ void WrappedVulkan::vkFreeMemory(VkDevice device, VkDeviceMemory memory, memMapState->refData = NULL; } - // destroy the wholeMemBuf + // destroy the wholeMemBuf if it's one we allocated ourselves + if(!memMapState->dedicated) { ObjDisp(device)->DestroyBuffer(Unwrap(device), Unwrap(memMapState->wholeMemBuf), NULL); GetResourceManager()->ReleaseWrappedResource(memMapState->wholeMemBuf); @@ -713,7 +755,8 @@ VkResult WrappedVulkan::vkMapMemory(VkDevice device, VkDeviceMemory mem, VkDevic state.refData = NULL; state.mapOffset = offset; - state.mapSize = size == VK_WHOLE_SIZE ? (memrecord->Length - offset) : size; + state.mapSize = size == VK_WHOLE_SIZE ? (memrecord->Length - offset) + : RDCMIN(memrecord->Length - offset, size); state.mapFlushed = false; *ppData = realData + misalignedOffset; @@ -1287,6 +1330,7 @@ VkResult WrappedVulkan::vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkD record->AddParent(memrecord); record->baseResource = id; + record->dedicated = memrecord->memMapState->dedicated; record->memOffset = memoryOffset; memrecord->storable |= record->storable; @@ -1406,12 +1450,15 @@ VkResult WrappedVulkan::vkBindImageMemory(VkDevice device, VkImage image, VkDevi // to memory mid-frame record->AddChunk(chunk); - record->AddParent(GetRecord(mem)); + VkResourceRecord *memrecord = GetRecord(mem); + + record->AddParent(memrecord); // images are a base resource but we want to track where their memory comes from. // Anything that looks up a baseResource for an image knows not to chase further // than the image. - record->baseResource = GetResID(mem); + record->baseResource = memrecord->GetResourceID(); + record->dedicated = memrecord->memMapState->dedicated; } else { @@ -1799,6 +1846,7 @@ VkResult WrappedVulkan::vkCreateBufferView(VkDevice device, const VkBufferViewCr // store the base resource record->baseResource = bufferRecord->GetResourceID(); record->baseResourceMem = bufferRecord->baseResource; + record->dedicated = bufferRecord->dedicated; record->resInfo = bufferRecord->resInfo; record->memOffset = bufferRecord->memOffset + pCreateInfo->offset; record->memSize = pCreateInfo->range; @@ -2337,6 +2385,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->dedicated = imageRecord->dedicated; record->resInfo = imageRecord->resInfo; record->viewRange = pCreateInfo->subresourceRange; record->viewRange.setViewType(pCreateInfo->viewType); @@ -2457,6 +2506,7 @@ VkResult WrappedVulkan::vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCo bufrecord->AddParent(memrecord); bufrecord->baseResource = memrecord->GetResourceID(); + bufrecord->dedicated = memrecord->memMapState->dedicated; bufrecord->memOffset = pBindInfos[i].memoryOffset; memrecord->storable |= bufrecord->storable; @@ -2591,6 +2641,7 @@ VkResult WrappedVulkan::vkBindImageMemory2(VkDevice device, uint32_t bindInfoCou // Anything that looks up a baseResource for an image knows not to chase further // than the image. imgrecord->baseResource = memrecord->GetResourceID(); + imgrecord->dedicated = memrecord->memMapState->dedicated; } } else