Document Forward+ measurements and Linux lighting evidence
Native and manual checks / native (ubuntu-24.04) (push) Failing after 35s
Native and manual checks / manual (push) Successful in 27s
Native and manual checks / native (windows-2025) (push) Canceled after 0s
Windows editor and software Vulkan / windows-graphics (push) Canceled after 0s

This commit is contained in:
Emil
2026-09-24 03:46:40 +03:00
parent a0a4e29d48
commit f32e4b4058
15 changed files with 1533 additions and 32 deletions
@@ -0,0 +1,105 @@
# P3 Forward+ experiment: correctness and cost on localized lights
The fixed 1920×1080 P3 benchmark crossed the agreed threshold for trying
Forward+. A depth-free 16×16 tiled implementation now exists, but the measured
**build + raster** cost is higher than a full light scan on that benchmark's
dense lights. `RendererConfig::lighting_mode = Auto` therefore keeps the forward
path. `Tiled` is an explicit option for scenes whose projected light volumes
are localized. There is no unmeasured automatic occupancy heuristic.
This is a follow-up to the fixed-scene baseline sweep, which is being merged
as a separate study. It compares both paths in the same source revision
`a0a4e29d480ed3344f19bd3565d48668ca913fed`. The baseline's dense
placement remains the default. An explicit `--light-layout localized` changes
only point-light range from 8 to 1.75 world units; camera, nine casters,
receiver, positions, colors, light count, and output size are unchanged. The
localized fixture is a separate workload, not a replacement for the fixed
baseline gate.
## Renderer behavior and safety
The compute pass builds up to 64 stable-order light indices per screen tile.
It tests each world-space range sphere against four clip-space tile planes.
It does not use depth or reject near-plane intersections. A tile with more than
64 candidates sets an overflow bit; the fragment shader then scans **all**
submitted lights for that tile. Zero lights, missing capability, excessive
buffer size, failed optional allocation, and `Auto` use the forward path. The
shader contract checks the new compute entry's descriptors and 96-byte push
constants; Direct and P2 GPU graphics still use materials at set 0, lighting
at set 1, and GPU scene data at set 2. The tile list is set 1 binding 4 in the
shared fragment shader. Sprite/UI shading returns before tile reads.
The Linux Vulkan image test compares forward and tiled output in Direct, GPU
frustum, and GPU occlusion modes, including a cropped scene viewport, near-plane
crossing point light and shadow, resize, an offscreen light, and 80 coincident
lights that exceed tile capacity. Every overflowing tile falls back to the full
list. Shader reload preserves a working tiled pipeline after invalid bytecode
and recreates it after a valid reload. A separate 1920×1080 capture with 128
localized lights was byte-identical across both paths; its SHA-256 is in the
[provenance record](data/p3-forward-plus-provenance-2026-09-24.json).
## Measurement
The device was NVIDIA GeForce RTX 2080 Ti with NVIDIA driver 595.84.0.0,
Linux Clang Release, Direct visibility, shadows off, 1920×1080. Each mode had
three independent process runs with ten warm-up and thirty measured frames.
Forward/tiled run order alternated. The table uses the median of the three
per-run medians in milliseconds. The tile build column is an actual GPU
timestamp; `build + raster` also includes post raster if present. The dense
and localized CSVs contain every one of the 1080 measured frames, with a
`source_csv` identifier. The executable and all loaded `.spv`/reflection
SHA-256 values are in the provenance record.
| Light layout | Lights | Forward raster | Tile build | Tiled raster | Tiled build + raster | Tiled change |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| Dense fixed scene | 32 | 0.5500 | 0.0617 | 0.5527 | 0.6144 | +0.0644 ms (11.7% slower) |
| Dense fixed scene | 64 | 1.0701 | 0.1177 | 1.0740 | 1.1921 | +0.1220 ms (11.4% slower) |
| Dense fixed scene | 128 | 2.1172 | 0.2219 | 2.1164 | 2.3388 | +0.2216 ms (10.5% slower) |
| Localized range 1.75 | 32 | 0.2336 | 0.0555 | 0.0758 | 0.1312 | −0.1025 ms (43.9% faster) |
| Localized range 1.75 | 64 | 0.4254 | 0.1060 | 0.1057 | 0.2109 | −0.2144 ms (50.4% faster) |
| Localized range 1.75 | 128 | 0.8094 | 0.2048 | 0.1643 | 0.3691 | −0.4404 ms (54.4% faster) |
At 32 dense lights, the first forward process had a 0.7405 ms run median;
the other two were 0.5488 and 0.5500 ms. A single paired run would have
incorrectly suggested a tiled win. The median of three process medians and a
separate earlier repeat both support the slower dense result. This is why
`Auto` remains forward despite the localized-scene gain. The total GPU frame
also includes visibility, shadow fallback, copies, and synchronous readback;
the table isolates the passes that the optimization changes. For example, at
32 localized lights the full GPU frame was 1.6494 ms forward and 1.6472 ms
tiled, essentially unchanged despite lower build + raster cost. At 128 it
was 2.2788 versus 1.7948 ms.
One diagnostic frame per layout/count copied the tile buffer after the timed
draw. That copy was **not enabled** in the 1080 performance frames. The grid
has 8160 tiles and a 64-index capacity per tile.
| Layout | Lights | Stored candidates across tiles | Overflowed tiles |
| --- | ---: | ---: | ---: |
| Dense | 32 | 259,896 | 0 |
| Dense | 64 | 519,792 | 0 |
| Dense | 128 | 522,240 | 8,160 |
| Localized | 32 | 38,237 | 0 |
| Localized | 64 | 76,103 | 0 |
| Localized | 128 | 152,202 | 0 |
The dense 128 candidate count is capped at 64 × 8160 stored slots; all tiles
overflow and correctly evaluate all 128 lights in the fragment shader. This
explains why paying for tile construction cannot help that frame. The localized
128 scene averages about 19 stored candidates per tile and avoids fallback.
Raw data: [all paired frames](data/p3-forward-plus-ab-2026-09-24.csv),
[diagnostic frames](data/p3-forward-plus-diagnostics-2026-09-24.csv), and
[binary/shader provenance](data/p3-forward-plus-provenance-2026-09-24.json).
## Verification and scope
At the implementation revision, Linux Debug built all targets and passed
62/63 CTests, with the compositor-dependent window lifecycle case skipped and
no failures. The pinned Linux SwiftShader ICD passed all six P3 cases, including
the tiled parity/overflow test. The [lighting validation record](../validation/p3-lighting-2026-09-24/README.md)
retains those logs. These are functional checks on Linux and software Vulkan,
not physical Windows GPU performance. The A/B numbers apply to one GPU, driver,
camera, receiver and two synthetic light layouts. They do not establish an
engine-wide speedup. A measured runtime occupancy predictor and representative
game scenes are prerequisites before changing `Auto` from forward.
+2 -1
View File
@@ -1,6 +1,6 @@
# Исследования для Faset Engine
Обновлено 23.09.2026. Исходники и официальная документация исследовались прежде всего 17.09.2026; затем результаты согласованы с принятой архитектурой. P2 implementation/acceptance добавлены позже и отделены от исходного статического исследования.
Обновлено 24.09.2026. Исходники и официальная документация исследовались прежде всего 17.09.2026; затем результаты согласованы с принятой архитектурой. P2/P3 implementation/acceptance добавлены позже и отделены от исходного статического исследования.
**Актуальные решения — в [ARCHITECTURE.md](../ARCHITECTURE.md), порядок реализации — в [PLAN.md](../../PLAN.md).** Реализация MVP и проверки идут отдельно: [журнал реализации](../IMPLEMENTATION.md), [результаты проверок](../validation/README.md), [пользовательский Manual](../manual/index.md). Исследования дают обоснования и проверочные сценарии; их статический анализ не является измерением Faset.
@@ -41,6 +41,7 @@ Linux/Windows, десктопные 2D/3D, C++ сначала и Lua следу
- [19 — P2 GPU visibility: протокол приёмки](19-p2-gpu-visibility-acceptance.md): GPU-сценарии, допуски сравнения и методика измерений; отделяет проверку реализации от предложений исследования 15.
- [20 — P2 GPU visibility: первый benchmark](20-p2-gpu-visibility-benchmark-2026-09-23.md): три запуска, raw CSV, p50/p95 и границы интерпретации на Linux reference GPU.
- [21 — P2 GPU visibility: оптимизация MainCull](21-p2-gpu-visibility-optimization-2026-09-23.md): отдельные измерения переноса выходных буферов в память GPU и замены CAS-цикла на atomic add.
- [23 — P3 Forward+: корректность и стоимость](23-p3-forward-plus-2026-09-24.md): сравнение полной цены построения плиток и рисования на плотной и локализованной сценах, raw CSV и точный shader/binary provenance.
## Происхождение и воспроизводимость
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
light_count,light_layout,shadows,visibility,effective_visibility,lighting_path,requested_lighting,build_configuration,run_index,frame,device,driver,commit,width,height,validation_enabled,validation_errors,submitted_local_lights,omitted_local_lights,requested_local_shadow_faces,rendered_local_shadow_faces,dropped_shadow_faces,shadow_atlas_full_drops,shadow_tiles,draw_calls,gpu_bytes,gpu_main_raster_ms,gpu_post_raster_ms,gpu_post_visible,visibility_counters_valid,gpu_sun_shadow_ms,gpu_local_shadow_ms,gpu_shadow_ms,gpu_light_tiles_ms,gpu_build_plus_raster_ms,light_tile_count,light_tile_counts_valid,light_tile_candidate_count,light_tile_overflow_count,gpu_ms,cpu_ms,readback_cpu_ms
32,dense,off,direct,direct,tiled,tiled,Release,0,0,NVIDIA GeForce RTX 2080 Ti,NVIDIA 595.84.0.0,a0a4e29d480ed3344f19bd3565d48668ca913fed,1920,1080,0,0,32,0,0,0,0,0,0,10,63881248,0.551200,0.000000,0,0,0.000000,0.000000,0.000000,0.061472,0.612672,8160,1,259896,0,3.324384,4.920211,1.106698
64,dense,off,direct,direct,tiled,tiled,Release,0,0,NVIDIA GeForce RTX 2080 Ti,NVIDIA 595.84.0.0,a0a4e29d480ed3344f19bd3565d48668ca913fed,1920,1080,0,0,64,0,0,0,0,0,0,10,63883808,1.077376,0.000000,0,0,0.000000,0.000000,0.000000,0.117440,1.194816,8160,1,519792,0,3.713568,5.236988,1.014093
128,dense,off,direct,direct,tiled,tiled,Release,0,0,NVIDIA GeForce RTX 2080 Ti,NVIDIA 595.84.0.0,a0a4e29d480ed3344f19bd3565d48668ca913fed,1920,1080,0,0,128,0,0,0,0,0,0,10,63888928,2.109440,0.000000,0,0,0.000000,0.000000,0.000000,0.221184,2.330624,8160,1,522240,8160,4.435136,6.211166,0.970080
32,localized,off,direct,direct,tiled,tiled,Release,0,0,NVIDIA GeForce RTX 2080 Ti,NVIDIA 595.84.0.0,a0a4e29d480ed3344f19bd3565d48668ca913fed,1920,1080,0,0,32,0,0,0,0,0,0,10,63881248,0.075328,0.000000,0,0,0.000000,0.000000,0.000000,0.055296,0.130624,8160,1,38237,0,2.355808,3.586245,0.930515
64,localized,off,direct,direct,tiled,tiled,Release,0,0,NVIDIA GeForce RTX 2080 Ti,NVIDIA 595.84.0.0,a0a4e29d480ed3344f19bd3565d48668ca913fed,1920,1080,0,0,64,0,0,0,0,0,0,10,63883808,0.105248,0.000000,0,0,0.000000,0.000000,0.000000,0.105312,0.210560,8160,1,76103,0,2.445600,3.884127,1.069417
128,localized,off,direct,direct,tiled,tiled,Release,0,0,NVIDIA GeForce RTX 2080 Ti,NVIDIA 595.84.0.0,a0a4e29d480ed3344f19bd3565d48668ca913fed,1920,1080,0,0,128,0,0,0,0,0,0,10,63888928,0.215040,0.000000,0,0,0.000000,0.000000,0.000000,0.229376,0.444416,8160,1,152202,0,2.585504,4.059668,0.951374
1 light_count light_layout shadows visibility effective_visibility lighting_path requested_lighting build_configuration run_index frame device driver commit width height validation_enabled validation_errors submitted_local_lights omitted_local_lights requested_local_shadow_faces rendered_local_shadow_faces dropped_shadow_faces shadow_atlas_full_drops shadow_tiles draw_calls gpu_bytes gpu_main_raster_ms gpu_post_raster_ms gpu_post_visible visibility_counters_valid gpu_sun_shadow_ms gpu_local_shadow_ms gpu_shadow_ms gpu_light_tiles_ms gpu_build_plus_raster_ms light_tile_count light_tile_counts_valid light_tile_candidate_count light_tile_overflow_count gpu_ms cpu_ms readback_cpu_ms
2 32 dense off direct direct tiled tiled Release 0 0 NVIDIA GeForce RTX 2080 Ti NVIDIA 595.84.0.0 a0a4e29d480ed3344f19bd3565d48668ca913fed 1920 1080 0 0 32 0 0 0 0 0 0 10 63881248 0.551200 0.000000 0 0 0.000000 0.000000 0.000000 0.061472 0.612672 8160 1 259896 0 3.324384 4.920211 1.106698
3 64 dense off direct direct tiled tiled Release 0 0 NVIDIA GeForce RTX 2080 Ti NVIDIA 595.84.0.0 a0a4e29d480ed3344f19bd3565d48668ca913fed 1920 1080 0 0 64 0 0 0 0 0 0 10 63883808 1.077376 0.000000 0 0 0.000000 0.000000 0.000000 0.117440 1.194816 8160 1 519792 0 3.713568 5.236988 1.014093
4 128 dense off direct direct tiled tiled Release 0 0 NVIDIA GeForce RTX 2080 Ti NVIDIA 595.84.0.0 a0a4e29d480ed3344f19bd3565d48668ca913fed 1920 1080 0 0 128 0 0 0 0 0 0 10 63888928 2.109440 0.000000 0 0 0.000000 0.000000 0.000000 0.221184 2.330624 8160 1 522240 8160 4.435136 6.211166 0.970080
5 32 localized off direct direct tiled tiled Release 0 0 NVIDIA GeForce RTX 2080 Ti NVIDIA 595.84.0.0 a0a4e29d480ed3344f19bd3565d48668ca913fed 1920 1080 0 0 32 0 0 0 0 0 0 10 63881248 0.075328 0.000000 0 0 0.000000 0.000000 0.000000 0.055296 0.130624 8160 1 38237 0 2.355808 3.586245 0.930515
6 64 localized off direct direct tiled tiled Release 0 0 NVIDIA GeForce RTX 2080 Ti NVIDIA 595.84.0.0 a0a4e29d480ed3344f19bd3565d48668ca913fed 1920 1080 0 0 64 0 0 0 0 0 0 10 63883808 0.105248 0.000000 0 0 0.000000 0.000000 0.000000 0.105312 0.210560 8160 1 76103 0 2.445600 3.884127 1.069417
7 128 localized off direct direct tiled tiled Release 0 0 NVIDIA GeForce RTX 2080 Ti NVIDIA 595.84.0.0 a0a4e29d480ed3344f19bd3565d48668ca913fed 1920 1080 0 0 128 0 0 0 0 0 0 10 63888928 0.215040 0.000000 0 0 0.000000 0.000000 0.000000 0.229376 0.444416 8160 1 152202 0 2.585504 4.059668 0.951374
@@ -0,0 +1,33 @@
{
"commit": "a0a4e29d480ed3344f19bd3565d48668ca913fed",
"device": "NVIDIA GeForce RTX 2080 Ti",
"driver": "NVIDIA 595.84.0.0",
"build": "Linux Clang Release",
"executable_sha256": "db151a07eeaee04871920f8617f5bcf4c8ac7cb11abf4e36e5595cc526440a36",
"shader_bundle_sha256": "60d2abf2f43557f72f39de7a50f4bc92816eb7859c613b2797c0410e72dbaeed",
"shader_bundle_hash_method": "SHA256 of UTF-8 canonical JSON mapping sorted shader filenames to per-file SHA256",
"shader_files": {
"vertexMain.spv": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
"vertexMain.reflection.json": "b3bdff863d53a0b385e06a36701a83a6ecafe9a93e97281a732cce8ff862c0db",
"fragmentMain.spv": "eb65edf62a4ead573f740903dbbd1a61565fe97d234fbe8a09934ce6415bec92",
"fragmentMain.reflection.json": "6b62a42ea448d9ae253d78b6b326dfe0d761532ce695b49263689ec649ede36c",
"shadowMain.spv": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
"shadowMain.reflection.json": "d39e2f83c797589296eac9dce139b9ad836a895d6685bc40f79dd2609d687fee",
"lightTileMain.spv": "92850edcc5ee5b586a90ce84ee69a98075a6fff3c13db4a57528d9431afe8b68",
"lightTileMain.reflection.json": "bf6a9256aaa6d6edacfa1e1c265d7c8ce2c1e4ea4036e0bea078c22fd4b536ca",
"gpuVertexMain.spv": "fc9770f304976875f8dd1f6acbe380c77cb06c13276f5596554b3f0b396b31bd",
"gpuVertexMain.reflection.json": "09166d80fba7ab4167e97f85125a7c58ab92ea447c1a6a2ab5084e657401dae9",
"gpuShadowMain.spv": "2da7e7f96bc7de4e9c8ac365fe0a63f608c7bb26ab3e7bfebfcf88b32e86c71d",
"gpuShadowMain.reflection.json": "c9dd844aefb3840f29caad5dfc53986cacc2220f886eda5ad345ebdbb9ff5b1c",
"gpuCullMain.spv": "7691360ec55f41d40d43652f506b051cef8b3a3ddcdcc7db61a7d4d97f9e87d8",
"gpuCullMain.reflection.json": "996fe5c7e31c6b8f316d8f290b3be0ae7063eb46c500a661e8715e9b822a2598",
"gpuHzbMain.spv": "08682362ee2120ed19d260e613285071747c3e436bb09bb6238e46f9cedc2308",
"gpuHzbMain.reflection.json": "589818f670881c64f3aba726ee3bc82fe4b9d835a347f99134e0e157dc4a112e",
"gpuPostCullMain.spv": "62cb72e356346e1511c6d640a3cecb4a6e5283795338299b357edae5f7f52be4",
"gpuPostCullMain.reflection.json": "eed140bbe09c7d14935b688c770261ac0e81677c0974aa811c88ed67ea779b95"
},
"matrix": "Direct, shadows off, 1920x1080, dense or localized, 32/64/128 lights, 3 repeats, 10 warmup + 30 measured frames; alternating A/B order",
"raw_rows": 1080,
"localized_128_capture_sha256": "2aa5d408867f7193b7fd83984f2333b188623bda4d083512ede6b8318f11b45c",
"localized_128_capture_exact_equal": true
}