wip(standalone): GPU step 13 -- near base/skirts/connectors cheaper to compile; warm-up still ~2.0 s
Cold first use: near base 4.2 ms, near detail 1,595 ms (the floor), connector rings 630 -> 409, skirt classify+emit ~1,409 -> 366. Production warm-up is still ~2.03-2.06 s; whole view median CPU 1.356 s vs hybrid 3.044 s. Near 960 + far 1,114 tiles: 0 topology/protected/thin diffs vs CPU and WARP; hashes, walk 5,642/5,642, survival pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
05b1523c54
commit
a96fd0b95b
18 files changed
+776
-75
No files matched your search
@@ -120,7 +120,7 @@ if ($Target -eq 'All') {
|
||||
Sort-Object -Property FullName -Descending | Select-Object -First 1
|
||||
if ($FxC) {
|
||||
[IO.Directory]::CreateDirectory($PrecompiledShaderDir) | Out-Null
|
||||
foreach ($Entry in @('EvaluateFarFieldCS','EvaluateNearFieldCS','ClassifyCS','ClassifyFarCS','ScanGroupsCS','EmitCS','EmitNearCS','NoiseProbeCS','BuildFarConnectorRingsCS','EmitFarConnectorPanelsCS','ClassifyFarSkirtsCS','ScanFarSkirtsCS','EmitFarSkirtsCS')) {
|
||||
foreach ($Entry in @('EvaluateFarFieldCS','EvaluateNearFieldCS','ApplyNearFieldDetailCS','ClassifyCS','ClassifyFarCS','ScanGroupsCS','EmitCS','EmitNearCS','NoiseProbeCS','BuildFarConnectorRingsCS','EmitFarConnectorPanelsCS','ClassifyFarSkirtsCS','ScanFarSkirtsCS','EmitFarSkirtsCS')) {
|
||||
$ShaderBinary = Join-Path $PrecompiledShaderDir ($Entry+'.cso')
|
||||
$CommandLine = '"{0}" /nologo /T cs_5_0 /E {1} /O3 /Gis /Ges /Fo "{2}" "{3}"' -f $FxC.FullName,$Entry,$ShaderBinary,$ShaderSource
|
||||
Invoke-FieldViewerBuildCommand $CommandLine "precompile HLSL entry $Entry"
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
VIEWS = (
|
||||
"chamber",
|
||||
"tunnel",
|
||||
"passage",
|
||||
"far",
|
||||
"passage_floor_closeup",
|
||||
"tunnel_bend",
|
||||
"remote_yaw0",
|
||||
"remote_yaw90",
|
||||
"remote_yaw180",
|
||||
"remote_yaw270",
|
||||
)
|
||||
|
||||
rows = []
|
||||
for view in VIEWS:
|
||||
cpu_path = ROOT / f"step13_cpu_{view}.png"
|
||||
gpu_path = ROOT / f"step13_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:
|
||||
raise RuntimeError(f"dimension mismatch for {view}: {cpu.shape} vs {gpu.shape}")
|
||||
diff = np.abs(cpu - gpu)
|
||||
pixel_max = diff.max(axis=2)
|
||||
rows.append(
|
||||
(
|
||||
view,
|
||||
f"{cpu.shape[1]}x{cpu.shape[0]}",
|
||||
float(diff.mean()),
|
||||
float(np.sqrt(np.square(diff, dtype=np.float64).mean())),
|
||||
float(np.count_nonzero(pixel_max) * 100.0 / pixel_max.size),
|
||||
float(np.count_nonzero(pixel_max > 32) * 100.0 / pixel_max.size),
|
||||
int(pixel_max.max()),
|
||||
)
|
||||
)
|
||||
|
||||
lines = [
|
||||
"# Step 13 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.",
|
||||
"",
|
||||
"| View | Size | RGB MAE | RGB RMSE | Changed pixels | Pixels max channel >32 | Max channel |",
|
||||
"|---|---:|---:|---:|---:|---:|---:|",
|
||||
]
|
||||
for row in rows:
|
||||
view, size, mae, rmse, changed, over32, maximum = row
|
||||
lines.append(
|
||||
f"| {view} | {size} | {mae:.4f} | {rmse:.4f} | {changed:.4f}% | {over32:.4f}% | {maximum} |"
|
||||
)
|
||||
|
||||
report = ROOT / "step13_capture_comparison.md"
|
||||
report.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
print(report.read_text(encoding="utf-8"), end="")
|
||||
@@ -148,6 +148,19 @@ namespace
|
||||
std::int32_t detailMinVoxel[4], detailMaxVoxel[4];
|
||||
};
|
||||
static_assert(sizeof(FarFieldConstants) == 80);
|
||||
struct NearFieldDetailBaseGpu
|
||||
{
|
||||
float geometry[4];
|
||||
float influences[4];
|
||||
};
|
||||
static_assert(sizeof(NearFieldDetailBaseGpu) == 32);
|
||||
struct FarSkirtCachedSamplesGpu
|
||||
{
|
||||
float endpointDensities[2];
|
||||
float centerDensities[4];
|
||||
std::uint32_t metadata[4];
|
||||
};
|
||||
static_assert(sizeof(FarSkirtCachedSamplesGpu) == 40);
|
||||
static_assert(sizeof(FarFieldPrimitiveGpu) == 224);
|
||||
static_assert(sizeof(FarFieldSpatialBin) == 24);
|
||||
static_assert(sizeof(FarFieldStratumBoundary) == 8);
|
||||
@@ -527,17 +540,20 @@ namespace
|
||||
struct FarScratch
|
||||
{
|
||||
std::uint32_t sampleCount=0,cellCount=0,groupCount=0;
|
||||
ComPtr<ID3D11Buffer> signs,tri,density,nearNormalDensity,midpointIds,midpointRecords;
|
||||
ComPtr<ID3D11Buffer> signs,tri,density,nearNormalDensity,nearDetailBase,midpointIds,midpointRecords;
|
||||
ComPtr<ID3D11Buffer> cases,localOffsets,groupCounts,groupOffsets;
|
||||
ComPtr<ID3D11Buffer> tileConstants,farConstants;
|
||||
ComPtr<ID3D11Buffer> connectorConstants,connectorRings;
|
||||
ComPtr<ID3D11ShaderResourceView> signSrv,triSrv,densitySrv,nearNormalDensitySrv,midpointIdSrv,midpointRecordSrv;
|
||||
ComPtr<ID3D11ShaderResourceView> signSrv,triSrv,densitySrv,nearNormalDensitySrv,nearDetailBaseSrv,midpointIdSrv,midpointRecordSrv;
|
||||
ComPtr<ID3D11ShaderResourceView> caseSrv,localOffsetSrv,groupCountSrv,groupOffsetSrv;
|
||||
ComPtr<ID3D11ShaderResourceView> connectorRingSrv;
|
||||
ComPtr<ID3D11UnorderedAccessView> densityUav,nearNormalDensityUav,caseUav,localOffsetUav,groupCountUav,groupOffsetUav;
|
||||
ComPtr<ID3D11UnorderedAccessView> densityUav,nearNormalDensityUav,nearDetailBaseUav,caseUav,localOffsetUav,groupCountUav,groupOffsetUav;
|
||||
ComPtr<ID3D11UnorderedAccessView> connectorRingUav;
|
||||
ComPtr<ID3D11Buffer> skirtScratch;
|
||||
ComPtr<ID3D11UnorderedAccessView> skirtScratchUav;
|
||||
ComPtr<ID3D11Buffer> skirtProbeData;
|
||||
ComPtr<ID3D11ShaderResourceView> skirtProbeSrv;
|
||||
ComPtr<ID3D11UnorderedAccessView> skirtProbeUav;
|
||||
std::uint32_t skirtScratchCapacity=0;
|
||||
DynamicInput shapes,ranges,ids,protectedAir,protectedSolid,nearPackedProxy;
|
||||
DynamicInput connectors;
|
||||
@@ -551,7 +567,7 @@ namespace
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
ComPtr<ID3D11DeviceContext> immediateContext,deferredContext;
|
||||
ComPtr<ID3D11ComputeShader> fieldEval, fieldEvalNear, classify, fieldClassify, scan, emit, emitNear, noiseProbe;
|
||||
ComPtr<ID3D11ComputeShader> fieldEval, fieldEvalNear, fieldEvalNearDetail, classify, fieldClassify, scan, emit, emitNear, noiseProbe;
|
||||
ComPtr<ID3D11ComputeShader> connectorRings,connectorPanels;
|
||||
ComPtr<ID3D11ComputeShader> classifyFarSkirts,scanFarSkirts,emitFarSkirts;
|
||||
ComPtr<IDXGIAdapter3> memoryAdapter;
|
||||
@@ -596,6 +612,7 @@ namespace
|
||||
};
|
||||
Create("EvaluateFarFieldCS",fieldEval);
|
||||
Create("EvaluateNearFieldCS",fieldEvalNear);
|
||||
Create("ApplyNearFieldDetailCS",fieldEvalNearDetail);
|
||||
Create("ClassifyCS",classify);
|
||||
Create("ClassifyFarCS",fieldClassify);
|
||||
Create("ScanGroupsCS",scan);
|
||||
@@ -614,8 +631,9 @@ namespace
|
||||
void QueueTinyShaderWarmup(bool dispatchShaders,const std::string& entryFilter)
|
||||
{
|
||||
const auto WarmupStart=Clock::now();
|
||||
static constexpr std::array<std::string_view,13> entries={
|
||||
static constexpr std::array<std::string_view,14> entries={
|
||||
"EvaluateFarFieldCS","EvaluateNearFieldCS","ClassifyCS","ClassifyFarCS","ScanGroupsCS","EmitCS",
|
||||
"ApplyNearFieldDetailCS",
|
||||
"EmitNearCS","BuildFarConnectorRingsCS","EmitFarConnectorPanelsCS",
|
||||
"ClassifyFarSkirtsCS","ScanFarSkirtsCS","EmitFarSkirtsCS","NoiseProbeCS"};
|
||||
if(!entryFilter.empty()&&std::find(entries.begin(),entries.end(),entryFilter)==entries.end())
|
||||
@@ -625,7 +643,7 @@ namespace
|
||||
tile.cells=1;tile.sampleDim=3;tile.cellCount=cellCount;tile.groupCount=groupCount;
|
||||
tile.stepVoxels=entryFilter=="EmitNearCS"?1:2;
|
||||
tile.nearFieldMode=(entryFilter.empty()||entryFilter=="EvaluateNearFieldCS"
|
||||
||entryFilter=="EmitNearCS")?1u:0u;
|
||||
||entryFilter=="ApplyNearFieldDetailCS"||entryFilter=="EmitNearCS")?1u:0u;
|
||||
tile.voxelSizeCm=25.0f;tile.outputVertexCapacity=3;
|
||||
FarFieldConstants field{};
|
||||
field.strataLo=-100.0f;field.strataHi=100.0f;field.strataBlend=12.0f;
|
||||
@@ -659,6 +677,9 @@ namespace
|
||||
std::array<float,sampleCount> zeroDensity{};
|
||||
auto density=Structured(zeroDensity.data(),sampleCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto nearNormal=Structured(zeroDensity.data(),sampleCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
std::array<NearFieldDetailBaseGpu,sampleCount> zeroNearDetailBase{};
|
||||
auto nearDetailBase=Structured(zeroNearDetailBase.data(),sampleCount,
|
||||
D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto evalCounters=Structured<std::uint32_t>(nullptr,sampleCount,D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto signs=Structured(&zeroWord,1,D3D11_BIND_SHADER_RESOURCE);
|
||||
std::array<std::int32_t,256*16> triTable{};triTable.fill(-1);
|
||||
@@ -677,9 +698,12 @@ namespace
|
||||
FarConnectorRingRecord emptyRing{};
|
||||
auto connectorRingBuffer=Structured(&emptyRing,1,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto skirtScratch=Structured<std::uint32_t>(nullptr,3,D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto skirtProbeData=Structured<FarSkirtCachedSamplesGpu>(nullptr,3,
|
||||
D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
|
||||
auto densitySrv=Srv<float>(density.Get(),sampleCount);
|
||||
auto nearNormalSrv=Srv<float>(nearNormal.Get(),sampleCount);
|
||||
auto nearDetailBaseSrv=Srv<NearFieldDetailBaseGpu>(nearDetailBase.Get(),sampleCount);
|
||||
auto shapeSrv=Srv<FarFieldPrimitiveGpu>(shapes.Get(),1);
|
||||
auto binSrv=Srv<FarFieldSpatialBin>(bins.Get(),1);
|
||||
auto shapeIdSrv=Srv<std::uint32_t>(shapeIds.Get(),1);
|
||||
@@ -697,8 +721,10 @@ namespace
|
||||
auto midpointRecordSrv=Srv<MidpointRecord>(midpointRecords.Get(),1);
|
||||
auto connectorPanelSrv=Srv<FarFieldConnectorPanel>(panelBuffer.Get(),1);
|
||||
auto connectorRingSrv=Srv<FarConnectorRingRecord>(connectorRingBuffer.Get(),1);
|
||||
auto skirtProbeSrv=Srv<FarSkirtCachedSamplesGpu>(skirtProbeData.Get(),3);
|
||||
auto densityUav=Uav(density.Get(),sampleCount);
|
||||
auto nearNormalUav=Uav(nearNormal.Get(),sampleCount);
|
||||
auto nearDetailBaseUav=Uav(nearDetailBase.Get(),sampleCount);
|
||||
auto evalCounterUav=Uav(evalCounters.Get(),sampleCount);
|
||||
auto caseUav=Uav(cases.Get(),cellCount);
|
||||
auto localOffsetUav=Uav(localOffsets.Get(),cellCount);
|
||||
@@ -706,6 +732,7 @@ namespace
|
||||
auto groupOffsetUav=Uav(groupOffsets.Get(),groupCount);
|
||||
auto connectorRingUav=Uav(connectorRingBuffer.Get(),1);
|
||||
auto skirtScratchUav=Uav(skirtScratch.Get(),3);
|
||||
auto skirtProbeUav=Uav(skirtProbeData.Get(),3);
|
||||
|
||||
auto args=RawMeshBuffer(11u*sizeof(std::uint32_t),D3D11_BIND_UNORDERED_ACCESS,
|
||||
D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS|D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS);
|
||||
@@ -746,9 +773,9 @@ namespace
|
||||
ID3D11Buffer* constants[3]={tileCb.Get(),fieldCb.Get(),connectorCb.Get()};
|
||||
context->CSSetConstantBuffers(0,3,constants);
|
||||
std::uint32_t dispatchCount=0;
|
||||
auto ClearBindings=[&](UINT srvCount=20)
|
||||
auto ClearBindings=[&](UINT srvCount=22)
|
||||
{
|
||||
ID3D11ShaderResourceView* nullSrvs[20]{};
|
||||
ID3D11ShaderResourceView* nullSrvs[22]{};
|
||||
ID3D11UnorderedAccessView* nullUavs[8]{};
|
||||
context->CSSetShaderResources(0,srvCount,nullSrvs);
|
||||
context->CSSetUnorderedAccessViews(0,8,nullUavs,nullptr);
|
||||
@@ -765,17 +792,28 @@ namespace
|
||||
std::chrono::duration<double,std::milli>(Clock::now()-start).count());
|
||||
};
|
||||
|
||||
ID3D11ShaderResourceView* evalSrvs[20]{};
|
||||
ID3D11ShaderResourceView* evalSrvs[21]{};
|
||||
evalSrvs[10]=shapeSrv.Get();evalSrvs[11]=binSrv.Get();evalSrvs[12]=shapeIdSrv.Get();
|
||||
evalSrvs[13]=protectedAirSrv.Get();evalSrvs[14]=protectedSolidSrv.Get();
|
||||
evalSrvs[16]=detailSrv.Get();evalSrvs[17]=proxySrv.Get();
|
||||
context->CSSetShaderResources(0,20,evalSrvs);
|
||||
ID3D11UnorderedAccessView* evalUavs[8]{};
|
||||
evalUavs[1]=nearDetailBaseUav.Get();
|
||||
evalUavs[5]=nearNormalUav.Get();evalUavs[6]=evalCounterUav.Get();evalUavs[7]=densityUav.Get();
|
||||
context->CSSetUnorderedAccessViews(0,8,evalUavs,nullptr);
|
||||
Dispatch(fieldEval.Get(),"EvaluateFarFieldCS");ClearBindings();
|
||||
Dispatch(fieldEvalNear.Get(),"EvaluateNearFieldCS");ClearBindings();
|
||||
|
||||
ID3D11ShaderResourceView* nearDetailSrvs[21]{};
|
||||
nearDetailSrvs[13]=protectedAirSrv.Get();nearDetailSrvs[14]=protectedSolidSrv.Get();
|
||||
nearDetailSrvs[16]=detailSrv.Get();nearDetailSrvs[17]=proxySrv.Get();
|
||||
nearDetailSrvs[20]=nearDetailBaseSrv.Get();
|
||||
context->CSSetShaderResources(0,21,nearDetailSrvs);
|
||||
ID3D11UnorderedAccessView* nearDetailUavs[8]{};
|
||||
nearDetailUavs[5]=nearNormalUav.Get();nearDetailUavs[7]=densityUav.Get();
|
||||
context->CSSetUnorderedAccessViews(0,8,nearDetailUavs,nullptr);
|
||||
Dispatch(fieldEvalNearDetail.Get(),"ApplyNearFieldDetailCS");ClearBindings();
|
||||
|
||||
ID3D11ShaderResourceView* classifySrvs[16]{};
|
||||
classifySrvs[0]=signSrv.Get();classifySrvs[1]=triangleSrv.Get();
|
||||
context->CSSetShaderResources(0,16,classifySrvs);
|
||||
@@ -818,12 +856,14 @@ namespace
|
||||
context->CSSetUnorderedAccessViews(0,8,panelUavs,nullptr);
|
||||
Dispatch(connectorPanels.Get(),"EmitFarConnectorPanelsCS");ClearBindings();
|
||||
|
||||
ID3D11ShaderResourceView* skirtSrvs[20]{};
|
||||
ID3D11ShaderResourceView* skirtSrvs[22]{};
|
||||
skirtSrvs[10]=shapeSrv.Get();skirtSrvs[11]=binSrv.Get();skirtSrvs[12]=shapeIdSrv.Get();
|
||||
skirtSrvs[13]=protectedAirSrv.Get();skirtSrvs[14]=protectedSolidSrv.Get();skirtSrvs[19]=vertexSrv.Get();
|
||||
context->CSSetShaderResources(0,20,skirtSrvs);
|
||||
skirtSrvs[21]=skirtProbeSrv.Get();
|
||||
context->CSSetShaderResources(0,22,skirtSrvs);
|
||||
ID3D11UnorderedAccessView* classifySkirtUavs[8]{};
|
||||
classifySkirtUavs[0]=skirtScratchUav.Get();classifySkirtUavs[4]=argsUav.Get();
|
||||
classifySkirtUavs[0]=skirtScratchUav.Get();classifySkirtUavs[2]=skirtProbeUav.Get();
|
||||
classifySkirtUavs[4]=argsUav.Get();
|
||||
context->CSSetUnorderedAccessViews(0,8,classifySkirtUavs,nullptr);
|
||||
Dispatch(classifyFarSkirts.Get(),"ClassifyFarSkirtsCS");ClearBindings();
|
||||
|
||||
@@ -832,7 +872,7 @@ namespace
|
||||
context->CSSetUnorderedAccessViews(0,8,scanSkirtUavs,nullptr);
|
||||
Dispatch(scanFarSkirts.Get(),"ScanFarSkirtsCS");ClearBindings();
|
||||
|
||||
context->CSSetShaderResources(0,20,skirtSrvs);
|
||||
context->CSSetShaderResources(0,22,skirtSrvs);
|
||||
ID3D11UnorderedAccessView* emitSkirtUavs[8]{};
|
||||
emitSkirtUavs[0]=skirtScratchUav.Get();emitSkirtUavs[4]=argsUav.Get();
|
||||
emitSkirtUavs[5]=panelVertexUav.Get();emitSkirtUavs[6]=panelIndexUav.Get();
|
||||
@@ -1165,6 +1205,8 @@ namespace
|
||||
scratch.density=Structured<float>(nullptr,samples,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
scratch.nearNormalDensity=Structured<float>(nullptr,samples,
|
||||
D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
scratch.nearDetailBase=Structured<NearFieldDetailBaseGpu>(nullptr,samples,
|
||||
D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
std::vector<std::uint32_t> invalidIds(cells,InvalidIndex);
|
||||
scratch.midpointIds=Structured(invalidIds.data(),invalidIds.size(),D3D11_BIND_SHADER_RESOURCE);
|
||||
const MidpointRecord zeroRecord{};
|
||||
@@ -1176,10 +1218,13 @@ namespace
|
||||
scratch.skirtScratchCapacity=std::max<std::uint32_t>(1,farMaxVerticesPerTile);
|
||||
scratch.skirtScratch=Structured<std::uint32_t>(nullptr,scratch.skirtScratchCapacity,
|
||||
D3D11_BIND_UNORDERED_ACCESS);
|
||||
scratch.skirtProbeData=Structured<FarSkirtCachedSamplesGpu>(nullptr,
|
||||
scratch.skirtScratchCapacity,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
scratch.signSrv=Srv<std::uint32_t>(scratch.signs.Get(),1);
|
||||
scratch.triSrv=Srv<std::int32_t>(scratch.tri.Get(),256u*16u);
|
||||
scratch.densitySrv=Srv<float>(scratch.density.Get(),samples);
|
||||
scratch.nearNormalDensitySrv=Srv<float>(scratch.nearNormalDensity.Get(),samples);
|
||||
scratch.nearDetailBaseSrv=Srv<NearFieldDetailBaseGpu>(scratch.nearDetailBase.Get(),samples);
|
||||
scratch.midpointIdSrv=Srv<std::uint32_t>(scratch.midpointIds.Get(),cells);
|
||||
scratch.midpointRecordSrv=Srv<MidpointRecord>(scratch.midpointRecords.Get(),1);
|
||||
scratch.caseSrv=Srv<std::uint32_t>(scratch.cases.Get(),cells);
|
||||
@@ -1188,11 +1233,15 @@ namespace
|
||||
scratch.groupOffsetSrv=Srv<std::uint32_t>(scratch.groupOffsets.Get(),groups);
|
||||
scratch.densityUav=Uav(scratch.density.Get(),samples);
|
||||
scratch.nearNormalDensityUav=Uav(scratch.nearNormalDensity.Get(),samples);
|
||||
scratch.nearDetailBaseUav=Uav(scratch.nearDetailBase.Get(),samples);
|
||||
scratch.caseUav=Uav(scratch.cases.Get(),cells);
|
||||
scratch.localOffsetUav=Uav(scratch.localOffsets.Get(),cells);
|
||||
scratch.groupCountUav=Uav(scratch.groupCounts.Get(),groups);
|
||||
scratch.groupOffsetUav=Uav(scratch.groupOffsets.Get(),groups);
|
||||
scratch.skirtScratchUav=Uav(scratch.skirtScratch.Get(),scratch.skirtScratchCapacity);
|
||||
scratch.skirtProbeSrv=Srv<FarSkirtCachedSamplesGpu>(scratch.skirtProbeData.Get(),
|
||||
scratch.skirtScratchCapacity);
|
||||
scratch.skirtProbeUav=Uav(scratch.skirtProbeData.Get(),scratch.skirtScratchCapacity);
|
||||
const auto DynamicConstant=[&](UINT bytes,const char* label)
|
||||
{
|
||||
D3D11_BUFFER_DESC desc{};desc.ByteWidth=bytes;desc.Usage=D3D11_USAGE_DYNAMIC;
|
||||
@@ -1324,23 +1373,24 @@ namespace
|
||||
if (farField)
|
||||
result.d3dBufferBytes += farField->protectedAir.size() * sizeof(std::uint32_t)
|
||||
+ farField->protectedSolid.size() * sizeof(std::uint32_t)
|
||||
+ farField->nearPackedProxy.size() * sizeof(std::uint32_t)
|
||||
+ farField->connectorPanels.size() * sizeof(FarFieldConnectorPanel)
|
||||
+ tile.density.size() * sizeof(float)
|
||||
+ sizeof(FarFieldConstants);
|
||||
+ farField->nearPackedProxy.size() * sizeof(std::uint32_t)
|
||||
+ farField->connectorPanels.size() * sizeof(FarFieldConnectorPanel)
|
||||
+ tile.density.size() * sizeof(float)
|
||||
+ tile.density.size() * sizeof(NearFieldDetailBaseGpu)
|
||||
+ sizeof(FarFieldConstants);
|
||||
if (readback)
|
||||
result.d3dBufferBytes += cellCount * sizeof(std::uint32_t)
|
||||
+ std::max<std::uint32_t>(1, tile.expectedVertexCount) * sizeof(GpuVertex)
|
||||
+ std::max<std::uint32_t>(1, tile.expectedVertexCount) * sizeof(std::uint32_t)
|
||||
+ 5 * sizeof(std::uint32_t);
|
||||
ComPtr<ID3D11Buffer> signs,triBuffer,density,nearNormalDensity,midpointIds,midpointRecords;
|
||||
ComPtr<ID3D11Buffer> signs,triBuffer,density,nearNormalDensity,nearDetailBase,midpointIds,midpointRecords;
|
||||
ComPtr<ID3D11Buffer> cases,localOffsets,groupCounts,groupOffsets;
|
||||
ComPtr<ID3D11ShaderResourceView> signSrv,triSrv,densitySrv,nearNormalDensitySrv,farShapeSrv,farRangeSrv,farIdSrv;
|
||||
ComPtr<ID3D11ShaderResourceView> signSrv,triSrv,densitySrv,nearNormalDensitySrv,nearDetailBaseSrv,farShapeSrv,farRangeSrv,farIdSrv;
|
||||
ComPtr<ID3D11ShaderResourceView> farProtectedSrv,farProtectedSolidSrv,farNearProxySrv;
|
||||
ComPtr<ID3D11ShaderResourceView> farConnectorSrv,farConnectorRingSrv;
|
||||
ComPtr<ID3D11ShaderResourceView> midpointIdSrv,midpointRecordSrv,caseSrv,localOffsetSrv;
|
||||
ComPtr<ID3D11ShaderResourceView> groupCountSrv,groupOffsetSrv;
|
||||
ComPtr<ID3D11UnorderedAccessView> caseUav,localOffsetUav,groupCountUav,groupOffsetUav,densityUav,nearNormalDensityUav;
|
||||
ComPtr<ID3D11UnorderedAccessView> caseUav,localOffsetUav,groupCountUav,groupOffsetUav,densityUav,nearNormalDensityUav,nearDetailBaseUav;
|
||||
ComPtr<ID3D11UnorderedAccessView> farConnectorRingUav;
|
||||
ComPtr<ID3D11Buffer> farConnectorConstantsBuffer;
|
||||
ComPtr<ID3D11Buffer> farConnectorRingBuffer;
|
||||
@@ -1359,15 +1409,18 @@ namespace
|
||||
FarScratch& scratch=farScratch;
|
||||
signs=scratch.signs;triBuffer=scratch.tri;density=scratch.density;
|
||||
nearNormalDensity=scratch.nearNormalDensity;
|
||||
nearDetailBase=scratch.nearDetailBase;
|
||||
midpointIds=scratch.midpointIds;midpointRecords=scratch.midpointRecords;
|
||||
cases=scratch.cases;localOffsets=scratch.localOffsets;
|
||||
groupCounts=scratch.groupCounts;groupOffsets=scratch.groupOffsets;
|
||||
signSrv=scratch.signSrv;triSrv=scratch.triSrv;densitySrv=scratch.densitySrv;
|
||||
nearNormalDensitySrv=scratch.nearNormalDensitySrv;
|
||||
nearDetailBaseSrv=scratch.nearDetailBaseSrv;
|
||||
midpointIdSrv=scratch.midpointIdSrv;midpointRecordSrv=scratch.midpointRecordSrv;
|
||||
caseSrv=scratch.caseSrv;localOffsetSrv=scratch.localOffsetSrv;
|
||||
groupCountSrv=scratch.groupCountSrv;groupOffsetSrv=scratch.groupOffsetSrv;
|
||||
densityUav=scratch.densityUav;nearNormalDensityUav=scratch.nearNormalDensityUav;
|
||||
nearDetailBaseUav=scratch.nearDetailBaseUav;
|
||||
caseUav=scratch.caseUav;
|
||||
localOffsetUav=scratch.localOffsetUav;groupCountUav=scratch.groupCountUav;
|
||||
groupOffsetUav=scratch.groupOffsetUav;
|
||||
@@ -1398,8 +1451,12 @@ namespace
|
||||
density=Structured(farField?static_cast<const float*>(nullptr):tile.density.data(),
|
||||
tile.density.size(),D3D11_BIND_SHADER_RESOURCE|(farField?D3D11_BIND_UNORDERED_ACCESS:0));
|
||||
if(farField)
|
||||
{
|
||||
nearNormalDensity=Structured<float>(nullptr,tile.density.size(),
|
||||
D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
nearDetailBase=Structured<NearFieldDetailBaseGpu>(nullptr,tile.density.size(),
|
||||
D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
}
|
||||
midpointIds=Structured(tile.midpointIds.data(),tile.midpointIds.size(),D3D11_BIND_SHADER_RESOURCE);
|
||||
const MidpointRecord zeroRecord{};
|
||||
midpointRecords=Structured(tile.midpointRecords.empty()?&zeroRecord:tile.midpointRecords.data(),
|
||||
@@ -1412,7 +1469,10 @@ namespace
|
||||
triSrv=Srv<std::int32_t>(triBuffer.Get(),triCount);
|
||||
densitySrv=Srv<float>(density.Get(),tile.density.size());
|
||||
if(farField)
|
||||
{
|
||||
nearNormalDensitySrv=Srv<float>(nearNormalDensity.Get(),tile.density.size());
|
||||
nearDetailBaseSrv=Srv<NearFieldDetailBaseGpu>(nearDetailBase.Get(),tile.density.size());
|
||||
}
|
||||
midpointIdSrv=Srv<std::uint32_t>(midpointIds.Get(),tile.midpointIds.size());
|
||||
midpointRecordSrv=Srv<MidpointRecord>(midpointRecords.Get(),std::max<std::size_t>(1,tile.midpointRecords.size()));
|
||||
caseSrv=Srv<std::uint32_t>(cases.Get(),cellCount);
|
||||
@@ -1424,6 +1484,8 @@ namespace
|
||||
densityUav=farField?Uav(density.Get(),tile.density.size()):ComPtr<ID3D11UnorderedAccessView>{};
|
||||
nearNormalDensityUav=farField?Uav(nearNormalDensity.Get(),tile.density.size()):
|
||||
ComPtr<ID3D11UnorderedAccessView>{};
|
||||
nearDetailBaseUav=farField?Uav(nearDetailBase.Get(),tile.density.size()):
|
||||
ComPtr<ID3D11UnorderedAccessView>{};
|
||||
if(farField)
|
||||
{
|
||||
const std::uint32_t zeroWord=0;
|
||||
@@ -1463,6 +1525,9 @@ namespace
|
||||
ComPtr<ID3D11UnorderedAccessView> connectorVertexUav,connectorIndexUav;
|
||||
ComPtr<ID3D11Buffer> skirtScratchBuffer;
|
||||
ComPtr<ID3D11UnorderedAccessView> skirtScratchUav;
|
||||
ComPtr<ID3D11Buffer> skirtProbeBuffer;
|
||||
ComPtr<ID3D11ShaderResourceView> skirtProbeSrv;
|
||||
ComPtr<ID3D11UnorderedAccessView> skirtProbeUav;
|
||||
const std::uint32_t connectorPanelCapacity=pooledChunk?FarPanelVertexCapacity:
|
||||
std::max<std::uint32_t>(1,farField&&(farField->visibleSkirtFaceMask!=0)
|
||||
?FarPanelVertexCapacity:(farField?farField->connectorVertexCount:0));
|
||||
@@ -1476,6 +1541,8 @@ namespace
|
||||
connectorVertices=pooledChunk->connectorVertices;connectorIndices=pooledChunk->connectorIndices;
|
||||
connectorVertexUav=pooledChunk->connectorVertexUav;connectorIndexUav=pooledChunk->connectorIndexUav;
|
||||
skirtScratchBuffer=farScratch.skirtScratch;skirtScratchUav=farScratch.skirtScratchUav;
|
||||
skirtProbeBuffer=farScratch.skirtProbeData;skirtProbeSrv=farScratch.skirtProbeSrv;
|
||||
skirtProbeUav=farScratch.skirtProbeUav;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1500,6 +1567,12 @@ namespace
|
||||
skirtScratchBuffer=Structured<std::uint32_t>(nullptr,
|
||||
static_cast<std::uint32_t>(maxVertices),D3D11_BIND_UNORDERED_ACCESS);
|
||||
skirtScratchUav=Uav(skirtScratchBuffer.Get(),static_cast<UINT>(maxVertices));
|
||||
skirtProbeBuffer=Structured<FarSkirtCachedSamplesGpu>(nullptr,
|
||||
static_cast<std::uint32_t>(maxVertices),
|
||||
D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
skirtProbeSrv=Srv<FarSkirtCachedSamplesGpu>(skirtProbeBuffer.Get(),
|
||||
static_cast<UINT>(maxVertices));
|
||||
skirtProbeUav=Uav(skirtProbeBuffer.Get(),static_cast<UINT>(maxVertices));
|
||||
}
|
||||
}
|
||||
D3D11_BUFFER_DESC cbDesc{};
|
||||
@@ -1615,7 +1688,8 @@ namespace
|
||||
beginKernel(0);
|
||||
context->CSSetConstantBuffers(1,1,farCb.GetAddressOf());
|
||||
context->CSSetConstantBuffers(2,1,farConnectorConstantsBuffer.GetAddressOf());
|
||||
context->CSSetShader(constants.nearFieldMode!=0?fieldEvalNear.Get():fieldEval.Get(),nullptr,0);
|
||||
const bool evaluateNear=constants.nearFieldMode!=0;
|
||||
context->CSSetShader(evaluateNear?fieldEvalNear.Get():fieldEval.Get(),nullptr,0);
|
||||
ID3D11ShaderResourceView* fieldSrvs[18]{};
|
||||
fieldSrvs[10]=farShapeSrv.Get();fieldSrvs[11]=farRangeSrv.Get();
|
||||
fieldSrvs[12]=farIdSrv.Get();fieldSrvs[13]=farProtectedSrv.Get();
|
||||
@@ -1623,16 +1697,32 @@ namespace
|
||||
fieldSrvs[16]=farWorldResources.detailLayers.srv.Get();
|
||||
fieldSrvs[17]=farNearProxySrv.Get();
|
||||
context->CSSetShaderResources(0,18,fieldSrvs);
|
||||
ID3D11UnorderedAccessView* fieldUavs[8]{};fieldUavs[5]=nearNormalDensityUav.Get();
|
||||
ID3D11UnorderedAccessView* fieldUavs[8]{};fieldUavs[1]=nearDetailBaseUav.Get();
|
||||
fieldUavs[5]=nearNormalDensityUav.Get();
|
||||
fieldUavs[6]=farEvalCounterUav.Get();
|
||||
fieldUavs[7]=densityUav.Get();
|
||||
context->CSSetUnorderedAccessViews(0,8,fieldUavs,nullptr);
|
||||
context->Dispatch(static_cast<UINT>((tile.density.size()+63)/64),1,1);
|
||||
endKernel(0);
|
||||
ID3D11ShaderResourceView* clearSrvs[19]{};
|
||||
ID3D11ShaderResourceView* clearSrvs[21]{};
|
||||
ID3D11UnorderedAccessView* clearUavs[8]{};
|
||||
context->CSSetShaderResources(0,19,clearSrvs);
|
||||
context->CSSetShaderResources(0,21,clearSrvs);
|
||||
context->CSSetUnorderedAccessViews(0,8,clearUavs,nullptr);
|
||||
if(evaluateNear)
|
||||
{
|
||||
context->CSSetShader(fieldEvalNearDetail.Get(),nullptr,0);
|
||||
ID3D11ShaderResourceView* nearDetailSrvs[21]{};
|
||||
nearDetailSrvs[13]=farProtectedSrv.Get();nearDetailSrvs[14]=farProtectedSolidSrv.Get();
|
||||
nearDetailSrvs[16]=farWorldResources.detailLayers.srv.Get();
|
||||
nearDetailSrvs[17]=farNearProxySrv.Get();nearDetailSrvs[20]=nearDetailBaseSrv.Get();
|
||||
context->CSSetShaderResources(0,21,nearDetailSrvs);
|
||||
ID3D11UnorderedAccessView* nearDetailUavs[8]{};
|
||||
nearDetailUavs[5]=nearNormalDensityUav.Get();nearDetailUavs[7]=densityUav.Get();
|
||||
context->CSSetUnorderedAccessViews(0,8,nearDetailUavs,nullptr);
|
||||
context->Dispatch(static_cast<UINT>((tile.density.size()+63)/64),1,1);
|
||||
context->CSSetShaderResources(0,21,clearSrvs);
|
||||
context->CSSetUnorderedAccessViews(0,8,clearUavs,nullptr);
|
||||
}
|
||||
endKernel(0);
|
||||
if(captureGpuTiming&&!batchTimingMode)context->End(fieldEndQuery.Get());
|
||||
}
|
||||
beginKernel(1);
|
||||
@@ -1712,22 +1802,24 @@ namespace
|
||||
{
|
||||
ID3D11Buffer* skirtCbs[3]={cb.Get(),farCb.Get(),farConnectorConstantsBuffer.Get()};
|
||||
context->CSSetConstantBuffers(0,3,skirtCbs);
|
||||
ID3D11ShaderResourceView* skirtSrvs[20]{};
|
||||
ID3D11ShaderResourceView* skirtSrvs[22]{};
|
||||
skirtSrvs[10]=farShapeSrv.Get();skirtSrvs[11]=farRangeSrv.Get();
|
||||
skirtSrvs[12]=farIdSrv.Get();skirtSrvs[13]=farProtectedSrv.Get();
|
||||
skirtSrvs[14]=farProtectedSolidSrv.Get();skirtSrvs[19]=surfaceVertexSrv.Get();
|
||||
context->CSSetShaderResources(0,20,skirtSrvs);
|
||||
skirtSrvs[21]=skirtProbeSrv.Get();
|
||||
context->CSSetShaderResources(0,22,skirtSrvs);
|
||||
ID3D11UnorderedAccessView* classifySkirtUavs[8]{};
|
||||
classifySkirtUavs[0]=skirtScratchUav.Get();classifySkirtUavs[4]=argsUav.Get();
|
||||
classifySkirtUavs[0]=skirtScratchUav.Get();classifySkirtUavs[2]=skirtProbeUav.Get();
|
||||
classifySkirtUavs[4]=argsUav.Get();
|
||||
const std::uint32_t skirtDispatchVertices=constants.outputVertexCapacity;
|
||||
beginKernel(6);
|
||||
context->CSSetShader(classifyFarSkirts.Get(),nullptr,0);
|
||||
context->CSSetUnorderedAccessViews(0,8,classifySkirtUavs,nullptr);
|
||||
context->Dispatch((skirtDispatchVertices+63u)/64u,1,1);
|
||||
endKernel(6);
|
||||
ID3D11ShaderResourceView* nullSkirtSrvs[20]{};
|
||||
ID3D11ShaderResourceView* nullSkirtSrvs[22]{};
|
||||
ID3D11UnorderedAccessView* nullSkirtUavs[8]{};
|
||||
context->CSSetShaderResources(0,20,nullSkirtSrvs);
|
||||
context->CSSetShaderResources(0,22,nullSkirtSrvs);
|
||||
context->CSSetUnorderedAccessViews(0,8,nullSkirtUavs,nullptr);
|
||||
|
||||
beginKernel(7);
|
||||
@@ -1739,7 +1831,7 @@ namespace
|
||||
endKernel(7);
|
||||
context->CSSetUnorderedAccessViews(0,8,nullSkirtUavs,nullptr);
|
||||
|
||||
context->CSSetShaderResources(0,20,skirtSrvs);
|
||||
context->CSSetShaderResources(0,22,skirtSrvs);
|
||||
beginKernel(8);
|
||||
context->CSSetShader(emitFarSkirts.Get(),nullptr,0);
|
||||
ID3D11UnorderedAccessView* emitSkirtUavs[8]{};
|
||||
@@ -1748,7 +1840,7 @@ namespace
|
||||
context->CSSetUnorderedAccessViews(0,8,emitSkirtUavs,nullptr);
|
||||
context->Dispatch((skirtDispatchVertices+63u)/64u,1,1);
|
||||
endKernel(8);
|
||||
context->CSSetShaderResources(0,20,nullSkirtSrvs);
|
||||
context->CSSetShaderResources(0,22,nullSkirtSrvs);
|
||||
context->CSSetUnorderedAccessViews(0,8,nullSkirtUavs,nullptr);
|
||||
}
|
||||
if(captureGpuTiming)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep13Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
$Views=@(
|
||||
@{Name='chamber';Camera='-11.75,-123.25,-19.85,0,0'},
|
||||
@{Name='tunnel';Camera='-11.75,-123.25,-19.85,90,0'},
|
||||
@{Name='passage';Camera='-39.19,6.27,-28.51,63,0'},
|
||||
@{Name='far';Camera='-11.61244,-118.2212,-19.8452,0,0'},
|
||||
@{Name='passage_floor_closeup';Camera='-39.19,6.27,-25.51,63,-25'},
|
||||
@{Name='tunnel_bend';Camera='-198.97,-99.57,-45.58,33.59,23.17'},
|
||||
@{Name='remote_yaw0';Camera='500,0,0,0,0'},
|
||||
@{Name='remote_yaw90';Camera='500,0,0,90,0'},
|
||||
@{Name='remote_yaw180';Camera='500,0,0,180,0'},
|
||||
@{Name='remote_yaw270';Camera='500,0,0,270,0'}
|
||||
)
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
foreach($View in $Views)
|
||||
{
|
||||
foreach($Mode in @('cpu','gpu'))
|
||||
{
|
||||
$Stem="step13_${Mode}_$($View.Name)"
|
||||
$CaptureName="$Stem.png"
|
||||
$Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap','--capture-after-clipmap',
|
||||
"--camera=$($View.Camera)","--$Mode-far",
|
||||
"--capture=Research/OwnerShapeWorld/gpu_field_port/$CaptureName")
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Stem+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Stem+'.stderr.log')
|
||||
$CapturePath=Join-Path $PSScriptRoot $CaptureName
|
||||
Write-Output "STEP13_CAPTURE mode=$Mode view=$($View.Name) affinity=0xFF00 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($PeakPrivate-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$ChildExitCode=[int]$Child.ExitCode
|
||||
if($ChildExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ChildExitCode-eq-1073741502){throw '0xC0000142 repeated after its single permitted retry.'}
|
||||
if($OverMemoryLimit){throw "Capture viewer stopped at the 8 GiB private-memory ceiling: $Stem"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]')-or-not(Test-Path -LiteralPath $CapturePath -PathType Leaf))
|
||||
{throw "Full-residency capture missing: $Stem; exit=$ChildExitCode"}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Capture exceeded conservative private + DXGI-local 8 GiB ceiling: $Stem ($CombinedGB GiB)"}
|
||||
$Ready=[regex]::Match($LogText,'(?m)^\[InitialClipmapReady\] ([0-9.]+) s')
|
||||
Write-Output "STEP13_CAPTURE_DONE mode=$Mode view=$($View.Name) ready_s=$($Ready.Groups[1].Value) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) path=$CapturePath exit=$ChildExitCode"
|
||||
if($ChildExitCode-ne0){throw "Capture viewer returned $ChildExitCode`: $Stem"}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep13Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
$Reference=$null
|
||||
foreach($Workers in @(1,8))
|
||||
{
|
||||
$Name="step13_cpu_reference_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',
|
||||
'--clip-radius=3',"--workers=$Workers")
|
||||
Write-Output "STEP13_CPU_REFERENCE workers=$Workers affinity=0xFF00 priority=BelowNormal command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($PeakPrivate-ge8GB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$ChildExitCode=[int]$Child.ExitCode
|
||||
if($ChildExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ChildExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "CPU reference stopped at the 8 GiB private-memory ceiling: W$Workers"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
$Stream=[regex]::Match($LogText,'(?m)^\[StreamFullClipmap\].*generated=2226/2226.*density_hash=(0x[0-9a-fA-F]+) mesh_hash=(0x[0-9a-fA-F]+) payload_hash=(0x[0-9a-fA-F]+) topology_hash=(0x[0-9a-fA-F]+)')
|
||||
$Walkability=[regex]::Match($LogText,'(?m)^\[Walkability\] PASS 5642/5642')
|
||||
if(-not$Stream.Success-or-not$Walkability.Success)
|
||||
{throw "CPU reference failed full-generation/hash/walkability checks for W$Workers; exit=$ChildExitCode"}
|
||||
$Hashes=@($Stream.Groups[1].Value.ToLowerInvariant(),$Stream.Groups[2].Value.ToLowerInvariant(),
|
||||
$Stream.Groups[3].Value.ToLowerInvariant(),$Stream.Groups[4].Value.ToLowerInvariant())
|
||||
if($null-eq$Reference){$Reference=$Hashes}
|
||||
elseif(($Reference-join'|')-ne($Hashes-join'|')){throw 'CPU hashes differ between W1 and W8.'}
|
||||
Write-Output "STEP13_CPU_REFERENCE_RESULT workers=$Workers hashes=$($Hashes -join ',') walkability=5642/5642 peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) exit=$ChildExitCode"
|
||||
if($ChildExitCode-ne0){throw "CPU reference returned $ChildExitCode`: W$Workers"}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep13Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
|
||||
$Runs=@(
|
||||
@{Mode='cpu';Name='step13_race_cpu_A'},
|
||||
@{Mode='gpu';Name='step13_race_gpu_A'},
|
||||
@{Mode='gpu';Name='step13_race_gpu_B'},
|
||||
@{Mode='cpu';Name='step13_race_cpu_B'}
|
||||
)
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
foreach($Run in $Runs)
|
||||
{
|
||||
$Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap',"--$($Run.Mode)-far")
|
||||
if($Run.Mode-eq'gpu'){$Arguments+='--gpu-far-no-present-hold'}
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Run.Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Run.Name+'.stderr.log')
|
||||
Write-Output "STEP13_RACE_RUN mode=$($Run.Mode) name=$($Run.Name) priority=BelowNormal affinity=0xFF00 workers=8 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$HostRunClock=[Diagnostics.Stopwatch]::StartNew()
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 50
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$HostRunClock.Stop();$HostRunMs=$HostRunClock.Elapsed.TotalMilliseconds
|
||||
$ViewerExitCode=[int]$Child.ExitCode
|
||||
if($ViewerExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ViewerExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "Viewer stopped at the 8 GiB private-memory ceiling: $($Run.Name)"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]'))
|
||||
{throw "Full clipmap was not ready in $($Run.Name); exit=$ViewerExitCode"}
|
||||
$Ready=[regex]::Match($LogText,'(?m)^\[InitialClipmapReady\] ([0-9.]+) s')
|
||||
$Presented=[regex]::Match($LogText,'(?m)^\[WholeViewPresented\] at_ms=([0-9.]+) present_ms=([0-9.]+).*hr=0x([0-9A-Fa-f]{8})')
|
||||
if(-not$Presented.Success){throw "Whole-view present marker missing in $($Run.Name)"}
|
||||
$Warmup=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=[0-9]+ .*queue_ms=([0-9.]+)')
|
||||
$Wait=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] completion_wait_ms=([0-9.]+)')
|
||||
$WarmupMs=if($Warmup.Success){[double]$Warmup.Groups[1].Value+$(if($Wait.Success){[double]$Wait.Groups[1].Value}else{0.0})}else{0.0}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Viewer exceeded conservative private + DXGI-local 8 GiB ceiling: $($Run.Name) ($CombinedGB GiB)"}
|
||||
Write-Output "STEP13_RACE_RESULT mode=$($Run.Mode) name=$($Run.Name) warmup_ms=$([math]::Round($WarmupMs,3)) ready_ms=$([math]::Round([double]$Ready.Groups[1].Value*1000,3)) viewer_whole_view_present_return_ms=$($Presented.Groups[1].Value) present_ms=$($Presented.Groups[2].Value) present_hr=0x$($Presented.Groups[3].Value.ToUpperInvariant()) host_process_exit_ms=$([math]::Round($HostRunMs,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ViewerExitCode"
|
||||
$Controls=[regex]::Match($LogText,'(?m)^\[ProcessControls\].*')
|
||||
if($Controls.Success){Write-Output $Controls.Value}
|
||||
if($ViewerExitCode-ne0){throw "Viewer returned $ViewerExitCode`: $($Run.Name)"}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep13Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{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='step13_gpu_survival'
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log')
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
Write-Output "STEP13_SURVIVAL_RUN command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$ChildExitCode=[int]$Child.ExitCode
|
||||
if($ChildExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ChildExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw 'GPU survival audit stopped at the private-memory ceiling.'}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]')){throw "GPU survival audit did not reach full residency; exit=$ChildExitCode"}
|
||||
$Audit=[regex]::Match($LogText,'(?m)^\[GpuFarSurvivalAudit\].*status=(PASS|FAIL)')
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
if(-not$Audit.Success){throw 'GPU survival audit result marker missing.'}
|
||||
$DxgiMB=if($Memory.Success){[double]$Memory.Groups[1].Value}else{0.0}
|
||||
$CombinedGB=($PeakPrivate+$DxgiMB*1MB)/1GB
|
||||
if($CombinedGB-ge8.0){throw "GPU survival exceeded conservative private + DXGI-local 8 GiB ceiling: $CombinedGB GiB"}
|
||||
Write-Output "STEP13_SURVIVAL_RESULT audit=$($Audit.Groups[1].Value) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) dxgi_local_peak_mb=$DxgiMB conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ChildExitCode stdout=$StdoutPath stderr=$StderrPath"
|
||||
if($Audit.Groups[1].Value-ne'PASS'){throw 'GPU survival audit failed.'}
|
||||
if($ChildExitCode-ne0){throw "Viewer returned $ChildExitCode"}
|
||||
break
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep13Warmup.exe',[string]$OnlyEntry='')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
|
||||
$Entries=@('EvaluateFarFieldCS','EvaluateNearFieldCS','ApplyNearFieldDetailCS','ClassifyCS','ClassifyFarCS','ScanGroupsCS','EmitCS','EmitNearCS',
|
||||
'BuildFarConnectorRingsCS','EmitFarConnectorPanelsCS','ClassifyFarSkirtsCS',
|
||||
'ScanFarSkirtsCS','EmitFarSkirtsCS','NoiseProbeCS')
|
||||
if($OnlyEntry)
|
||||
{
|
||||
if($OnlyEntry-notin$Entries){throw "Unknown shader entry: $OnlyEntry"}
|
||||
$Entries=@($OnlyEntry)
|
||||
}
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
foreach($Entry in $Entries)
|
||||
{
|
||||
$Name='step13_shader_'+$Entry
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log')
|
||||
$Arguments=@('--workers=8','--gpu-far-warmup-only',"--gpu-far-warmup-entry=$Entry")
|
||||
Write-Output "STEP13_SHADER_RUN entry=$Entry freshness=fresh_process priority=BelowNormal affinity=0xFF00 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$HostRunClock=[Diagnostics.Stopwatch]::StartNew()
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 50
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$HostRunClock.Stop();$HostRunMs=$HostRunClock.Elapsed.TotalMilliseconds
|
||||
$ViewerExitCode=[int]$Child.ExitCode
|
||||
if($ViewerExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ViewerExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "Warmup process stopped at the 8 GiB private-memory ceiling: $Entry"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
$Selected=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=1 selected='+[regex]::Escape($Entry)+'.*queue_ms=([0-9.]+)')
|
||||
$Dispatch=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] entry='+[regex]::Escape($Entry)+' dispatch_call_ms=([0-9.]+)')
|
||||
$Wait=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] completion_wait_ms=([0-9.]+)')
|
||||
$Create=[regex]::Match($LogText,'(?m)^\[GpuPipelineProfile\] stage=shader_object_create entry='+[regex]::Escape($Entry)+' duration_ms=([0-9.]+)')
|
||||
if(-not$Selected.Success-or-not$Dispatch.Success-or-not$Wait.Success-or-not$Create.Success)
|
||||
{throw "Isolated warmup markers missing for $Entry; exit=$ViewerExitCode"}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Warmup exceeded conservative private + DXGI-local 8 GiB ceiling: $Entry ($CombinedGB GiB)"}
|
||||
Write-Output "STEP13_SHADER_RESULT entry=$Entry object_create_ms=$($Create.Groups[1].Value) dispatch_call_ms=$($Dispatch.Groups[1].Value) isolated_queue_ms=$($Selected.Groups[1].Value) completion_wait_ms=$($Wait.Groups[1].Value) host_process_exit_ms=$([math]::Round($HostRunMs,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ViewerExitCode"
|
||||
if($ViewerExitCode-ne0){throw "Warmup process returned $ViewerExitCode for $Entry"}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
# GPU port, step 13: near detail, connector rings, and skirts
|
||||
|
||||
## Result
|
||||
|
||||
The near evaluator is now split into a compact base pass and a detail pass. This moved the base shader's cold first use to 4.2 ms, but the detail pass still takes 1.596 s. The connector-ring cold first use fell from 630 ms to 409 ms. Reusing skirt probe values between classification and emission reduced those two shader first uses from about 1.409 s combined to 366 ms combined.
|
||||
|
||||
The production hybrid remains slower than CPU: in the fresh interleaved race its median full-view readiness was 3.044 s versus 1.356 s CPU. Shader warm-up measured about 2.04 s, and near detail remains the largest individual cold cost.
|
||||
|
||||
## Changes
|
||||
|
||||
- Added an intermediate near-field base buffer. `EvaluateNearFieldCS` writes geometry and influence values; `ApplyNearFieldDetailCS` evaluates owner/detail noise and applies the existing protected overrides. The detail noise uses one looped generic routine for the macro, mid, and fine bands. The shared octave and cellular loops use an HLSL `[loop]` annotation; the macro expands to nothing in C++.
|
||||
- Reworked `FarConnectorRadius` so nominal evaluation, correction, and refinement share a loop body while retaining the same query order and convergence checks. These connector probes are off the sample lattice, so the connector still evaluates its own field probes.
|
||||
- Classification now caches each skirt edge's endpoint and center probe densities in a 40-byte record. Emission consumes those values instead of evaluating the same probes again. The clipping, inside tests, and emitted geometry rules remain the same.
|
||||
- Added Step 13 build, cold-first-use, CPU reference, GPU survival, capture, numeric comparison, and race scripts. No shader cache or driver settings were changed.
|
||||
|
||||
## Cold first-use timings
|
||||
|
||||
Fresh-process per-shader dispatch timings, under `BelowNormal` priority and affinity `0xFF00`:
|
||||
|
||||
| Shader | Step 13 cold first use |
|
||||
|---|---:|
|
||||
| `EvaluateFarFieldCS` | 3.008 ms |
|
||||
| `EvaluateNearFieldCS` (base) | 4.233 ms |
|
||||
| `ApplyNearFieldDetailCS` | 1,595.548 ms |
|
||||
| `ClassifyCS` | 3.828 ms |
|
||||
| `ClassifyFarCS` | 2.666 ms |
|
||||
| `ScanGroupsCS` | 2.158 ms |
|
||||
| `EmitCS` | 2.756 ms |
|
||||
| `EmitNearCS` | 2,235.559 ms |
|
||||
| `BuildFarConnectorRingsCS` | 408.708 ms |
|
||||
| `EmitFarConnectorPanelsCS` | 4.822 ms |
|
||||
| `ClassifyFarSkirtsCS` | 258.476 ms |
|
||||
| `ScanFarSkirtsCS` | 3.844 ms |
|
||||
| `EmitFarSkirtsCS` | 107.877 ms |
|
||||
| `NoiseProbeCS` | 2.922 ms |
|
||||
|
||||
Cold-table checkpoints during the work:
|
||||
|
||||
| Checkpoint | Near shader timing | Connector rings | Skirt classify | Skirt emit |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Shared `[loop]` annotations only | 1,795 ms | 531 ms | 466 ms | 966 ms |
|
||||
| Near base/detail split, before connector/skirt restructuring | 3.2 ms base + 1,642 ms detail | 584 ms | 469 ms | 983 ms |
|
||||
| Final Step 13 | 4.233 ms base + 1,595.548 ms detail | 408.708 ms | 258.476 ms | 107.877 ms |
|
||||
|
||||
The loop annotations alone did not improve near-detail first use. The pass split isolated the cost in `ApplyNearFieldDetailCS`; the later connector and skirt changes produced the reductions shown in the final row.
|
||||
|
||||
`EmitNearCS` remains expensive when measured alone, but it is a diagnostic near-meshing entry and is not on the production far-startup path. The production viewer's two race runs measured shader warm-up at 2,025.079 and 2,058.319 ms. The near detail pass is still the main isolated first-use floor; connector and skirt classification add several hundred milliseconds each.
|
||||
|
||||
| Work | Step 12 baseline | Step 13 | Change |
|
||||
|---|---:|---:|---:|
|
||||
| Near evaluation | 1,782.9 ms | 1,599.8 ms base + detail | 10.3% lower |
|
||||
| Connector rings | 630.3 ms | 408.7 ms | 35.2% lower |
|
||||
| Skirt classification + emission | about 1,409 ms | 366.4 ms | about 74.0% lower |
|
||||
|
||||
## Correctness and survival
|
||||
|
||||
- Whole near-detail agreement covered 960 tiles. Hardware and WARP both had zero topology differences; all 229,376 protected exception cells matched, with zero protected differences. Repeated GPU output was bit-identical.
|
||||
- Whole far agreement covered 1,114 eligible tiles and skipped 152 near-transition tiles. Hardware and WARP both had zero topology differences; all 127,401 protected exception cells and 353 thin-feature cells matched. Repeated GPU output was bit-identical.
|
||||
- CPU reference at one and eight workers produced the same hashes: density `0xdb2991c73215af4c`, mesh `0x8236c5edd7fc8e4f`, payload `0x4c48fa75a543d58e`, topology `0xbea22e76b34a4dfc`. Walkability passed at 5,642/5,642. These match Step 12.
|
||||
- GPU survival audit passed after full clipmap residency. Peak private memory was 3.12 GiB and sampled DXGI local memory was 2,043.3 MiB, or 5.11 GiB combined by the conservative accounting used by the runner.
|
||||
- All ten CPU/GPU capture pairs reached full residency at 1280×800. GPU viewer readiness ranged from 3.215 to 3.484 s; the highest reported combined private plus DXGI local usage was 5.44 GiB. Captures were compared numerically as RGB arrays and were not opened in an image viewer. Pairwise RGB MAE ranged from 0.0484 to 1.6092; per-view values are in [step13_capture_comparison.md](step13_capture_comparison.md).
|
||||
|
||||
## Interleaved fresh-launch race
|
||||
|
||||
Order was CPU A, GPU A, GPU B, CPU B. The viewers ran hidden, under `BelowNormal`, affinity `0xFF00`, and eight workers. The present call returned `DXGI_STATUS_OCCLUDED`, so the clocks below measure clipmap readiness and API return, not physical scanout.
|
||||
|
||||
| Run | Viewer readiness / present return | Shader warm-up | Host process exit |
|
||||
|---|---:|---:|---:|
|
||||
| CPU A | 1,359 ms | — | 1,512.945 ms |
|
||||
| GPU A | 3,003 ms | 2,025.079 ms | 3,153.714 ms |
|
||||
| GPU B | 3,084 ms | 2,058.319 ms | 3,275.952 ms |
|
||||
| CPU B | 1,353 ms | — | 1,484.837 ms |
|
||||
|
||||
Median viewer readiness was **1.356 s CPU vs 3.044 s hybrid**, a **1.688 s / 2.25× CPU lead**. Median host-clock process exit was **1.499 s CPU vs 3.215 s hybrid**, a **1.716 s / 2.15× CPU lead**. The hybrid does not beat CPU yet.
|
||||
|
||||
## Remaining work
|
||||
|
||||
The main remaining first-use cost is near detail at 1.596 s. The capture and survival audits pass, but the direct-GPU LOD3/4 coverage case `(6,2,0,lod3)` was not addressed in this step.
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
# Step 13 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.
|
||||
|
||||
| View | Size | RGB MAE | RGB RMSE | Changed pixels | Pixels max channel >32 | Max channel |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| chamber | 1280x800 | 0.6076 | 1.8655 | 42.6368% | 0.0183% | 124 |
|
||||
| tunnel | 1280x800 | 0.6383 | 3.3799 | 31.7335% | 0.2772% | 130 |
|
||||
| passage | 1280x800 | 1.6092 | 3.6878 | 50.4982% | 0.1733% | 52 |
|
||||
| far | 1280x800 | 0.7909 | 2.1558 | 44.8325% | 0.0198% | 128 |
|
||||
| passage_floor_closeup | 1280x800 | 0.9314 | 2.4800 | 43.0219% | 0.0500% | 100 |
|
||||
| tunnel_bend | 1280x800 | 0.8129 | 2.1599 | 40.9629% | 0.0708% | 55 |
|
||||
| remote_yaw0 | 1280x800 | 0.1989 | 2.6627 | 4.2433% | 0.2415% | 125 |
|
||||
| remote_yaw90 | 1280x800 | 0.4083 | 4.3552 | 2.2432% | 0.6948% | 94 |
|
||||
| remote_yaw180 | 1280x800 | 0.0484 | 1.3206 | 2.9787% | 0.0341% | 102 |
|
||||
| remote_yaw270 | 1280x800 | 0.2355 | 3.1104 | 5.5592% | 0.4098% | 107 |
|
||||
Reference in new issue
Block a user