From c54854b2bdd997be1ebbc224dbdacfa3d8942f9e Mon Sep 17 00:00:00 2001 From: Yunus Shaikh <75296019+EagleBearerYS@users.noreply.github.com> Date: Wed, 14 Oct 2026 02:38:14 -0700 Subject: [PATCH] fix(agc): find a view's region when the cached address space dissolves after UploadPrepare UploadFinish dissolves the cached address space when an import was retired after the space was built. The space's base regions are then merged with the build's own regions, which since readsOverBase may overlap them. owner() searched the merged list for the region with the greatest begin, a base region of one mapping, so a read-only V# merged into an own region that began earlier was bound through it again: guest buffer view 0x1f0390c1c4+0x10c1cc exceeds its GPU owner 0x1f03900000-0x1f03910000 (buffer 0, direct 1, mirror 0) The dissolve now notes when the merged list overlaps, and owner() then looks back for a region that holds the whole range. The test's third build retires the imports between UploadPrepare and UploadFinish. --- .../Graphics/include/GuestBufferMemory.hpp | 1 + .../Graphics/src/GuestBufferMemory.cpp | 20 +++++++++++++++---- .../libSceAgcDriver/tests/BdaResources.cpp | 6 ++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp b/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp index 9e71901ebd..d2fedc76af 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp @@ -389,6 +389,7 @@ private: // Whether `regions` is in ascending address order (true right after AcquireRegistered, whose // regions follow the registry's order), so AddSnapshot can search instead of scanning. bool regionsSorted = false; + bool regionsOverlap = false; std::vector> writes; std::vector> readsOverBase; std::vector>> heapReferences; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp index b4771f1a6a..d91dc92ba1 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp @@ -2580,6 +2580,11 @@ void GuestBufferMemory::dissolveSpace(bool resolve) { // Both sorted and disjoint (UploadPrepare merged this build's regions; the space's are // registered ranges), so the merge keeps the order Descriptor searches. std::merge(space->base.begin(), space->base.end(), std::make_move_iterator(regions.begin()), std::make_move_iterator(regions.end()), std::back_inserter(merged), [](const Region& left, const Region& right) { return left.begin < right.begin; }); + std::uint64_t reached = 0; + for (const auto& region : merged) { + regionsOverlap = regionsOverlap || region.begin < reached; + reached = std::max(reached, region.end); + } } else { merged.assign(space->base.begin(), space->base.end()); merged.insert(merged.end(), std::make_move_iterator(regions.begin()), std::make_move_iterator(regions.end())); @@ -2597,12 +2602,19 @@ void GuestBufferMemory::dissolveSpace(bool resolve) { } const GuestBufferMemory::Region* GuestBufferMemory::owner(std::uint64_t address, std::uint64_t end) const { - const auto candidate = [address](const std::vector& list) -> const Region* { + const auto candidate = [address, end](const std::vector& list, bool overlapping) -> const Region* { const auto found = std::upper_bound(list.begin(), list.end(), address, [](std::uint64_t value, const Region& region) { return value < region.begin; }); - return found == list.begin() ? nullptr : &*std::prev(found); + if (found == list.begin()) return nullptr; + if (overlapping) { + for (auto it = found; it != list.begin();) { + --it; + if (end <= it->end) return &*it; + } + } + return &*std::prev(found); }; - const auto* own = candidate(regions); - const auto* shared = space != nullptr ? candidate(space->base) : nullptr; + const auto* own = candidate(regions, regionsOverlap); + const auto* shared = space != nullptr ? candidate(space->base, false) : nullptr; const auto holds = [end](const Region* region) { return region != nullptr && end <= region->end; }; if (holds(own) != holds(shared)) return holds(own) ? own : shared; if (own == nullptr || (shared != nullptr && shared->begin > own->begin)) return shared; diff --git a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp index e056c5abb4..ab710def2b 100644 --- a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp @@ -581,12 +581,14 @@ void spaceReadsAcrossImportsMergedTests(const Context& context, const BdaTestAcc const std::uint64_t lowerBytes = 512; const std::uint64_t upper = second + 128; const std::uint64_t upperBytes = third + 256 - upper; - for (int build = 0; build < 2; ++build) { + for (int build = 0; build < 3; ++build) { GuestBufferMemory leased(importing); leased.AcquireRegistered(); leased.AddReadable(lower, lowerBytes); leased.AddReadable(upper, upperBytes); - leased.Upload(true); + leased.UploadPrepare(true); + if (build == 2) ClearHostImports(importing.device); + leased.UploadFinish(true); for (const auto& [address, bytes] : {std::pair{lower, lowerBytes}, std::pair{upper, upperBytes}}) { std::uint32_t adjustment = 0; const auto view = leased.Descriptor(address, bytes, adjustment);