From 4309bffdb0d704a6ea97bd2842772816b5722e5f Mon Sep 17 00:00:00 2001 From: AlxcBTW <187763517+AlxcBTW@users.noreply.github.com> Date: Mon, 12 Oct 2026 17:09:31 +0200 Subject: [PATCH] fix(agc): take the dword pattern-fill kernel only through a 32-bit output format The kernel #2081 matches stores each pattern dword with buffer_store_format_x, so what lands in memory depends on the output descriptor's FORMAT (bits 12-18 of user[3]). Only 32_UINT, 32_SINT and 32_FLOAT (20-22) store the dword unchanged. Other formats convert it, and an 8- or 16-bit one writes 1 or 2 bytes of every 4-byte element, so a buffer fill would also overwrite the bytes in between. Such a dispatch now goes to the recompiler. Co-Authored-By: Claude Opus 5.5 --- .../Execution/src/Driver/Memory/BufferFill.cpp | 3 ++- .../libSceAgcDriver/tests/execution/DwordPatternFill.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Memory/BufferFill.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Memory/BufferFill.cpp index b8e7adb77..d947ec51e 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Memory/BufferFill.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Memory/BufferFill.cpp @@ -49,8 +49,9 @@ std::optional MatchDwordPatternFill(std::span> 31u) & 1u) != 0; const bool addTid = ((userData[3] >> 23u) & 1u) != 0; const auto type = userData[3] >> 30u; + const auto format = (userData[3] >> 12u) & 0x7fu; const auto period = userData[9]; - if (type != 0 || stride != 4 || swizzled || addTid || (period != 1u && period != 2u && period != 4u) || (packet[4] & 0x20u) != 0 || packet[2] != 1 || packet[3] != 1) return std::nullopt; + if (type != 0 || stride != 4 || swizzled || addTid || format < 20u || format > 22u || (period != 1u && period != 2u && period != 4u) || (packet[4] & 0x20u) != 0 || packet[2] != 1 || packet[3] != 1) return std::nullopt; const auto dwords = std::min({static_cast(packet[1]) * 64u, userData[8], userData[2]}); const auto base = userData[0] | (static_cast(userData[1] & 0xffffu) << 32u); if (dwords == 0 || dwords % 4u != 0 || base % 16u != 0) return std::nullopt; diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/DwordPatternFill.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/DwordPatternFill.cpp index 9c0191c6f..1629b1645 100644 --- a/core/libs/prx/libSceAgcDriver/tests/execution/DwordPatternFill.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/execution/DwordPatternFill.cpp @@ -55,6 +55,12 @@ void MatchTests() { Require(!MatchDwordPatternFill(packet, Code, UserData(Output.data(), 1024, 250, 4), compute), "a count of whole dwords not filling 16-byte units matched"); Require(!MatchDwordPatternFill(packet, Code, UserData(Output.data() + 1, 1024, 256, 4), compute), "an unaligned destination matched"); Require(!MatchDwordPatternFill(packet, Code, UserData(Output.data(), 1024, 256, 4, 0x00814004u), compute), "an add-tid descriptor matched"); + for (const std::uint32_t format : {0x00015004u, 0x00016004u}) { + Require(MatchDwordPatternFill(packet, Code, UserData(Output.data(), 1024, 256, 4, format), compute).has_value(), "a 32-bit output format was refused"); + } + for (const std::uint32_t format : {0x00005004u, 0x0000b004u, 0x0000d004u, 0x0001b004u, 0x00027facu, 0x0004b004u}) { + Require(!MatchDwordPatternFill(packet, Code, UserData(Output.data(), 1024, 256, 4, format), compute), "an output format whose elements are not one 32-bit value matched"); + } auto extra = data; extra.push_back(0); Require(!MatchDwordPatternFill(packet, Code, extra, compute), "a different user SGPR count matched (the group id moves)");