diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index f42151415..635223814 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -527,8 +527,8 @@ constexpr Vop1SdwaRule VOP1_SDWA_RULES[] = { {Opcode::V_CVT_F32_F16, SdwaSelWords() | SdwaSelFull(), 0, 0, true}, {Opcode::V_CVT_F16_F32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), SdwaSelWords(), SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), true}, - {Opcode::V_CVT_F16_U16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords(), - SdwaSelWords() | SdwaSelFull(), false}, + {Opcode::V_CVT_F16_U16, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), SdwaSelWords(), + SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), false}, {Opcode::V_CVT_U16_F16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords(), SdwaSelWords() | SdwaSelFull(), true}, {Opcode::V_CVT_F16_I16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords(), @@ -618,13 +618,14 @@ bool SupportsVop1Clamp(Opcode opcode) { } bool ValidateVop1Sdwa(Instruction& inst, uint32_t opcode, uint32_t modifier) { - const auto dst_sel = (modifier >> 8u) & 0x7u; - const auto dst_u = (modifier >> 11u) & 0x3u; - const auto clamp = (modifier >> 13u) & 0x1u; - const auto omod = (modifier >> 14u) & 0x3u; - const auto src0_sel = (modifier >> 16u) & 0x7u; - const auto src0_neg = (modifier >> 20u) & 0x1u; - const auto src0_abs = (modifier >> 21u) & 0x1u; + const auto dst_sel = (modifier >> 8u) & 0x7u; + const auto dst_u = (modifier >> 11u) & 0x3u; + const auto clamp = (modifier >> 13u) & 0x1u; + const auto omod = (modifier >> 14u) & 0x3u; + const auto src0_sel = (modifier >> 16u) & 0x7u; + const auto src0_sext = (modifier >> 19u) & 0x1u; + const auto src0_neg = (modifier >> 20u) & 0x1u; + const auto src0_abs = (modifier >> 21u) & 0x1u; if (src0_sel > 6u || dst_sel > 6u) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 SDWA selector is invalid"); @@ -640,7 +641,8 @@ bool ValidateVop1Sdwa(Instruction& inst, uint32_t opcode, uint32_t modifier) { "VOP1 SDWA destination selector is not supported"); return false; } - if (!IsVop1SdwaSourceSupported(inst.opcode, src0_sel, src0_neg != 0u, src0_abs != 0u)) { + if (!IsVop1SdwaSourceSupported(inst.opcode, src0_sel, src0_neg != 0u, src0_abs != 0u) || + (inst.opcode == Opcode::V_CVT_F16_U16 && src0_sel <= 3u && src0_sext != 0u)) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 SDWA source selector is not supported"); return false; } diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 6e7d418a5..580cb89d4 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -19624,6 +19624,33 @@ TestCase VectorMinMaxF16Ops() { O::S_ENDPGM}}; } +TestCase VectorCvtF16U16CapturedByteSource() { + using O = ShaderOpcode; + + constexpr std::array inputs = {0xff123456u, 0x80123456u, 0x00123456u}; + std::vector code; + AppendVMovLiteral(&code, 16, 0xa5a55a5au); + for (u32 i = 0; i < inputs.size(); i++) { + AppendVMovU32(&code, 30, i * 4u); + AppendBufferLoadDword(&code, 18, 30); + // Captured shader 0x15082e211725205f: unsigned byte3 -> FP16 word0, + // preserving word1 of v16. + code.insert(code.end(), {0x7e20a0f9u, 0x00031412u}); + AppendStoreVgpr(&code, 16, i); + } + AppendEnd(&code); + + TestCase test; + test.name = "VectorCvtF16U16CapturedByteSource"; + test.code = std::move(code); + test.initial.assign(inputs.begin(), inputs.end()); + test.expected = {0xa5a55bf8u, 0xa5a55800u, 0xa5a50000u}; + test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_CVT_F16_U16, + O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + test.required_spirv = {"OpBitFieldUExtract", "OpConvertUToF"}; + return test; +} + TestCase VectorCvtU16F16Sdwa() { using O = ShaderOpcode; @@ -27458,6 +27485,7 @@ std::vector MakeCases() { AddCase(CvtPkrtzF16F32SdwaAndOutputModifiers); AddCase(PackedMinMaxF16NanAndSignedZeroEdges); AddCase(VectorMinMaxF16Ops); + AddCase(VectorCvtF16U16CapturedByteSource); AddCase(VectorCvtU16F16Sdwa); AddCase(NativeAndSdwa16BitDestinationWrites); AddCase(VectorMinMaxMed3F16Ops); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 5f5670222..8ee408f84 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -3466,6 +3466,13 @@ void TestNewShaderRecompilerCapturedVop1SdwaByteConvert() { Check(SpirvContainsOpcode(result.spirv, 112), "captured SDWA byte conversion did not emit OpConvertUToF"); CheckSpirvBinaryValidates(result.spirv); + + const uint32_t byte_sext[] = {0x7e20a0f9u, 0x000b1412u}; + ShaderRecompiler::Decoder::Instruction decoded; + ShaderRecompiler::Decoder::DecodeInstruction(byte_sext, 0, decoded); + Check(decoded.word_count == 2u && + decoded.opcode == ShaderRecompiler::Decoder::Opcode::UNSUPPORTED, + "V_CVT_F16_U16 accepted unimplemented SDWA byte sign extension"); } void TestNewShaderRecompilerVop1SdwaNotDestination() {