From e393705239a3104846c1a91548e7c1fc9a2f9a38 Mon Sep 17 00:00:00 2001 From: Ondra97 <47064087+Ondra97@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:55:55 +0200 Subject: [PATCH] fix(agc): retire native depth before binding an overlapping layout --- .../Graphics/src/DepthSurface.cpp | 21 ++++------ .../execution/NativeMultisampleDepth.cpp | 40 +++++++++++++++++-- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp index 458af384d52..d5c8909cf30 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp @@ -1963,20 +1963,15 @@ VkImageView DepthSurfaceView(const Context& context, const DepthTarget& target, const bool created = surface == nullptr; GuestAllocations::Lease creationLease; if (created) { - for (const auto& surface : surfaces()) { - if (!surface->active->load(std::memory_order_acquire) || !surface->samplingActive || surface->context.device != context.device) continue; - const auto bytes = target.samples == 1u ? DepthSliceBytes(target.extent, target.format == VK_FORMAT_D16_UNORM ? 2u : 4u) : MultisampledDepthBytes_nid_no_patch(target.extent, target.format == VK_FORMAT_D16_UNORM ? 2u : 4u, target.samples); - Require(target.address <= std::numeric_limits::max() - bytes && target.htileAddress <= std::numeric_limits::max() - HtileMetadataBytes(target.extent), "native depth attachment range overflows"); - for (const auto& range : surface->sampling.initial) { - Require(target.address >= range.address + range.bytes || range.address >= target.address + bytes, "native multisample depth attachment layout or metadata changed"); - if (target.stencilAddress != 0u) { - const auto stencilBytes = target.samples == 1u ? DepthSliceBytes(target.extent, 1u) : MultisampledDepthBytes_nid_no_patch(target.extent, 1u, target.samples); - Require(target.stencilAddress <= std::numeric_limits::max() - stencilBytes && (target.stencilAddress >= range.address + range.bytes || range.address >= target.stencilAddress + stencilBytes), "native multisample stencil attachment aliases a resident depth surface"); - } - if (target.htileAddress != 0u) Require(target.htileAddress >= range.address + range.bytes || range.address >= target.htileAddress + HtileMetadataBytes(target.extent), "native multisample depth attachment layout or metadata changed"); - } - } + const bool d16 = target.format == VK_FORMAT_D16_UNORM || target.format == VK_FORMAT_D16_UNORM_S8_UINT; + const auto depthBytes = target.samples == 1u ? DepthSliceBytes(target.extent, d16 ? 2u : 4u) : MultisampledDepthBytes_nid_no_patch(target.extent, d16 ? 2u : 4u, target.samples); + const auto stencilBytes = target.stencilAddress == 0u ? 0u : target.samples == 1u ? DepthSliceBytes(target.extent, 1u) : MultisampledDepthBytes_nid_no_patch(target.extent, 1u, target.samples); + const auto metadataBytes = target.htileAddress == 0u ? 0u : HtileMetadataBytes(target.extent); + Require(target.address <= std::numeric_limits::max() - depthBytes && target.stencilAddress <= std::numeric_limits::max() - stencilBytes && target.htileAddress <= std::numeric_limits::max() - metadataBytes, "native depth attachment range overflows"); lock.unlock(); + RequireNoResidentDepthRead_nid_no_patch(target.address, static_cast(depthBytes)); + if (stencilBytes != 0u) RequireNoResidentDepthRead_nid_no_patch(target.stencilAddress, static_cast(stencilBytes)); + if (metadataBytes != 0u) RequireNoResidentDepthRead_nid_no_patch(target.htileAddress, static_cast(metadataBytes)); auto sampling = target.samples == 1u ? DepthSamplingState{} : prepareDepthSampling(context, target); creationLease = target.samples == 1u || !sampling.refusal.empty() ? GuestAllocations::Lease{} : GuestAllocations::GuestAllocationsAcquireAll_nid_postfix(); lock.lock(); diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/NativeMultisampleDepth.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/NativeMultisampleDepth.cpp index 641eaf93b0d..460f76f800a 100644 --- a/core/libs/prx/libSceAgcDriver/tests/execution/NativeMultisampleDepth.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/execution/NativeMultisampleDepth.cpp @@ -672,6 +672,39 @@ void CheckDrawFeedback() { std::puts("Native depth feedback refused through the draw resource path; a written surface refused and a depth-tested one retired on guest read"); } +void CheckDepthAttachmentAlias() { + const auto device = OpenVulkanTestDevice(); + Require(device != nullptr, "native depth attachment alias requires Vulkan"); + const auto context = device->graphicsContext(); + constexpr VkExtent2D extent{5u, 3u}; + constexpr std::uint32_t samples = 4u; + const auto bytes = static_cast(MultisampledDepthBytes_nid_no_patch(extent, 4u, samples)); + TargetMemory memory(bytes), firstMetadata(65536u), secondMetadata(65536u); + std::memset(memory.Data(), 0x3c, bytes); + std::memset(firstMetadata.Data(), 0, 65536u); + std::memset(secondMetadata.Data(), 0, 65536u); + struct Cleanup { + AgcDriver::VulkanDevice& device; + ~Cleanup() { device.WaitIdle(); ClearCachedTextures(device.Device()); ClearDepthSurfaces(device.Device()); } + } cleanup{*device}; + DepthTarget first{memory.Address(), 0u, extent, VK_FORMAT_D32_SFLOAT, 0.0f, 0u, firstMetadata.Address(), false, samples}; + first.depthSwizzle = 24u; + first.iterate256 = first.htilePipeAligned = first.htileDepthOnly = true; + const auto firstView = DepthSurfaceView(context, first); + const auto words = DepthSampleWords(first); + auto kept = DepthSurfaceTexture(context, words, DecodeTextureResource(words), VkComponentMapping{}); + Require(kept != nullptr, "attachment alias fixture has no held native depth view"); + auto second = first; + second.extent.width = 6u; + second.htileAddress = secondMetadata.Address(); + Require(MultisampledDepthBytes_nid_no_patch(second.extent, 4u, samples) <= bytes, "attachment alias fixture exceeds its backing"); + const auto secondView = DepthSurfaceView(context, second); + Require(secondView != VK_NULL_HANDLE && secondView != firstView, "an aliased depth attachment reused the previous layout's view"); + Require(DepthSurfaceView(context, second) == secondView, "an unchanged native depth attachment was not reused"); + for (std::size_t offset = 0u; offset < bytes; ++offset) Require(memory.Data()[offset] == std::byte{0x3c}, "retiring an unwritten attachment alias changed guest bytes"); + std::puts("native depth attachment alias changes layout while retaining held GPU views"); +} + enum class ClearFault { None, PartialStore, CpuWrite, DepthWrite, BadMetadata, UnprovenDispatch, PendingWrite, Overlap, PossibleStore, CompletedPossibleStore, DriverDispatch, ImportWindowWrite }; void CheckClearDispatch() { @@ -927,10 +960,10 @@ void CheckDepthTarget(Context context, VkFormat format, std::uint32_t fragments, Require(probe[0] == std::byte{0xa5}, "resident depth guard blocked an unrelated read"); auto alias = target; alias.htileAddress += 65536u; - TargetRefuses([&] { DepthSurfaceView(context, alias); }, "layout or metadata changed"); + TargetRefuses([&] { DepthSurfaceView(context, alias); }, "sample-preserving guest publication"); alias = target; alias.htileDepthOnly = !target.htileDepthOnly; - TargetRefuses([&] { DepthSurfaceView(context, alias); }, "layout or metadata changed"); + TargetRefuses([&] { DepthSurfaceView(context, alias); }, "sample-preserving guest publication"); auto resource = DecodeTextureResource(words); for (std::uint32_t field = 0u; field < 18u; ++field) { auto changed = resource; @@ -1042,7 +1075,7 @@ void CheckHtileRouting(Context context, VkFormat format, std::uint32_t fragments auto alias = target; alias.samples = 1u; alias.address = single.Address(); - TargetRefuses([&] { DepthSurfaceView(context, alias); }, "layout or metadata changed"); + Require(DepthSurfaceView(context, alias) != VK_NULL_HANDLE, "a single-sample bind could not retire an unwritten native HTILE owner"); Require(untouched(), "a single-sample bind over a native owner's HTILE stored expanded words into it"); std::printf("Native depth format=%u samples=%u: binds over the owner's HTILE left its words alone\n", static_cast(format), fragments); } @@ -1304,6 +1337,7 @@ int main(int argc, char** argv) { } CheckDrawFeedback(); const auto context = device->GetContext(); + if (argc == 1) CheckDepthAttachmentAlias(); std::unique_lock lock(AgcDriver::GuestMemory::GpuMutex()); Require(DepthSupported(context, VK_FORMAT_D32_SFLOAT, 4u), "the native depth regression requires sampled D32 with four samples"); if (argc == 2 && std::string_view(argv[1]) == "--clear-refusals") {