Vulkan vs DX12 Physics: Real-World Frame-Time Benchmark
Average FPS is a poor referee for physics-heavy games. A title can report 90 FPS while producing repeated 30–50 ms stalls when a ragdoll activates, a new area streams in, shaders compile, or the CPU waits for the GPU.
The practical answer to the Vulkan-versus-DX12 question is not that one API always wins. The better choice is the one that keeps rendering, physics, shader compilation, and synchronization inside the frame budget on the platforms you actually ship.
Frame budgets: 60 FPS allows 16.67 ms per frame. At 120 FPS, the budget falls to 8.33 ms. A single 40 ms stall is more damaging than a modest average-FPS lead.
Physics changes what an API benchmark can tell you
DirectX 12 and Vulkan are graphics APIs, not physics engines. They control command submission, resource transitions, synchronization, and memory access. They do not determine how quickly Jolt, PhysX, or a custom solver generates contacts and resolves constraints.
Physics performance is shaped primarily by:
- Broadphase and narrowphase algorithms
- Constraint and contact solving
- Character and vehicle queries
- Continuous collision detection
- Gameplay callbacks
- Thread scheduling and synchronization
- Scene design and object activity
- The engine’s integration of the physics library
That distinction matters. If physics takes 11 ms of a 16.67 ms frame, reducing render-submission overhead by 1 ms won’t transform the game. In fact, a 1 ms API gain is irrelevant if the render thread then waits 3 ms for the solver or for gameplay code to consume collision results.
API overhead becomes important when the render thread is the limiting factor: large numbers of draw calls, frequent descriptor updates, expensive state changes, or poorly batched submissions. A physics-heavy game may instead be limited by solver work, scene queries, or synchronization.
What to measure
| Measurement | What it reveals |
|---|---|
| Median frame time | Typical responsiveness |
| 99th and 99.9th percentile frame time | The slowest 1% and 0.1% of frames |
| Physics time | Simulation cost and stability |
| Render-thread time | CPU submission pressure |
| GPU time | Rendering workload |
| Maximum frame time | Worst visible hitch |
| Shader and pipeline events | Cold-start and traversal stutter |
| Synchronization time | Waiting between simulation and rendering |
Frame-time percentiles deserve special attention. A “1% low” reported in FPS is usually calculated by converting slow frame times into FPS and averaging or selecting a tail of those values. That number is easy to understand, but it can obscure the original stalls because FPS is nonlinear: 16.67 ms equals 60 FPS, while 33.33 ms equals 30 FPS.
For diagnosing stutter, a frame-time chart or a 99th-percentile frame-time value is generally more useful. Keep FPS-based 1% lows for summaries, but inspect the underlying frame times before drawing conclusions.
What historical API tests actually prove
The 3DMark API Overhead feature test is useful because it isolates command-submission behavior. It is not a game benchmark and says nothing directly about solver performance.
In published results from UL’s test, a GeForce GTX 1060 delivered roughly 26.4 million draw calls per second with Vulkan and 20.0 million with DirectX 12. On an AMD Radeon RX 480, DX12 led at approximately 26 million draw calls per second, while Vulkan reached about 24.9 million. Results on a GTX 1080 Ti were close.
The lesson is not “Vulkan wins.” Driver quality, GPU architecture, command patterns, synchronization, and engine implementation all matter. The test is most relevant when the game is CPU-bound on rendering submission. It becomes much less predictive when the dominant cost is physics or gameplay.
Source: UL’s 3DMark API Overhead feature test.
Jolt and PhysX: benchmark the workload, not the body count
Jolt and PhysX are often compared using the number of rigid bodies in a scene. That is a weak shortcut. A thousand sleeping boxes may cost less than 200 active ragdolls with joints, continuous collision detection, contact callbacks, and character queries.
A published Jolt comparison used a demanding scene with 3,680 ragdoll bodies, convex shapes, a 2,000-triangle collision mesh, discrete and continuous collision detection, and several thread configurations. Jolt reached roughly 4.9× one-thread performance at eight threads and about 5.7× at 16 SMT threads. PhysX showed stronger single-thread performance in at least one tested configuration.
Those figures describe one workload, hardware setup, and integration. They are not a universal ranking. Compiler settings, object activation, SIMD paths, allocator behavior, and thread contention can reverse the result in a production game.
Measure the physics stages separately:
| Physics cost | Why it matters |
|---|---|
| Broadphase | Maintaining potential collision pairs |
| Narrowphase | Shape intersection and contact generation |
| Solver | Resolving contacts and constraints |
| CCD | Fast-object collision checks |
| Scene queries | Character, AI, and gameplay requests |
| Thread scaling | Whether extra cores help the real scene |
| Synchronization | Waiting between simulation stages |
Sources: Jolt Physics performance notes and NVIDIA PhysX documentation.
GPU physics needs another layer of scrutiny. If AI, gameplay, audio, or networking forces the CPU to read back collision results every frame, the solver’s headline speed can disappear behind a synchronization stall. GPU physics works best when simulation data remains on the GPU through several downstream stages.
A small case study: when the API lead does not matter
Consider the same destruction replay run on two renderers at a 60 FPS target.
| Measurement | DX12 | Vulkan |
|---|---|---|
| Physics | 9.4 ms | 9.4 ms |
| Render thread | 3.1 ms | 2.3 ms |
| GPU | 7.8 ms | 7.9 ms |
| Synchronization and miscellaneous CPU work | 2.0 ms | 2.0 ms |
| Frame time | 14.5 ms | 13.7 ms |
Vulkan is 0.8 ms faster in this example, but both renderers fit within 16.67 ms. The difference may be invisible during ordinary gameplay.
Now activate 150 ragdolls:
| Measurement | DX12 | Vulkan |
|---|---|---|
| Physics | 13.8 ms | 13.8 ms |
| Render thread | 3.1 ms | 2.3 ms |
| Synchronization and callbacks | 2.4 ms | 2.4 ms |
| Frame time | 19.3 ms | 18.5 ms |
Both APIs now miss the frame budget. Vulkan still wins the submission portion, but the player experiences a physics hitch either way. Engineering effort should move to solver scheduling, callback cost, or workload reduction—not another round of API micro-optimization.
This is why a useful benchmark pairs API timings with physics timings. Without both, it’s easy to optimize the least important part of the frame.
Windows, Linux, Steam Deck, and Proton
Native Vulkan is often the cleanest starting point for Linux and Steam Deck, but “native” does not guarantee smooth performance. DX12 through Proton is a translation path: vkd3d-proton converts the game’s DX12 usage into Vulkan rather than running DX12 directly on Linux.
That path can perform well, especially when the DX12 renderer is mature. It also adds another layer where shader compilation, feature mapping, synchronization, and presentation behavior can affect frame pacing.
Test these cache states:
- Cold cache: Clear shader and pipeline caches before launching.
- Warm cache: Repeat the same route after compilation has completed.
- Partial cache: Enter a new area or invalidate selected content.
Use the same replay, camera path, graphics settings, frame cap, and power profile for every run. PresentMon’s current command-line documentation supports a timed capture such as:
PresentMon.exe --process_name Game.exe --output_file vulkan-cold.csv --timed 120
Check the syntax against the installed PresentMon release, since options can change between builds. The PresentMon documentation is the appropriate reference.
On Linux and Steam Deck, MangoHud and Gamescope can expose frame time, CPU and GPU load, clocks, and power behavior. Lock the performance profile before comparing APIs.
| Platform and renderer | What to record | Common risk |
|---|---|---|
| Windows + DX12 | Cold/warm frame times, physics spikes | Shader and barrier stalls |
| Windows + Vulkan | Same replay and cache states | Driver and pipeline variance |
| Linux + Vulkan | Frame time, presentation mode, power | Driver and compositor behavior |
| Steam Deck + Vulkan | Frame time, clocks, power limit | CPU limits and shader warming |
| Linux + DX12 through Proton | Translation overhead and cache state | vkd3d-proton compatibility and shader behavior |
Never compare a fresh DX12 launch with a Vulkan run that has already warmed its pipeline cache. The chart may look impressive, but the experiment is invalid.
A benchmark protocol that holds up
Use a fixed game build, fixed driver versions, fixed graphics settings, and a deterministic replay. Disable background downloads and avoid testing immediately after a driver update, when caches may be rebuilding.
Include at least four scenes:
- A destruction or rigid-body event
- A ragdoll and character-heavy encounter
- A vehicle or CCD-heavy sequence
- A traversal through previously unseen content
Capture timestamps around:
Physics.Broadphase
Physics.Narrowphase
Physics.Solver
Gameplay.CollisionCallbacks
RenderThread.Submit
GPU.Frame
ShaderCompile
PipelineCacheMiss
Report median frame time, 99th and 99.9th percentile frame time, maximum frame time, physics time, render-thread time, GPU time, memory use, and shader events. If the report contains only average FPS, it is not a frame-pacing benchmark.
For cross-platform physics, replay identical input and compare state hashes at fixed simulation ticks. Floating-point behavior, SIMD paths, compiler flags, thread order, and entity insertion order can all produce different results even when the code is nominally deterministic.
Choosing the backend
Choose DX12 first when Windows and Xbox dominate, the team relies on PIX and HLSL, or the renderer already has mature DXR and mesh-shader support.
Choose Vulkan first when Linux, Steam Deck, Android, or a shared cross-platform renderer is a launch requirement. Budget time for shader pipelines, synchronization, presentation modes, and driver testing.
Support both when the commercial case justifies two backends and the team can maintain the testing matrix. It isn’t a free checkbox.
Choose Jolt when multicore CPU scaling, source access, and a portable simulation core matter. Choose PhysX when its established vehicle workflows, feature set, or GPU path performs better in the actual game.
The practical rule is simple: if APIs are within about 5% of each other, choose the one with fewer cold-cache spikes and better high-percentile frame times. A stable 58 FPS usually feels better than 65 FPS interrupted by repeated 40 ms hitches.
Frequently asked questions
Is Vulkan faster than DX12 in CPU-bound games?
Not consistently. First identify whether the CPU is spending time on rendering submission, physics, gameplay, or synchronization. The API only addresses part of that work.
Does Vulkan automatically provide better 1% lows?
No. It may reduce submission overhead or offer a cleaner Linux path, while DX12 may have a more mature Windows pipeline. Measure cold and warm traversal instead of assuming.
Should Steam Deck games use Vulkan or DX12 through Proton?
Native Vulkan is a sensible starting point, but measured frame pacing decides the release configuration. A polished DX12-through-vkd3d-proton path can outperform a rushed Vulkan backend.
How should shader stutter be reported?
Show cold, warm, and partially cached runs. Include frame-time percentiles and maximum frame time alongside any FPS-based 1% low, so readers can see whether a result reflects ordinary variance or genuine stalls.
Share this research breakdown
Help friends and peers stay ahead with autonomous AI insights.
This technical article was compiled using autonomous research pipelines and third-party foundation models (including OpenAI and web-retrieval systems) to analyze papers, documentation, and market data. Content is structured by EveeStatistic for informational exploration. Readers should independently verify critical benchmarks.