mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
fix(shader): give an exact zero mix f16 sum -0 when rounding toward -infinity
With f16 rounding toward -infinity, v_fma_mixlo_f16 and v_fma_mixhi_f16 gave +0 for an exact cancellation such as 1.0 * 1.0 + -1.0, because the f64 sum is computed to nearest. RDNA2 gives -0 there, as IEEE 754 does for an exact zero sum rounded toward -infinity, measured on gfx1036 in #2631. An exact zero sum now gives -0 in that mode unless both the product and the addend are +0. A nonzero result that rounds to zero keeps its sign, so a tiny positive sum still gives +0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f22b9fa02a
commit
bc517d6058
2 files changed
+16
-1
No files matched your search
@@ -121,7 +121,7 @@ struct DirectedRow {
|
||||
std::array<std::uint32_t, 4> expected;
|
||||
};
|
||||
|
||||
constexpr std::array<DirectedRow, 10> DirectedRows{{
|
||||
constexpr std::array<DirectedRow, 16> DirectedRows{{
|
||||
{0xbfc00000u, 0x33800000u, 0x00800000u, {0x8001u, 0x8001u, 0x8002u, 0x8001u}},
|
||||
{0x3fc00000u, 0x33800000u, 0x00800000u, {0x0002u, 0x0002u, 0x0001u, 0x0001u}},
|
||||
{0x3f800000u, 0x3f801400u, 0x00000000u, {0x3c01u, 0x3c01u, 0x3c00u, 0x3c00u}},
|
||||
@@ -132,6 +132,12 @@ constexpr std::array<DirectedRow, 10> DirectedRows{{
|
||||
{0x3fc00000u, 0x40000000u, 0x3e800000u, {0x4280u, 0x4280u, 0x4280u, 0x4280u}},
|
||||
{0x3f800000u, 0x3f800000u, 0xbf7fffffu, {0x0001u, 0x0001u, 0x0001u, 0x0001u}},
|
||||
{0xbf800000u, 0x3f800000u, 0x3f7fffffu, {0x8001u, 0x8001u, 0x8001u, 0x8001u}},
|
||||
{0x3f800000u, 0x3f800000u, 0xbf800000u, {0x0000u, 0x0000u, 0x8000u, 0x0000u}},
|
||||
{0x40000000u, 0x3f800000u, 0xc0000000u, {0x0000u, 0x0000u, 0x8000u, 0x0000u}},
|
||||
{0x00000000u, 0x3f800000u, 0x80000000u, {0x0000u, 0x0000u, 0x8000u, 0x0000u}},
|
||||
{0x80000000u, 0x3f800000u, 0x80000000u, {0x8000u, 0x8000u, 0x8000u, 0x8000u}},
|
||||
{0x33000000u, 0x3f000000u, 0x00000000u, {0x0000u, 0x0001u, 0x0000u, 0x0000u}},
|
||||
{0xb3000000u, 0x3f000000u, 0x00000000u, {0x8000u, 0x8000u, 0x8001u, 0x8000u}},
|
||||
}};
|
||||
|
||||
float Quarter(std::uint32_t index) {
|
||||
|
||||
@@ -298,6 +298,15 @@ std::uint32_t Interpolate(SpirvEmitterState& state, std::uint32_t delta, std::ui
|
||||
if (rounding16 == 1u) limit = Select(state, u32, negative, ConstantU32(state, 0x40effc00u), ConstantU32(state, 0x40f00000u));
|
||||
if (rounding16 == 2u) limit = Select(state, u32, negative, ConstantU32(state, 0x40f00000u), ConstantU32(state, 0x40effc00u));
|
||||
rounded = ToF64(state, Join(state, SelectBits(state, overflow, {ConstantU32(state, 0u), Binary(state, spv::OpBitwiseOr, u32, sign, limit)}, bits)));
|
||||
if (rounding16 == 2u) {
|
||||
const auto boolean = TypeBool(state);
|
||||
const auto zeroBits = [&](F64Bits value, std::uint32_t highMask) {
|
||||
return Binary(state, spv::OpLogicalAnd, boolean, Binary(state, spv::OpIEqual, boolean, Binary(state, spv::OpBitwiseAnd, u32, value.high, ConstantU32(state, highMask)), ConstantU32(state, 0u)), Binary(state, spv::OpIEqual, boolean, value.low, ConstantU32(state, 0u)));
|
||||
};
|
||||
const auto positiveZeros = Binary(state, spv::OpLogicalAnd, boolean, zeroBits(Split(state, FromF64(state, product)), 0xffffffffu), zeroBits(Split(state, FromF64(state, FromF32Exact(state, base))), 0xffffffffu));
|
||||
const auto negativeZero = Binary(state, spv::OpLogicalAnd, boolean, zeroBits(Split(state, FromF64(state, sum)), 0x7fffffffu), Unary(state, spv::OpLogicalNot, boolean, positiveZeros));
|
||||
rounded = ToF64(state, Join(state, SelectBits(state, negativeZero, {ConstantU32(state, 0u), ConstantU32(state, 0x80000000u)}, Split(state, FromF64(state, rounded)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto finite = F32BitsOfRounded(state, rounded);
|
||||
|
||||
Reference in new issue
Block a user