From fe8440363bd64b745670c5f394b6309c3437dd99 Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 8 Nov 2015 19:28:35 +0100 Subject: [PATCH] [Sparse #5] Implement stubs for updating page tables (opaque or image) * Not supporting images with arrays or mips for now as that becomes more complicated. In theory a page table each, but then need to handle mip tail and stuff. --- renderdoc/driver/vulkan/vk_manager.cpp | 2 +- renderdoc/driver/vulkan/vk_resources.cpp | 208 +++++++++++++++++++++++ renderdoc/driver/vulkan/vk_resources.h | 2 +- 3 files changed, 210 insertions(+), 2 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_manager.cpp b/renderdoc/driver/vulkan/vk_manager.cpp index 81f05d95e..013f56a15 100644 --- a/renderdoc/driver/vulkan/vk_manager.cpp +++ b/renderdoc/driver/vulkan/vk_manager.cpp @@ -296,7 +296,7 @@ void VulkanResourceManager::MarkSparseMapReferenced(SparseMapping *sparse) } for(size_t i=0; i < sparse->opaquemappings.size(); i++) - MarkResourceFrameReferenced(GetResID(sparse->opaquemappings[i].first), eFrameRef_Read); + MarkResourceFrameReferenced(GetResID(sparse->opaquemappings[i].mem), eFrameRef_Read); for(int a=0; a < VK_IMAGE_ASPECT_NUM; a++) for(VkDeviceSize i=0; sparse->pages[a] && i < sparse->imgdim.width*sparse->imgdim.height*sparse->imgdim.depth; i++) diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 446878ad8..20cbfde5a 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -511,8 +511,216 @@ VkResourceRecord::~VkResourceRecord() void SparseMapping::Update(uint32_t numBindings, const VkSparseImageMemoryBindInfo *pBindings) { + // update image page table mappings + + for(uint32_t b=0; b < numBindings; b++) + { + const VkSparseImageMemoryBindInfo &newBind = pBindings[b]; + + // VKTODOMED handle sparse image arrays or sparse images with mips + RDCASSERT(newBind.subresource.arrayLayer == 0 && newBind.subresource.mipLevel == 0); + + pair *pageTable = pages[newBind.subresource.aspect]; + + VkOffset3D offsInPages = newBind.offset; + offsInPages.x /= pagedim.width; + offsInPages.y /= pagedim.height; + offsInPages.z /= pagedim.depth; + + VkExtent3D extInPages = newBind.extent; + extInPages.width /= pagedim.width; + extInPages.height /= pagedim.height; + extInPages.depth /= pagedim.depth; + + pair mempair = std::make_pair(newBind.mem, newBind.memOffset); + + for(int32_t z=offsInPages.z; z < offsInPages.z+extInPages.depth; z++) + { + for(int32_t y=offsInPages.y; y < offsInPages.y+extInPages.height; y++) + { + for(int32_t x=offsInPages.x; x < offsInPages.x+extInPages.width; x++) + { + pageTable[ z*imgdim.width*imgdim.height + y*imgdim.width + x ] = mempair; + } + } + } + } } void SparseMapping::Update(uint32_t numBindings, const VkSparseMemoryBindInfo *pBindings) { + // update opaque mappings + + for(uint32_t b=0; b < numBindings; b++) + { + const VkSparseMemoryBindInfo &curRange = pBindings[b]; + + bool found = false; + + // this could be improved to do a binary search since the vector is sorted. + for(auto it=opaquemappings.begin(); it != opaquemappings.end(); ++it) + { + VkSparseMemoryBindInfo &newRange = *it; + + // the binding we're applying is after this item in the list, + // keep searching + if(curRange.rangeOffset+curRange.rangeSize <= newRange.rangeOffset) continue; + + // the binding we're applying is before this item, but doesn't + // overlap. Insert before us in the list + if(curRange.rangeOffset >= newRange.rangeOffset+newRange.rangeSize) + { + opaquemappings.insert(it, newRange); + found = true; + break; + } + + // with sparse mappings it will be reasonably common to update an exact + // existing range, so check that first + if(curRange.rangeOffset == newRange.rangeOffset && curRange.rangeSize == newRange.rangeSize) + { + *it = curRange; + found = true; + break; + } + + // handle subranges within the current range + if(curRange.rangeOffset <= newRange.rangeOffset && curRange.rangeOffset+curRange.rangeSize >= newRange.rangeOffset+newRange.rangeSize) + { + // they start in the same place + if(curRange.rangeOffset == newRange.rangeOffset) + { + // change the current range to be the leftover second half + it->rangeOffset += curRange.rangeSize; + + // insert the new mapping before our current one + opaquemappings.insert(it, newRange); + found = true; + break; + } + // they end in the same place + else if(curRange.rangeOffset+curRange.rangeSize == newRange.rangeOffset+newRange.rangeSize) + { + // save a copy + VkSparseMemoryBindInfo cur = curRange; + + // set the new size of the first half + cur.rangeSize = newRange.rangeOffset - curRange.rangeOffset; + + // add the new range where the current iterator was + *it = newRange; + + // insert the old truncated mapping before our current position + opaquemappings.insert(it, cur); + found = true; + break; + } + // the new range is a subsection + else + { + // save a copy + VkSparseMemoryBindInfo first = curRange; + + // set the new size of the first part + first.rangeSize = newRange.rangeOffset - curRange.rangeOffset; + + // set the current range (third part) to start after the new range ends + it->rangeOffset = newRange.rangeOffset+newRange.rangeSize; + + // first insert the new range before our current range + it = opaquemappings.insert(it, newRange); + + // now insert the remaining first part before that + opaquemappings.insert(it, first); + + found = true; + break; + } + } + + // this new range overlaps the current one and some subsequent ranges. Merge together + + // find where this new range stops overlapping + auto endit=it; + for(; endit != opaquemappings.end(); ++endit) + { + if(newRange.rangeOffset+newRange.rangeSize <= endit->rangeOffset+endit->rangeSize) + break; + } + + // see if there are any leftovers of the overlapped ranges at the start or end + bool leftoverstart = (curRange.rangeOffset < newRange.rangeOffset); + bool leftoverend = (endit != opaquemappings.end() && (endit->rangeOffset+endit->rangeSize > newRange.rangeOffset+newRange.rangeSize)); + + // no leftovers, the new range entirely covers the current and last (if there is one) + if(!leftoverstart && !leftoverend) + { + // erase all of the ranges. If endit points to a valid range, + // it won't be erased, so we overwrite it. Otherwise it pointed + // to end() so we just push_back() + auto last = opaquemappings.erase(it, endit); + if(last != opaquemappings.end()) + *last = newRange; + else + opaquemappings.push_back(newRange); + } + // leftover at the start, but not the end + else if(leftoverstart && !leftoverend) + { + // save the current range + VkSparseMemoryBindInfo cur = curRange; + + // modify the size to reflect what's left over + cur.rangeSize = newRange.rangeOffset - cur.rangeOffset; + + // as above, erase and either re-insert or push_back() + auto last = opaquemappings.erase(it, endit); + if(last != opaquemappings.end()) + { + *last = newRange; + opaquemappings.insert(last, cur); + } + else + { + opaquemappings.push_back(cur); + opaquemappings.push_back(newRange); + } + } + // leftover at the end, but not the start + else if(!leftoverstart && leftoverend) + { + // erase up to but not including endit + auto last = opaquemappings.erase(it, endit); + // modify the leftovers at the end + last->rangeOffset = newRange.rangeOffset+newRange.rangeSize; + // insert the new range before + opaquemappings.insert(last, newRange); + } + // leftovers at both ends + else + { + // save the current range + VkSparseMemoryBindInfo cur = curRange; + + // modify the size to reflect what's left over + cur.rangeSize = newRange.rangeOffset - cur.rangeOffset; + + // erase up to but not including endit + auto last = opaquemappings.erase(it, endit); + // modify the leftovers at the end + last->rangeOffset = newRange.rangeOffset+newRange.rangeSize; + // insert the new range before + auto newit = opaquemappings.insert(last, newRange); + // insert the modified leftovers before that + opaquemappings.insert(newit, cur); + } + + found = true; + break; + } + + // if it wasn't found, this binding is after all mappings in our list + if(!found) + opaquemappings.push_back(curRange); + } } diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index ac92be08b..7bb84f00b 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -586,7 +586,7 @@ struct SparseMapping } // for buffers or non-sparse-resident images (bound with opaque mappings) - vector< pair > opaquemappings; + vector opaquemappings; // for sparse resident images: // total image size (in pages)