From da15b25789897973dede77210fb3d92bffc145dc Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 29 Oct 2015 17:09:37 +0100 Subject: [PATCH] Handle image dirty & initial state tracking more correctly * Still not doing buffer<->image copy for proper decode/encode. * Images are dirtied in preference to their memory, and their initial state consists of the memory backing behind them, which is copied and restored in the same way as dirty memory. --- renderdoc/driver/vulkan/vk_core.h | 2 +- renderdoc/driver/vulkan/vk_initstate.cpp | 101 +++++++++++------- renderdoc/driver/vulkan/vk_resources.h | 8 +- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 6 +- .../vulkan/wrappers/vk_descriptor_funcs.cpp | 4 +- .../driver/vulkan/wrappers/vk_draw_funcs.cpp | 32 +++--- .../vulkan/wrappers/vk_resource_funcs.cpp | 4 + 7 files changed, 97 insertions(+), 60 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 82a7dc6a5..48b7ed442 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -102,7 +102,7 @@ private: friend class VulkanDebugManager; enum { - eInitialContents_ClearColorImage = 0, + eInitialContents_ClearColorImage = 1, eInitialContents_ClearDepthStencilImage, }; diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 712d03da3..bc1452a87 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -51,11 +51,8 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(NULL, 0, (byte *)info)); return true; } - else if(type == eResDeviceMemory) + else if(type == eResDeviceMemory || type == eResImage) { - VkResourceRecord *record = GetResourceManager()->GetResourceRecord(id); - RDCASSERT(record->Length > 0); - VkResult vkr = VK_SUCCESS; VkDevice d = GetDev(); @@ -63,22 +60,48 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) // a bit more - maybe not all in one command buffer, but // at least more than one each VkCmdBuffer cmd = GetNextCmd(); + + VkResourceRecord *record = GetResourceManager()->GetResourceRecord(id); + + VkMemoryRequirements immrq = {0}; + if(type == eResImage) + ObjDisp(d)->GetImageMemoryRequirements(Unwrap(d), ToHandle(res), &immrq); + + VkDeviceSize dataoffs = (type == eResImage) ? record->memOffset : 0; + VkDeviceMemory datamem = (type == eResImage) ? Unwrap(record->mem) : ToHandle(res); + VkDeviceSize datasize = (type == eResImage) ? immrq.size : (VkDeviceSize)record->Length; - VkDeviceMemory mem = VK_NULL_HANDLE; + RDCASSERT(datamem); + if(type == eResImage) + record = GetResourceManager()->GetResourceRecord(record->baseResource); + + RDCASSERT(record->Length > 0); + VkDeviceSize memsize = (VkDeviceSize)record->Length; + + VkDeviceMemory readbackmem = VK_NULL_HANDLE; + + // VKTODOMED we just dump the backing memory for this image via an aliased buffer + // copy, instead of doing a proper copy from image to buffer, which would be + // independent of the image memory layout and do any unswizzling/untiling VkBufferCreateInfo bufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, - (VkDeviceSize)record->Length, VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT|VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT, 0, + 0, VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT|VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT, 0, VK_SHARING_MODE_EXCLUSIVE, 0, NULL, }; // since these are very short lived, they are not wrapped VkBuffer srcBuf, dstBuf; - vkr = ObjDisp(d)->CreateBuffer(Unwrap(d), &bufInfo, &srcBuf); - RDCASSERT(vkr == VK_SUCCESS); + // dstBuf is just over the allocated memory, so only the image's size + bufInfo.size = datasize; vkr = ObjDisp(d)->CreateBuffer(Unwrap(d), &bufInfo, &dstBuf); RDCASSERT(vkr == VK_SUCCESS); + + // srcBuf spans the entire memory, then we copy out the sub-region we're interested in + bufInfo.size = memsize; + vkr = ObjDisp(d)->CreateBuffer(Unwrap(d), &bufInfo, &srcBuf); + RDCASSERT(vkr == VK_SUCCESS); VkMemoryRequirements mrq = { 0 }; @@ -87,19 +110,19 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) VkMemoryAllocInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, NULL, - (VkDeviceSize)record->Length, GetReadbackMemoryIndex(mrq.memoryTypeBits), + datasize, GetReadbackMemoryIndex(mrq.memoryTypeBits), }; allocInfo.allocationSize = AlignUp(allocInfo.allocationSize, mrq.alignment); - vkr = ObjDisp(d)->AllocMemory(Unwrap(d), &allocInfo, &mem); + vkr = ObjDisp(d)->AllocMemory(Unwrap(d), &allocInfo, &readbackmem); RDCASSERT(vkr == VK_SUCCESS); - GetResourceManager()->WrapResource(Unwrap(d), mem); + GetResourceManager()->WrapResource(Unwrap(d), readbackmem); - vkr = ObjDisp(d)->BindBufferMemory(Unwrap(d), srcBuf, ToHandle(res), 0); + vkr = ObjDisp(d)->BindBufferMemory(Unwrap(d), srcBuf, datamem, 0); RDCASSERT(vkr == VK_SUCCESS); - vkr = ObjDisp(d)->BindBufferMemory(Unwrap(d), dstBuf, Unwrap(mem), 0); + vkr = ObjDisp(d)->BindBufferMemory(Unwrap(d), dstBuf, Unwrap(readbackmem), 0); RDCASSERT(vkr == VK_SUCCESS); VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT }; @@ -107,7 +130,7 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) vkr = ObjDisp(d)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERT(vkr == VK_SUCCESS); - VkBufferCopy region = { 0, 0, (VkDeviceSize)record->Length }; + VkBufferCopy region = { dataoffs, 0, datasize }; ObjDisp(d)->CmdCopyBuffer(Unwrap(cmd), srcBuf, dstBuf, 1, ®ion); @@ -124,15 +147,7 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) ObjDisp(d)->DestroyBuffer(Unwrap(d), srcBuf); ObjDisp(d)->DestroyBuffer(Unwrap(d), dstBuf); - GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(GetWrapped(mem), (uint32_t)record->Length, NULL)); - - return true; - } - else if(type == eResImage) - { - VULKANNOTIMP("image initial states not implemented"); - - // VKTODOHIGH: need to copy off contents to memory somewhere else + GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(GetWrapped(readbackmem), (uint32_t)datasize, NULL)); return true; } @@ -172,7 +187,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) m_pSerialiser->SerialiseComplexArray("Bindings", info, numElems); } - else if(type == eResDeviceMemory) + else if(type == eResDeviceMemory || type == eResImage) { VkDevice d = GetDev(); @@ -185,9 +200,9 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) ObjDisp(d)->UnmapMemory(Unwrap(d), ToHandle(initContents.resource)); } - else if(type == eResImage) + else { - VULKANNOTIMP("image initial states not implemented"); + RDCERR("Unhandled resource type %d", type); } } else @@ -310,7 +325,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(NULL, validBinds, blob)); } - else if(type == eResDeviceMemory) + else if(type == eResDeviceMemory || type == eResImage) { byte *data = NULL; size_t dataSize = 0; @@ -367,9 +382,9 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(GetWrapped(buf), (uint32_t)dataSize, NULL)); } - else if(type == eResImage) + else { - VULKANNOTIMP("image initial states not implemented"); + RDCERR("Unhandled resource type %d", type); } } @@ -450,11 +465,28 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, VulkanResourceManager bind[d] = writes[i].pDescriptors[d]; } } - else if(type == eResDeviceMemory) + else if(type == eResDeviceMemory || type == eResImage) { + if(type == eResImage && initial.resource == NULL) + { + RDCASSERT(initial.num == eInitialContents_ClearColorImage || initial.num == eInitialContents_ClearDepthStencilImage); + return; + } + VkBuffer srcBuf = (VkBuffer)(uint64_t)initial.resource; - uint32_t memsize = initial.num; + VkDeviceSize datasize = (VkDeviceSize)initial.num; VkDeviceMemory dstMem = (VkDeviceMemory)(uint64_t)live; // maintain the wrapping, for consistency + VkDeviceSize dstMemOffs = 0; + VkDeviceSize memsize = datasize; + + if(type == eResImage) + { + dstMem = m_ImageLayouts[id].mem; + dstMemOffs = m_ImageLayouts[id].memoffs; + + // create buffer over all memory, then copy into sub-region + memsize = m_CreationInfo.m_Memory[GetResID(dstMem)].size; + } VkResult vkr = VK_SUCCESS; @@ -483,7 +515,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, VulkanResourceManager vkr = ObjDisp(d)->BindBufferMemory(Unwrap(d), dstBuf, Unwrap(dstMem), 0); RDCASSERT(vkr == VK_SUCCESS); - VkBufferCopy region = { 0, 0, memsize }; + VkBufferCopy region = { 0, dstMemOffs, datasize }; ObjDisp(cmd)->CmdCopyBuffer(Unwrap(cmd), Unwrap(srcBuf), dstBuf, 1, ®ion); @@ -510,11 +542,6 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, VulkanResourceManager ObjDisp(d)->DestroyBuffer(Unwrap(d), dstBuf); } - else if(type == eResImage) - { - // VKTODOHIGH: need to copy initial copy to live - VULKANNOTIMP("image initial states not implemented"); - } else { RDCERR("Unhandled resource type %d", type); diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index f3b7b6422..fb8eb196a 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -603,6 +603,8 @@ struct VkResourceRecord : public ResourceRecord ResourceRecord(id, true), bakedCommands(NULL), pool(NULL), + mem(VK_NULL_HANDLE), + memOffset(0), layout(NULL), swapInfo(NULL), cmdInfo(NULL) @@ -651,6 +653,9 @@ struct VkResourceRecord : public ResourceRecord } WrappedVkRes *Resource; + + VkDeviceMemory mem; + VkDeviceSize memOffset; // this points to the base resource, either memory or an image - // ie. the resource that can be modified or changes (or can become dirty) @@ -686,11 +691,12 @@ struct VkResourceRecord : public ResourceRecord struct ImageLayouts { - ImageLayouts() : arraySize(1), mipLevels(1), mem(VK_NULL_HANDLE) {} + ImageLayouts() : arraySize(1), mipLevels(1), mem(VK_NULL_HANDLE), memoffs(0) {} vector subresourceStates; int arraySize, mipLevels; VkDeviceMemory mem; + VkDeviceSize memoffs; }; bool IsBlockFormat(VkFormat f); diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 38389b713..5d4c284fe 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -599,9 +599,9 @@ void WrappedVulkan::vkCmdBeginRenderPass( for(size_t i=0; i < ARRAY_COUNT(fb->imageAttachments); i++) { if(fb->imageAttachments[i] == NULL) break; - record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResource, eFrameRef_Read); - record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResourceMem, eFrameRef_Write); - record->cmdInfo->dirtied.insert(fb->imageAttachments[i]->baseResourceMem); + record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResource, eFrameRef_Write); + record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResourceMem, eFrameRef_Read); + record->cmdInfo->dirtied.insert(fb->imageAttachments[i]->baseResource); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index d84da785b..d9dc6d45f 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -651,8 +651,8 @@ void WrappedVulkan::vkUpdateDescriptorSets( if(bind.imageView != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(bind.imageView), eFrameRef_Read); - record->AddBindFrameRef(GetRecord(bind.imageView)->baseResource, eFrameRef_Read); - record->AddBindFrameRef(GetRecord(bind.imageView)->baseResourceMem, ref); + record->AddBindFrameRef(GetRecord(bind.imageView)->baseResource, ref); + record->AddBindFrameRef(GetRecord(bind.imageView)->baseResourceMem, eFrameRef_Read); } if(bind.sampler != VK_NULL_HANDLE) { diff --git a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp index 819654947..31b338651 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp @@ -177,9 +177,9 @@ void WrappedVulkan::vkCmdBlitImage( record->MarkResourceFrameReferenced(GetResID(srcImage), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(srcImage)->baseResource, eFrameRef_Read); - record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Read); - record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(GetRecord(destImage)->baseResource); + record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); + record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); + record->cmdInfo->dirtied.insert(GetResID(destImage)); } } @@ -254,9 +254,9 @@ void WrappedVulkan::vkCmdResolveImage( record->MarkResourceFrameReferenced(GetResID(srcImage), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(srcImage)->baseResource, eFrameRef_Read); - record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Read); - record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(GetRecord(destImage)->baseResource); + record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); + record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); + record->cmdInfo->dirtied.insert(GetResID(destImage)); } } @@ -330,9 +330,9 @@ void WrappedVulkan::vkCmdCopyImage( record->AddChunk(scope.Get()); record->MarkResourceFrameReferenced(GetResID(srcImage), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(srcImage)->baseResource, eFrameRef_Read); - record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Read); - record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(GetRecord(destImage)->baseResource); + record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); + record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); + record->cmdInfo->dirtied.insert(GetResID(destImage)); } } @@ -420,9 +420,9 @@ void WrappedVulkan::vkCmdCopyBufferToImage( record->MarkResourceFrameReferenced(GetResID(srcBuffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(srcBuffer)->baseResource, eFrameRef_Read); - record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Read); - record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(GetRecord(destImage)->baseResource); + record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); + record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); + record->cmdInfo->dirtied.insert(GetResID(destImage)); } } @@ -656,8 +656,8 @@ void WrappedVulkan::vkCmdClearColorImage( Serialise_vkCmdClearColorImage(localSerialiser, cmdBuffer, image, imageLayout, pColor, rangeCount, pRanges); record->AddChunk(scope.Get()); - record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Read); - record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Write); + record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Write); + record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Read); } } @@ -723,8 +723,8 @@ void WrappedVulkan::vkCmdClearDepthStencilImage( Serialise_vkCmdClearDepthStencilImage(localSerialiser, cmdBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges); record->AddChunk(scope.Get()); - record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Read); - record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Write); + record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Write); + record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Read); } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index e91575a47..6ced4e4cd 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -492,6 +492,7 @@ bool WrappedVulkan::Serialise_vkBindImageMemory( ObjDisp(device)->BindImageMemory(Unwrap(device), Unwrap(image), Unwrap(mem), offs); m_ImageLayouts[GetResID(image)].mem = mem; + m_ImageLayouts[GetResID(image)].memoffs = offs; } return true; @@ -529,6 +530,9 @@ VkResult WrappedVulkan::vkBindImageMemory( // Anything that looks up a baseResource for an image knows not to chase further // than the image. record->baseResource = GetResID(mem); + + record->mem = mem; + record->memOffset = memOffset; } return ObjDisp(device)->BindImageMemory(Unwrap(device), Unwrap(image), Unwrap(mem), memOffset);