Status note: read
HANDOFF.mdfirst. It is the authoritative source for current findings, the two active product goals, P0 blockers, and the next implementation slice. This roadmap retains historical context and must be updated only after the handoff.
Current workload focus: Original Particle (
stream), Plasma/GPU Burn (gpu_burn) and the current Cinematic Liquid (cinematic_liquid_v2_physical_scene_v8or its successor). N-body is not a dual-GPU target.
-
gpu_burn_v1original Plasma Bloom visual burn: solid no-hole crystal scene (not particles and not a FurMark donut), safe 16-step probe with per-device auto-tuning, Vulkan/DX12/DX11/OpenGL + WARP, versionedGpix-step/s, WinUI/history/charts, and 15 s + capture-at-5 s flow. RTX 5090 validation reached eight consecutive 99% NVML utilisation samples at approximately 599–600 W. - Vulkan compute + graphics pipeline with particle simulation
- DirectX 12 / DirectX 11 / Metal backend ports
- GPU timestamp profiling (all backends)
- Benchmark mode with standardised report output
- Multi-GPU selection (
--gpuflag) - HarmonyOS (OHOS) Vulkan port via XComponent
- Benchmark result history — auto-save, list, compare, delete, CSV export
- Interactive main menu with quick run / custom run / comparison / delete
- OpenGL 4.3 compute shader backend with GLAD2 loader
-
VK_EXT_debug_utilsintegration — debug labels and object names for RenderDoc - RenderDoc In-Application API — auto-detect, F12 capture,
--capture <seconds>CLI - Python benchmark tooling — chart generation, batch runner, markdown/HTML report export
- Headless compute mode (
--headless) — pure GPU compute without window/swapchain/rendering - Configurable frames-in-flight (
--flights N) — test swapchain depth impact - Configurable particle count — preset sizes (65K–16M) or custom values
- RX 9070 XT (RDNA 4) benchmarks — cross-API, particle scaling, headless analysis
- Multi-workload suite — five cross-API axes selectable via
--workload:stream(bandwidth, GB/s),nbody(achievable compute, GFLOP/s),stress(fractal fill, G-iter/s),synthpeak(peak FLOPS by precision fp32/fp16/fp64/int32),render3d(true-3D instanced billboards with depth, MQuad/s). Per-axisscore/scoreUnitpersisted to results; cross-API charts viascripts/plot_workloads.py. Seebenchmark-workload-suite.md. (Vulkan/DX12/DX11/OpenGL implemented & validated on RTX 5090; Metal written, untested — no macOS. FP16 synthpeak works on Vulkan, DX12 (precompiled SM 6.2 DXIL via SDK DXC), OpenGL (GL_NV_gpu_shader5, NVIDIA) and Metal; impossible on DX11 (SM 5 cap). FP64 unavailable on Metal.)
Results are automatically saved to ~/.gpu_bench/results.json after each run.
Full metrics are persisted: graphics API, GPU, CPU, particle count, difficulty,
timing breakdown (compute / render / total GPU), FPS, and bottleneck analysis.
| Feature | Interactive | CLI |
|---|---|---|
| List all results | Main menu → Delete results | --results |
| Compare (ranked table) | Main menu → Compare results | --compare |
| Detailed side-by-side | Compare → enter two rank #s | --compare <id1> <id2> |
| Delete one result | Delete → enter ID | --results-delete <id> |
| Clear all results | Delete → type all |
--results-clear |
| Export to CSV | — | --results-export <file.csv> |
On startup (when no CLI flags are given), the application presents:
========== Mangekyo GPU Benchmark ==========
[0] Quick run (Vulkan 1.2 / RTX 5090 / Medium) <- default
[1] Custom run (choose API / GPU / difficulty)
[2] Run again (same settings)
[3] Compare results (N saved)
[4] Delete results
[5] Full analysis — one GPU (all APIs + RenderDoc + charts)
[6] Full analysis — all GPUs x APIs (+ RenderDoc + charts)
[7] Flights test — one GPU (all APIs + RenderDoc, custom flights)
[8] Particle count test — one GPU (all APIs + RenderDoc, custom particles)
[9] Headless compute — one GPU (all APIs, pure compute, no rendering)
[10] Exit
====================================
-
Quick run auto-selects the best GPU (discrete > integrated > software) and the best API that GPU supports (Vulkan > DX12 > DX11 > Metal).
-
Run again appears after the first run and reuses the previous settings.
-
Full analysis [5]/[6] — one-click workflow that:
- [5] selects one GPU (default: best dGPU); [6] runs every GPU.
- Benchmarks every supported API on the selected GPU(s) (1M particles, 15s).
- Triggers a RenderDoc frame capture at the 5-second mark on each run (if RenderDoc is attached or the in-app API detects the DLL).
- After all runs, automatically calls Python scripts to generate:
- FPS comparison charts →
docs/images/ - Markdown results table →
docs/results-table.md - Standalone HTML report →
docs/report.html
- FPS comparison charts →
- Prints a final comparison table to the console.
Requires
pip install -r scripts/requirements.txtfor the Python step. -
Flights test [7] — benchmarks with a custom number of frames-in-flight (swapchain images). Tests how swapchain depth affects throughput. RenderDoc capture filenames include the flights count (e.g.
_flights3). -
Particle count test [8] — benchmarks with a custom particle count (preset sizes from 65K to 16M, or enter any number). Tests GPU scaling behaviour. RenderDoc capture filenames include the particle count.
-
Headless compute [9] — pure GPU compute benchmark with no window, swapchain, rendering, or presentation. Eliminates swapchain throttling and semaphore wait pollution, revealing true compute throughput. On the RX 9070 XT, headless mode achieves 21,000+ FPS across all APIs (vs ~1,750 FPS windowed) — a 12× speedup.
-
After each run the menu reappears — no need to restart the application.
Current cinematic_liquid_v2 acceptance status (v7 history preserved; shared-scene changes now use v8):
- Vulkan physical-scene slice: 128x64x96 MLS-MPM, ten substeps and
320,920 particles (142x14x98 base + 48x37x71 dam), with stiffness 45,000,
viscosity 0.035 and max speed 8. The result identity is
now
cinematic_liquid_v2_physical_scene_v8, shader version 9 and scene version 5. V8 isolates the later shared-scene changes: pool inset 0.45, wall-top fraction 0.42 and extinction(12,3.6,2.5). Historical v7 remains unchanged and has no formal score. The user's adjusted mother duck and three ducklings are preserved together with the seven-body index ABI: boat=2, sink sphere=3, ducklings=4-6. - Surface/optics slice: fixed-u32 Spiky-squared particle splat into an
independent 128x64x96 R32F volume, then a 5x5x5 binomial blend with
mix = 0.90. The current renderer follows at most four medium interfaces, applying Fresnel/Snell, per-segment Beer-Lambert attenuation and opaque scene depth sorting. Current v8 usesextinction=(12,3.6,2.5), linear exposure and zero density at volume boundaries. The reconstruction now adaptively preserves low-support spray/drop cells instead of erasing them. Historical iterative-optics v6 keeps its original(30,10,8)metadata. - Physical scene response: body-2 is now a finite 34 kg boat with a soft mooring; propeller reaction and fluid forces can drive and rock it, but its trajectory has not yet received visual acceptance. Body-3 remains a sealed sphere with density ratio 1.06, releases at 4.28 s, uses -9.81 gravity and 0.015 air damping, and gates material water drag by immersed displaced mass. Its entry crown and whitewater come from the GPU body state and local fluid rather than a fragment-only fake; no secondary spray-particle pass exists yet.
- Finite-height pool walls are embedded with inset 0.45 and wall top at fraction 0.42 of the simulation-domain height. A limited outer simulation catch band lets particles cross the rim and fall to the ground, but it is not an infinite fluid domain. The foreground soft-PVC film is a separate IOR-1.50 Fresnel/weak-absorption/wrinkle approximation, not a full multi-medium PVC ray path. Rendered pool/PVC/liner/grass and the physical particle floor share ground y=0, with ring separation derived from twice the tube radius. The environment adds infinite procedural grass and an atmospheric sky/cloud treatment without cubemap assets.
- Historical identities remain isolated: v1;
cinematic_liquid_v2_surface_splat_optics_v4/ shader version 6 formal;cinematic_liquid_v2_duck_family_v5/ shader version 7 previews; andcinematic_liquid_v2_iterative_optics_v6/ shader version 8 previews; physical-scene v7 is also historical and isolated from current v8. The implementation uses only architecture and parameter proportions from MIT-licensed jeantimex/fluid; no upstream code or assets are vendored. - Historical optics_v4 RTX 5090 Vulkan formal 15-second run plus 5.1-second RenderDoc capture
passed: result
20260715-170629-492, Compute 10.572 ms, Render 1.553 ms, Total 12.125 ms, 263.98 MParticle-step/s and 966 measured frames. The 0.103-second capture was excluded; one attempt saved one capture. The checked frame isrdoc_captures/cinematic-liquid-v2-5s-formal-optics-v4.png. - Historical v6 short preview passed on RTX 5090/Vulkan: result
20260715-221447-024, Compute 9.450 ms, Render 3.003 ms, Total 12.454 ms, 257.01 MParticle-step/s and 284 measured frames. Its excluded 0.117-second capture isrdoc_captures/cinematic-liquid-v2-5s-iterative-optics-v6-final-preview.png. This is a six-second_preview; v6 has no formal 15-second score. - Historical v7 shader compilation, all six final SPIR-V validations, CLI
Release and WinUI Release x64 builds passed. WinUI produced zero errors
and only existing MSB8027/C4996/LNK4042-class warnings (two duplicate
WinAppSDK warnings in the latest incremental build; four when affected
sources were rebuilt). Only automatically
terminating six/eight-second smoke runs were used. There is no formal
15-second v7 score, reliably saved new RenderDoc capture, or complete
visual acceptance; transient console value
241.13is not a formal or persisted result. A window closing after a few seconds is the smoke script's--time 8lifecycle, not an established crash. - Run the v8 formal 15-second + five-second capture flow only after the fixed-timestep trajectory contract is frozen; do not reuse any v4/v6/v7 score.
- Exercise WinUI selection/run/history on the final build and record exact boat, sink-sphere and overflow-particle trajectories. Build success and short smoke runs are not GUI or visual acceptance.
- Freeze a cross-GPU trajectory contract that removes fixed-dt/render-rate feedback; audit Vulkan timestamp boundaries; and close abnormal-exit cleanup for every new surface buffer, image, descriptor and pipeline.
- Implement and validate DX12, DX11, OpenGL and Metal versions after the Vulkan scene/pass/quality contract is frozen; they are not supported now.
The independently versioned SPH vertical slice is now implemented at 318,464
particles. A complete 15-second RTX 5090/Vulkan visual run kept the pool, water,
duck family, balls, boat and environment stable; it stopped normally and the
user accepted the current appearance. Visual iteration is therefore closed for
this slice. Every duration is therefore forced into
cinematic_liquid_sph_slice_v1_preview. Formal scoring is still blocked by
render-frame-driven simulation, missing per-substep rigid-body impulse clearing,
the in-place viscosity SSBO race and nondeterministic atomic-scatter cell order;
secondary spray/foam and SPH propeller wake remain later enhancements. The
accepted scene uses pool inset 0.45, wall-top fraction 0.42,
extinction=(12,3.6,2.5) and a staggered 0.50–1.80 simulation-second grass-soak
countdown.
- Keep the accepted SPH appearance fixed while closing its correctness contract: decouple simulation time from render rate, clear body impulses every substep, remove the viscosity race, make atomic-scatter ordering deterministic, then run the formal 15-second + fifth-second RenderDoc/timestamp acceptance. Preserve all MLS-MPM versions unchanged and isolated.
- Immediately add three non-scored modes: Liquid Lab with a free camera and adjustable parameters, GPU Burn Unlimited Soak, and VRAM Integrity Soak. Explore/Soak sessions must never enter the benchmark leaderboard.
- Use the generated v0.1.0 ZIP/Setup as the clean-machine candidate. Runtime Vulkan delay-load, official RenderDoc 1.45 staging, real Inno Setup 6.7.3, stage/ZIP inventories and Release asset hashes are complete. Remaining gates are the frozen report worker, project license, Authenticode signing, clean Windows VM install/upgrade/uninstall/capture, and physical GT 120 validation.
- Continue WebGPU/backend registry and the wider cross-GPU matrix afterward.
- Treat Vulkan KHR ray-query hybrid water RT, later DXR/Metal RT, frozen-snapshot path tracing, and DLSS/FSR/XeSS/MetalFX comparisons as later, separately versioned rendering suites rather than changes to the v2 score contract. Hardware RT and the current software density raymarch must remain separate capability paths and score groups.
Execution gate: item 5 is documentation-only for now. Do not start it until the existing Stream/Particle and GPU Burn tests, scored Cinematic Liquid v2, GUI integration, fixed 15-second/capture flow, and result contracts have all passed their acceptance checks and the user explicitly raises its priority.
- Native
cpu_mixed_v1kernel with integer/branch/FP32/FP64 work, fixed three-round median aggregation, per-logical-processor sweep and all-logical- processor throughput. Every per-core target uses the same seed; measured workers perform no stdout work, multi emits nothing inside a timing window, and worker publications do not false-share. It opens no graphics window and invokes no RenderDoc. - CLI flags:
--cpu-benchmark [per-core|multi|all],--cpu-time,--cpu-warmup, and--cpu-no-save; the CPU path exits before GLFW/GPU probing. The WinUI CPU page provides Quick/Formal, live progress, detailed logical-processor rows, summary, raw output and Run/Cancel. CPU/GPU/Charts launches are mutually exclusive; the complete formal pair is 15.0/0.2, live output is batched and an incomplete child protocol is rejected. - Successful summaries persist to
results.json. Formal is exactly 15.0 s measurement + 0.2 s warm-up + three rounds; previews, affinity capability, timing and multi standalone/after-percore sequence receive separate result identities. - Windows Release smoke on a Ryzen 7 9800X3D: 16 logical / 8 physical / SMT2, Windows CPU Set topology, 16/16 per-core and 16/16 multi workers strict- pinned, exit 0. An isolated 0.1-second WinUI E2E also produced 16 rows, both summaries and 100%/Done. These short smokes are not formal scores.
- Rebuild and clean-machine-test the ZIP/Inno installer with this CPU slice; verify installed GUI-to-CLI discovery, Run/Cancel and History persistence.
- Validate >64-logical processor groups and a real hybrid CPU. Core-class names remain inferred OS-metadata ranks, not authoritative P/E/Mid/LPE identities.
- Native-test Linux/Android
strict_sched_affinity(set plus readback; failure is invalid/exit 3) across host/container/cpuset/device cases, and macOS as scheduler-managed; implement/validate iOS and Web/WASM separately. Their results must never mix with Windows strict-affinity groups.
- Replace optimistic DX11 detection with a real FL10_0/10_1/11.x device probe and optional DirectCompute 4.x feature query; expose the compute bit to WinUI and workload-aware API scheduling.
- Compile FL10 workloads as SM4, skip compute/UAV resources for fragment-only tests, reject FP64 and oversized dispatches, and cap SM4 N-body at 4,096. All 16 production SM4 HLSL entries compile with Windows SDK FXC.
- Delay-load
vulkan-1.dllso a DirectX-only machine can enter DX11/WARP; guard both automatic probing and explicit Vulkan selection. - Validate on the physical GeForce GT 120 under Windows 10 1809+ with its legacy driver. Do not add DX9: it cannot preserve the compute workloads or the RenderDoc capture contract. A Windows 7 target would require a separate legacy CLI/OS package because the current WinUI installer is Windows 10 1809+.
End-to-end RenderDoc profiling on multiple GPUs: RX 9070 XT (RDNA 4, 64 CU),
RX 6900 XT (RDNA 2, 80 CU), and the AMD iGPU (2 CU) as baseline.
Full step-by-step guide: renderdoc-capture-guide.md.
- Run baseline benchmarks (9070 XT + 6900 XT + iGPU, Vulkan + DX11) without RenderDoc.
- Capture one Vulkan frame on each GPU via
--capture 5(at 5s mark). - Take 7 annotated screenshots (event list, compute pipeline, SSBO data, graphics pipeline, barrier, render output, per-event timing).
- Cross-validate app timestamp queries against RenderDoc GPU timing (< 5 % deviation target).
- Write cross-GPU comparison (CU scaling, memory bandwidth, barrier cost).
- Compare RDNA 4 vs RDNA 2 per-CU efficiency via RenderDoc per-event timing.
-
Propose optimisations— deferred; current analysis is sufficient. - Fill in
renderdoc-analysis.mdand updatereport.md.
Code integration already complete:
VK_EXT_debug_utilslabels and object names in the Vulkan backend.- RenderDoc In-Application API: auto-detect on launch, F12 manual capture,
--capture <seconds>for time-based unattended capture.
A scripts/ directory with Python utilities for automated benchmark data
analysis, satisfying the JD's "Scripting languages — Python, Perl, shell"
requirement.
| Script | Purpose |
|---|---|
scripts/plot_results.py |
Read ~/.gpu_bench/results.json and generate 4 charts: FPS by GPU × API, GPU time breakdown (compute/render), CPU overhead, particle-count scaling |
scripts/batch_benchmark.py |
Automate batch runs across all GPU × API × particle-count combinations, with --dry-run preview |
scripts/export_report.py |
Export results as markdown tables (for docs) or a standalone sortable HTML report |
scripts/compare_3dmark.py |
Cross-validate project FPS against 3DMark Time Spy / Fire Strike scores — normalised bar chart, R² correlation scatter plot, deviation table |
scripts/rdoc_export_timing.py |
Export per-event GPU timing from a RenderDoc .rdc capture to JSON — works in RenderDoc GUI Python Shell or standalone via renderdoc module |
scripts/compare_rdoc_timing.py |
Cross-validate app timestamp queries vs RenderDoc GPU timing — side-by-side comparison, deviation analysis, per-event breakdown |
scripts/3dmark_scores.json |
3DMark reference scores (edit with your own or public data) |
scripts/requirements.txt |
Python dependencies (matplotlib, numpy) |
# Install dependencies
pip install -r scripts/requirements.txt
# Generate charts as PNGs
python scripts/plot_results.py --save docs/images
# Batch-run all GPU × API combos (dry-run first)
python scripts/batch_benchmark.py --gpus 0 1 --dry-run
python scripts/batch_benchmark.py --gpus 0 1 --frames 500
# Export markdown table
python scripts/export_report.py --md docs/results-table.md
# Export standalone HTML report
python scripts/export_report.py --html docs/report.html
# Cross-validate against 3DMark
# Option A: auto-import from .3dmark-result files (saved by 3DMark GUI)
python scripts/compare_3dmark.py --import-3dmark "C:/Users/*/Documents/3DMark/*.3dmark-result"
# Option B: auto-import from exported XML (3DMark Professional --export)
python scripts/compare_3dmark.py --import-xml path/to/timespy.xml path/to/firestrike.xml
# Option C: manually edit scripts/3dmark_scores.json, then:
python scripts/compare_3dmark.py --save docs/images # generate charts
python scripts/compare_3dmark.py --md # markdown table to stdout
# RenderDoc timing export & cross-validation
# Step 1: Export timing from .rdc capture (inside RenderDoc Python Shell)
# exec(open('scripts/rdoc_export_timing.py').read())
# Step 1 (alt): Standalone (requires renderdoc on PYTHONPATH)
python scripts/rdoc_export_timing.py capture_6900xt.rdc -o rdoc_6900xt.json
python scripts/rdoc_export_timing.py capture_igpu.rdc -o rdoc_igpu.json
# Step 2: Compare app timestamps vs RenderDoc timing
python scripts/compare_rdoc_timing.py rdoc_6900xt.json rdoc_igpu.jsonBrowser-based port of the particle benchmark, inspired by projects such as Volume Shader BM. Goals:
- WebGPU compute shader path (WGSL) for browsers with WebGPU support.
- WebGL 2.0 fallback using transform feedback for particle updates.
- Hosted as a static site so anyone can run the benchmark without installing drivers or SDKs.
- Cross-platform, cross-system league table comparing results from native backends (Vulkan / DX / Metal) against web backends on the same hardware.
Written analysis document comparing frame rates and GPU timings across a range of AMD and NVIDIA hardware spanning 16 years (2009–2025):
| GPU | Architecture | CUs / SPs | VRAM | Platform | Notes |
|---|---|---|---|---|---|
| RTX 5090 | Blackwell (NVIDIA) | 170 SMs | 32 GB GDDR7 | Windows | Current flagship — reference for cross-vendor comparison |
| RX 9070 XT | RDNA 4 (AMD) | 64 CUs | 16 GB GDDR6 | Windows | Latest AMD architecture — fastest per-CU compute tested |
| GTX 970 | Maxwell (NVIDIA) | 13 SMs | 4 GB GDDR5 | Windows | Older NVIDIA — reveals API ranking reversal vs modern GPUs |
| RX 6900 XT | RDNA 2 | 80 CUs | 16 GB | Windows | Flagship RDNA 2 |
| RX 6600 XT | RDNA 2 | 32 CUs | 8 GB | Windows | Mid-range RDNA 2 — half the CU count of 9070 XT, enables per-CU comparison |
| Vega Frontier Edition | Vega (GCN 5) | 64 CUs | 16 GB HBM2 | Windows | Prosumer / compute |
| RX 580 | Polaris (GCN 4) | 36 CUs | 8 GB | Windows | Mid-range GCN — baseline for normalised comparisons |
| FirePro D700 | Tahiti (GCN 1.0) | 2048 SPs | 6 GB | Windows | Mac Pro 2013 dual-GPU — each card benchmarked independently |
| HD 5770 | Evergreen (TeraScale 2, before GCN) | 800 SPs | 1 GB | Windows (DX11) | Legacy DX11-era GPU |
| Ryzen 7 9800X3D iGPU | RDNA 2 | 2 CUs | Shared | Windows | Integrated graphics |
| Ryzen 7 9800X3D (WARP) | Software | — | System RAM | Windows | Microsoft WARP software rasteriser on AMD CPU |
HD 5770 note: Evergreen does not support Vulkan. Testing will use the DX11 backend only (Feature Level 11_0).
FirePro D700 note: The Mac Pro (Late 2013) has two identical D700 GPUs (GCN 1.0, Tahiti XT). macOS does not support CrossFire; each GPU is an independent
MTLDevice. Both cards are benchmarked individually first. Dual-GPU collaboration is attempted only after a capability probe proves concurrent execution; it is never inferred from two adapter entries or from summed independent scores. Metal is the most direct path. On the current Boot Camp machine Vulkan enumerates both D700s but fails logical-device creation, while DX adapter routing still needs a physical-engine probe, so both Windows routes remain blocked rather than assumed working.WARP note: The Windows Advanced Rasterization Platform (WARP) is a high-performance software renderer included in DirectX. Running the DX11 / DX12 backends on WARP with an AMD CPU provides a pure-software baseline, isolating CPU compute throughput from GPU hardware.
The document covers:
- Per-backend (Vulkan / DX11 / DX12 / Metal / OpenGL / WARP) frame-rate comparison.
- Scaling behaviour when increasing particle count (65 K → 1 M → 16 M).
- Compute vs render timing breakdown per GPU (and CPU via WARP).
- Hardware vs software rendering comparison (discrete GPU vs WARP baseline).
- RX 9070 XT (RDNA 4) vs RX 6600 XT (RDNA 2): 4.1× per-CU compute improvement with 2× the CU count (64 vs 32), demonstrating generational architectural gains.
- Headless compute mode: removing swapchain/render/present reveals true compute throughput — RX 9070 XT achieves 21,000+ FPS in headless vs 1,750 windowed.
- Swapchain semaphore wait pollution analysis — why fast GPUs (9070 XT, RTX 5090) report inflated render timestamps in windowed mode.
- Cross-validation against 3DMark Time Spy and Fire Strike across all GPUs.
- OpenGL compute dispatch overhead on AMD GPUs (2.6–48 ms, vs 0.03 ms on Vulkan).
- Generational progression from TeraScale 2 → GCN 1.0 → GCN 4 → GCN 5 → RDNA 2 → RDNA 4.
- Mac Pro 2013 dual-GPU analysis: display GPU vs headless GPU performance isolation, and macOS Metal vs Boot Camp DX11 cross-platform comparison.
Sweep local_size_x across powers of two (32, 64, 128, 256, 512, 1024) and
measure the impact on compute dispatch time for each GPU above. Publish
findings as an analysis document covering:
- Optimal workgroup size per architecture (GCN vs RDNA 2 vs RDNA 4 vs Maxwell vs Blackwell).
- Occupancy and wavefront utilisation implications.
- Correlation with CU count and cache hierarchy.
Benchmark and document the performance difference between:
| Strategy | Vulkan Flags | Use Case |
|---|---|---|
| Host-visible / host-coherent | HOST_VISIBLE | HOST_COHERENT |
Current approach — simple, CPU-mappable |
| Device-local + staging buffer | DEVICE_LOCAL + staging copy |
Optimal for discrete GPUs |
| Persistent mapping | HOST_VISIBLE | HOST_COHERENT + persistent vkMapMemory |
Avoids repeated map/unmap |
| Device-local host-visible (ReBAR) | DEVICE_LOCAL | HOST_VISIBLE |
AMD SAM / ReBAR on supported GPUs |
Measure particle-buffer throughput and compute dispatch latency for each strategy across integrated and discrete GPUs.
The current benchmark issues a single compute dispatch and a single draw call
per frame — a workload profile that favours DX11's highly optimised implicit
driver path over DX12/Vulkan's explicit model (see
report.md for measured data).
To demonstrate the scalability advantage of explicit APIs, add an optional multi-draw-call mode:
- Render particles in batches (e.g. 1 draw call per 1 024 particles), producing 1 000+ draw calls per frame at default particle counts.
- Record draw commands across 4–8 threads on DX12 (secondary command lists) and Vulkan (secondary command buffers), then submit in a single primary.
- Compare single-threaded vs multi-threaded CPU submission time per API.
- Expected outcome: DX12/Vulkan overtake DX11 when draw-call count is high enough for the driver's single-threaded path to become the bottleneck.
This will complete the cross-API analysis by showing both sides of the implicit-vs-explicit trade-off.
Extend the compute shader to support richer physics:
- Gravitational attraction — N-body style pairwise forces (shared-memory tiling for O(N log N) or O(N²) with optimisation notes).
- Simple collision response — spatial hashing or grid-based broad phase.
- Attractors / repulsors — mouse-driven interactive forces.
This demonstrates more complex compute shader design, including shared-memory optimisation and synchronisation within workgroups.
Add a headless (no rendering) compute benchmark using AMD's HIP runtime:
- Port the particle-update kernel from GLSL/HLSL to a HIP kernel.
- Time kernel dispatch with
hipEventand output the same standardised benchmark report as the graphics backends. - Compare HIP kernel throughput against Vulkan/DX compute shader dispatch on identical AMD hardware.
- HIP compiles for both AMD (ROCm) and NVIDIA (CUDA back-end) GPUs, so the same source covers both vendors.
Equivalent headless compute benchmark targeting NVIDIA GPUs natively:
- Port the particle-update kernel to a CUDA kernel (
.cu). - Time with
cudaEventand produce the same report format. - Compare CUDA kernel throughput against Vulkan compute and the HIP path on NVIDIA hardware.
Implement explicit multi-GPU collaboration for one fixed workload, never two independent benchmark runs whose scores are added together. Target hardware is the Mac Pro 2013 dual FirePro D700 (GCN 1.0, 6 GB each). The first gate is a diagnostic proving that both physical adapters execute concurrently; if the Boot Camp driver routes both logical selections to one GPU, stop the Windows implementation and report it as unsupported.
| API | Mechanism | Status |
|---|---|---|
| Metal (primary) | MTLCopyAllDevices() → two MTLDevice / MTLCommandQueue, per-device resources and explicit copy/sync |
Planned — macOS natively exposes both D700s |
| DX12 | linked-adapter nodes, node-local queues/backbuffers/PSOs/fences, ResizeBuffers1 present queues |
Measured ~1.96–2.05× on dual D700 when using 4 flights with RenderDoc disabled |
| Vulkan | physical-device group, command/acquire/submit/present device masks | Functional but serial on AMD 20.45.40.15: graphics family exposes one VkQueue; no measured gain |
| DX11 | implicit driver AFR or AMD AGS explicit AFR | Final AGS 6.3.1 probe sees both D700s, but explicit and driver modes both return crossfireAPI=0, crossfireGPUCount=1; unavailable on this FireGL stack |
| OpenGL | WGL_AMD_gpu_association contexts plus cross-context framebuffer blit |
Driver enumerates two IDs but returns NULL when creating GPU-2 associated context; explicit SFR unavailable |
Tasks:
- Capability probe: enumerate both D700s, submit uniquely marked work to both at the same time, verify completion and physical-engine utilisation.
- Original Particle: keep the total particle count fixed, let each device own/update/render half, then composite one frame on the display adapter. Score total particles divided by the slower device's completion time.
- Plasma/GPU Burn: implement the first explicit AFR vertical slice. Device A renders even
frame ids and device B odd frame ids into one ordered presentation stream.
Corrected D700 acceptance proved DX12 scaling with four flights and no
RenderDoc injection; Vulkan device-group submissions remain serial on the
single graphics queue. The final dual-compute-queue/storage-swapchain AFR
experiment also ran and exited correctly, but measured only ~98% aggregate
GPU-equivalent utilisation (no cross-frame overlap), so it was fully
reverted. No further single-
VkDeviceVulkan AFR/SFR work remains; a two-VkDeviceexternal-memory design would require a separate future project and score contract. - Plasma/GPU Burn DX12 SFR vertical slice: split one logical frame 50/50,
shade on both linked nodes, copy the secondary half through a Tier-1
cross-node buffer, then compose and present once. D700 short-run acceptance:
16 steps 112 -> 69 FPS (copy-bound regression), 128 steps 19 -> 28 FPS
(1.47x speed-up, but below AFR's ~39 FPS). Keep
..._sfr2experimental. - Current Cinematic Liquid: do not alternate independent simulations. Measure a simulation-GPU/render-GPU pipeline and the required state copy; keep it only if the same fixed scene becomes faster. No duplicate full simulation and no domain decomposition.
- Report single-vs-dual strong scaling, PCIe/copy cost, synchronisation, frame pacing and both adapter identities in a separate result contract.