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.
This commit is contained in:
baldurk
2021-01-05 16:18:58 +00:00
parent f5f9e78dde
commit 3e4cac4985
4 changed files with 83 additions and 22 deletions
+1 -1
View File
@@ -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;
}
+12 -4
View File
@@ -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;
+2
View File
@@ -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);
@@ -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