wip(standalone): GPU step 14 -- warm-up 2.04 -> 1.05 s; cold path now waits on streaming, not shaders
Per-kernel fences in the production viewer put 1.73-1.98 s on the near-detail Flush (shader creation 17-19 ms, dispatch calls ~0): skipping only that dispatch cut idle warm-up 1.893 -> 0.521 s. Near detail rewritten with a shared owner-roughness loop and shared Perlin samples: DXBC 448,588 -> 120,860 bytes, cold first use 1,596 -> 709 ms. Warm-up median 1.052 s, yet whole view is unchanged (CPU 1.352 s vs hybrid 3.196 s): after input export the hybrid spends 1.78-2.00 s streaming 1,082 GPU + 1,144 CPU-fallback tiles. Audits: 0 diffs near/far vs CPU and WARP, hashes, walk 5,642/5,642, survival. 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
a96fd0b95b
commit
f322b1c089
14 files changed
+774
-38
No files matched your search
@@ -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"step14_cpu_{view}.png"
|
||||||
|
gpu_path = ROOT / f"step14_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 14 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 / "step14_capture_comparison.md"
|
||||||
|
report.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||||
|
print(report.read_text(encoding="utf-8"), end="")
|
||||||
@@ -26,7 +26,7 @@ namespace VoxelForgeGpuFarViewer
|
|||||||
const std::filesystem::path& shaderPath,std::string& error);
|
const std::filesystem::path& shaderPath,std::string& error);
|
||||||
bool QueueFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
bool QueueFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||||
const std::filesystem::path& shaderPath,bool dispatchShaders,
|
const std::filesystem::path& shaderPath,bool dispatchShaders,
|
||||||
const std::string& entryFilter,std::string& error);
|
const std::string& entryFilter,bool fenceEachKernel,std::string& error);
|
||||||
bool CompleteFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
bool CompleteFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||||
const std::filesystem::path& shaderPath,std::string& error);
|
const std::filesystem::path& shaderPath,std::string& error);
|
||||||
bool ReserveFarOutputPool(ID3D11Device* device,ID3D11DeviceContext* context,
|
bool ReserveFarOutputPool(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||||
|
|||||||
@@ -628,22 +628,27 @@ namespace
|
|||||||
std::chrono::duration<double,std::milli>(std::chrono::steady_clock::now()-PipelineStart).count());
|
std::chrono::duration<double,std::milli>(std::chrono::steady_clock::now()-PipelineStart).count());
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueTinyShaderWarmup(bool dispatchShaders,const std::string& entryFilter)
|
void QueueTinyShaderWarmup(bool dispatchShaders,const std::string& entryFilter,
|
||||||
|
bool fenceEachKernel)
|
||||||
{
|
{
|
||||||
const auto WarmupStart=Clock::now();
|
const auto WarmupStart=Clock::now();
|
||||||
|
const auto ResourceCreateStart=Clock::now();
|
||||||
static constexpr std::array<std::string_view,14> entries={
|
static constexpr std::array<std::string_view,14> entries={
|
||||||
"EvaluateFarFieldCS","EvaluateNearFieldCS","ClassifyCS","ClassifyFarCS","ScanGroupsCS","EmitCS",
|
"EvaluateFarFieldCS","EvaluateNearFieldCS","ClassifyCS","ClassifyFarCS","ScanGroupsCS","EmitCS",
|
||||||
"ApplyNearFieldDetailCS",
|
"ApplyNearFieldDetailCS",
|
||||||
"EmitNearCS","BuildFarConnectorRingsCS","EmitFarConnectorPanelsCS",
|
"EmitNearCS","BuildFarConnectorRingsCS","EmitFarConnectorPanelsCS",
|
||||||
"ClassifyFarSkirtsCS","ScanFarSkirtsCS","EmitFarSkirtsCS","NoiseProbeCS"};
|
"ClassifyFarSkirtsCS","ScanFarSkirtsCS","EmitFarSkirtsCS","NoiseProbeCS"};
|
||||||
if(!entryFilter.empty()&&std::find(entries.begin(),entries.end(),entryFilter)==entries.end())
|
const bool skipEntryFilter=entryFilter.starts_with("skip:");
|
||||||
|
const std::string_view filteredEntry=skipEntryFilter
|
||||||
|
?std::string_view(entryFilter).substr(5):std::string_view(entryFilter);
|
||||||
|
if(!entryFilter.empty()&&std::find(entries.begin(),entries.end(),filteredEntry)==entries.end())
|
||||||
throw std::runtime_error("unknown shader warmup entry: "+entryFilter);
|
throw std::runtime_error("unknown shader warmup entry: "+entryFilter);
|
||||||
constexpr std::uint32_t sampleCount=27,cellCount=1,groupCount=1;
|
constexpr std::uint32_t sampleCount=27,cellCount=1,groupCount=1;
|
||||||
TileConstants tile{};
|
TileConstants tile{};
|
||||||
tile.cells=1;tile.sampleDim=3;tile.cellCount=cellCount;tile.groupCount=groupCount;
|
tile.cells=1;tile.sampleDim=3;tile.cellCount=cellCount;tile.groupCount=groupCount;
|
||||||
tile.stepVoxels=entryFilter=="EmitNearCS"?1:2;
|
tile.stepVoxels=filteredEntry=="EmitNearCS"?1:2;
|
||||||
tile.nearFieldMode=(entryFilter.empty()||entryFilter=="EvaluateNearFieldCS"
|
tile.nearFieldMode=(entryFilter.empty()||filteredEntry=="EvaluateNearFieldCS"
|
||||||
||entryFilter=="ApplyNearFieldDetailCS"||entryFilter=="EmitNearCS")?1u:0u;
|
||filteredEntry=="ApplyNearFieldDetailCS"||filteredEntry=="EmitNearCS")?1u:0u;
|
||||||
tile.voxelSizeCm=25.0f;tile.outputVertexCapacity=3;
|
tile.voxelSizeCm=25.0f;tile.outputVertexCapacity=3;
|
||||||
FarFieldConstants field{};
|
FarFieldConstants field{};
|
||||||
field.strataLo=-100.0f;field.strataHi=100.0f;field.strataBlend=12.0f;
|
field.strataLo=-100.0f;field.strataHi=100.0f;field.strataBlend=12.0f;
|
||||||
@@ -763,6 +768,12 @@ namespace
|
|||||||
auto noiseInputSrv=Srv<NoiseProbeInput>(noiseInputs.Get(),noiseInput.size());
|
auto noiseInputSrv=Srv<NoiseProbeInput>(noiseInputs.Get(),noiseInput.size());
|
||||||
auto noiseOutputUav=Uav(noiseOutputs.Get(),noiseInput.size());
|
auto noiseOutputUav=Uav(noiseOutputs.Get(),noiseInput.size());
|
||||||
|
|
||||||
|
const double resourceCreateMs=std::chrono::duration<double,std::milli>(
|
||||||
|
Clock::now()-ResourceCreateStart).count();
|
||||||
|
if(fenceEachKernel)
|
||||||
|
std::printf("[GpuShaderWarmupProfile] stage=warmup_resource_create duration_ms=%.3f\n",
|
||||||
|
resourceCreateMs);
|
||||||
|
|
||||||
if(!dispatchShaders)
|
if(!dispatchShaders)
|
||||||
{
|
{
|
||||||
std::printf("[GpuShaderWarmup] resources_only=true tiny_samples=%u tiny_cells=%u dispatches=0\n",
|
std::printf("[GpuShaderWarmup] resources_only=true tiny_samples=%u tiny_cells=%u dispatches=0\n",
|
||||||
@@ -780,121 +791,174 @@ namespace
|
|||||||
context->CSSetShaderResources(0,srvCount,nullSrvs);
|
context->CSSetShaderResources(0,srvCount,nullSrvs);
|
||||||
context->CSSetUnorderedAccessViews(0,8,nullUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,nullUavs,nullptr);
|
||||||
};
|
};
|
||||||
auto Dispatch=[&](ID3D11ComputeShader* shader,const char* entry)
|
auto Dispatch=[&](ID3D11ComputeShader* shader,const char* entry,
|
||||||
|
Clock::time_point stateStart)
|
||||||
{
|
{
|
||||||
if(!entryFilter.empty()&&entryFilter!=entry)return;
|
if(!entryFilter.empty()&&!skipEntryFilter&&filteredEntry!=entry)return;
|
||||||
if(entryFilter.empty()&&(std::string_view(entry)=="ClassifyCS"
|
if(skipEntryFilter&&filteredEntry==entry)return;
|
||||||
|
if((entryFilter.empty()||skipEntryFilter)&&(std::string_view(entry)=="ClassifyCS"
|
||||||
||std::string_view(entry)=="EmitNearCS"||std::string_view(entry)=="NoiseProbeCS"))return;
|
||std::string_view(entry)=="EmitNearCS"||std::string_view(entry)=="NoiseProbeCS"))return;
|
||||||
const auto start=Clock::now();
|
const auto start=Clock::now();
|
||||||
context->CSSetShader(shader,nullptr,0);context->Dispatch(1,1,1);
|
context->CSSetShader(shader,nullptr,0);context->Dispatch(1,1,1);
|
||||||
++dispatchCount;
|
++dispatchCount;
|
||||||
std::printf("[GpuShaderWarmup] entry=%s dispatch_call_ms=%.3f groups=1\n",entry,
|
const double stateMs=std::chrono::duration<double,std::milli>(start-stateStart).count();
|
||||||
std::chrono::duration<double,std::milli>(Clock::now()-start).count());
|
const double dispatchMs=std::chrono::duration<double,std::milli>(Clock::now()-start).count();
|
||||||
|
if(fenceEachKernel)
|
||||||
|
{
|
||||||
|
D3D11_QUERY_DESC eventDesc{D3D11_QUERY_EVENT,0};
|
||||||
|
ComPtr<ID3D11Query> eventQuery;
|
||||||
|
const auto queryStart=Clock::now();
|
||||||
|
Check(device->CreateQuery(&eventDesc,&eventQuery),
|
||||||
|
(std::string("CreateQuery(shader warmup ")+entry+")").c_str());
|
||||||
|
const double queryCreateMs=std::chrono::duration<double,std::milli>(
|
||||||
|
Clock::now()-queryStart).count();
|
||||||
|
context->End(eventQuery.Get());
|
||||||
|
const auto flushStart=Clock::now();
|
||||||
|
context->Flush();
|
||||||
|
const double flushMs=std::chrono::duration<double,std::milli>(
|
||||||
|
Clock::now()-flushStart).count();
|
||||||
|
const auto fenceStart=Clock::now();
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
const HRESULT hr=immediateContext->GetData(eventQuery.Get(),nullptr,0,
|
||||||
|
D3D11_ASYNC_GETDATA_DONOTFLUSH);
|
||||||
|
if(hr==S_OK)break;
|
||||||
|
if(FAILED(hr))throw std::runtime_error(
|
||||||
|
std::string("GetData(shader warmup ")+entry+") failed");
|
||||||
|
if(std::chrono::duration<double>(Clock::now()-fenceStart).count()>10.0)
|
||||||
|
throw std::runtime_error(std::string("shader warmup fence timed out: ")+entry);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
const double fenceWaitMs=std::chrono::duration<double,std::milli>(
|
||||||
|
Clock::now()-fenceStart).count();
|
||||||
|
std::printf("[GpuShaderWarmupProfile] entry=%s state_bind_ms=%.3f first_dispatch_ms=%.3f query_create_ms=%.3f flush_ms=%.3f fence_wait_ms=%.3f fence=complete\n",
|
||||||
|
entry,stateMs,dispatchMs,queryCreateMs,flushMs,fenceWaitMs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::printf("[GpuShaderWarmup] entry=%s dispatch_call_ms=%.3f groups=1\n",entry,dispatchMs);
|
||||||
};
|
};
|
||||||
|
|
||||||
ID3D11ShaderResourceView* evalSrvs[21]{};
|
ID3D11ShaderResourceView* evalSrvs[21]{};
|
||||||
evalSrvs[10]=shapeSrv.Get();evalSrvs[11]=binSrv.Get();evalSrvs[12]=shapeIdSrv.Get();
|
evalSrvs[10]=shapeSrv.Get();evalSrvs[11]=binSrv.Get();evalSrvs[12]=shapeIdSrv.Get();
|
||||||
evalSrvs[13]=protectedAirSrv.Get();evalSrvs[14]=protectedSolidSrv.Get();
|
evalSrvs[13]=protectedAirSrv.Get();evalSrvs[14]=protectedSolidSrv.Get();
|
||||||
evalSrvs[16]=detailSrv.Get();evalSrvs[17]=proxySrv.Get();
|
evalSrvs[16]=detailSrv.Get();evalSrvs[17]=proxySrv.Get();
|
||||||
|
auto stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,20,evalSrvs);
|
context->CSSetShaderResources(0,20,evalSrvs);
|
||||||
ID3D11UnorderedAccessView* evalUavs[8]{};
|
ID3D11UnorderedAccessView* evalUavs[8]{};
|
||||||
evalUavs[1]=nearDetailBaseUav.Get();
|
evalUavs[1]=nearDetailBaseUav.Get();
|
||||||
evalUavs[5]=nearNormalUav.Get();evalUavs[6]=evalCounterUav.Get();evalUavs[7]=densityUav.Get();
|
evalUavs[5]=nearNormalUav.Get();evalUavs[6]=evalCounterUav.Get();evalUavs[7]=densityUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,evalUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,evalUavs,nullptr);
|
||||||
Dispatch(fieldEval.Get(),"EvaluateFarFieldCS");ClearBindings();
|
Dispatch(fieldEval.Get(),"EvaluateFarFieldCS",stateStart);ClearBindings();
|
||||||
Dispatch(fieldEvalNear.Get(),"EvaluateNearFieldCS");ClearBindings();
|
stateStart=Clock::now();
|
||||||
|
Dispatch(fieldEvalNear.Get(),"EvaluateNearFieldCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
ID3D11ShaderResourceView* nearDetailSrvs[21]{};
|
ID3D11ShaderResourceView* nearDetailSrvs[21]{};
|
||||||
nearDetailSrvs[13]=protectedAirSrv.Get();nearDetailSrvs[14]=protectedSolidSrv.Get();
|
nearDetailSrvs[13]=protectedAirSrv.Get();nearDetailSrvs[14]=protectedSolidSrv.Get();
|
||||||
nearDetailSrvs[16]=detailSrv.Get();nearDetailSrvs[17]=proxySrv.Get();
|
nearDetailSrvs[16]=detailSrv.Get();nearDetailSrvs[17]=proxySrv.Get();
|
||||||
nearDetailSrvs[20]=nearDetailBaseSrv.Get();
|
nearDetailSrvs[20]=nearDetailBaseSrv.Get();
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,21,nearDetailSrvs);
|
context->CSSetShaderResources(0,21,nearDetailSrvs);
|
||||||
ID3D11UnorderedAccessView* nearDetailUavs[8]{};
|
ID3D11UnorderedAccessView* nearDetailUavs[8]{};
|
||||||
nearDetailUavs[5]=nearNormalUav.Get();nearDetailUavs[7]=densityUav.Get();
|
nearDetailUavs[5]=nearNormalUav.Get();nearDetailUavs[7]=densityUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,nearDetailUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,nearDetailUavs,nullptr);
|
||||||
Dispatch(fieldEvalNearDetail.Get(),"ApplyNearFieldDetailCS");ClearBindings();
|
Dispatch(fieldEvalNearDetail.Get(),"ApplyNearFieldDetailCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
ID3D11ShaderResourceView* classifySrvs[16]{};
|
ID3D11ShaderResourceView* classifySrvs[16]{};
|
||||||
classifySrvs[0]=signSrv.Get();classifySrvs[1]=triangleSrv.Get();
|
classifySrvs[0]=signSrv.Get();classifySrvs[1]=triangleSrv.Get();
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,16,classifySrvs);
|
context->CSSetShaderResources(0,16,classifySrvs);
|
||||||
ID3D11UnorderedAccessView* classifyUavs[8]{};
|
ID3D11UnorderedAccessView* classifyUavs[8]{};
|
||||||
classifyUavs[0]=caseUav.Get();classifyUavs[1]=localOffsetUav.Get();classifyUavs[2]=groupCountUav.Get();
|
classifyUavs[0]=caseUav.Get();classifyUavs[1]=localOffsetUav.Get();classifyUavs[2]=groupCountUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,classifyUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,classifyUavs,nullptr);
|
||||||
Dispatch(classify.Get(),"ClassifyCS");ClearBindings(16);
|
Dispatch(classify.Get(),"ClassifyCS",stateStart);ClearBindings(16);
|
||||||
|
|
||||||
ID3D11ShaderResourceView* farClassifySrvs[16]{};
|
ID3D11ShaderResourceView* farClassifySrvs[16]{};
|
||||||
farClassifySrvs[1]=triangleSrv.Get();farClassifySrvs[15]=densitySrv.Get();
|
farClassifySrvs[1]=triangleSrv.Get();farClassifySrvs[15]=densitySrv.Get();
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,16,farClassifySrvs);
|
context->CSSetShaderResources(0,16,farClassifySrvs);
|
||||||
context->CSSetUnorderedAccessViews(0,8,classifyUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,classifyUavs,nullptr);
|
||||||
Dispatch(fieldClassify.Get(),"ClassifyFarCS");ClearBindings(16);
|
Dispatch(fieldClassify.Get(),"ClassifyFarCS",stateStart);ClearBindings(16);
|
||||||
|
|
||||||
ID3D11ShaderResourceView* scanSrvs[9]{};scanSrvs[8]=groupCountSrv.Get();
|
ID3D11ShaderResourceView* scanSrvs[9]{};scanSrvs[8]=groupCountSrv.Get();
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,9,scanSrvs);
|
context->CSSetShaderResources(0,9,scanSrvs);
|
||||||
ID3D11UnorderedAccessView* scanUavs[8]{};scanUavs[3]=groupOffsetUav.Get();scanUavs[4]=argsUav.Get();
|
ID3D11UnorderedAccessView* scanUavs[8]{};scanUavs[3]=groupOffsetUav.Get();scanUavs[4]=argsUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,scanUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,scanUavs,nullptr);
|
||||||
Dispatch(scan.Get(),"ScanGroupsCS");ClearBindings(9);
|
Dispatch(scan.Get(),"ScanGroupsCS",stateStart);ClearBindings(9);
|
||||||
|
|
||||||
ID3D11ShaderResourceView* emitSrvs[20]{};
|
ID3D11ShaderResourceView* emitSrvs[20]{};
|
||||||
emitSrvs[1]=triangleSrv.Get();emitSrvs[2]=densitySrv.Get();emitSrvs[3]=caseSrv.Get();
|
emitSrvs[1]=triangleSrv.Get();emitSrvs[2]=densitySrv.Get();emitSrvs[3]=caseSrv.Get();
|
||||||
emitSrvs[4]=localOffsetSrv.Get();emitSrvs[5]=groupOffsetSrv.Get();
|
emitSrvs[4]=localOffsetSrv.Get();emitSrvs[5]=groupOffsetSrv.Get();
|
||||||
emitSrvs[6]=midpointIdSrv.Get();emitSrvs[7]=midpointRecordSrv.Get();
|
emitSrvs[6]=midpointIdSrv.Get();emitSrvs[7]=midpointRecordSrv.Get();
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,20,emitSrvs);
|
context->CSSetShaderResources(0,20,emitSrvs);
|
||||||
ID3D11UnorderedAccessView* emitUavs[8]{};emitUavs[5]=vertexUav.Get();emitUavs[6]=indexUav.Get();
|
ID3D11UnorderedAccessView* emitUavs[8]{};emitUavs[5]=vertexUav.Get();emitUavs[6]=indexUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,emitUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,emitUavs,nullptr);
|
||||||
Dispatch(emit.Get(),"EmitCS");ClearBindings();
|
Dispatch(emit.Get(),"EmitCS",stateStart);ClearBindings();
|
||||||
Dispatch(emitNear.Get(),"EmitNearCS");ClearBindings();
|
stateStart=Clock::now();
|
||||||
|
Dispatch(emitNear.Get(),"EmitNearCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
ID3D11ShaderResourceView* ringSrvs[5]={connectorPanelSrv.Get(),nullptr,shapeSrv.Get(),binSrv.Get(),shapeIdSrv.Get()};
|
ID3D11ShaderResourceView* ringSrvs[5]={connectorPanelSrv.Get(),nullptr,shapeSrv.Get(),binSrv.Get(),shapeIdSrv.Get()};
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(8,5,ringSrvs);
|
context->CSSetShaderResources(8,5,ringSrvs);
|
||||||
ID3D11UnorderedAccessView* ringUavs[8]{};ringUavs[4]=argsUav.Get();ringUavs[7]=connectorRingUav.Get();
|
ID3D11UnorderedAccessView* ringUavs[8]{};ringUavs[4]=argsUav.Get();ringUavs[7]=connectorRingUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,ringUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,ringUavs,nullptr);
|
||||||
Dispatch(connectorRings.Get(),"BuildFarConnectorRingsCS");ClearBindings();
|
Dispatch(connectorRings.Get(),"BuildFarConnectorRingsCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
ID3D11ShaderResourceView* panelSrvs[2]={connectorPanelSrv.Get(),connectorRingSrv.Get()};
|
ID3D11ShaderResourceView* panelSrvs[2]={connectorPanelSrv.Get(),connectorRingSrv.Get()};
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(8,2,panelSrvs);
|
context->CSSetShaderResources(8,2,panelSrvs);
|
||||||
ID3D11UnorderedAccessView* panelUavs[8]{};panelUavs[5]=panelVertexUav.Get();panelUavs[6]=panelIndexUav.Get();
|
ID3D11UnorderedAccessView* panelUavs[8]{};panelUavs[5]=panelVertexUav.Get();panelUavs[6]=panelIndexUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,panelUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,panelUavs,nullptr);
|
||||||
Dispatch(connectorPanels.Get(),"EmitFarConnectorPanelsCS");ClearBindings();
|
Dispatch(connectorPanels.Get(),"EmitFarConnectorPanelsCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
ID3D11ShaderResourceView* skirtSrvs[22]{};
|
ID3D11ShaderResourceView* skirtSrvs[22]{};
|
||||||
skirtSrvs[10]=shapeSrv.Get();skirtSrvs[11]=binSrv.Get();skirtSrvs[12]=shapeIdSrv.Get();
|
skirtSrvs[10]=shapeSrv.Get();skirtSrvs[11]=binSrv.Get();skirtSrvs[12]=shapeIdSrv.Get();
|
||||||
skirtSrvs[13]=protectedAirSrv.Get();skirtSrvs[14]=protectedSolidSrv.Get();skirtSrvs[19]=vertexSrv.Get();
|
skirtSrvs[13]=protectedAirSrv.Get();skirtSrvs[14]=protectedSolidSrv.Get();skirtSrvs[19]=vertexSrv.Get();
|
||||||
skirtSrvs[21]=skirtProbeSrv.Get();
|
skirtSrvs[21]=skirtProbeSrv.Get();
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,22,skirtSrvs);
|
context->CSSetShaderResources(0,22,skirtSrvs);
|
||||||
ID3D11UnorderedAccessView* classifySkirtUavs[8]{};
|
ID3D11UnorderedAccessView* classifySkirtUavs[8]{};
|
||||||
classifySkirtUavs[0]=skirtScratchUav.Get();classifySkirtUavs[2]=skirtProbeUav.Get();
|
classifySkirtUavs[0]=skirtScratchUav.Get();classifySkirtUavs[2]=skirtProbeUav.Get();
|
||||||
classifySkirtUavs[4]=argsUav.Get();
|
classifySkirtUavs[4]=argsUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,classifySkirtUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,classifySkirtUavs,nullptr);
|
||||||
Dispatch(classifyFarSkirts.Get(),"ClassifyFarSkirtsCS");ClearBindings();
|
Dispatch(classifyFarSkirts.Get(),"ClassifyFarSkirtsCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
ID3D11UnorderedAccessView* scanSkirtUavs[8]{};
|
ID3D11UnorderedAccessView* scanSkirtUavs[8]{};
|
||||||
|
stateStart=Clock::now();
|
||||||
scanSkirtUavs[0]=skirtScratchUav.Get();scanSkirtUavs[4]=argsUav.Get();
|
scanSkirtUavs[0]=skirtScratchUav.Get();scanSkirtUavs[4]=argsUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,scanSkirtUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,scanSkirtUavs,nullptr);
|
||||||
Dispatch(scanFarSkirts.Get(),"ScanFarSkirtsCS");ClearBindings();
|
Dispatch(scanFarSkirts.Get(),"ScanFarSkirtsCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,22,skirtSrvs);
|
context->CSSetShaderResources(0,22,skirtSrvs);
|
||||||
ID3D11UnorderedAccessView* emitSkirtUavs[8]{};
|
ID3D11UnorderedAccessView* emitSkirtUavs[8]{};
|
||||||
emitSkirtUavs[0]=skirtScratchUav.Get();emitSkirtUavs[4]=argsUav.Get();
|
emitSkirtUavs[0]=skirtScratchUav.Get();emitSkirtUavs[4]=argsUav.Get();
|
||||||
emitSkirtUavs[5]=panelVertexUav.Get();emitSkirtUavs[6]=panelIndexUav.Get();
|
emitSkirtUavs[5]=panelVertexUav.Get();emitSkirtUavs[6]=panelIndexUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,emitSkirtUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,emitSkirtUavs,nullptr);
|
||||||
Dispatch(emitFarSkirts.Get(),"EmitFarSkirtsCS");ClearBindings();
|
Dispatch(emitFarSkirts.Get(),"EmitFarSkirtsCS",stateStart);ClearBindings();
|
||||||
|
|
||||||
ID3D11ShaderResourceView* noiseSrvs[10]{};noiseSrvs[9]=noiseInputSrv.Get();
|
ID3D11ShaderResourceView* noiseSrvs[10]{};noiseSrvs[9]=noiseInputSrv.Get();
|
||||||
|
stateStart=Clock::now();
|
||||||
context->CSSetShaderResources(0,10,noiseSrvs);
|
context->CSSetShaderResources(0,10,noiseSrvs);
|
||||||
ID3D11UnorderedAccessView* noiseUavs[8]{};noiseUavs[6]=noiseOutputUav.Get();
|
ID3D11UnorderedAccessView* noiseUavs[8]{};noiseUavs[6]=noiseOutputUav.Get();
|
||||||
context->CSSetUnorderedAccessViews(0,8,noiseUavs,nullptr);
|
context->CSSetUnorderedAccessViews(0,8,noiseUavs,nullptr);
|
||||||
Dispatch(noiseProbe.Get(),"NoiseProbeCS");ClearBindings(10);
|
Dispatch(noiseProbe.Get(),"NoiseProbeCS",stateStart);ClearBindings(10);
|
||||||
ID3D11Buffer* nullConstants[3]{};context->CSSetConstantBuffers(0,3,nullConstants);
|
ID3D11Buffer* nullConstants[3]{};context->CSSetConstantBuffers(0,3,nullConstants);
|
||||||
context->CSSetShader(nullptr,nullptr,0);
|
context->CSSetShader(nullptr,nullptr,0);
|
||||||
|
|
||||||
D3D11_QUERY_DESC eventDesc{D3D11_QUERY_EVENT,0};
|
if(!fenceEachKernel)
|
||||||
Check(device->CreateQuery(&eventDesc,&shaderWarmupCompletion),"CreateQuery(shader warmup completion)");
|
{
|
||||||
context->End(shaderWarmupCompletion.Get());context->Flush();
|
D3D11_QUERY_DESC eventDesc{D3D11_QUERY_EVENT,0};
|
||||||
|
Check(device->CreateQuery(&eventDesc,&shaderWarmupCompletion),"CreateQuery(shader warmup completion)");
|
||||||
|
context->End(shaderWarmupCompletion.Get());context->Flush();
|
||||||
|
}
|
||||||
if(dispatchShaders&&dispatchCount==0)
|
if(dispatchShaders&&dispatchCount==0)
|
||||||
throw std::runtime_error("shader warmup selected no dispatches");
|
throw std::runtime_error("shader warmup selected no dispatches");
|
||||||
std::printf("[GpuShaderWarmup] dispatched=%u selected=%s tiny_samples=%u tiny_cells=%u queue_ms=%.3f completion=pending\n",
|
std::printf("[GpuShaderWarmup] dispatched=%u selected=%s tiny_samples=%u tiny_cells=%u queue_ms=%.3f completion=%s\n",
|
||||||
dispatchCount,entryFilter.empty()?"production":entryFilter.c_str(),sampleCount,cellCount,
|
dispatchCount,entryFilter.empty()?"production":entryFilter.c_str(),sampleCount,cellCount,
|
||||||
std::chrono::duration<double,std::milli>(Clock::now()-WarmupStart).count());
|
std::chrono::duration<double,std::milli>(Clock::now()-WarmupStart).count(),
|
||||||
|
fenceEachKernel?"per_kernel_fenced":"pending");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompleteTinyShaderWarmup()
|
bool CompleteTinyShaderWarmup()
|
||||||
@@ -3219,11 +3283,12 @@ namespace VoxelForgeGpuFarViewer
|
|||||||
|
|
||||||
bool QueueFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
bool QueueFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||||
const std::filesystem::path& shaderPath,bool dispatchShaders,
|
const std::filesystem::path& shaderPath,bool dispatchShaders,
|
||||||
const std::string& entryFilter,std::string& error)
|
const std::string& entryFilter,bool fenceEachKernel,std::string& error)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
GetFarViewerRunner(device,context,shaderPath).QueueTinyShaderWarmup(dispatchShaders,entryFilter);
|
GetFarViewerRunner(device,context,shaderPath).QueueTinyShaderWarmup(
|
||||||
|
dispatchShaders,entryFilter,fenceEachKernel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch(const std::exception& e){error=e.what();return false;}
|
catch(const std::exception& e){error=e.what();return false;}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param([string]$ExecutableName='VoxelForgeGpuFieldStep14Warmup.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="step14_${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 "STEP14_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 "STEP14_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='VoxelForgeGpuFieldStep14Warmup.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="step14_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 "STEP14_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($Child.PrivateMemorySize64-ge(8L*1GB))
|
||||||
|
{$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 "STEP14_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='VoxelForgeGpuFieldStep14Warmup.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='step14_race_cpu_A'},
|
||||||
|
@{Mode='gpu';Name='step14_race_gpu_A'},
|
||||||
|
@{Mode='gpu';Name='step14_race_gpu_B'},
|
||||||
|
@{Mode='cpu';Name='step14_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 "STEP14_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 "STEP14_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='VoxelForgeGpuFieldStep14Warmup.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='step14_gpu_survival'
|
||||||
|
$StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log')
|
||||||
|
$StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log')
|
||||||
|
$EightGB=8L*1024L*1024L*1024L
|
||||||
|
Write-Output "STEP14_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 "STEP14_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,67 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string]$ExecutableName='VoxelForgeGpuFieldStep14Warmup.exe',
|
||||||
|
[string]$Entry='ApplyNearFieldDetailCS',
|
||||||
|
[string]$SampleName='near_detail'
|
||||||
|
)
|
||||||
|
|
||||||
|
$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"}
|
||||||
|
if($Entry-ne'ApplyNearFieldDetailCS'){throw "Unsupported Step 14 shader entry: $Entry"}
|
||||||
|
$Name='step14_shader_'+$SampleName
|
||||||
|
$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",'--gpu-far-warmup-kernel-fences')
|
||||||
|
$EightGB=8L*1024L*1024L*1024L
|
||||||
|
Write-Output "STEP14_SHADER_RUN entry=$Entry sample=$SampleName 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()
|
||||||
|
$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 "Shader profile stopped at the 8 GiB private-memory ceiling: $SampleName"}
|
||||||
|
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||||
|
$Create=[regex]::Match($LogText,'(?m)^\[GpuPipelineProfile\] stage=shader_object_create entry='+[regex]::Escape($Entry)+' duration_ms=([0-9.]+)')
|
||||||
|
$Profile=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmupProfile\] entry='+[regex]::Escape($Entry)+' .*')
|
||||||
|
$Warmup=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=1 selected='+[regex]::Escape($Entry)+'.*queue_ms=([0-9.]+)')
|
||||||
|
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||||
|
if(-not$Create.Success-or-not$Profile.Success-or-not$Warmup.Success)
|
||||||
|
{throw "Isolated profile markers missing for $Entry; exit=$ViewerExitCode"}
|
||||||
|
$CombinedGB=$PeakPrivate/1GB
|
||||||
|
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||||
|
if($CombinedGB-ge8.0){throw "Shader profile exceeded private + DXGI-local 8 GiB ceiling: $SampleName ($CombinedGB GiB)"}
|
||||||
|
Write-Output "STEP14_SHADER_RESULT entry=$Entry sample=$SampleName object_create_ms=$($Create.Groups[1].Value) profile_ms=$($Profile.Groups[0].Value) isolated_queue_ms=$($Warmup.Groups[1].Value) host_process_exit_ms=$([math]::Round($HostRunClock.Elapsed.TotalMilliseconds,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ViewerExitCode"
|
||||||
|
if($ViewerExitCode-ne0){throw "Viewer returned $ViewerExitCode for $SampleName"}
|
||||||
|
break
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param([string]$ExecutableName='VoxelForgeGpuFieldStep14Warmup.exe',[switch]$SkipControlOnly,[string]$Label='profile')
|
||||||
|
|
||||||
|
$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=@(
|
||||||
|
@{Name="step14_${Label}_workers_active";Idle=$false;WarmupOnly=$false},
|
||||||
|
@{Name="step14_${Label}_workers_idle";Idle=$true;WarmupOnly=$false},
|
||||||
|
@{Name="step14_${Label}_skip_near_detail";Idle=$true;WarmupOnly=$true}
|
||||||
|
)
|
||||||
|
if($SkipControlOnly){$Runs=@($Runs[2])}
|
||||||
|
$EightGB=8L*1024L*1024L*1024L
|
||||||
|
foreach($Run in $Runs)
|
||||||
|
{
|
||||||
|
if($Run.WarmupOnly)
|
||||||
|
{$Arguments=@('--workers=8','--gpu-far-warmup-only','--gpu-far-warmup-kernel-fences',
|
||||||
|
'--gpu-far-warmup-entry=skip:ApplyNearFieldDetailCS')}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap','--gpu-far',
|
||||||
|
'--gpu-far-warmup-kernel-fences')
|
||||||
|
if($Run.Idle){$Arguments+='--gpu-far-warmup-before-workers'}
|
||||||
|
}
|
||||||
|
$StdoutPath=Join-Path $PSScriptRoot ($Run.Name+'.stdout.log')
|
||||||
|
$StderrPath=Join-Path $PSScriptRoot ($Run.Name+'.stderr.log')
|
||||||
|
Write-Output "STEP14_PROFILE_RUN name=$($Run.Name) cpu_workers_idle=$($Run.Idle.ToString().ToLowerInvariant()) 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()
|
||||||
|
$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 "Profile process stopped at the 8 GiB private-memory ceiling: $($Run.Name)"}
|
||||||
|
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||||
|
if(-not$Run.WarmupOnly-and-not$LogText.Contains('[InitialClipmapReady]'))
|
||||||
|
{throw "Full clipmap did not become ready in $($Run.Name); exit=$ViewerExitCode"}
|
||||||
|
if(-not$LogText.Contains('[GpuShaderWarmupProfile] stage=warmup_resource_create'))
|
||||||
|
{throw "Warmup profile markers are missing in $($Run.Name); exit=$ViewerExitCode"}
|
||||||
|
$Warmup=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=[0-9]+ .*queue_ms=([0-9.]+) completion=per_kernel_fenced')
|
||||||
|
$Ready=[regex]::Match($LogText,'(?m)^\[InitialClipmapReady\] ([0-9.]+) s')
|
||||||
|
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||||
|
if(-not$Warmup.Success-or(-not$Run.WarmupOnly-and-not$Ready.Success))
|
||||||
|
{throw "Warmup or ready timing missing in $($Run.Name)"}
|
||||||
|
$CombinedGB=$PeakPrivate/1GB
|
||||||
|
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||||
|
if($CombinedGB-ge8.0){throw "Warmup profile exceeded private + DXGI-local 8 GiB ceiling: $($Run.Name) ($CombinedGB GiB)"}
|
||||||
|
$ReadyMs=if($Ready.Success){[math]::Round([double]$Ready.Groups[1].Value*1000,3)}else{'not_applicable'}
|
||||||
|
Write-Output "STEP14_PROFILE_RESULT name=$($Run.Name) cpu_workers_idle=$($Run.Idle.ToString().ToLowerInvariant()) warmup_ms=$($Warmup.Groups[1].Value) ready_ms=$ReadyMs host_process_exit_ms=$([math]::Round($HostRunClock.Elapsed.TotalMilliseconds,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ViewerExitCode"
|
||||||
|
if($ViewerExitCode-ne0){throw "Viewer returned $ViewerExitCode`: $($Run.Name)"}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# GPU port, step 14: warm-up attribution and near-detail compile cost
|
||||||
|
|
||||||
|
Date: 2026-10-07. All edits and generated artifacts are under `Standalone\`. MSVC builds used `/MP8`; viewer and probe processes ran hidden at BelowNormal priority and affinity `0xFF00`. No `0xC0000142` retry was needed, maximum conservative private plus DXGI-local memory was 5.44 GiB, and no cache or driver settings were changed. No viewer remained open, and no full-size capture was opened in an image viewer. No commit, push, or stash was made.
|
||||||
|
|
||||||
|
## Result
|
||||||
|
|
||||||
|
The production warm-up was not the sum of isolated shader first-use times. In the production queue, `ApplyNearFieldDetailCS` accounts for most of the first-use stall, and its driver submission cost is paid on the immediate-context `Flush`. Creating its shader object, making warm-up resources, binding state, dispatching, and waiting on the final event are all small by comparison. A control that creates every shader object and warm-up resource but skips only the near-detail dispatch cuts the warm-up substantially; the connector-ring dispatch then becomes the next visible first-use stall.
|
||||||
|
|
||||||
|
The near-detail HLSL now shares the anchored/direct owner-roughness loop body and evaluates standard/ridged fractal outputs from the same Perlin samples. The Step 13 `ApplyNearFieldDetailCS` bytecode was 448,588 bytes; the Step 14 bytecode is 120,860 bytes, a 73.1% reduction. Its isolated first-use queue fell from 1,595.548 ms to 709.471 ms, a 55.5% reduction.
|
||||||
|
|
||||||
|
Production warm-up fell from the Step 13 median of 2,041.698 ms to 1,052.313 ms. Whole-view readiness did not improve with it: the Step 14 interleaved race measured 1.352 s CPU versus 3.196 s hybrid. Most shader warm-up overlaps CPU shape compilation; the remaining hybrid floor is the tile stream after warm-up.
|
||||||
|
|
||||||
|
## Warm-up attribution
|
||||||
|
|
||||||
|
The viewer now has an opt-in `--gpu-far-warmup-kernel-fences` profile. It records pipeline shader-object creation, warm-up resource creation, resource/state binding, each first dispatch, event-query creation, `Flush`, and completion fence, in production dispatch order. The normal production queue remains batched and uses one final event. `--gpu-far-warmup-before-workers` runs the same path before CPU generation workers start.
|
||||||
|
|
||||||
|
Baseline Step 13 shader, per-kernel fenced:
|
||||||
|
|
||||||
|
| Stage | CPU workers active | CPU workers idle |
|
||||||
|
|---|---:|---:|
|
||||||
|
| Shader pipeline creation, all entries | 52.733 ms | 61.128 ms |
|
||||||
|
| `ApplyNearFieldDetailCS` shader-object creation | 16.586 ms | 18.803 ms |
|
||||||
|
| Warm-up resource creation | 2.356 ms | 2.395 ms |
|
||||||
|
| Near-detail state binding | 0.005 ms | 0.006 ms |
|
||||||
|
| Near-detail dispatch call | 0.002 ms | 0.003 ms |
|
||||||
|
| Near-detail `Flush` | **1,980.816 ms** | **1,734.219 ms** |
|
||||||
|
| Near-detail completion fence | 7.101 ms | 8.804 ms |
|
||||||
|
| Entire fenced warm-up | 2,139.680 ms | 1,892.968 ms |
|
||||||
|
|
||||||
|
The skip control used the same shader-object creation and resources, then fenced all production entries except `ApplyNearFieldDetailCS`. Its idle-worker queue was 520.764 ms; `BuildFarConnectorRingsCS` took 363.553 ms in `Flush`. With near detail dispatched first, that ring `Flush` was under 0.4 ms in both baseline profiles. This demonstrates why adding isolated cold costs overcounts production: the entries share driver-side first-use work. The near-detail dispatch accounts for the majority of the warm-up, while the connector ring is the secondary cold entry.
|
||||||
|
|
||||||
|
The final Step 14 per-kernel profile measured near-detail `Flush` at 964.597 ms with workers active and 667.969 ms with workers idle. The corresponding complete fenced queues were 1,138.410 ms and 837.211 ms. The final skip-near-detail control was 535.680 ms, with a 382.239 ms connector-ring `Flush`.
|
||||||
|
|
||||||
|
The evidence identifies first-use driver work on the shader submission path: direct dispatch calls remain about 0.002–0.006 ms, object creation is milliseconds, resource creation is about 2 ms, and the long delay lands in `Flush`; the skip control removes that dispatch while leaving object creation intact. The D3D11 API does not expose a driver compiler timer, so the exact internal AMD operation cannot be separated from other driver translation/validation work. The measured behavior is consistent with synchronous first-use shader translation/compilation at `Flush`, serialized by the per-entry control.
|
||||||
|
|
||||||
|
## Near-detail restructuring
|
||||||
|
|
||||||
|
- Kept the generic looped value-noise routine introduced in Step 13.
|
||||||
|
- Replaced separate anchored (step 8) and direct (step 2) owner-roughness call paths with a `[loop]` over those two sample modes. The direct sample is still skipped when passage influence is at or below 0.40.
|
||||||
|
- Added `NearOwnerFractalPair`, which computes the standard and ridged accumulators from one Perlin sample per octave. The owner noise type selects the same prior output, including the averaged type.
|
||||||
|
- `ApplyNearFieldDetailCS` does not call `NearFieldDensityAt` or the root-refinement helper, so root refinement was not part of this kernel and was not removed.
|
||||||
|
|
||||||
|
The isolated shader profile after both changes reported object creation 5.831 ms, state binding 0.001 ms, dispatch 0.003 ms, `Flush` 689.707 ms, event wait 16.272 ms, and queue 709.471 ms. The event wait includes the profiling loop's 1 ms polling interval; it is not a GPU execution-time estimate.
|
||||||
|
|
||||||
|
## Correctness, survival, and captures
|
||||||
|
|
||||||
|
- Whole near audit: **960/960 tiles**, zero hardware topology differences, zero WARP topology differences, zero differences across **229,376 protected cells**, and bit-identical repeated GPU output.
|
||||||
|
- Whole far audit: **1,114** eligible tiles, 152 near-transition tiles skipped, zero hardware and WARP topology differences, zero differences across **127,401 protected cells** and **353 thin-feature cells**, and bit-identical repeated GPU output.
|
||||||
|
- CPU reference at 1 and 8 workers: identical density `0xdb2991c73215af4c`, mesh `0x8236c5edd7fc8e4f`, payload `0x4c48fa75a543d58e`, topology `0xbea22e76b34a4dfc`; walkability **5,642/5,642**.
|
||||||
|
- Full-residency GPU survival audit passed at **5.08 GiB** conservative private plus DXGI-local memory.
|
||||||
|
- All ten 1280×800 CPU/GPU capture pairs reached full residency. Numeric RGB results exactly match the Step 13 comparison: MAE range **0.0484–1.6092**; the highest combined private plus DXGI-local sample was **5.44 GiB**. See [step14_capture_comparison.md](step14_capture_comparison.md). The PNGs were compared as arrays and not viewed.
|
||||||
|
|
||||||
|
## Interleaved whole-view race
|
||||||
|
|
||||||
|
Order was CPU A, GPU A, GPU B, CPU B. All runs used 8 workers. The GPU warm-up numbers below are the normal batched production path without per-kernel fences.
|
||||||
|
|
||||||
|
| Run | Warm-up | Viewer ready / present return | Host process exit |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| CPU A | — | 1,353 ms | 1,522.097 ms |
|
||||||
|
| GPU A | 1,048.305 ms | 3,084 ms | 3,235.229 ms |
|
||||||
|
| GPU B | 1,056.321 ms | 3,308 ms | 3,466.244 ms |
|
||||||
|
| CPU B | — | 1,350 ms | 1,471.182 ms |
|
||||||
|
|
||||||
|
Median viewer readiness was **1.352 s CPU vs 3.196 s hybrid**: CPU leads by **1.845 s / 2.36×**. Median host-clock process exit was **1.497 s CPU vs 3.351 s hybrid**: CPU leads by **1.854 s / 2.24×**. Median warm-up was **1.052 s**, about 0.989 s below Step 13. `Present` returned `DXGI_STATUS_OCCLUDED`, so these clocks measure readiness and API return, not physical scanout.
|
||||||
|
|
||||||
|
The warm-up overlaps shape compilation: GPU shape compilation took 835–903 ms while a 1.048–1.056 s warm-up ran. After GPU input export completed at 1.302–1.306 s, whole-view readiness took another 1.778–2.003 s. Those runs queued 1,082 GPU tiles in 35 batches and kept 1,144 CPU fallback tiles; CPU input preparation was 112–119 ms wall time and measured GPU dispatch timestamps summed to 200–216 ms. The current floor is therefore the post-warm-up hybrid tile stream and CPU fallback/submission path, not near-detail compilation alone. The GPU path still loses the whole-view race.
|
||||||
|
|
||||||
|
## Lower-priority coverage case
|
||||||
|
|
||||||
|
The direct-GPU `(6,2,0,lod3)` coverage issue remains open. The viewer's established CPU fallback for remote LOD3/4 remains enabled; this step's whole-far audit skips near transitions and does not claim direct LOD3/4 coverage parity. The prior diagnostic and capture evidence remains in [STEP9_REPORT.md](STEP9_REPORT.md).
|
||||||
|
|
||||||
|
## Reproduction artifacts
|
||||||
|
|
||||||
|
- Warm-up controls: [RunStep14WarmupProfile.ps1](RunStep14WarmupProfile.ps1) and `step14_profile_*` / `step14_final_*` logs.
|
||||||
|
- Near shader compile and first-use: [CompileStep14Shader.ps1](CompileStep14Shader.ps1), [RunStep14ShaderFirstUse.ps1](RunStep14ShaderFirstUse.ps1), and the `step14_shader_*.stdout.log` files.
|
||||||
|
- Agreement: `step14_whole_near_agreement.stdout.log`, `step14_whole_far_agreement.stdout.log`.
|
||||||
|
- CPU reference: [RunStep14CpuReference.ps1](RunStep14CpuReference.ps1) and `step14_cpu_reference_w*.stdout.log`.
|
||||||
|
- Survival: [RunStep14GpuSurvival.ps1](RunStep14GpuSurvival.ps1) and `step14_gpu_survival.stdout.log`.
|
||||||
|
- Captures: [RunStep14CaptureMatrix.ps1](RunStep14CaptureMatrix.ps1), [CompareStep14Captures.py](CompareStep14Captures.py), and `step14_capture_comparison.md`.
|
||||||
|
- Race: [RunStep14FinalInterleaved.ps1](RunStep14FinalInterleaved.ps1) and `step14_race_*.stdout.log`.
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,16 @@
|
|||||||
|
# Step 14 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.1994 | 2.6632 | 4.2472% | 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.5593% | 0.4098% | 107 |
|
||||||
@@ -289,6 +289,80 @@ FarFieldSpatialBin FarFieldFindBin(float3 position)
|
|||||||
return emptyBin;
|
return emptyBin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NearOwnerFractalPair(float x,float y,float z,int octaves,
|
||||||
|
out float standardValue,out float ridgedValue)
|
||||||
|
{
|
||||||
|
float standardTotal=0.0f,ridgedTotal=0.0f,maxValue=0.0f;
|
||||||
|
float frequency=1.0f,amplitude=1.0f,weight=1.0f;
|
||||||
|
[loop]
|
||||||
|
for(int octave=0;octave<octaves;++octave)
|
||||||
|
{
|
||||||
|
const float noise=VF_FieldPerlin3D(x*frequency,y*frequency,z*frequency);
|
||||||
|
standardTotal+=noise*amplitude;
|
||||||
|
float ridge=noise*1.25f;
|
||||||
|
ridge=1.0f-abs(ridge);
|
||||||
|
ridge=ridge*ridge;
|
||||||
|
ridge*=weight;
|
||||||
|
weight=clamp(ridge*2.0f,0.0f,1.0f);
|
||||||
|
ridgedTotal+=ridge*amplitude;
|
||||||
|
maxValue+=amplitude;
|
||||||
|
amplitude*=0.5f;
|
||||||
|
frequency*=2.0f;
|
||||||
|
}
|
||||||
|
standardValue=standardTotal/maxValue;
|
||||||
|
ridgedValue=(ridgedTotal/maxValue)*2.0f-1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float NearOwnerRoughnessCore(float x,float y,float z,uint seed,
|
||||||
|
float surfaceRoughness,float roughnessFrequency,float verticalScale,
|
||||||
|
float domainWarpStrength,float domainWarpFrequency,uint noiseType)
|
||||||
|
{
|
||||||
|
if(!(roughnessFrequency>0.0f))return 0.0f;
|
||||||
|
const float effectiveZ=verticalScale>0.0f&&verticalScale!=1.0f?z/verticalScale:z;
|
||||||
|
const float mainX=x*roughnessFrequency+VF_FieldVoxelSeedOffset(seed,11.3f);
|
||||||
|
const float mainY=y*roughnessFrequency+VF_FieldVoxelSeedOffset(seed,13.7f);
|
||||||
|
const float mainZ=effectiveZ*roughnessFrequency+VF_FieldVoxelSeedOffset(seed,17.1f);
|
||||||
|
float fineX=x*roughnessFrequency*3.0f+VF_FieldVoxelSeedOffset(seed,19.1f)+2000.0f;
|
||||||
|
float fineY=y*roughnessFrequency*3.0f+VF_FieldVoxelSeedOffset(seed,23.7f)+2500.0f;
|
||||||
|
float fineZ=effectiveZ*roughnessFrequency*3.0f+VF_FieldVoxelSeedOffset(seed,29.3f)+3000.0f;
|
||||||
|
float mx=mainX,my=mainY,mz=mainZ;
|
||||||
|
if(domainWarpStrength>0.0f)
|
||||||
|
{
|
||||||
|
const float wf=domainWarpFrequency,ws=domainWarpStrength;
|
||||||
|
float wx=VF_FieldPerlin3D(x*wf+VF_FieldVoxelSeedOffset(seed,5.2f),
|
||||||
|
y*wf+VF_FieldVoxelSeedOffset(seed,1.3f),effectiveZ*wf+VF_FieldVoxelSeedOffset(seed,9.7f));
|
||||||
|
float wy=VF_FieldPerlin3D(x*wf+100.0f+VF_FieldVoxelSeedOffset(seed,7.7f),
|
||||||
|
y*wf+200.0f+VF_FieldVoxelSeedOffset(seed,3.1f),effectiveZ*wf+300.0f);
|
||||||
|
float wz=VF_FieldPerlin3D(x*wf+400.0f,y*wf+500.0f+VF_FieldVoxelSeedOffset(seed,11.9f),
|
||||||
|
effectiveZ*wf+600.0f+VF_FieldVoxelSeedOffset(seed,13.3f));
|
||||||
|
wx*=1.25f*ws;wy*=1.25f*ws;wz*=1.25f*ws;
|
||||||
|
mx+=wx;my+=wy;mz+=wz;
|
||||||
|
fineX+=wx;fineY+=wy;fineZ+=wz;
|
||||||
|
}
|
||||||
|
float rough=0.0f,fine=0.0f;
|
||||||
|
if(noiseType==3u)
|
||||||
|
{
|
||||||
|
rough=VF_FieldOwnerCellular(mx,my,mz);
|
||||||
|
fine=VF_FieldOwnerCellular(fineX,fineY,fineZ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float roughStandard,roughRidged,fineStandard,fineRidged;
|
||||||
|
NearOwnerFractalPair(mx,my,mz,3,roughStandard,roughRidged);
|
||||||
|
NearOwnerFractalPair(fineX,fineY,fineZ,2,fineStandard,fineRidged);
|
||||||
|
if(noiseType==1u)
|
||||||
|
{ rough=roughRidged;fine=fineRidged; }
|
||||||
|
else if(noiseType==2u)
|
||||||
|
{
|
||||||
|
rough=(roughStandard+roughRidged)*0.5f;
|
||||||
|
fine=(fineStandard+fineRidged)*0.5f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ rough=roughStandard;fine=fineStandard; }
|
||||||
|
}
|
||||||
|
return (rough+fine*0.4f)*1.25f*surfaceRoughness;
|
||||||
|
}
|
||||||
|
|
||||||
float NearOwnerRoughnessAtStep(float3 position,float surfaceSdf,float caveInfluence,
|
float NearOwnerRoughnessAtStep(float3 position,float surfaceSdf,float caveInfluence,
|
||||||
FarFieldDetailLayer layer,uint anchorStep)
|
FarFieldDetailLayer layer,uint anchorStep)
|
||||||
{
|
{
|
||||||
@@ -301,17 +375,17 @@ float NearOwnerRoughnessAtStep(float3 position,float surfaceSdf,float caveInflue
|
|||||||
float total;
|
float total;
|
||||||
if(sampleZ1>sampleZ0)
|
if(sampleZ1>sampleZ0)
|
||||||
{
|
{
|
||||||
const float lower=VF_FieldOwnerRoughnessCore(position.x,position.y,sampleZ0,
|
const float lower=NearOwnerRoughnessCore(position.x,position.y,sampleZ0,
|
||||||
FarFieldSeed,layer.surfaceRoughness,layer.roughnessFrequency,layer.verticalScale,
|
FarFieldSeed,layer.surfaceRoughness,layer.roughnessFrequency,layer.verticalScale,
|
||||||
layer.domainWarpStrength,layer.domainWarpFrequency,layer.roughnessNoiseType);
|
layer.domainWarpStrength,layer.domainWarpFrequency,layer.roughnessNoiseType);
|
||||||
const float upper=VF_FieldOwnerRoughnessCore(position.x,position.y,sampleZ1,
|
const float upper=NearOwnerRoughnessCore(position.x,position.y,sampleZ1,
|
||||||
FarFieldSeed,layer.surfaceRoughness,layer.roughnessFrequency,layer.verticalScale,
|
FarFieldSeed,layer.surfaceRoughness,layer.roughnessFrequency,layer.verticalScale,
|
||||||
layer.domainWarpStrength,layer.domainWarpFrequency,layer.roughnessNoiseType);
|
layer.domainWarpStrength,layer.domainWarpFrequency,layer.roughnessNoiseType);
|
||||||
const float alpha=(position.z-sampleZ0)/(sampleZ1-sampleZ0);
|
const float alpha=(position.z-sampleZ0)/(sampleZ1-sampleZ0);
|
||||||
total=lower+(upper-lower)*alpha;
|
total=lower+(upper-lower)*alpha;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
total=VF_FieldOwnerRoughnessCore(position.x,position.y,position.z,
|
total=NearOwnerRoughnessCore(position.x,position.y,position.z,
|
||||||
FarFieldSeed,layer.surfaceRoughness,layer.roughnessFrequency,layer.verticalScale,
|
FarFieldSeed,layer.surfaceRoughness,layer.roughnessFrequency,layer.verticalScale,
|
||||||
layer.domainWarpStrength,layer.domainWarpFrequency,layer.roughnessNoiseType);
|
layer.domainWarpStrength,layer.domainWarpFrequency,layer.roughnessNoiseType);
|
||||||
if(surfaceSdf<0.0f)
|
if(surfaceSdf<0.0f)
|
||||||
@@ -324,9 +398,18 @@ float NearOwnerRoughness(float3 position,float surfaceSdf,float caveInfluence,
|
|||||||
float passageInfluence,FarFieldDetailLayer layer)
|
float passageInfluence,FarFieldDetailLayer layer)
|
||||||
{
|
{
|
||||||
const float passage=saturate(passageInfluence);
|
const float passage=saturate(passageInfluence);
|
||||||
const float anchored=NearOwnerRoughnessAtStep(position,surfaceSdf,caveInfluence,layer,8);
|
float anchored=0.0f,direct=0.0f;
|
||||||
|
[loop]
|
||||||
|
for(uint sampleIndex=0;sampleIndex<2;++sampleIndex)
|
||||||
|
{
|
||||||
|
if(sampleIndex==1&&passage<=0.40f)continue;
|
||||||
|
const uint anchorStep=sampleIndex==0?8u:2u;
|
||||||
|
const float value=NearOwnerRoughnessAtStep(position,surfaceSdf,caveInfluence,
|
||||||
|
layer,anchorStep);
|
||||||
|
if(sampleIndex==0)anchored=value;
|
||||||
|
else direct=value;
|
||||||
|
}
|
||||||
if(passage<=0.40f)return anchored;
|
if(passage<=0.40f)return anchored;
|
||||||
const float direct=NearOwnerRoughnessAtStep(position,surfaceSdf,caveInfluence,layer,2);
|
|
||||||
if(passage>=0.60f)return direct;
|
if(passage>=0.60f)return direct;
|
||||||
const float directWeight=VF_FieldSmoothUnit((passage-0.40f)/0.20f);
|
const float directWeight=VF_FieldSmoothUnit((passage-0.40f)/0.20f);
|
||||||
const float anchoredWeight=1.0f-directWeight;
|
const float anchoredWeight=1.0f-directWeight;
|
||||||
|
|||||||
@@ -1491,6 +1491,7 @@ namespace
|
|||||||
bool bGpuFarShaderPrewarm=false,bDisableGpuWarmupPresentHold=false;
|
bool bGpuFarShaderPrewarm=false,bDisableGpuWarmupPresentHold=false;
|
||||||
bool bGpuFarWarmupResourcesOnly=false;
|
bool bGpuFarWarmupResourcesOnly=false;
|
||||||
bool bGpuFarWarmupNormalPriority=false,bGpuFarWarmupBeforeWorkers=false;
|
bool bGpuFarWarmupNormalPriority=false,bGpuFarWarmupBeforeWorkers=false;
|
||||||
|
bool bGpuFarWarmupKernelFences=false;
|
||||||
bool bGpuFarWarmupOnly=false;
|
bool bGpuFarWarmupOnly=false;
|
||||||
std::string GpuWarmupEntryFilter;
|
std::string GpuWarmupEntryFilter;
|
||||||
std::thread GpuShaderWarmupThread;
|
std::thread GpuShaderWarmupThread;
|
||||||
@@ -1897,6 +1898,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
|||||||
}
|
}
|
||||||
bGpuShaderWarmupQueueSucceeded=VoxelForgeGpuFarViewer::QueueFarShaderWarmup(
|
bGpuShaderWarmupQueueSucceeded=VoxelForgeGpuFarViewer::QueueFarShaderWarmup(
|
||||||
Device,Context,GpuFarShaderPath,!bGpuFarWarmupResourcesOnly,GpuWarmupEntryFilter,
|
Device,Context,GpuFarShaderPath,!bGpuFarWarmupResourcesOnly,GpuWarmupEntryFilter,
|
||||||
|
bGpuFarWarmupKernelFences,
|
||||||
GpuShaderWarmupQueueError);
|
GpuShaderWarmupQueueError);
|
||||||
});
|
});
|
||||||
std::printf("[GpuShaderWarmup] queue_thread=started overlap=%s\n",
|
std::printf("[GpuShaderWarmup] queue_thread=started overlap=%s\n",
|
||||||
@@ -5620,6 +5622,8 @@ int main(int Argc,char** Argv)
|
|||||||
App.bGpuFarEnabled=true,App.bGpuFarShaderPrewarm=true,App.bGpuFarWarmupBeforeWorkers=true,
|
App.bGpuFarEnabled=true,App.bGpuFarShaderPrewarm=true,App.bGpuFarWarmupBeforeWorkers=true,
|
||||||
App.bShapeWorld=true,App.bForceGenerate=true,App.bPresentCpuFrameBeforeGpu=true,
|
App.bShapeWorld=true,App.bForceGenerate=true,App.bPresentCpuFrameBeforeGpu=true,
|
||||||
App.bHoldCpuFrameDuringGpuWarmup=true;
|
App.bHoldCpuFrameDuringGpuWarmup=true;
|
||||||
|
else if(Arg=="--gpu-far-warmup-kernel-fences")
|
||||||
|
App.bGpuFarWarmupKernelFences=true;
|
||||||
else if(Arg=="--gpu-far-warmup-only")
|
else if(Arg=="--gpu-far-warmup-only")
|
||||||
App.bGpuFarEnabled=true,App.bGpuFarShaderPrewarm=true,App.bGpuFarWarmupOnly=true,
|
App.bGpuFarEnabled=true,App.bGpuFarShaderPrewarm=true,App.bGpuFarWarmupOnly=true,
|
||||||
App.bShapeWorld=true,App.bForceGenerate=true;
|
App.bShapeWorld=true,App.bForceGenerate=true;
|
||||||
@@ -5891,7 +5895,7 @@ int main(int Argc,char** Argv)
|
|||||||
const auto WarmupOnlyStart=std::chrono::steady_clock::now();
|
const auto WarmupOnlyStart=std::chrono::steady_clock::now();
|
||||||
std::string WarmupError;
|
std::string WarmupError;
|
||||||
if(!VoxelForgeGpuFarViewer::QueueFarShaderWarmup(App.Device,App.Context,App.GpuFarShaderPath,
|
if(!VoxelForgeGpuFarViewer::QueueFarShaderWarmup(App.Device,App.Context,App.GpuFarShaderPath,
|
||||||
true,App.GpuWarmupEntryFilter,WarmupError))
|
true,App.GpuWarmupEntryFilter,App.bGpuFarWarmupKernelFences,WarmupError))
|
||||||
{std::fprintf(stderr,"[GpuShaderWarmupError] queue: %s\n",WarmupError.c_str());return 5;}
|
{std::fprintf(stderr,"[GpuShaderWarmupError] queue: %s\n",WarmupError.c_str());return 5;}
|
||||||
if(!VoxelForgeGpuFarViewer::CompleteFarShaderWarmup(App.Device,App.Context,
|
if(!VoxelForgeGpuFarViewer::CompleteFarShaderWarmup(App.Device,App.Context,
|
||||||
App.GpuFarShaderPath,WarmupError))
|
App.GpuFarShaderPath,WarmupError))
|
||||||
|
|||||||
Reference in new issue
Block a user