diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp index f654198b8..0770c9d09 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAlu.cpp @@ -94,35 +94,23 @@ uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t value) { } uint32_t EmitF32ToU32(EmitterState& state, uint32_t src, bool signed_value) { - const auto trunc = EmitTruncF32Value(state, src); - const auto converted_raw = state.builder.AllocateId(); - if (signed_value) { - const auto converted_i = state.builder.AllocateId(); - state.builder.AddFunction(spv::OpConvertFToS, TypeI32(state), converted_i, trunc); - state.builder.AddFunction(spv::OpBitcast, TypeU32(state), converted_raw, converted_i); - } else { - state.builder.AddFunction(spv::OpConvertFToU, TypeU32(state), converted_raw, trunc); - } - const auto nan = Unary(state, spv::OpIsNan, TypeBool(state), src); - if (signed_value) { - const auto below = Binary(state, spv::OpFOrdLessThanEqual, TypeBool(state), src, - ConstantF32(state, 0xcf000000u)); - const auto above = Binary(state, spv::OpFOrdGreaterThanEqual, TypeBool(state), src, - ConstantF32(state, 0x4f000000u)); - const auto high = - Select(state, TypeU32(state), above, ConstantU32(state, 0x7fffffffu), converted_raw); - const auto low = - Select(state, TypeU32(state), below, ConstantU32(state, 0x80000000u), high); - return Select(state, TypeU32(state), nan, ConstantU32(state, 0), low); - } - const auto below = - Binary(state, spv::OpFOrdLessThanEqual, TypeBool(state), src, ConstantF32(state, 0)); - const auto above = Binary(state, spv::OpFOrdGreaterThanEqual, TypeBool(state), src, - ConstantF32(state, 0x4f800000u)); - const auto zero = Binary(state, spv::OpLogicalOr, TypeBool(state), nan, below); + // Clamping first keeps the truncating conversion defined; NaN and values past the largest + // float below the integer limit are selected afterwards. + const auto clamped = + EmitExt(state, TypeF32(state), GLSLstd450NClamp, + {src, ConstantF32(state, signed_value ? 0xcf000000u : 0u), + ConstantF32(state, signed_value ? 0x4effffffu : 0x4f7fffffu)}); + const auto converted = signed_value + ? Unary(state, spv::OpBitcast, TypeU32(state), + Unary(state, spv::OpConvertFToS, TypeI32(state), clamped)) + : Unary(state, spv::OpConvertFToU, TypeU32(state), clamped); + const auto above = Binary(state, spv::OpFOrdGreaterThanEqual, TypeBool(state), src, + ConstantF32(state, signed_value ? 0x4f000000u : 0x4f800000u)); const auto high = - Select(state, TypeU32(state), above, ConstantU32(state, 0xffffffffu), converted_raw); - return Select(state, TypeU32(state), zero, ConstantU32(state, 0), high); + Select(state, TypeU32(state), above, + ConstantU32(state, signed_value ? 0x7fffffffu : 0xffffffffu), converted); + return Select(state, TypeU32(state), Unary(state, spv::OpIsNan, TypeBool(state), src), + ConstantU32(state, 0), high); } } // namespace diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h index bc6b7b45e..293ab7098 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h @@ -518,8 +518,6 @@ uint32_t EmitClassMaskF16(EmitterState& state, uint32_t bits, uint32_t mask); uint32_t EmitMinMaxF32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value); -inline constexpr auto EmitTruncF32Value = EmitGlsl; - uint32_t EmitFlushF32DenormToSignedZero(EmitterState& state, uint32_t value); uint32_t EmitTrigCycleF32(EmitterState& state, uint32_t src, bool preserve_signed_zero);