mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
fix(shader): decode the high-half result of v_interp_p2_f16
Forspoken (PPSA03984) has a pixel shader with v_interp_p2_f16 v1, ..., v7 op_sel:[0,0,0,1], and main throws "VOP3 interpolation modifiers are not implemented" one second after start. On GFX10, op_sel[3] of a 16-bit VOP3 result selects the high half of the destination and keeps the other half. The decoder already maps that bit to destination.sdwaSel 5 for the other 16-bit VOP3 ops, and write16Bits/writeRawU32 then insert the result into bits 31:16 and keep bits 15:0. v_interp_p2_f16 is the only 16-bit-result interpolation instruction, so only it accepts the bit; other op_sel bits and the bit on the 32-bit-result p1ll/p1lv forms are still refused. agc_vop3_interp_decode checks the decoded selector with and without the bit, and that v_interp_p1ll_f16 still refuses it. In agc_driver_interpolation_f16 the second v_interp_p2_f16 now writes the high half of a register holding 0x00001234, and the GPU result must keep 0x1234 in the low half. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0aa4cb1c2f
commit
2265e8b1cd
3 files changed
+22
-3
No files matched your search
@@ -61,6 +61,7 @@ int main() {
|
||||
{{0xd6000005u, 0x02020500u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with the packed-half selector"},
|
||||
{{0xd6000105u, 0x02020400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with an absolute source 0"},
|
||||
{{0xd6020005u, 0x22000200u}, "modifiers are not implemented", "v_interp_mov_f32_e64 with a negated parameter"},
|
||||
{{0xd7424005u, 0x00020201u}, "modifiers are not implemented", "v_interp_p1ll_f16 with the high-half destination selector"},
|
||||
};
|
||||
int failures = 0;
|
||||
for (const auto& test : accepted) {
|
||||
@@ -104,5 +105,21 @@ int main() {
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
for (const std::uint32_t selector : {0x0u, 0x4000u}) {
|
||||
const std::vector<std::uint32_t> code{0xd75a0005u | selector, 0x041e0201u, 0xbf810000u};
|
||||
try {
|
||||
const auto decoded = RdnaInstructionDecoder{}.Decode(code);
|
||||
const auto& instruction = decoded.instructions.at(0);
|
||||
const std::uint32_t half = selector != 0u ? 5u : 6u;
|
||||
if (instruction.op != RdnaOpcode::VInterpP2F16 || instruction.destination.reg != Destination || instruction.destination.sdwaSel != half ||
|
||||
instruction.sourceCount != 4u || instruction.source0.reg != 1u || instruction.source1.value != 1u || instruction.source3.reg != 7u) {
|
||||
std::fprintf(stderr, "v_interp_p2_f16 v5, v1, attr1.x, v7%s decoded to the wrong opcode or operands\n", selector != 0u ? " op_sel:[0,0,0,1]" : "");
|
||||
++failures;
|
||||
}
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "v_interp_p2_f16 v5, v1, attr1.x, v7%s was refused: %s\n", selector != 0u ? " op_sel:[0,0,0,1]" : "", error.what());
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
return failures == 0 ? 0 : 1;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ alignas(256) constexpr std::array<std::uint32_t, 10> VertexCode{
|
||||
alignas(256) constexpr std::array<std::uint32_t, 47> PixelCode{
|
||||
0x7e080f02u, 0x7e0a0f03u, 0xd5430006u, 0x0411ff05u, 0x000000c0u, 0x7e300300u, 0x7e320301u, 0xd742001au,
|
||||
0x00020000u, 0x7e3602ffu, 0xabcd0000u, 0xd75a001bu, 0x046a0200u, 0xd7420008u, 0x00020100u, 0x7e3802ffu,
|
||||
0x12340000u, 0xd75a001cu, 0x04220300u, 0x7e1e02ffu, 0x4500bc00u, 0xd743001du, 0x043e0140u, 0x7e3c0280u,
|
||||
0x00001234u, 0xd75a401cu, 0x04220300u, 0x7e1e02ffu, 0x4500bc00u, 0xd743001du, 0x043e0140u, 0x7e3c0280u,
|
||||
0xd75a001eu, 0x04760340u, 0x7e3e0280u, 0xd75a801fu, 0x046a0200u, 0xd7420020u, 0x00020181u, 0xd7420021u,
|
||||
0x000201c1u, 0xd7420022u, 0x40020000u, 0xd7430023u, 0x043e0000u, 0xe0782000u, 0x80011806u, 0xe0782010u,
|
||||
0x80011c06u, 0xe0782020u, 0x80012006u, 0x7e0e02f2u, 0xf800180fu, 0x07070707u, 0xbf810000u,
|
||||
@@ -235,7 +235,7 @@ void Check(std::uint32_t waveSize) {
|
||||
result[1],
|
||||
std::bit_cast<std::uint32_t>(lowX),
|
||||
0xabcd0000u | HalfOf(SecondStep(Delta(LowX, 2), j, lowX)),
|
||||
0x12340000u | HalfOf(SecondStep(Delta(HighX, 2), j, highX)),
|
||||
0x1234u | (HalfOf(SecondStep(Delta(HighX, 2), j, highX)) << 16u),
|
||||
std::bit_cast<std::uint32_t>(highY),
|
||||
HalfOf(SecondStep(Delta(HighY, 2), j, highY)),
|
||||
HalfOf(Saturate(SecondStep(Delta(LowX, 2), j, lowX))),
|
||||
|
||||
@@ -2090,7 +2090,8 @@ bool isVop3F16InterpolationOpcode(RdnaOpcode opcode) {
|
||||
void decodeVop3F16Interpolation(RdnaInstruction& instruction, std::uint32_t vdst, std::uint32_t src0, std::uint32_t src1, std::uint32_t src2, std::uint32_t abs, std::uint32_t opSel, std::uint32_t clamp, std::uint32_t omod, std::uint32_t neg) {
|
||||
const bool hasSource2 = instruction.op != RdnaOpcode::VInterpP1llF16;
|
||||
const bool f16Result = instruction.op == RdnaOpcode::VInterpP2F16;
|
||||
if ((abs & 0x1u) != 0u || (neg & 0x1u) != 0u || opSel != 0u || (f16Result && omod != 0u) || (!hasSource2 && ((abs | neg) & 0x4u) != 0u)) {
|
||||
const std::uint32_t resultHalf = f16Result ? 0x8u : 0x0u;
|
||||
if ((abs & 0x1u) != 0u || (neg & 0x1u) != 0u || (opSel & ~resultHalf) != 0u || (f16Result && omod != 0u) || (!hasSource2 && ((abs | neg) & 0x4u) != 0u)) {
|
||||
throw std::invalid_argument("VOP3 interpolation modifiers are not implemented");
|
||||
}
|
||||
if (src1 < 256u || (hasSource2 && src2 < 256u)) {
|
||||
@@ -2100,6 +2101,7 @@ void decodeVop3F16Interpolation(RdnaInstruction& instruction, std::uint32_t vdst
|
||||
instruction.destination = DecodeRdnaVectorGpr(vdst);
|
||||
instruction.destination.clamp = clamp != 0u;
|
||||
instruction.destination.omod = omod;
|
||||
if ((opSel & resultHalf) != 0u) instruction.destination.sdwaSel = 5u;
|
||||
instruction.source0 = DecodeRdnaVectorGpr(src1 - 256u);
|
||||
instruction.source0.absolute = (abs & 0x2u) != 0u;
|
||||
instruction.source0.negate = (neg & 0x2u) != 0u;
|
||||
|
||||
Reference in new issue
Block a user