From 9be607255ed6ce8259ca0fff2eb4a8874111cfa1 Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 8 Nov 2015 22:23:29 +0100 Subject: [PATCH] [Sparse #6] Implement sparse initial state stubs - page tables only --- renderdoc/driver/vulkan/vk_core.h | 4 +- renderdoc/driver/vulkan/vk_initstate.cpp | 304 ++++++++++++++++++++++- 2 files changed, 293 insertions(+), 15 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 2fdc0783e..a6666fc45 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -445,8 +445,8 @@ private: bool Prepare_SparseInitialState(WrappedVkBuffer *buf); bool Prepare_SparseInitialState(WrappedVkImage *im); - bool Serialise_SparseInitialState(WrappedVkBuffer *buf, VulkanResourceManager::InitialContentData contents); - bool Serialise_SparseInitialState(WrappedVkImage *im, VulkanResourceManager::InitialContentData contents); + bool Serialise_SparseInitialState(ResourceId id, WrappedVkBuffer *buf, VulkanResourceManager::InitialContentData contents); + bool Serialise_SparseInitialState(ResourceId id, WrappedVkImage *im, VulkanResourceManager::InitialContentData contents); bool Apply_SparseInitialState(WrappedVkBuffer *buf, VulkanResourceManager::InitialContentData contents); bool Apply_SparseInitialState(WrappedVkImage *im, VulkanResourceManager::InitialContentData contents); diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 43d863f3e..fa5aea40a 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -26,39 +26,317 @@ // VKTODOHIGH we are assuming in all the initial state handling that the image is VK_IMAGE_ASPECT_COLOR +struct PageInitState +{ + ResourceId memId; + VkDeviceSize memOffs; +}; + +template<> +void Serialiser::Serialise(const char *name, PageInitState &el) +{ + Serialise("memId", el.memId); + Serialise("memOffs", el.memOffs); +} + +struct SparseInitState +{ + uint32_t opaqueCount; + VkSparseMemoryBindInfo *opaque; + + VkExtent3D imgdim; // in pages + VkExtent3D pagedim; + uint32_t pageCount[VK_IMAGE_ASPECT_NUM]; + + // available on capture - filled out in Prepare_SparseInitialState and serialised to disk + PageInitState *pages[VK_IMAGE_ASPECT_NUM]; + + // available on replay - filled out in the READING path of Serialise_SparseInitialState + VkSparseImageMemoryBindInfo *pageBinds[VK_IMAGE_ASPECT_NUM]; +}; + bool WrappedVulkan::Prepare_SparseInitialState(WrappedVkBuffer *buf) { ResourceId id = buf->id; // VKTODOMED fetch contents of memory for the unique bound memory regions - GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(NULL, 0, (byte *)NULL)); + uint32_t numElems = (uint32_t)buf->record->sparseInfo->opaquemappings.size(); + + VkSparseMemoryBindInfo *info = (VkSparseMemoryBindInfo *)Serialiser::AllocAlignedBuffer(sizeof(VkSparseMemoryBindInfo)*numElems); + RDCEraseMem(info, sizeof(VkSparseMemoryBindInfo)*numElems); + + memcpy(info, &buf->record->sparseInfo->opaquemappings[0], sizeof(VkSparseMemoryBindInfo)*numElems); + + GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(NULL, numElems, (byte *)info)); return true; } bool WrappedVulkan::Prepare_SparseInitialState(WrappedVkImage *im) { + ResourceId id = im->id; + + SparseMapping *sparse = im->record->sparseInfo; + + // VKTODOMED fetch contents of memory for the unique bound memory regions + + uint32_t pagePerAspect = sparse->imgdim.width*sparse->imgdim.height*sparse->imgdim.depth; + + uint32_t totalPageCount = 0; + for(uint32_t a=0; a < VK_IMAGE_ASPECT_NUM; a++) + totalPageCount += sparse->pages[a] ? pagePerAspect : 0; + + uint32_t opaqueCount = (uint32_t)sparse->opaquemappings.size(); + + byte *blob = Serialiser::AllocAlignedBuffer(sizeof(SparseInitState) + + sizeof(VkSparseMemoryBindInfo)*opaqueCount + + sizeof(PageInitState)*totalPageCount); + + SparseInitState *state = (SparseInitState *)blob; + VkSparseMemoryBindInfo *opaque = (VkSparseMemoryBindInfo *)(state + 1); + PageInitState *pages = (PageInitState *)(opaque + opaqueCount); + + state->opaque = opaque; + state->opaqueCount = opaqueCount; + state->pagedim = sparse->pagedim; + state->imgdim = sparse->imgdim; + + if(opaqueCount > 0) + memcpy(opaque, &sparse->opaquemappings[0], sizeof(VkSparseMemoryBindInfo)*opaqueCount); + + for(uint32_t a=0; a < VK_IMAGE_ASPECT_NUM; a++) + { + state->pageCount[a] = (sparse->pages[a] ? pagePerAspect : 0); + + if(state->pageCount[a] != 0) + { + state->pages[a] = pages; + + for(uint32_t i=0; i < pagePerAspect; i++) + { + state->pages[a][i].memId = GetResID(sparse->pages[a][i].first); + state->pages[a][i].memOffs = sparse->pages[a][i].second; + } + + pages += pagePerAspect; + } + else + { + state->pages[a] = NULL; + } + } + + GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(NULL, 0, blob)); + return true; } -bool WrappedVulkan::Serialise_SparseInitialState(WrappedVkBuffer *buf, VulkanResourceManager::InitialContentData contents) +bool WrappedVulkan::Serialise_SparseInitialState(ResourceId id, WrappedVkBuffer *buf, VulkanResourceManager::InitialContentData contents) { + VkSparseMemoryBindInfo *info = (VkSparseMemoryBindInfo *)contents.blob; + uint32_t numElems = contents.num; + + m_pSerialiser->Serialise("numBinds", numElems); + + if(m_State < WRITING) + info = (VkSparseMemoryBindInfo *)Serialiser::AllocAlignedBuffer(sizeof(VkSparseMemoryBindInfo)*numElems); + + VkSparseMemoryBindInfo *binds = NULL; + m_pSerialiser->SerialiseComplexArray("binds", binds, numElems); + memcpy(info, binds, sizeof(VkSparseMemoryBindInfo)*numElems); + delete[] binds; + + if(m_State < WRITING) + GetResourceManager()->SetInitialContents(id, contents); + return true; } -bool WrappedVulkan::Serialise_SparseInitialState(WrappedVkImage *im, VulkanResourceManager::InitialContentData contents) +bool WrappedVulkan::Serialise_SparseInitialState(ResourceId id, WrappedVkImage *im, VulkanResourceManager::InitialContentData contents) { + if(m_State >= WRITING) + { + SparseInitState *state = (SparseInitState *)contents.blob; + + uint32_t totalPageCount = 0; + for(uint32_t a=0; a < VK_IMAGE_ASPECT_NUM; a++) + totalPageCount += state->pageCount[a]; + + m_pSerialiser->Serialise("opaqueCount", state->opaqueCount); + m_pSerialiser->Serialise("totalPageCount", totalPageCount); + m_pSerialiser->Serialise("imgdim", state->imgdim); + m_pSerialiser->Serialise("pagedim", state->pagedim); + + if(state->opaqueCount > 0) + m_pSerialiser->SerialiseComplexArray("opaque", state->opaque, state->opaqueCount); + + if(totalPageCount > 0) + { + for(uint32_t a=0; a < VK_IMAGE_ASPECT_NUM; a++) + { + m_pSerialiser->Serialise("aspectPageCount", state->pageCount[a]); + + if(state->pageCount[a] > 0) + m_pSerialiser->SerialiseComplexArray("pages", state->pages[a], state->pageCount[a]); + } + } + } + else + { + uint32_t opaqueCount = 0; + uint32_t pageCount = 0; + VkExtent3D imgdim = {}; + VkExtent3D pagedim = {}; + + m_pSerialiser->Serialise("opaqueCount", opaqueCount); + m_pSerialiser->Serialise("pageCount", pageCount); + m_pSerialiser->Serialise("imgdim", imgdim); + m_pSerialiser->Serialise("pagedim", pagedim); + + byte *blob = Serialiser::AllocAlignedBuffer(sizeof(SparseInitState) + + sizeof(VkSparseMemoryBindInfo)*opaqueCount + + sizeof(VkSparseImageMemoryBindInfo)*pageCount); + + SparseInitState *state = (SparseInitState *)blob; + VkSparseMemoryBindInfo *opaque = (VkSparseMemoryBindInfo *)(state + 1); + VkSparseImageMemoryBindInfo *pageBinds = (VkSparseImageMemoryBindInfo *)(opaque + opaqueCount); + + RDCEraseEl(state->pageBinds); + + state->opaqueCount = opaqueCount; + state->opaque = opaque; + state->imgdim = imgdim; + state->pagedim = pagedim; + + if(opaqueCount > 0) + { + VkSparseMemoryBindInfo *o = NULL; + m_pSerialiser->SerialiseComplexArray("opaque", o, opaqueCount); + memcpy(opaque, o, sizeof(VkSparseMemoryBindInfo)*opaqueCount); + delete[] o; + } + else + { + state->opaque = NULL; + } + + if(pageCount > 0) + { + for(uint32_t a=0; a < VK_IMAGE_ASPECT_NUM; a++) + { + m_pSerialiser->Serialise("aspectPageCount", state->pageCount[a]); + + if(state->pageCount[a] == 0) + { + state->pageBinds[a] = NULL; + } + else + { + state->pageBinds[a] = pageBinds; + pageBinds += state->pageCount[a]; + + PageInitState *pages = NULL; + m_pSerialiser->SerialiseComplexArray("pages", pages, state->pageCount[a]); + + uint32_t i=0; + + for(int32_t z=0; z < imgdim.depth; z++) + { + for(int32_t y=0; y < imgdim.height; y++) + { + for(int32_t x=0; x < imgdim.width; x++) + { + VkSparseImageMemoryBindInfo &p = state->pageBinds[a][i]; + + p.mem = Unwrap(GetResourceManager()->GetLiveHandle(pages[i].memId)); + p.memOffset = pages[i].memOffs; + p.extent = pagedim; + p.flags = 0; // VKTODOLOW do we need to preserve these flags? + p.subresource.aspect = (VkImageAspect)a; + p.subresource.arrayLayer = 0; + p.subresource.mipLevel = 0; + p.offset.x = x*p.extent.width; + p.offset.y = y*p.extent.height; + p.offset.z = z*p.extent.depth; + + i++; + } + } + } + + delete[] pages; + } + } + } + + GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(NULL, eInitialContents_Sparse, blob)); + } + return true; } bool WrappedVulkan::Apply_SparseInitialState(WrappedVkBuffer *buf, VulkanResourceManager::InitialContentData contents) { + VkSparseMemoryBindInfo *info = (VkSparseMemoryBindInfo *)contents.blob; + uint32_t numElems = contents.num; + + // unbind the entire buffer so that any new areas that are bound are unbound again + + VkSparseMemoryBindInfo unbind = { + 0, m_CreationInfo.m_Buffer[buf->id].size, + 0, VK_NULL_HANDLE, 0 + }; + + VkQueue q = GetQ(); + + ObjDisp(q)->QueueBindSparseBufferMemory(Unwrap(q), buf->real.As(), 1, &unbind); + ObjDisp(q)->QueueBindSparseBufferMemory(Unwrap(q), buf->real.As(), numElems, info); + return true; } bool WrappedVulkan::Apply_SparseInitialState(WrappedVkImage *im, VulkanResourceManager::InitialContentData contents) { + SparseInitState *info = (SparseInitState *)contents.blob; + + VkQueue q = GetQ(); + + if(info->opaque) + { + // unbind the entire image so that any new areas that are bound are unbound again + + // VKTODOMED not sure if this is the right size for opaque portion of partial resident + // sparse image? how is that determined? + VkSparseMemoryBindInfo unbind = { + 0, 0, + 0, VK_NULL_HANDLE, 0 + }; + + VkMemoryRequirements mrq; + ObjDisp(q)->GetImageMemoryRequirements(Unwrap(GetDev()), im->real.As(), &mrq); + unbind.rangeSize = mrq.size; + + ObjDisp(q)->QueueBindSparseImageOpaqueMemory(Unwrap(q), im->real.As(), 1, &unbind); + ObjDisp(q)->QueueBindSparseImageOpaqueMemory(Unwrap(q), im->real.As(), info->opaqueCount, info->opaque); + } + + for(uint32_t a=0; a < VK_IMAGE_ASPECT_NUM; a++) + { + if(!info->pageBinds[a]) continue; + + // unbind the entire image so that any new areas that are bound are unbound again + VkSparseImageMemoryBindInfo unbind = { + { (VkImageAspect)a, 0, 0 }, + { 0, 0, 0 }, + m_CreationInfo.m_Image[im->id].extent, + 0, VK_NULL_HANDLE, 0 + }; + + ObjDisp(q)->QueueBindSparseImageMemory(Unwrap(q), im->real.As(), 1, &unbind); + ObjDisp(q)->QueueBindSparseImageMemory(Unwrap(q), im->real.As(), info->pageCount[a], info->pageBinds[a]); + } + return true; } @@ -102,12 +380,6 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) { VkResult vkr = VK_SUCCESS; - VkDevice d = GetDev(); - // VKTODOLOW ideally the prepares could be batched up - // a bit more - maybe not all in one command buffer, but - // at least more than one each - VkCmdBuffer cmd = GetNextCmd(); - WrappedVkImage *im = (WrappedVkImage *)res; if(im->record->sparseInfo) @@ -117,6 +389,12 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) return Prepare_SparseInitialState((WrappedVkImage *)res); } + VkDevice d = GetDev(); + // VKTODOLOW ideally the prepares could be batched up + // a bit more - maybe not all in one command buffer, but + // at least more than one each + VkCmdBuffer cmd = GetNextCmd(); + ImageLayouts *layout = NULL; { SCOPED_LOCK(m_ImageLayoutsLock); @@ -377,7 +655,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) } else if(type == eResBuffer) { - return Serialise_SparseInitialState((WrappedVkBuffer *)res, initContents); + return Serialise_SparseInitialState(id, (WrappedVkBuffer *)res, initContents); } else if(type == eResDeviceMemory || type == eResImage) { @@ -391,7 +669,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) { // contains page mapping RDCASSERT(type == eResImage); - return Serialise_SparseInitialState((WrappedVkImage *)res, initContents); + return Serialise_SparseInitialState(id, (WrappedVkImage *)res, initContents); } byte *ptr = NULL; @@ -530,7 +808,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) } else if(type == eResBuffer) { - return Serialise_SparseInitialState((WrappedVkBuffer *)NULL, VulkanResourceManager::InitialContentData()); + return Serialise_SparseInitialState(id, (WrappedVkBuffer *)NULL, VulkanResourceManager::InitialContentData()); } else if(type == eResImage) { @@ -539,7 +817,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res) if(isSparse) { - return Serialise_SparseInitialState((WrappedVkImage *)NULL, VulkanResourceManager::InitialContentData()); + return Serialise_SparseInitialState(id, (WrappedVkImage *)NULL, VulkanResourceManager::InitialContentData()); } byte *data = NULL;