From e5e02c0908bcdc679d8210acca838748c4335417 Mon Sep 17 00:00:00 2001 From: kuba Date: Fri, 31 Jul 2026 11:09:50 +0200 Subject: [PATCH] Shader: implement V_BFE_I32 and correct VOP3 0x36A mapping (#714) * Implement VOP3 0x149 V_BFE_I32 and 0x36A V_CVT_PKRTZ_F16_F32 PPSA10112 dropped three shaders per run on two unimplemented VOP3 opcodes. The translator fails a whole shader on an opcode it does not know, so each one costs a dropped draw rather than wrong pixels. 0x149 sits between 0x148 V_BFE_U32 and 0x14A V_BFI_B32, and 0x36A between 0x369 V_CVT_PKNORM_U16_F32 and 0x36D V_ADD3_U32; the surrounding table entries already match the canonical map densely on both sides of each gap. V_CVT_PKRTZ_F16_F32 needed no emitter - it was already implemented for the VOP2 form at 0x2F and its VOP3 alias at 0x12F, and only the VOP3-only opcode number was missing. V_BFE_I32 mirrors its unsigned sibling, masking offset and width to 5 bits, and differs only in extracting through a signed type so the field sign-extends. GCN defines width 0 as returning 0 where SPIR-V leaves a zero Count unspecified; VBfeU32 has the same gap, so this matches it deliberately rather than diverging - fix both together if it matters. Also widen ReportGuestPointerSplit, which filtered to an incoming value of exactly 1. The crash being hunted leaves 0x0000007000000000, whose low dword is 0, so the one detector built to catch this bug class could never have reported it. Verified: unsupported-opcode errors 3-4 per run -> 0, over a 130s run that survives to the same stage. Metal translator still lacks VBfeI32; Vulkan/MoltenVK is the macOS path so it is a divergence, not a blocker. * Correct VOP3 0x36A: V_CVT_PK_U16_U32, not V_CVT_PKRTZ_F16_F32 a2d186e mapped 0x36A to V_CVT_PKRTZ_F16_F32 on the strength of a gap in our own opcode table. That was wrong, and wrong in the worst available way: an emitter for V_CVT_PKRTZ_F16_F32 already existed, so instead of failing loudly like an unknown opcode, the mapping would have emitted float-pack semantics for an integer-pack instruction and produced silently incorrect results. LLVM is unambiguous: defm V_CVT_PK_U16_U32 : VOP3Only_Real_gfx10<0x36a>; defm V_CVT_PKRTZ_F16_F32 : VOP2_Real_gfx6_gfx7_gfx10<0x02f>; so on Gen5 the float pack is VOP2 0x2F with VOP3 alias 0x12F - both of which our table already had - and there is no VOP3-only encoding of it to add. 0x36A sits with the other integer/normalised pack conversions at 0x368/0x369/0x36B. silent-hill-minimal-rebased had this right all along. The V_BFE_I32 half of a2d186e stands: LLVM confirms 0x149, and that branch maps it identically. Lesson, since I had just warned someone else about exactly this: a gap in a table is evidence about numbering, not about identity. Inference from neighbouring entries is fine for narrowing candidates and worth nothing as a conclusion - especially when a plausible emitter already exists to swallow the mistake quietly. --- .../Gen5SpirvTranslator.Alu.cs | 16 ++++++++++++++++ .../Gen5ShaderTranslator.cs | 2 ++ 2 files changed, 18 insertions(+) diff --git a/src/SharpEmu.ShaderCompiler.Vulkan/Gen5SpirvTranslator.Alu.cs b/src/SharpEmu.ShaderCompiler.Vulkan/Gen5SpirvTranslator.Alu.cs index 6c692696..82ec4cd3 100644 --- a/src/SharpEmu.ShaderCompiler.Vulkan/Gen5SpirvTranslator.Alu.cs +++ b/src/SharpEmu.ShaderCompiler.Vulkan/Gen5SpirvTranslator.Alu.cs @@ -903,6 +903,22 @@ public static partial class Gen5SpirvTranslator width); break; } + case "VBfeI32": + { + // Same extract as VBfeU32 but sign-extended from the top bit + // of the extracted field, so the result type must be signed + // and bitcast back for storage. + var width = BitwiseAnd(GetRawSource(instruction, 2), UInt(31)); + result = Bitcast( + _uintType, + _module.AddInstruction( + SpirvOp.BitFieldSExtract, + _intType, + Bitcast(_intType, GetRawSource(instruction, 0)), + BitwiseAnd(GetRawSource(instruction, 1), UInt(31)), + width)); + break; + } case "VBfiB32": { var mask = GetRawSource(instruction, 0); diff --git a/src/SharpEmu.ShaderCompiler/Gen5ShaderTranslator.cs b/src/SharpEmu.ShaderCompiler/Gen5ShaderTranslator.cs index f81a0dbe..4e1478a4 100644 --- a/src/SharpEmu.ShaderCompiler/Gen5ShaderTranslator.cs +++ b/src/SharpEmu.ShaderCompiler/Gen5ShaderTranslator.cs @@ -1157,6 +1157,7 @@ public static class Gen5ShaderTranslator 0x15D => "VSadU32", 0x15E => "VCvtPkU8F32", 0x148 => "VBfeU32", + 0x149 => "VBfeI32", 0x169 => "VMulLoU32", 0x16A => "VMulHiU32", 0x16B => "VMulLoI32", @@ -1170,6 +1171,7 @@ public static class Gen5ShaderTranslator 0x366 => "VMbcntHiU32B32", 0x368 => "VCvtPknormI16F32", 0x369 => "VCvtPknormU16F32", + 0x36A => "VCvtPkU16U32", 0x373 => "VMadU32U16", 0x346 => "VLshlAddU32", 0x347 => "VAddLshlU32",