Repository navigation
perf(agc): probe the f32 denormal flush on MoltenVK - #8578
Conversation
The startup probe that lets shaders use the device's f32 denormal flush instead of the emulated one only ran on devices that declare shaderDenormFlushToZeroFloat32 with independent denormal behavior. MoltenVK declares neither flushing nor preserving f32 denormals, so every shader kept the emulated flush on every f32 add, multiply, fma, min, max and comparison. On MoltenVK the probe now runs too. Since the device declares no DenormFlushToZero capability there, a module compiled for the hardware flush declares no DenormFlushToZero execution mode and relies on the native behavior the probe measured; when any probe result differs from the emulated flush, shaders keep the emulation as before. Devices that declare the capability are unchanged.
|
Traces of the four captures in the table above, in the same order (each file name matches the 1-base-1-aps5-trace-7cf8c610c6a7-63071.json.gz They open in ui.perfetto.dev; |
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
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.
|
|
Checked the decision table ( |
|
Tested the M1 probe on a MacBook Pro (Apple M1, macOS 27.0.1) with LunarG Vulkan SDK 1.4.363.0 and MoltenVK 1.4.2. The filtered
Three tests that failed at baseline passed at the #8578 revision: The reference-profile failure lists are included below. “Failed/aborted” follows CTest’s summary; Baseline failures — 2bfbc2f (51)
With #8578 — a4a16a6 (48)
Tests were run with assistance from OpenAI Codex; the figures and test lists were checked against the captured local logs. No game-performance claim is inferred from these tests. |
What
The startup probe that switches shaders from the emulated f32 denormal flush to the device's own flush (
FloatFlushProbe, which compares 5472 results against the emulation and switches only when none differ) runs only on devices that declareshaderDenormFlushToZeroFloat32with independent denormal behavior. MoltenVK declares neither, so on macOS every shader keeps the emulated flush around every f32 add, multiply, fma, min, max and comparison.Float32FlushControlFor(new, Execution/include/Float32FlushControl.hpp) now decides two things from the driver ID and the float controls: whether to probe (as before, plusVK_DRIVER_ID_MOLTENVK) and whether the device declares the flush.VulkanDevicekeeps the driver ID from the driver properties query and addsCapabilityDenormFlushToZeroonly when it is declared;SpirvModuleSetupemits theDenormFlushToZeroexecution mode only when that capability is supported. On MoltenVK a module compiled for the hardware flush therefore declares no execution mode and relies on the native behavior the probe measured; if any probe result differs, shaders keep the emulation as before. For every other driver the decision is the old condition, so nothing changes there.agc_float32_flush_controlcovers the decision;agc_driver_f32_denormal_flushalso checks the natively flushed module (no execution mode, fewer words than the emulated one).#8014 also stores the driver ID in
VulkanDevice; whichever of the two merges second can use the other's field.Tested
Apple M4 Pro, macOS 27.0.1, x86-64 under Rosetta 2, MoltenVK 1.4.2 (Vulkan SDK 1.4.363.0), Apple clang 21.0.0.
main8375116: the libraries do not build on macOS, so the changed files (VulkanDevice.cpp, SpirvModuleSetup.cpp, F32DenormalFlush.cpp) were compiled on their own andagc_float32_flush_controlwas run: passes.ci/macos-series-253db0ba (plus feat(libkernel): JIT shared memory on macOS hosts #7937's code commits, needed to build libkernel, and fix(libkernel): keep host fault signals available on macOS #8477), AGC and shader suites on MoltenVK: 761/807 without this change, 762/808 with it, the same 46 failures. All 10 probe lines in that run read[float-controls] f32 denormal flush: hardware (0 of 5472 probe results differ from the emulated flush).agc_driver_f32_denormal_flushfails in both runs at the same case (v_mul_f32 v25, |v4|, -v5gives0x00000000, expected0x80000000): a signed zero lost by SPIRV-Cross's helper for NoContraction multiplies, unrelated to the flush.APS5_TRACE_SECONDS=140:5only, base and change alternated twice in one session. The base is the macOS integration head 7cf8c61 (former feat: macOS on Apple Silicon host support (Rosetta 2 and MoltenVK) #7332) and notmain, because titles do not run frommainon macOS. The presenter waits about 4 ms less per frame for the GPU (GPU busy per present is noisier), and the frame rate rises by about 10%:Summary lines
{"commit":"7cf8c610c6a7","dirty":false,"env":{"APS5_ASYNC_PIPELINES":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"140:5"},"gpu":"Apple M4 Pro","driver":"MoltenVK 1.4.2","os":"Darwin 27.0.0","resolution":"3840x2160","window":{"spec":"seconds 140:5","first_present":5264,"ms":5032.929},"presents":127,"frame_ms":{"p50":39.459,"p90":41.929,"p99":45.242,"max":59.616},"gpu_busy_ms_per_present":22.226,"worker_busy_pct":{"queue worker 0x0":70.944},"top_phases_ms_per_frame":{"Driver.Packet":27.888,"Driver.Packet.draw":22.728,"Driver.Draw":22.532,"Graphics.Draw":14.661,"Driver.Draw.shader_compile_and_link":14.565,"VideoOut.Flip":10.904,"Driver.Present":10.141,"VideoOut.Flip.present":10.062},"trace_dropped":false,"trace":"aps5-trace-7cf8c610c6a7-63071.json.gz"} {"commit":"bb294211065d","dirty":false,"env":{"APS5_ASYNC_PIPELINES":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"140:5"},"gpu":"Apple M4 Pro","driver":"MoltenVK 1.4.2","os":"Darwin 27.0.0","resolution":"3840x2160","window":{"spec":"seconds 140:5","first_present":5877,"ms":5000.632},"presents":139,"frame_ms":{"p50":35.568,"p90":38.840,"p99":45.673,"max":55.205},"gpu_busy_ms_per_present":21.484,"worker_busy_pct":{"queue worker 0x0":77.581},"top_phases_ms_per_frame":{"Driver.Packet":27.657,"Driver.Packet.draw":22.200,"Driver.Draw":22.007,"Graphics.Draw":14.757,"Driver.Draw.shader_compile_and_link":14.109,"Graphics.Draw.draw_and_resource_release":9.637,"VideoOut.Flip":7.256,"Shader.DrawStage":7.220},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":4.949,"events_lost":3181,"totals_full":false}},"trace":"aps5-trace-bb294211065d-64633.json.gz"} {"commit":"7cf8c610c6a7","dirty":false,"env":{"APS5_ASYNC_PIPELINES":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"140:5"},"gpu":"Apple M4 Pro","driver":"MoltenVK 1.4.2","os":"Darwin 27.0.0","resolution":"3840x2160","window":{"spec":"seconds 140:5","first_present":5264,"ms":5011.095},"presents":127,"frame_ms":{"p50":39.534,"p90":41.368,"p99":45.362,"max":48.058},"gpu_busy_ms_per_present":24.782,"worker_busy_pct":{"queue worker 0x0":69.381},"top_phases_ms_per_frame":{"Driver.Packet":27.141,"Driver.Packet.draw":21.848,"Driver.Draw":21.651,"Graphics.Draw":14.490,"Driver.Draw.shader_compile_and_link":13.997,"VideoOut.Flip":11.166,"Driver.Present":10.443,"VideoOut.Flip.present":10.363},"trace_dropped":false,"trace":"aps5-trace-7cf8c610c6a7-66252.json.gz"} {"commit":"bb294211065d","dirty":false,"env":{"APS5_ASYNC_PIPELINES":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"140:5"},"gpu":"Apple M4 Pro","driver":"MoltenVK 1.4.2","os":"Darwin 27.0.0","resolution":"3840x2160","window":{"spec":"seconds 140:5","first_present":5852,"ms":5008.229},"presents":140,"frame_ms":{"p50":35.669,"p90":37.750,"p99":49.340,"max":54.747},"gpu_busy_ms_per_present":17.935,"worker_busy_pct":{"queue worker 0x0":79.566},"top_phases_ms_per_frame":{"Driver.Packet":28.213,"Driver.Packet.draw":22.872,"Driver.Draw":22.671,"Graphics.Draw":14.922,"Driver.Draw.shader_compile_and_link":14.747,"Graphics.Draw.draw_and_resource_release":9.768,"Shader.DrawStage":7.534,"VideoOut.Flip":6.730},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":4.790,"events_lost":12286,"totals_full":false}},"trace":"aps5-trace-bb294211065d-67934.json.gz"}In the two captures of the change the queue worker's trace buffer filled 4.8 and 4.9 s into the 5 s window (
trace_dropped). The four traces are attached in a comment below. Linux and Windows were not run; for drivers other than MoltenVK the probe decision is unchanged, as the unit test checks.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)