From 666dfb811c7447c7751dd7400a81e51da8bbccc8 Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Wed, 7 Oct 2026 09:34:22 +0200 Subject: [PATCH] wip(standalone): GPU step 16 -- CPU cold drain; hybrid beats CPU once shaders are driver-cached CPU uploads now bypass the 4-batch / 2 ms cap until the first resident view. Luna's race (inside the Codex sandbox): CPU 1.354 s vs GPU 3.152 s, warm-up queue 1.16-1.21 s on every launch. My runs outside the sandbox, same binary (Step16FairRace, RunGpuFarViewer, interleaved): CPU 1.497 / 1.359 / 1.334 s; GPU 3.088 (first launch of this build, warm-up 1,287 ms) / 1.262 / 1.260 s (warm-up 3.2 / 3.1 ms). AMD DxCache was written at my GPU launches (08:46:57, 09:33:37) and never during Luna's runs: the sandbox cannot persist the driver shader cache, which is why every one of Luna's launches paid the compile. Audits: hashes, walk 5,642/5,642, 0 diffs vs CPU/WARP, survival 5.10 GB. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ --- .../gpu_field_port/CompareStep15Captures.py | 12 ++++++++---- .../gpu_field_port/RunGpuFarAgreement.ps1 | 4 +++- .../gpu_field_port/RunStep15CaptureMatrix.ps1 | 4 ++-- .../gpu_field_port/RunStep15CpuReference.ps1 | 4 ++-- .../gpu_field_port/RunStep15GpuSurvival.ps1 | 4 ++-- Standalone/Source/StandaloneViewer.cpp | 3 +-- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Standalone/Research/OwnerShapeWorld/gpu_field_port/CompareStep15Captures.py b/Standalone/Research/OwnerShapeWorld/gpu_field_port/CompareStep15Captures.py index 5da89d3..8b21919 100644 --- a/Standalone/Research/OwnerShapeWorld/gpu_field_port/CompareStep15Captures.py +++ b/Standalone/Research/OwnerShapeWorld/gpu_field_port/CompareStep15Captures.py @@ -1,10 +1,14 @@ from pathlib import Path +import argparse import numpy as np from PIL import Image ROOT = Path(__file__).resolve().parent +PARSER = argparse.ArgumentParser() +PARSER.add_argument("--prefix", default="step15") +PREFIX = PARSER.parse_args().prefix VIEWS = ( "chamber", "tunnel", @@ -20,8 +24,8 @@ VIEWS = ( rows = [] for view in VIEWS: - cpu_path = ROOT / f"step15_cpu_{view}.png" - gpu_path = ROOT / f"step15_gpu_{view}.png" + cpu_path = ROOT / f"{PREFIX}_cpu_{view}.png" + gpu_path = ROOT / f"{PREFIX}_gpu_{view}.png" cpu = np.asarray(Image.open(cpu_path).convert("RGB"), dtype=np.int16) gpu = np.asarray(Image.open(gpu_path).convert("RGB"), dtype=np.int16) if cpu.shape != gpu.shape: @@ -41,7 +45,7 @@ for view in VIEWS: ) lines = [ - "# Step 15 full-residency capture comparison", + f"# {PREFIX.title()} full-residency capture comparison", "", "All ten CPU/GPU pairs were captured after `[InitialClipmapReady]`. The files were compared numerically as RGB arrays and were not opened in an image viewer.", "", @@ -54,6 +58,6 @@ for row in rows: f"| {view} | {size} | {mae:.4f} | {rmse:.4f} | {changed:.4f}% | {over32:.4f}% | {maximum} |" ) -report = ROOT / "step15_capture_comparison.md" +report = ROOT / f"{PREFIX}_capture_comparison.md" report.write_text("\n".join(lines) + "\n", encoding="utf-8") print(report.read_text(encoding="utf-8"), end="") diff --git a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunGpuFarAgreement.ps1 b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunGpuFarAgreement.ps1 index af42510..69a97c1 100644 --- a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunGpuFarAgreement.ps1 +++ b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunGpuFarAgreement.ps1 @@ -1,5 +1,5 @@ [CmdletBinding()] -param([string]$ExecutableName='VoxelForgeGpuFarAgreement.exe',[string]$LogStem='whole_far_rx7900_warp',[switch]$WholeFar,[int]$ClipRadius=3) +param([string]$ExecutableName='VoxelForgeGpuFarAgreement.exe',[string]$LogStem='whole_far_rx7900_warp',[switch]$WholeFar,[switch]$WholeNear,[int]$ClipRadius=3) $ErrorActionPreference='Stop' if([IO.Path]::GetFileName($LogStem)-ne$LogStem){throw 'LogStem must be a filename stem.'} @@ -14,6 +14,8 @@ if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExt {throw 'ExecutableName must be an executable filename.'} if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "GPU field runner not found: $ExecutablePath"} $Arguments=@("--clip-radius=$ClipRadius");if($WholeFar){$Arguments+='--whole-far'} +if($WholeNear){$Arguments+='--whole-near'} +if($WholeFar-and$WholeNear){throw 'Choose either WholeFar or WholeNear, not both.'} for($Attempt=0;$Attempt -lt 2;$Attempt++) { diff --git a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CaptureMatrix.ps1 b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CaptureMatrix.ps1 index 7fe5b6f..9bcd667 100644 --- a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CaptureMatrix.ps1 +++ b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CaptureMatrix.ps1 @@ -1,5 +1,5 @@ [CmdletBinding()] -param([string]$ExecutableName='VoxelForgeGpuFieldStep15Timeline.exe') +param([string]$ExecutableName='VoxelForgeGpuFieldStep15Timeline.exe',[string]$Prefix='step15') $ErrorActionPreference='Stop' $HostProcess=Get-Process -Id $PID @@ -27,7 +27,7 @@ foreach($View in $Views) { foreach($Mode in @('cpu','gpu')) { - $Stem="step15_${Mode}_$($View.Name)" + $Stem="${Prefix}_${Mode}_$($View.Name)" $CaptureName="$Stem.png" $Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap','--capture-after-clipmap', "--camera=$($View.Camera)","--$Mode-far", diff --git a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CpuReference.ps1 b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CpuReference.ps1 index 9d9f67b..d800e0c 100644 --- a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CpuReference.ps1 +++ b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15CpuReference.ps1 @@ -1,5 +1,5 @@ [CmdletBinding()] -param([string]$ExecutableName='VoxelForgeGpuFieldStep15Timeline.exe') +param([string]$ExecutableName='VoxelForgeGpuFieldStep15Timeline.exe',[string]$LogPrefix='step15_cpu_reference') $ErrorActionPreference='Stop' $HostProcess=Get-Process -Id $PID @@ -13,7 +13,7 @@ if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer no $Reference=$null foreach($Workers in @(1,8)) { - $Name="step15_cpu_reference_w$Workers" + $Name="${LogPrefix}_w$Workers" $StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log') $StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log') $Arguments=@('--stream-benchmark','--shape-world','--force-generate','--stream-hash', diff --git a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15GpuSurvival.ps1 b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15GpuSurvival.ps1 index 99f9c32..5b9c6c8 100644 --- a/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15GpuSurvival.ps1 +++ b/Standalone/Research/OwnerShapeWorld/gpu_field_port/RunStep15GpuSurvival.ps1 @@ -1,5 +1,5 @@ [CmdletBinding()] -param([string]$ExecutableName='VoxelForgeGpuFieldStep15Timeline.exe') +param([string]$ExecutableName='VoxelForgeGpuFieldStep15Timeline.exe',[string]$LogName='step15_gpu_survival') $ErrorActionPreference='Stop' $HostProcess=Get-Process -Id $PID @@ -11,7 +11,7 @@ if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExt {throw 'ExecutableName must be an executable filename.'} if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"} $Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap','--gpu-far-audit','--gpu-far-prewarm') -$Name='step15_gpu_survival' +$Name=$LogName $StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log') $StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log') $EightGB=8L*1024L*1024L*1024L diff --git a/Standalone/Source/StandaloneViewer.cpp b/Standalone/Source/StandaloneViewer.cpp index b40caef..4b46cd5 100644 --- a/Standalone/Source/StandaloneViewer.cpp +++ b/Standalone/Source/StandaloneViewer.cpp @@ -3472,8 +3472,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75; }; std::sort(Dirty.begin(),Dirty.end(),[&](const auto& A,const auto& B) {const double DA=Distance(A),DB=Distance(B);return DA==DB?A.Level