diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp index 1be2747bf..f537ad995 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp @@ -2258,6 +2258,20 @@ void GuestBufferMemory::AcquireRegistered() { publish = false; spaces.unpublished.fetch_add(1, std::memory_order_relaxed); } else { + std::size_t kept = 0; + for (std::size_t index = 0; index < regions.size(); ++index) { + auto& region = regions[index]; + if (kept != 0) { + auto& previous = regions[kept - 1]; + if (region.direct != nullptr && previous.direct == region.direct && previous.end == region.begin && previous.writable == region.writable && region.mirror == nullptr && previous.mirror == nullptr && !region.sparse && !previous.sparse && region.end <= region.direct->base + region.direct->bytes) { + previous.end = region.end; + continue; + } + } + if (kept != index) regions[kept] = std::move(region); + ++kept; + } + regions.erase(regions.begin() + static_cast(kept), regions.end()); for (const auto& region : regions) { if (region.direct != nullptr || region.mirror != nullptr) ranges.push_back(addressRange(region)); } diff --git a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp index cca74f789..5a1f81054 100644 --- a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp @@ -175,6 +175,42 @@ void failedImportRemapTests(const Context& context, const BdaTestAccess& access) ::operator delete(block, std::align_val_t{piece}); } +void spaceImportRunTests(const Context& context) { + constexpr std::size_t piece = 65536; + void* block = ::operator new(2 * piece, std::align_val_t{piece}); + const auto first = reinterpret_cast(block); + std::memset(block, 0x3c, 2 * piece); + auto importing = context; + importing.hostImportAlignment = piece; + const auto change = [&](std::uint8_t* range, bool add) { + auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix(); + if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, piece, true, false, true); + else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, range); + GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation); + }; + auto* guest = static_cast(block); + change(guest, true); + change(guest + piece, true); + for (int build = 0; build < 2; ++build) { + const auto before = AddressSpaceCounters(); + GuestBufferMemory leased(importing); + leased.AcquireRegistered(); + leased.AddReadable(first + piece - 256, 512); + leased.Upload(true); + std::uint32_t adjustment = 0; + const auto view = leased.Descriptor(first + piece - 256, 512, adjustment); + Require(view.buffer != VK_NULL_HANDLE && view.range == 512 + adjustment, "a V# across one import's ranges has no descriptor"); + const auto ranges = leased.AddressRanges(); + Require(std::any_of(ranges.begin(), ranges.end(), [&](const auto& range) { return range.begin <= first && first + 2 * piece <= range.end; }), "one import's adjacent ranges are not one BDA table entry"); + leased.WriteBack(); + const auto after = AddressSpaceCounters(); + if (after.enabled && build == 1) Require(after.hits == before.hits + 1 && after.dissolvedOverlap == before.dissolvedOverlap, "a V# across one import's ranges dissolved the cached address space"); + } + change(guest, false); + change(guest + piece, false); + ::operator delete(block, std::align_val_t{piece}); +} + void importWindowTests(const Context& context) { constexpr std::size_t piece = 65536; constexpr std::size_t window = 2 * piece; @@ -1202,6 +1238,7 @@ void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) { importCrossingTests(context, access); importSpanTests(context); failedImportRemapTests(context, access); + spaceImportRunTests(context); importWindowTests(context); heapMirrorTests(context, access); importedHeapMirrorTests(context, access);