[SpirvTranslator] Match guest F32 denormal and trigonometric semantics

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>
This commit is contained in:
ParantezTech 2026-10-08 17:26:59 +03:00
parent c566dba5a1
commit b368247d64
2 changed files with 126 additions and 6 deletions

View File

@ -442,6 +442,15 @@ public static partial class Gen5SpirvTranslator
break;
}
case "VRcpF32":
result = EmitFloatResult(
instruction,
_module.AddInstruction(
SpirvOp.FDiv,
_floatType,
Float(1),
EmitFlushF32DenormToSignedZero(
GetFloatSource(instruction, 0))));
break;
case "VRcpIflagF32":
result = EmitFloatResult(
instruction,
@ -454,7 +463,11 @@ public static partial class Gen5SpirvTranslator
case "VLogF32":
result = EmitFloatResult(
instruction,
Ext(30, _floatType, GetFloatSource(instruction, 0)));
Ext(
30,
_floatType,
EmitFlushF32DenormToSignedZero(
GetFloatSource(instruction, 0))));
break;
case "VLdexpF32":
result = EmitFloatResult(
@ -468,12 +481,20 @@ public static partial class Gen5SpirvTranslator
case "VExpF32":
result = EmitFloatResult(
instruction,
Ext(29, _floatType, GetFloatSource(instruction, 0)));
Ext(
29,
_floatType,
EmitFlushF32DenormToSignedZero(
GetFloatSource(instruction, 0))));
break;
case "VRsqF32":
result = EmitFloatResult(
instruction,
Ext(32, _floatType, GetFloatSource(instruction, 0)));
Ext(
32,
_floatType,
EmitFlushF32DenormToSignedZero(
GetFloatSource(instruction, 0))));
break;
case "VRcpF16":
result = EmitFloat16Result(instruction, destination, _module.AddInstruction(SpirvOp.FDiv, _floatType, Float(1), GetFloat16Source(instruction, 0)));
@ -542,7 +563,11 @@ public static partial class Gen5SpirvTranslator
case "VSqrtF32":
result = EmitFloatResult(
instruction,
Ext(31, _floatType, GetFloatSource(instruction, 0)));
Ext(
31,
_floatType,
EmitFlushF32DenormToSignedZero(
GetFloatSource(instruction, 0))));
break;
case "VSinF32":
result = EmitFloatResult(
@ -553,7 +578,9 @@ public static partial class Gen5SpirvTranslator
_module.AddInstruction(
SpirvOp.FMul,
_floatType,
GetFloatSource(instruction, 0),
EmitTrigCycleF32(
GetFloatSource(instruction, 0),
preserveSignedZero: true),
Float(MathF.Tau))));
break;
case "VCosF32":
@ -565,7 +592,9 @@ public static partial class Gen5SpirvTranslator
_module.AddInstruction(
SpirvOp.FMul,
_floatType,
GetFloatSource(instruction, 0),
EmitTrigCycleF32(
GetFloatSource(instruction, 0),
preserveSignedZero: false),
Float(MathF.Tau))));
break;
case "VAddF32":

View File

@ -0,0 +1,91 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
namespace SharpEmu.ShaderCompiler.Vulkan;
public static partial class Gen5SpirvTranslator
{
private sealed partial class CompilationContext
{
private uint EmitFlushF32DenormToSignedZero(uint value)
{
var bits = Bitcast(_uintType, value);
var absolute = _module.AddInstruction(
SpirvOp.BitwiseAnd,
_uintType,
bits,
UInt(0x7FFF_FFFF));
var sign = _module.AddInstruction(
SpirvOp.BitwiseAnd,
_uintType,
bits,
UInt(0x8000_0000));
var nonZero = IsNotZero(absolute);
var subnormal = _module.AddInstruction(
SpirvOp.ULessThan,
_boolType,
absolute,
UInt(0x0080_0000));
var flush = _module.AddInstruction(
SpirvOp.LogicalAnd,
_boolType,
nonZero,
subnormal);
var selected = _module.AddInstruction(
SpirvOp.Select,
_uintType,
flush,
sign,
bits);
return Bitcast(_floatType, selected);
}
private uint EmitTrigCycleF32(uint source, bool preserveSignedZero)
{
var fraction = Ext(10, _floatType, source);
var bits = Bitcast(_uintType, source);
var absolute = _module.AddInstruction(
SpirvOp.BitwiseAnd,
_uintType,
bits,
UInt(0x7FFF_FFFF));
var large = _module.AddInstruction(
SpirvOp.UGreaterThanEqual,
_boolType,
absolute,
UInt(0x4B00_0000));
var finite = _module.AddInstruction(
SpirvOp.ULessThan,
_boolType,
absolute,
UInt(0x7F80_0000));
var largeFinite = _module.AddInstruction(
SpirvOp.LogicalAnd,
_boolType,
large,
finite);
var reduced = _module.AddInstruction(
SpirvOp.Select,
_floatType,
largeFinite,
Float(0),
fraction);
if (!preserveSignedZero)
{
return reduced;
}
var zero = _module.AddInstruction(
SpirvOp.IEqual,
_boolType,
absolute,
UInt(0));
return _module.AddInstruction(
SpirvOp.Select,
_floatType,
zero,
source,
reduced);
}
}
}