7.2 KiB
P3 integrated Forward+ decision on the P1+P3 renderer checkpoint
The P1+P3 integration keeps Auto on the simple forward light loop. On the
fixed, dense 1920 × 1080 scene, the complete tile-build-plus-raster work is
slower at every nonzero light count in all three visibility modes and both
shadow states. Explicit Tiled remains available: when the same lights have a
shorter range, it wins in the affected passes. This is a measured choice for the
recorded fixture, not a universal performance claim or an automatic light-
occupancy heuristic.
This is the combined final-code repeat of the initial 32-light gate
and the Forward+ implementation experiment.
Both A/B paths used clean source revision
4a3453e2b1868555d833f578d43f48b8bc47d41a, the same Release
benchmark executable SHA-256
ceb4fbde8f65bad60a3eb4d24c917619769ff058c66851bc10748ef0af5b45fd,
and an unchanged, per-file hashed shader bundle. This revision contains the
integrated temporal shader and P1 build changes, although temporal was off
in this lighting benchmark. The GPU was a physical NVIDIA GeForce RTX 2080 Ti,
Linux driver 595.84, with Vulkan validation disabled for timings.
Method and results
Each path ran 36 configurations: shadows on/off × Direct/GPU frustum/GPU occlusion × 0/4/16/32/64/128 lights. There were three fresh-process repeats per configuration, ten warm-up plus thirty measured frames per repeat: 108 runs and 3,240 measured frame rows per path, 6,480 rows total. The wrapper checked clean source, binary and shader hashes, actual Vulkan device, requested lighting and visibility path, light counts, per-frame GPU timestamps, shadow face counts, and zero reported validation errors. Zero errors in these validation-off sweeps is not a validation-layer result. Values below are the median of the three process medians; the change is the paired median difference reported by the comparison tool. Units are GPU milliseconds, 1920 × 1080.
| Shadows | Dense lights | Forward build + raster | Tile build | Tiled raster | Tiled build + raster | Tiled change |
|---|---|---|---|---|---|---|
| Off | 32 | 0.5519 | 0.0621 | 0.5541 | 0.6161 | +0.0642 (+11.6%) |
| Off | 64 | 1.0653 | 0.1185 | 1.0784 | 1.1968 | +0.1321 (+12.4%) |
| Off | 128 | 2.1048 | 0.2240 | 2.1223 | 2.3460 | +0.2402 (+11.4%) |
| On | 32 | 0.5811 | 0.0622 | 0.5898 | 0.6519 | +0.0712 (+12.2%) |
| On | 64 | 1.1052 | 0.1189 | 1.1158 | 1.2351 | +0.1301 (+11.8%) |
| On | 128 | 2.1509 | 0.2242 | 2.1688 | 2.3924 | +0.2414 (+11.2%) |
The other two visibility modes follow the same direction. Across all three modes, the 32-light dense penalty spans +0.0642–0.0710 ms with shadows off and +0.0688–0.0720 ms with shadows on; at 128 lights it spans +0.2402–0.2425 ms off and +0.2343–0.2420 ms on. The 36-configuration comparison holds every point and paired-run difference. The forward 32-light overhead from its matched zero-light scene is 0.512–0.548 ms across the six shadow/visibility combinations; the 15% initial Forward+ investigation gate still triggers. A triggered investigation gate does not imply that its candidate wins.
A second A/B used the benchmark's localized layout (range 1.75 instead of
8 world units, all other scene inputs unchanged). It ran Direct visibility at
32/64/128 lights, shadows off/on, three repeats per path, another 36 runs and
1,080 measured frames. On this workload the tile pass avoids most fragment
light evaluations:
| Shadows | Localized lights | Forward build + raster | Tiled build + raster | Tiled change |
|---|---|---|---|---|
| Off | 32 | 0.2348 | 0.1327 | −0.1021 (−43.5%) |
| Off | 64 | 0.4260 | 0.2117 | −0.2143 (−50.3%) |
| Off | 128 | 0.8146 | 0.3716 | −0.4430 (−54.4%) |
| On | 32 | 0.2364 | 0.1340 | −0.1025 (−43.3%) |
| On | 64 | 0.4291 | 0.2133 | −0.2158 (−50.3%) |
| On | 128 | 0.8149 | 0.3723 | −0.4426 (−54.3%) |
The table isolates the changed passes; it does not say the whole Player
frame improves by the same percentages. The renderer benchmark also performs
visibility, shadow handling and synchronous image readback. The localized
A/B, like the dense sweep, is a synthetic scene on one device and driver.
Explicit Tiled is useful for a measured localized-light scene; Auto stays
forward until a representative runtime occupancy predictor and broader scene
set justify changing the default.
Reproduce and inspect
From a clean build of that revision with the Release benchmark target:
python3 tools/benchmark_p3_lighting.py --sweep \
--executable build/linux-release/faset_p3_lighting_benchmark \
--output /tmp/p3-forward --shadows both --lighting forward \
--validation off --driver 'NVIDIA GeForce RTX 2080 Ti 595.84'
python3 tools/benchmark_p3_lighting.py --sweep \
--executable build/linux-release/faset_p3_lighting_benchmark \
--output /tmp/p3-tiled --shadows both --lighting tiled \
--validation off --driver 'NVIDIA GeForce RTX 2080 Ti 595.84'
python3 tools/benchmark_p3_lighting.py --compare \
--forward-summary /tmp/p3-forward/summary.json \
--tiled-summary /tmp/p3-tiled/summary.json \
--comparison-output /tmp/p3-comparison.json
The checked-in forward
and tiled summaries
contain all acquisition-order and hash metadata. Their adjacent merged.csv
files and 216 individual raw/ CSVs retain every frame. The
localized paired summary
and its 36 adjacent CSVs retain that fixture. The localized paired recorder saved source/binary hashes but did not embed its
own shader-bundle manifest, so exact historical shader identity for that
secondary fixture is less strongly attested than for the dense comparison.
The localized paired command
varied --light-layout localized, --lights, --shadows, and --lighting
while preserving the same binary and 1920 × 1080 output; source and binary
hashes are in its summary. The earlier Forward+ study
contains a separate untimed tile-occupancy diagnostic and byte-identical
image-parity captures. This repeat is a performance check on combined code,
not a new image-parity or occupancy claim. The timed CSVs deliberately have
light_tile_counts_valid = 0; their zero light_tile_overflow_count field is
a placeholder, not evidence that any tile avoided overflow. The 128-light
dense fixture is expected from its geometry and tile capacity to fall back
to a full per-fragment scan. Likewise, the shadows-on fixture requests up to
768 local faces at 128 lights but renders only 12 under its fixed atlas budget.
The table does not imply 128 fully shadowed point lights.
Functional correctness belongs to the GPU image tests, including the Direct/P2 image equivalence, tile overflow fallback, shadows, shader reload, and temporal cases. The separate P3 acceptance record tracks those checks and the Linux/Windows CI revisions. The benchmark cannot prove physical Windows GPU performance, broad scene performance, or that Vulkan validation was active during its timed captures.