From 6b480cc2be64f326537d78321d21ce4f97ecc48d Mon Sep 17 00:00:00 2001 From: Gustavo Ariel Gamarra Rojas <111788638+GustavoGamarra95@users.noreply.github.com> Date: Tue, 13 Oct 2026 16:11:47 -0300 Subject: [PATCH] fix(agc): copy a depth surface's plane through the texture's padded linear slices The plane copy laid its staging buffer out as tight slices while the detiler writes the guest's linear layout, which pads rows and slices: a 32x32 D16 cube in a 64 KiB swizzle has 16384-byte slices, not 2048, and a 128x128 one has 512-byte rows and 64 KiB slices. Each region in record now takes the layer's LinearLayerOffset plus the mip's linear offset and its pitch as the row length, for both the slices copied from a live depth surface and the ones detiled from guest memory. The staging buffer grows to the padded size, keeping the buffer it replaces alive for copies already recorded, and a mismatch says which geometry it saw. --- .../Graphics/src/DepthSurface.cpp | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp index ce18ed4384..a16d0d64c4 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp @@ -316,7 +316,8 @@ public: allocation.memoryTypeIndex = context.MemoryType(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); Check(context.Function("vkAllocateMemory")(context.device, &allocation, nullptr, &memory), "vkAllocateMemory depth plane copy"); Check(context.Function("vkBindImageMemory")(context.device, image, memory, 0), "vkBindImageMemory depth plane copy"); - staging = std::make_unique(context, static_cast(sliceBytes()) * layers, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + stagingSize = static_cast(sliceBytes()) * layers; + staging = std::make_unique(context, stagingSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); } catch (...) { release(); throw; @@ -329,7 +330,17 @@ public: std::shared_ptr Refresh(std::span slices, const GuestTextureResource& resource, VkComponentMapping components, VkImageViewType viewType, std::uint32_t baseLayer) { Require(slices.size() == layers, "depth plane copy slices do not match its layers"); const auto geometry = DescribeSurface(resource); - Require(geometry.layers == layers && geometry.sliceLinearBytes == sliceBytes() && !geometry.mips.empty(), "depth plane copy geometry does not match its layers"); + if (geometry.layers != layers || geometry.sliceLinearBytes < sliceBytes() || geometry.mips.empty()) { + char text[320]; + std::snprintf(text, sizeof(text), "AGC graphics: depth plane copy geometry does not match its layers (copy %ux%u, %u layers, %llu bytes a slice; texture %ux%u guest format %u, dimension %d, tile mode %u, %u layers, %llu bytes a slice, %zu mips)", extent.width, extent.height, layers, static_cast(sliceBytes()), resource.width, resource.height, resource.format, static_cast(resource.dimension), resource.tileMode, geometry.layers, static_cast(geometry.sliceLinearBytes), geometry.mips.size()); + throw std::runtime_error(text); + } + const auto stagingBytes = static_cast(geometry.sliceLinearBytes) * layers; + if (stagingBytes > stagingSize) { + retiredStaging.push_back(std::move(staging)); + staging = std::make_unique(context, stagingBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + stagingSize = stagingBytes; + } std::vector> uploads; std::vector uploadLayers; std::vector copiedLayers; @@ -382,6 +393,8 @@ private: VkImage image = VK_NULL_HANDLE; VkDeviceMemory memory = VK_NULL_HANDLE; std::unique_ptr staging; + std::size_t stagingSize = 0; + std::vector> retiredStaging; std::map, std::shared_ptr> textures; std::vector guestLayers; std::vector surfaceLayers; @@ -399,9 +412,11 @@ private: const auto barrier = context.Resolved(&DeviceFunctions::cmdPipelineBarrier, "vkCmdPipelineBarrier"); RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT); std::vector regions; + const auto& mip = geometry.mips.front(); const auto region = [&](std::uint32_t layer, VkImageAspectFlags aspectMask, std::uint32_t imageLayer) { VkBufferImageCopy copy{}; - copy.bufferOffset = sliceBytes() * layer; + copy.bufferOffset = geometry.LinearLayerOffset(layer) + mip.linearOffset; + copy.bufferRowLength = mip.pitchBytes / (format == VK_FORMAT_D32_SFLOAT ? 4u : 2u); copy.imageSubresource = {aspectMask, 0, imageLayer, 1}; copy.imageExtent = {extent.width, extent.height, 1}; return copy;