From 3a842e1a6b5c2f5d46df64da4557ad707ac408b8 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 21 Oct 2026 23:33:42 +0200 Subject: [PATCH] shader: flush FP32 denormals with a float compare and multiply instead of bit masks --- .../backend/spirv/spirvEmitterAluHelpers.cpp | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp index ce9635fba..1f91231a8 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAluHelpers.cpp @@ -150,22 +150,14 @@ uint32_t EmitFPMedTri32(EmitterState& state, uint32_t a, uint32_t b, uint32_t c) } uint32_t EmitFlushF32DenormToSignedZero(EmitterState& state, uint32_t value) { - const auto bits = state.builder.AllocateId(); - const auto abs_bits = state.builder.AllocateId(); - const auto sign_bits = state.builder.AllocateId(); - const auto subnormal = state.builder.AllocateId(); - const auto selected = state.builder.AllocateId(); - const auto ret = state.builder.AllocateId(); - state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, value); - state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), abs_bits, bits, - ConstantU32(state, 0x7fffffffu)); - state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), sign_bits, bits, - ConstantU32(state, 0x80000000u)); - state.builder.AddFunction(spv::OpULessThan, TypeBool(state), subnormal, abs_bits, - ConstantU32(state, 0x00800000u)); - state.builder.AddFunction(spv::OpSelect, TypeU32(state), selected, subnormal, sign_bits, bits); - state.builder.AddFunction(spv::OpBitcast, TypeF32(state), ret, selected); - return ret; + // x * 0 keeps the sign of a denormal; NaN and infinity fail the ordered compare. + const auto magnitude = state.builder.AllocateId(); + state.builder.AddFunction(spv::OpExtInst, TypeF32(state), magnitude, GlslStd450(state), + GLSLstd450FAbs, value); + const auto denormal = Binary(state, spv::OpFOrdLessThan, TypeBool(state), magnitude, + ConstantF32(state, 0x00800000u)); + return Select(state, TypeF32(state), denormal, + Binary(state, spv::OpFMul, TypeF32(state), value, ConstantF32(state, 0)), value); } uint32_t EmitTrigCycleF32(EmitterState& state, uint32_t src, bool preserve_signed_zero) {