@@ -511,8 +511,216 @@ VkResourceRecord::~VkResourceRecord()
511511
512512void 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
516550void 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}
0 commit comments