Skip to content

Commit fe84403

Browse files
committed
[Sparse baldurk#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.
1 parent 28f448e commit fe84403

3 files changed

Lines changed: 210 additions & 2 deletions

File tree

renderdoc/driver/vulkan/vk_manager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ void VulkanResourceManager::MarkSparseMapReferenced(SparseMapping *sparse)
296296
}
297297

298298
for(size_t i=0; i < sparse->opaquemappings.size(); i++)
299-
MarkResourceFrameReferenced(GetResID(sparse->opaquemappings[i].first), eFrameRef_Read);
299+
MarkResourceFrameReferenced(GetResID(sparse->opaquemappings[i].mem), eFrameRef_Read);
300300

301301
for(int a=0; a < VK_IMAGE_ASPECT_NUM; a++)
302302
for(VkDeviceSize i=0; sparse->pages[a] && i < sparse->imgdim.width*sparse->imgdim.height*sparse->imgdim.depth; i++)

renderdoc/driver/vulkan/vk_resources.cpp

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,8 +511,216 @@ VkResourceRecord::~VkResourceRecord()
511511

512512
void SparseMapping::Update(uint32_t numBindings, const VkSparseImageMemoryBindInfo *pBindings)
513513
{
514+
// update image page table mappings
515+
516+
for(uint32_t b=0; b < numBindings; b++)
517+
{
518+
const VkSparseImageMemoryBindInfo &newBind = pBindings[b];
519+
520+
// VKTODOMED handle sparse image arrays or sparse images with mips
521+
RDCASSERT(newBind.subresource.arrayLayer == 0 && newBind.subresource.mipLevel == 0);
522+
523+
pair<VkDeviceMemory,VkDeviceSize> *pageTable = pages[newBind.subresource.aspect];
524+
525+
VkOffset3D offsInPages = newBind.offset;
526+
offsInPages.x /= pagedim.width;
527+
offsInPages.y /= pagedim.height;
528+
offsInPages.z /= pagedim.depth;
529+
530+
VkExtent3D extInPages = newBind.extent;
531+
extInPages.width /= pagedim.width;
532+
extInPages.height /= pagedim.height;
533+
extInPages.depth /= pagedim.depth;
534+
535+
pair<VkDeviceMemory, VkDeviceSize> mempair = std::make_pair(newBind.mem, newBind.memOffset);
536+
537+
for(int32_t z=offsInPages.z; z < offsInPages.z+extInPages.depth; z++)
538+
{
539+
for(int32_t y=offsInPages.y; y < offsInPages.y+extInPages.height; y++)
540+
{
541+
for(int32_t x=offsInPages.x; x < offsInPages.x+extInPages.width; x++)
542+
{
543+
pageTable[ z*imgdim.width*imgdim.height + y*imgdim.width + x ] = mempair;
544+
}
545+
}
546+
}
547+
}
514548
}
515549

516550
void SparseMapping::Update(uint32_t numBindings, const VkSparseMemoryBindInfo *pBindings)
517551
{
552+
// update opaque mappings
553+
554+
for(uint32_t b=0; b < numBindings; b++)
555+
{
556+
const VkSparseMemoryBindInfo &curRange = pBindings[b];
557+
558+
bool found = false;
559+
560+
// this could be improved to do a binary search since the vector is sorted.
561+
for(auto it=opaquemappings.begin(); it != opaquemappings.end(); ++it)
562+
{
563+
VkSparseMemoryBindInfo &newRange = *it;
564+
565+
// the binding we're applying is after this item in the list,
566+
// keep searching
567+
if(curRange.rangeOffset+curRange.rangeSize <= newRange.rangeOffset) continue;
568+
569+
// the binding we're applying is before this item, but doesn't
570+
// overlap. Insert before us in the list
571+
if(curRange.rangeOffset >= newRange.rangeOffset+newRange.rangeSize)
572+
{
573+
opaquemappings.insert(it, newRange);
574+
found = true;
575+
break;
576+
}
577+
578+
// with sparse mappings it will be reasonably common to update an exact
579+
// existing range, so check that first
580+
if(curRange.rangeOffset == newRange.rangeOffset && curRange.rangeSize == newRange.rangeSize)
581+
{
582+
*it = curRange;
583+
found = true;
584+
break;
585+
}
586+
587+
// handle subranges within the current range
588+
if(curRange.rangeOffset <= newRange.rangeOffset && curRange.rangeOffset+curRange.rangeSize >= newRange.rangeOffset+newRange.rangeSize)
589+
{
590+
// they start in the same place
591+
if(curRange.rangeOffset == newRange.rangeOffset)
592+
{
593+
// change the current range to be the leftover second half
594+
it->rangeOffset += curRange.rangeSize;
595+
596+
// insert the new mapping before our current one
597+
opaquemappings.insert(it, newRange);
598+
found = true;
599+
break;
600+
}
601+
// they end in the same place
602+
else if(curRange.rangeOffset+curRange.rangeSize == newRange.rangeOffset+newRange.rangeSize)
603+
{
604+
// save a copy
605+
VkSparseMemoryBindInfo cur = curRange;
606+
607+
// set the new size of the first half
608+
cur.rangeSize = newRange.rangeOffset - curRange.rangeOffset;
609+
610+
// add the new range where the current iterator was
611+
*it = newRange;
612+
613+
// insert the old truncated mapping before our current position
614+
opaquemappings.insert(it, cur);
615+
found = true;
616+
break;
617+
}
618+
// the new range is a subsection
619+
else
620+
{
621+
// save a copy
622+
VkSparseMemoryBindInfo first = curRange;
623+
624+
// set the new size of the first part
625+
first.rangeSize = newRange.rangeOffset - curRange.rangeOffset;
626+
627+
// set the current range (third part) to start after the new range ends
628+
it->rangeOffset = newRange.rangeOffset+newRange.rangeSize;
629+
630+
// first insert the new range before our current range
631+
it = opaquemappings.insert(it, newRange);
632+
633+
// now insert the remaining first part before that
634+
opaquemappings.insert(it, first);
635+
636+
found = true;
637+
break;
638+
}
639+
}
640+
641+
// this new range overlaps the current one and some subsequent ranges. Merge together
642+
643+
// find where this new range stops overlapping
644+
auto endit=it;
645+
for(; endit != opaquemappings.end(); ++endit)
646+
{
647+
if(newRange.rangeOffset+newRange.rangeSize <= endit->rangeOffset+endit->rangeSize)
648+
break;
649+
}
650+
651+
// see if there are any leftovers of the overlapped ranges at the start or end
652+
bool leftoverstart = (curRange.rangeOffset < newRange.rangeOffset);
653+
bool leftoverend = (endit != opaquemappings.end() && (endit->rangeOffset+endit->rangeSize > newRange.rangeOffset+newRange.rangeSize));
654+
655+
// no leftovers, the new range entirely covers the current and last (if there is one)
656+
if(!leftoverstart && !leftoverend)
657+
{
658+
// erase all of the ranges. If endit points to a valid range,
659+
// it won't be erased, so we overwrite it. Otherwise it pointed
660+
// to end() so we just push_back()
661+
auto last = opaquemappings.erase(it, endit);
662+
if(last != opaquemappings.end())
663+
*last = newRange;
664+
else
665+
opaquemappings.push_back(newRange);
666+
}
667+
// leftover at the start, but not the end
668+
else if(leftoverstart && !leftoverend)
669+
{
670+
// save the current range
671+
VkSparseMemoryBindInfo cur = curRange;
672+
673+
// modify the size to reflect what's left over
674+
cur.rangeSize = newRange.rangeOffset - cur.rangeOffset;
675+
676+
// as above, erase and either re-insert or push_back()
677+
auto last = opaquemappings.erase(it, endit);
678+
if(last != opaquemappings.end())
679+
{
680+
*last = newRange;
681+
opaquemappings.insert(last, cur);
682+
}
683+
else
684+
{
685+
opaquemappings.push_back(cur);
686+
opaquemappings.push_back(newRange);
687+
}
688+
}
689+
// leftover at the end, but not the start
690+
else if(!leftoverstart && leftoverend)
691+
{
692+
// erase up to but not including endit
693+
auto last = opaquemappings.erase(it, endit);
694+
// modify the leftovers at the end
695+
last->rangeOffset = newRange.rangeOffset+newRange.rangeSize;
696+
// insert the new range before
697+
opaquemappings.insert(last, newRange);
698+
}
699+
// leftovers at both ends
700+
else
701+
{
702+
// save the current range
703+
VkSparseMemoryBindInfo cur = curRange;
704+
705+
// modify the size to reflect what's left over
706+
cur.rangeSize = newRange.rangeOffset - cur.rangeOffset;
707+
708+
// erase up to but not including endit
709+
auto last = opaquemappings.erase(it, endit);
710+
// modify the leftovers at the end
711+
last->rangeOffset = newRange.rangeOffset+newRange.rangeSize;
712+
// insert the new range before
713+
auto newit = opaquemappings.insert(last, newRange);
714+
// insert the modified leftovers before that
715+
opaquemappings.insert(newit, cur);
716+
}
717+
718+
found = true;
719+
break;
720+
}
721+
722+
// if it wasn't found, this binding is after all mappings in our list
723+
if(!found)
724+
opaquemappings.push_back(curRange);
725+
}
518726
}

renderdoc/driver/vulkan/vk_resources.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ struct SparseMapping
586586
}
587587

588588
// for buffers or non-sparse-resident images (bound with opaque mappings)
589-
vector< pair<VkDeviceMemory, VkDeviceSize> > opaquemappings;
589+
vector<VkSparseMemoryBindInfo> opaquemappings;
590590

591591
// for sparse resident images:
592592
// total image size (in pages)

0 commit comments

Comments
 (0)