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.
This commit is contained in:
baldurk
2018-11-16 15:13:36 +00:00
parent 2d6b004381
commit 0253dbcc70
14 changed files with 276 additions and 118 deletions
+3 -3
View File
@@ -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);
}
+26
View File
@@ -268,6 +268,32 @@ VkBaseInStructure *FindNextStruct(VkStruct *haystack, VkStructureType needle)
return NULL;
}
template <typename VkStruct>
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,
+2 -2
View File
@@ -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
+1 -1
View File
@@ -354,7 +354,7 @@ template void VulkanResourceManager::SerialiseImageStates(WriteSerialiser &ser,
std::map<ResourceId, ImageLayouts> &states,
std::vector<VkImageMemoryBarrier> &barriers);
void VulkanResourceManager::MarkSparseMapReferenced(SparseMapping *sparse)
void VulkanResourceManager::MarkSparseMapReferenced(ResourceInfo *sparse)
{
if(sparse == NULL)
{
+1 -1
View File
@@ -404,7 +404,7 @@ public:
}
// helper for sparse mappings
void MarkSparseMapReferenced(SparseMapping *sparse);
void MarkSparseMapReferenced(ResourceInfo *sparse);
void SetInternalResource(ResourceId id);
+3 -3
View File
@@ -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
+8 -4
View File
@@ -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<VkSparseMemoryBind> 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<VkDeviceMemory, VkDeviceSize> *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<SparseMapping *> sparse;
set<ResourceInfo *> sparse;
// a list of all resources dirtied by this command buffer
set<ResourceId> 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
@@ -82,10 +82,10 @@ bool WrappedVulkan::Prepare_SparseInitialState(WrappedVkBuffer *buf)
map<VkDeviceMemory, VkDeviceSize> 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.
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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;
@@ -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);
}
}
}
@@ -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<VkDeviceMemory, VkDeviceSize>[numpages];
record->resInfo->pages[a] = new pair<VkDeviceMemory, VkDeviceSize>[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