pfx

Got questions or doubts? Ping me on Discord

pfx's speed, measured

Method: docs/measured.md
GPU frame, p50 4.4 ms
CPU frame, p99 1.7 ms
Dropped frames 0
1 4.4 ms GPU a frame, live, 4K p50 and p99, 0 dropped in 1,200 docs/measured.md
2 0 ms An idle frame a drifting camera 0.50 ms, every frame 4.9 ms docs/measured.md
3 33.7 MB Empty game, shipped with its content, against Godot's 73.5 and Bevy's 106.6 MB Against other engines
4 3.4 ms A .pitofx model, warm 159,200 triangles, against the GLB's 4.2 ms docs/pfx-file.md
5 5,969 ms Path-traced 4K still the workshop, adaptive to 64 samples docs/trace.md
6 4.8 s 128 lights, traced at 4K from 9.4 s light by light docs/trace-lights.md
7 274 ms Denoiser, 4K texture to texture, on the GPU docs/denoise.md
8 0.36 ms 2D pass, 4K 2,000 shots and 20,301 particles docs/measured.md

The numbers

Measured on this code, not promised

Every number was measured on pfx's own code, on an AMD Radeon RX 9060 XT with an AMD Ryzen 9 9950X under Linux, each GPU run through a GPU queue other jobs shared. pfx's docs give the command behind each one.

1

The live frame at 4K

The neutral room at 3840×2160, 1,200 frames a run, the median of five runs: 4.4 ms of GPU at p50 and at p99, about half of the 8.33 ms a 120 fps frame allows, with the rest left for the game. The CPU's simulate-and-submit takes 0.85 ms.

Method: docs/measured.md
Bar chart, live frame time at 4K on the neutral room, lower is better: GPU p50 4.4 ms, GPU p99 4.4 ms, CPU p50 0.85 ms, CPU p99 1.7 ms, against the 120 fps budget of 8.33 ms.
2

Frames on demand

pfx draws a frame only when something changed. On the desk at 4K a full frame costs 4.9 ms, a drifting camera 0.50 ms, and and an idle scene 0.

Method: docs/measured.md
Bar chart, GPU time a frame on the desk at 4K, lower is better: every frame 4.9 ms, a drifting camera 0.50 ms, idle 0.
3

Many lights, one sample

Past four point and spot lights, the tracer picks one light per bounce through a light tree ported from Cycles. A street of 128 lamps at 4K traces in 4,803 ms, against 9,356 ms light by light; 128 lights cost 6% more than 4.

Method: docs/trace-lights.md
Bar chart, a traced 4K still of a street of lamps at 16 samples, GPU milliseconds, lower is better: 4 lights 4,518 through the tree and 4,569 light by light; 32 lights 4,722 and 5,745; 128 lights 4,803 and 9,356.
Ratio chart, the light tree against light by light: 1.0 times at 4 lights, 1.2 times faster at 32, 1.9 times faster at 128.
4

The path tracer, release by release

The desk at 4K, path-traced and denoised, in seconds of wall time: 40.4 s at v0.26.0, 15.0 s at v0.27.0 and 11.2 s at v0.32.0 for the final picture, and 5.9 s, 2.5 s and 2.8 s for the draft. Same desk, same card.

Method: docs/trace.md
Bar chart, the path tracer on the desk scene at 4K in seconds of wall time, lower is better: final at v0.26.0 40.4 s, v0.27.0 15.0 s, v0.32.0 11.2 s; draft 5.9 s, 2.5 s and 2.8 s.
5

The path tracer's material record

Each material is split, as Cycles lays out its shaders, into a 128-byte hot record every hit reads and extension rows only the materials that use them carry. At 4K with ray queries, every still got 5.2% to 10.7% faster and every output stayed byte for byte the same.

Method: docs/trace.md
Bar chart, path-traced stills at 3840×2160 in milliseconds, lower is better, the split record against 532b979: the desk at 32 samples 3,250 and 3,570; the workshop final 5,969 and 6,409; the workshop draft 1,464 and 1,556; a 1920×1080 crop 2,286 and 2,560; an 8-frame clip 3,253 and 3,433.
6

Ray queries on Apple Silicon

Where the device offers ray queries (Vulkan, DX12, Metal on Apple Silicon) the tracer uses them, with its own BVH elsewhere. On an M1 Max, which runs the queries in compute, the desk's 4K draft takes 13.8 s with ray queries and 20.7 s on the BVH.

Method: docs/trace.md
Bar chart, the desk's 4K draft on an M1 Max in seconds, lower is better: 13.8 with ray queries, 20.7 on the software BVH.
7

Live AO and contact shadows

XeGTAO's ambient occlusion and Filament's contact shadows, ported, ground what rests on the floor. At 4K the high preset's screen passes take 2.72 ms; ultra is for stills.

Method: docs/live-renderer.md
Bar chart, live ambient occlusion and contact shadows at 4K, GPU milliseconds of screen passes, lower is better: high contact alone 0.86, medium with occlusion 1.67, high occlusion alone 2.47, high 2.72, ultra 5.89.
8

The .pitofx file

A car-sized model of 159,200 triangles: LZ4 takes the file to 2,974,760 bytes from the GLB's 5,780,288, and it loads in 3.4 ms warm and 7.9 ms cold, against the GLB's 4.2 ms and 8.8 ms.

Method: docs/pfx-file.md
Bar chart, a car-sized model on disk in bytes, lower is better: .pitofx LZ4 2,974,760, .pitofx stored 5,780,376, .glb 5,780,288.
Bar chart, loading a car-sized model in milliseconds, lower is better: warm 3.4 for .pitofx LZ4, 5.0 stored, 4.2 for .glb; cold 7.9, 8.4 and 8.8.
9

The denoiser by frame size

Textures in, texture out, warm: 96 ms at 1080p, 274 ms at 4K and 506 ms at 5K; with upload and readback, 110, 452 and 732 ms.

Method: docs/denoise.md
Bar chart, denoiser time by frame size, lower is better: 1920×1080 in 96 ms, 3840×2160 in 274 ms, 5120×2880 in 506 ms.
10

The rest of a game, per tick

The game systems' benches, one thread, in microseconds. A 120 fps frame is 8,333 of them; the largest here is 495.

Method: docs/measured.md
Bar chart, game systems' cost per tick in microseconds, lower is better: spawn director with 500 alive 11.5; 2,000 shots step and boxes 22.4; 2,000 shots against 400 targets 32.0; resolve 1,079 hits 5.0; journal snapshot after 25 minutes 23.4; save 205 live shots 63.7; 20 sine tones 239; 20 jittered hits mixed 495.

Against other engines

pfx 3.1 against Godot 4.7.2, Bevy 0.20.0 and Blender 5.2.2

Measured on 2026-10-19 and 2026-10-20 under Linux x86_64. Each row names what was measured and how; lower is better everywhere.

Measured How pfx Against
Download Linux x86_64 37.5 MB Godot 4.7.2: 77.9 MB (the editor, plus 1,281 MB of export templates)
Blender 5.2.2: 383 MB (its published download)
On disk unpacked 84.4 MB Godot 4.7.2: 146.4 MB
Blender 5.2.2: 1,236 MB
An empty shipped game with its content (a 29.1 MB binary), no editor 33.7 MB Godot 4.7.2: 73.5 MB
Bevy 0.20.0: 106.6 MB
The editor's first frame warm caches, an empty project 0.52 s Godot 4.7.2: 2.18 s
The editor at idle CPU, of one thread 0.05% Godot 4.7.2: 3.2%
The editor's memory an empty project 180 MB Godot 4.7.2: 1,064 MB
An empty game at idle CPU 1.05% Godot 4.7.2: 4.1%
An empty game at idle GPU. pfx presented no frame in 20 s 0% Godot 4.7.2: 0.94%
A running empty game memory 156.3 MB Godot 4.7.2: 261.2 MB
Bevy 0.20.0: 255.1 MB
Change one value, get a file to ship pfx set and pfx build; Godot: edit main.tscn, export the pack headless 63 ms Godot 4.7.2: 2,340 ms
Import a glTF a 6.8 MB GLB 46 ms Godot 4.7.2: 2,479 ms
Build a game from source a clean release build 87.4 s Bevy 0.20.0: 180.4 s
Rebuild after one change touching main.rs 0.96 s Bevy 0.20.0: 1.63 s

Build on pfx

pfx is open source under the AGPL-3.0: free for open-source projects, learning and hobby work. Read it, fork it, and send issues and pull requests on GitHub. Closed products and services built on pfx take a licence: free under $200k of yearly revenue plus funding, Indie and Pro above it.

© Catalin Ilinca, AGPL-3.0-only, with licences for closed products; releases up to 3.1.1 remain MIT. The PITO MD name, the pfx name and its logo are © Catalin Ilinca, all rights reserved.

Every picture and clip on this page is pfx's own, rendered or captured from its neutral scenes and licensed with its code (pfx's NOTICE.md); the pfx gui and game-editor clips were recorded by pfx from its v3.0.1 tag, the terminal clips with prec, the loops encoded with pito-codecs and the charts drawn with pito-compare from the numbers pfx v3.1.2 measures. Type: Exo 2 by NDISCOVER ( SIL Open Font License 1.1 ) and JetBrains Mono by JetBrains ( SIL Open Font License 1.1 ), from pfx's theme.