softgpu: Build with -ffp-contract=off

GCC defaults to -ffp-contract=fast and Clang to on, so both fuse a*b + c into a
single FMA where the hardware has one; MSVC /fp:precise doesn't contract at all.
On aarch64 FMLA is baseline, so the same source gives different depth, fog and
lighting values on Android/Linux than on Windows-on-ARM - exactly the kind of
same-architecture difference we're trying to eliminate. x86-64 only escapes today
because the SSE4.1 baseline has no FMA, which -march=native or x86-64-v3 (as used
by distro and Flatpak packagers) would undo.

Set per-source so it also covers the Math3D.h scalar operator chains inlined into
these TUs, which is where it actually matters. MSVC needs nothing.

Note this only covers the CMake build, which is what the shipping Android build
uses. The legacy android/jni ndk-build and libretro/Makefile.common have no
per-file mechanism, so they'd need it applied globally - left for the wider GPU/
evaluation.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Vd8ntC2brCUtCrDJMqLbs8
This commit is contained in:
Henrik RydgårdandClaude Opus 5 committed 2026-08-29 12:21:11 +02:00
1 parent e1c81f91be
commit 83bbe44f55
1 file changed
+29
+29
View File
@@ -197,6 +197,35 @@ set(GPU_SOURCES
add_library(GPU OBJECT ${GPU_SOURCES})
target_compile_features(GPU PUBLIC cxx_std_17)
# The software rasterizer has to produce identical output everywhere, so don't let the compiler
# fuse a*b + c into an FMA. GCC defaults to -ffp-contract=fast and Clang to on, while MSVC
# /fp:precise doesn't contract at all - which means the same source gives different depth, fog and
# lighting values on aarch64 Linux/Android than on Windows-on-ARM, where FMLA is baseline. x86-64
# only escapes today because the SSE4.1 baseline has no FMA; -march=native or x86-64-v3, which
# distro and Flatpak packagers do use, would lose that.
# This covers the Math3D.h scalar operator chains inlined into these TUs, which is where it matters.
# MSVC needs nothing - /fp:precise already implies no contraction.
# TODO: Evaluate whether the rest of GPU/ wants this too.
if(NOT MSVC)
set(SOFTGPU_SOURCES
Software/BinManager.cpp
Software/Clipper.cpp
Software/DrawPixel.cpp
Software/DrawPixelX86.cpp
Software/FuncId.cpp
Software/Lighting.cpp
Software/Rasterizer.cpp
Software/RasterizerRectangle.cpp
Software/RasterizerRegCache.cpp
Software/Sampler.cpp
Software/SamplerX86.cpp
Software/SoftGpu.cpp
Software/TransformUnit.cpp
)
# Listing sources that aren't in GPU_SOURCES on this platform (the X86 ones) is harmless.
set_source_files_properties(${SOFTGPU_SOURCES} PROPERTIES COMPILE_OPTIONS "-ffp-contract=off")
endif()
if(LIBRETRO)
target_include_directories(GPU PRIVATE ${CMAKE_SOURCE_DIR}/libretro/libretro-common/include)
endif()