Skip to content

fix(shader): round and flush f16 conversion results by FLOAT_MODE in every denormal mode - #5943

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
zmeizy:claude/f16-conversion-float-mode
Oct 16, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
zmeizy:claude/f16-conversion-float-mode

Conversation

@zmeizy

@zmeizy zmeizy commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

What

Two gaps in v_cvt_f16_f32, v_cvt_f16_i16, v_cvt_f16_u16 and v_ldexp_f16 that TechnicalDebt recorded as unmeasured:

  1. Directed rounding. It was applied only when f16 denormals are preserved (denorm16 3); the other modes fell back to round to nearest even. On hardware, all four instructions follow the f16 rounding field in every denormal mode.
  2. Tiny results. When the mode flushes f16 results (denorm16 0 and 1), v_cvt_f16_f32 kept denormal halves; with round to nearest too, for example 0x33400000 gave 0x0001 instead of 0x0000. On hardware, the result is a zero of its sign when the value, rounded in the mode with an unbounded exponent, is below 2^-14. So a value just below 2^-14 that rounds up to it stays 0x0400, while flushing the exact value would give zero there.

directedF16Rounding no longer depends on the denormal mode. writeF16Conversion applies the measured flush after the conversion through flushTinyF16Conversion; its threshold depends on the rounding direction and the sign. v_ldexp_f16 keeps its own flush, which already matched.

The clamp modifier is still applied before the conversion; gfx1030 matches that in every mode. The TechnicalDebt entry for directed f16 rounding is updated accordingly.

Source: measured on RDNA2, gfx1030 (RX 6800, Windows 11, AMD driver HIP runtime), with the hardware oracle's kernel template.

  • Modes: all 16 combinations of round16 0..3 and denorm16 0..3, with IEEE 0, DX10_CLAMP 1, f32 denormals flushed, f32 round to nearest, FP16_OVFL 0.
  • v_cvt_f16_f32, with and without clamp: 8,996 f32 inputs, both signs. Each half in the denormal range, around the smallest normal, around 1.0 and below the overflow boundary is taken exactly and at a quarter, half and three quarters of its step. Smaller powers of two, f32 denormals, overflow values, infinities and NaNs are included.
  • v_cvt_f16_u16, v_cvt_f16_i16 and v_cvt_f16_u16 with clamp: every 16-bit value.
  • v_ldexp_f16 (with and without clamp): 38 halves × 65 exponents.

Tested

Ubuntu 24.04, GCC 13.3, lavapipe, on main a453108c.

  • agc_driver_f16_conversion_float_mode (new) pins 62 measured rows over the five forms, each with an expected value for all 16 modes.
    • On main it fails (v_cvt_f16_f32 0x33400000 gives 0x0001 at round16 0, denorm16 0); with the change it passes in 1.4 s.
  • Every measured row in every mode matches the recompiler output with the change, for all three probes. Without it, there are up to 8,482 mismatches per mode for v_cvt_f16_f32, 29,184 for v_cvt_f16_u16 and 366 for v_ldexp_f16.
  • The 54 existing execution tests about f16, conversions, packing, rounding, denormals, interpolation, clamp and overflow pass, including agc_driver_float16_rounding and agc_driver_f16_denormal_flush.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt (n/a)
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source (n/a)
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA

…every denormal mode

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
@zmeizy

zmeizy commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

@github-actions github-actions Bot added shader core/shader docs agc libSceAgc* labels Oct 14, 2026

@jotitadev jotitadev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Run on an Apple GPU, since the PR was tested only on lavapipe.

GPUs tested: Apple M2 Max, MoltenVK 1.4.2 (Vulkan 1.4.357), macOS 27.2, x86-64 under Rosetta; also MoltenVK main built with KhronosGroup/SPIRV-Cross#2704 (keeps the sign of -0)

main does not run the GPU tests on macOS yet, so I tested on macos-port at b7eb6b6b (mugurc/AnyPS5) plus the ImportWatched change from #1, with this PR's own diff (merge-base..head 793224067) applied. Not main. Release build, LunarG Vulkan SDK 1.4.363.0. Suite: ctest -R "^agc" -E "agc_display_buffer_dcc|agc_driver_flip|agc_driver_lds_atomics64" -j1 --timeout 30. Without the PR, 13 tests fail on this setup (7 with the #2704 build), all known macOS failures listed in #1. The diff applies cleanly.

  • agc_driver_f16_conversion_float_mode passes with both MoltenVK builds.
  • With only the new test added to the unchanged branch, it fails with v_cvt_f16_f32 round16 0 denorm16 0 inputs 0x33400000 0x00000000 is 0x00000001, expected 0x00000000, the error in the description. So the test runs on this device.
  • Suite: the same 13 failures with and without the PR (7 and 7 with the #2704 build). None new, none fixed.
  • agc_driver_f16_denormal_flush passes. agc_driver_float16_rounding fails with stock MoltenVK both with and without the PR, and passes with the #2704 build. That is the known -0 issue from #1, not this change.

Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 4072 core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp
PR 5371 docs/dev/debt/shader.md
PR 5426 docs/dev/debt/shader.md
PR 5500 docs/dev/debt/shader.md
PR 6222 docs/dev/debt/shader.md
PR 6235 docs/dev/debt/shader.md
PR 6412 docs/dev/debt/shader.md

This was referenced Oct 15, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Measured v_cvt_f16_f32 (with and without clamp), v_cvt_f16_u16, v_cvt_f16_i16 and v_ldexp_f16 on gfx1035 in all 16 round16 × denorm16 modes (188,532 rows per mode, including NaN/Inf and the 2^-14 and overflow edges): the recompiler matches bit for bit, and the test fails without the change and passes on RADV and CI's lavapipe; merging once main builds again (#6784).

@adriadam10
adriadam10 merged commit 0936dc9 into boykopovar:main Oct 16, 2026
9 checks passed
@Amoenus

Amoenus commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Independent validation of the merged FP16 fixture on main 16a0f50, through fork integration 8858902:

  • agc_driver_f16_conversion_float_mode passes once on each verified physical device: NVIDIA GeForce RTX 5080 (10de:2c02), driver 610.62 / 32.0.16.1062; AMD Radeon Graphics (1002:13c0), driver 32.0.21036.18; both Windows 11 Enterprise 26200. Also passes on Ubuntu 24.04 WSL / Mesa 25.2.8 llvmpipe LLVM 20.1.2.
  • Each run executes the fixture's declared cases across all four round16 and all four denorm16 modes. No omissions or whole-test skips. Vulkan required; project shader cache disabled, driver caches uncontrolled.
  • The translation header, SubwordPacking.cpp, and this fixture are byte-identical to main16a. This is integration validation, not an unchanged-main checkout or a console/hardware-ISA oracle comparison. No pre-fix failure control was run for FP16.
  • Windows GCC 15.2 r7 and Linux GCC 13.3 application/libraries plus selected fixture builds pass. The independent uint/D32 readback-retile tests also pass on all three devices. All nine selected test invocations completed in at most 1.74 s each.

AI-assisted: Codex; author responsible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* docs shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants