diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp index 92b900e7d..91dab33a8 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp @@ -1966,6 +1966,7 @@ void GuestBufferMemory::UploadPrepare(bool addressable) { previous.hostBacked = true; } mergeBacked(previous, region); + if (region.end > previous.end) previous.direct = nullptr; previous.atomic = previous.atomic || region.atomic; // A range starting before the mirror (only possible after the swap) keeps its prefix; the // earlier merged region ends at or before it, so the merged list stays sorted. diff --git a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp index f803903fc..c3b5517eb 100644 --- a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace { @@ -32,6 +33,54 @@ void reject(TAction action, const char* reason) { throw std::runtime_error(std::string("expected BDA rejection: ") + reason); } +void importCrossingTests(const Context& context, const BdaTestAccess& access) { + constexpr std::size_t half = 65536; + void* block = ::operator new(2 * half, std::align_val_t{half}); + auto* guest = static_cast(block); + std::memset(guest, 0x11, half); + std::memset(guest + half, 0x22, half); + const auto first = reinterpret_cast(block); + const auto second = first + half; + auto importing = context; + importing.hostImportAlignment = half; + const auto registry = [&](bool add) { + auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix(); + for (auto* range : {guest, guest + half}) { + if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, half, true, false); + else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, range); + } + GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation); + }; + registry(true); + { + GuestBufferMemory leased(importing); + leased.AcquireRegistered(); + Require(HostImportCovers(importing, first, half) && HostImportCovers(importing, second, half), "the registered ranges were not imported"); + const auto secondImport = *HostImportFor(importing, second, half); + leased.AddReadable(second - 16, 32); + leased.AddReadable(second + 64, 16); + leased.Upload(true); + std::uint32_t adjustment = 0; + const auto crossing = leased.Descriptor(second - 16, 32, adjustment); + const auto crossingBytes = access.bytes(crossing.buffer); + Require(crossing.offset + crossing.range <= crossingBytes.size(), "a view crossing into the next registered range is bound past its host import"); + Require(crossingBytes[crossing.offset + adjustment + 15] == std::byte{0x11} && crossingBytes[crossing.offset + adjustment + 16] == std::byte{0x22}, "a view crossing into the next registered range misses its bytes"); + const auto inside = leased.Descriptor(second + 64, 16, adjustment); + const auto insideBytes = access.bytes(inside.buffer); + Require(inside.offset + inside.range <= insideBytes.size() && (inside.buffer == secondImport.buffer ? inside.offset + adjustment == 64 : insideBytes[inside.offset + adjustment] == std::byte{0x22}), "a view in the second registered range is bound past its buffer or misses its bytes"); + for (const auto& range : leased.AddressRanges()) { + if (range.end <= first || range.begin >= second + half) continue; + const auto mapped = access.addressBytes(range.deviceAddress); + Require(mapped.size() >= range.end - range.begin, "a BDA range runs past the end of its host import"); + if (range.begin <= second && second < range.end && range.deviceAddress != secondImport.address) Require(mapped[second - range.begin] == std::byte{0x22}, "the BDA range over the second registered range misses its bytes"); + } + leased.WriteBack(); + } + registry(false); + Require(HostImportFor(importing, first, half) == nullptr && !HostImportCovers(importing, second, half), "the host imports outlived their ranges"); + ::operator delete(block, std::align_val_t{half}); +} + ShaderRecompiler::DescriptorBinding binding(Role role, std::uint32_t slot) { return {ShaderRecompiler::DescriptorKind::StorageBuffer, role, 0, slot, 1, {}, false}; } @@ -385,6 +434,7 @@ void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) { const auto dropped = AddressSpaceCounters(); if (dropped.enabled) Require(dropped.waiterDrops == after.waiterDrops + 1 && LeaseCounters().cacheDrops == dropped.waiterDrops, "the free did not drop the cached address space"); } + importCrossingTests(context, access); heapMirrorTests(context, access); Require(AddressCopyOverflow({{0x1000, 0x3000, 0x2000, "uncommitted pages"}}, 0x2000).empty(), "copies within the limit were refused"); const auto copies = AddressCopyOverflow({{0x1000, 0x2000, 0x1000, "not mirrored"}, {0x10000, 0x30000, 0x18000, "uncommitted pages"}}, 0x2000); diff --git a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp index a035d3bf6..a22b85ecd 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp @@ -1300,6 +1300,12 @@ VKAPI_ATTR void VKAPI_CALL mockCmdBindDescriptorSets(VkCommandBuffer, VkPipeline mock.boundSets = count; } +VKAPI_ATTR VkResult VKAPI_CALL mockGetMemoryHostPointerProperties(VkDevice, VkExternalMemoryHandleTypeFlagBits type, const void* pointer, VkMemoryHostPointerPropertiesEXT* properties) { + Require(type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT && pointer != nullptr, "invalid host pointer import query"); + properties->memoryTypeBits = 1; + return VK_SUCCESS; +} + VKAPI_ATTR VkDeviceAddress VKAPI_CALL mockGetBufferDeviceAddress(VkDevice, const VkBufferDeviceAddressInfo* info) { Require(mock.bufferMemory.contains(info->buffer), "BDA buffer was not bound"); Require((mock.bufferUsage.at(info->buffer) & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0, "BDA buffer usage is missing"); @@ -1369,6 +1375,7 @@ VKAPI_ATTR void VKAPI_CALL mockCmdUpdateBuffer(VkCommandBuffer, VkBuffer buffer, PFN_vkVoidFunction VKAPI_CALL mockProc(VkDevice, const char* name) { static const std::map table{ {"vkGetBufferDeviceAddressKHR", reinterpret_cast(mockGetBufferDeviceAddress)}, + {"vkGetMemoryHostPointerPropertiesEXT", reinterpret_cast(mockGetMemoryHostPointerProperties)}, {"vkCreateBuffer", reinterpret_cast(mockCreateBuffer)}, {"vkGetBufferMemoryRequirements", reinterpret_cast(mockGetBufferMemoryRequirements)}, {"vkAllocateMemory", reinterpret_cast(mockAllocateMemory)},