<# .SYNOPSIS Capture the reproducible Atmospheric render-pack performance matrix. .DESCRIPTION Runs the existing isolated offline pixel gate for retail, Low, Medium, High, and Auto at 1920x1080, 2560x1440, and 3840x2160. Every row receives the same authored-time, camera, MSAA, and warmup pins. Capped and uncapped modes are selected explicitly with -FramePacing. The declared CPU and resident-memory ceilings are enforced for every enhanced row. The declared GPU ceilings are specifically 1080p ceilings, so 1440p and 4K GPU measurements are reported without comparing them to a threshold that was never declared for those resolutions. The exact 1080p Low/Medium/High CPU p50/p99, GPU p50/p99, and memory ceilings are immutable in this script and are emitted in both summaries. No credentials or live-session environment values are read or recorded. This wrapper never compares against or writes the user's normal settings: run-offline-pixel-gate.ps1 owns a separate isolated state directory for every row. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$Out, [ValidateSet('capped', 'uncapped', 'both')] [string]$FramePacing = 'both', [ValidateSet('retail', 'low', 'medium', 'high', 'auto')] [string[]]$PresetSet = @('retail', 'low', 'medium', 'high', 'auto'), [ValidateSet('1920x1080', '2560x1440', '3840x2160')] [string[]]$ResolutionSet = @('1920x1080', '2560x1440', '3840x2160'), [ValidateRange(45000, 600000)] [int]$WarmupMs = 45000, [int]$DayGroup = 0, [ValidateRange(0.0, 1.0)] [double]$WorldDayFraction = 0.5, [double]$SkyPhaseSeconds = 0, [ValidateRange(0.0, 5000.0)] [double]$OrbitDistanceMeters = 0, [Nullable[double]]$OrbitYawDegrees, [ValidateRange(-89.0, 89.0)] [Nullable[double]]$OrbitPitchDegrees, [switch]$SkipBuild ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $PSNativeCommandUseErrorActionPreference = $false . (Join-Path $PSScriptRoot 'atmospheric-performance-matrix-common.ps1') . (Join-Path $PSScriptRoot 'connected-render-pack-gate-common.ps1') $repo = Split-Path -Parent $PSScriptRoot $pixelGate = Join-Path $PSScriptRoot 'run-offline-pixel-gate.ps1' $solution = Join-Path $repo 'AcDream.slnx' $cli = Join-Path $repo 'src\AcDream.Cli\bin\Release\net10.0\AcDream.Cli.dll' $outputRoot = [IO.Path]::GetFullPath($Out) $jsonPath = Join-Path $outputRoot 'atmospheric-performance-matrix.json' $markdownPath = Join-Path $outputRoot 'atmospheric-performance-matrix.md' $presets = @($PresetSet | ForEach-Object { $_.ToLowerInvariant() } | Select-Object -Unique) $screenshotLeaf = 'world-offline' $resolutions = @($ResolutionSet | Select-Object -Unique) $pacingModes = switch ($FramePacing) { 'capped' { @('capped') } 'uncapped' { @('uncapped') } default { @('capped', 'uncapped') } } # These are the exact declarations in BuiltInAtmosphericRenderPack and the # campaign plan's Performance budget table. Do not relax them in this tool. $budgets = @{ low = [pscustomobject][ordered]@{ IncrementalCpuMillisecondsP50 = 0.15 IncrementalCpuMillisecondsP99 = 0.50 InclusiveGpuMillisecondsP50At1080p = 2.00 InclusiveGpuMillisecondsP99At1080p = 3.00 ResidentGpuBytes = 64L * 1024L * 1024L } medium = [pscustomobject][ordered]@{ IncrementalCpuMillisecondsP50 = 0.25 IncrementalCpuMillisecondsP99 = 0.75 InclusiveGpuMillisecondsP50At1080p = 3.25 InclusiveGpuMillisecondsP99At1080p = 4.50 ResidentGpuBytes = 128L * 1024L * 1024L } high = [pscustomobject][ordered]@{ IncrementalCpuMillisecondsP50 = 0.35 IncrementalCpuMillisecondsP99 = 1.00 InclusiveGpuMillisecondsP50At1080p = 4.50 InclusiveGpuMillisecondsP99At1080p = 6.00 ResidentGpuBytes = 256L * 1024L * 1024L } } function Get-RequiredProperty { param( [Parameter(Mandatory = $true)][object]$Value, [Parameter(Mandatory = $true)][string]$Name, [Parameter(Mandatory = $true)][string]$Context ) $property = $Value.PSObject.Properties[$Name] if ($null -eq $property) { throw "$Context is missing required property '$Name'." } return $property.Value } function Format-Invariant([double]$Value, [string]$Format = '0.###') { return $Value.ToString($Format, [Globalization.CultureInfo]::InvariantCulture) } function Add-Failure( [Collections.Generic.List[string]]$RowFailures, [string]$Message) { $null = $RowFailures.Add($Message) } function Assert-MatrixContainedPath([string]$Root, [string]$Path) { return Assert-ConnectedGateContainedPath $Root $Path } function Compare-MatrixFallbackFramebuffer { param( [Parameter(Mandatory = $true)][string]$Expected, [Parameter(Mandatory = $true)][string]$Actual, [Parameter(Mandatory = $true)][string]$ReportPath, [Parameter(Mandatory = $true)][string]$MaskPath) Add-Type -AssemblyName System.Drawing $image = [System.Drawing.Bitmap]::FromFile($Actual) try { $mask = [System.Drawing.Bitmap]::new( $image.Width, $image.Height, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb) try { $graphics = [System.Drawing.Graphics]::FromImage($mask) try { $graphics.Clear([System.Drawing.Color]::FromArgb(0, 0, 0, 0)) $opaque = [System.Drawing.SolidBrush]::new( [System.Drawing.Color]::FromArgb(255, 255, 0, 255)) try { $graphics.FillRectangle( $opaque, 0, 0, $image.Width, [Math]::Min(280, $image.Height)) } finally { $opaque.Dispose() } } finally { $graphics.Dispose() } $mask.Save($MaskPath, [System.Drawing.Imaging.ImageFormat]::Png) } finally { $mask.Dispose() } } finally { $image.Dispose() } & dotnet $cli compare-screenshots ` $Expected $Actual $ReportPath 2 0.001 $MaskPath | Out-Null $compareExitCode = $LASTEXITCODE if (-not (Test-Path -LiteralPath $ReportPath -PathType Leaf)) { return [pscustomobject][ordered]@{ Passed = $false DifferentPixelFraction = $null ExitCode = $compareExitCode ReportPath = $ReportPath Failure = 'fallback/default screenshot comparison produced no report' } } $verdict = Get-Content -Raw -LiteralPath $ReportPath | ConvertFrom-Json $passedProperty = $verdict.PSObject.Properties['passed'] if ($null -eq $passedProperty) { $passedProperty = $verdict.PSObject.Properties['Passed'] } $fractionProperty = $verdict.PSObject.Properties['differentPixelFraction'] if ($null -eq $fractionProperty) { $fractionProperty = $verdict.PSObject.Properties['DifferentPixelFraction'] } $passed = $null -ne $passedProperty -and [bool]$passedProperty.Value return [pscustomobject][ordered]@{ Passed = $passed DifferentPixelFraction = if ($null -eq $fractionProperty) { $null } else { [double]$fractionProperty.Value } ExitCode = $compareExitCode ReportPath = $ReportPath Failure = if ($passed) { $null } else { 'safe fallback framebuffer differs from its paired default beyond tolerance 2 / 0.001' } } } if (-not (Test-Path -LiteralPath $pixelGate)) { throw "Offline pixel gate not found at '$pixelGate'." } if (Test-Path -LiteralPath $outputRoot) { throw "Output directory already exists: '$outputRoot'. Choose a new directory." } $outputParent = Split-Path -Parent $outputRoot if (-not (Test-Path -LiteralPath $outputParent -PathType Container)) { throw "Output parent directory does not exist: '$outputParent'." } Assert-ConnectedGateNoReparsePoint $outputParent Assert-ConnectedGateSafeLeafName ([IO.Path]::GetFileName($outputRoot)) if (@(Get-Process -Name AcDream.App -ErrorAction SilentlyContinue).Count -gt 0) { throw 'An AcDream.App client is already running; close it gracefully before the matrix.' } if (-not $SkipBuild) { & dotnet build $solution -c Release --no-restore if ($LASTEXITCODE -ne 0) { throw "Release build failed with exit code $LASTEXITCODE." } } $exe = Join-Path $repo 'src\AcDream.App\bin\Release\net10.0\AcDream.App.exe' if (-not (Test-Path -LiteralPath $exe -PathType Leaf)) { throw "Client executable not found: '$exe'." } $binaryIdentity = Get-ConnectedGateBinaryIdentity ` -Repository $repo -Executable $exe -SkipBuild:$SkipBuild $null = New-Item -ItemType Directory -Path $outputRoot Assert-ConnectedGateNoReparsePoint $outputRoot $sourceCommit = $binaryIdentity.SourceCommit $sourceStatus = @($binaryIdentity.SourceTrackedStatus) $powershellExecutable = (Get-Process -Id $PID).Path $rows = [Collections.Generic.List[object]]::new() $matrixFailures = [Collections.Generic.List[string]]::new() $startedUtc = [DateTime]::UtcNow $expectedCasterCount = $null $expectedAdapterIdentity = $null foreach ($pacing in $pacingModes) { foreach ($resolution in $resolutions) { $dimensions = $resolution.Split('x') $expectedWidth = [int]$dimensions[0] $expectedHeight = [int]$dimensions[1] foreach ($preset in $presets) { $rowId = "$pacing-$preset-$($resolution.Replace('x', 'x'))" Assert-ConnectedGateSafeLeafName $rowId $rowDirectory = Assert-MatrixContainedPath $outputRoot (Join-Path $outputRoot $rowId) if (Test-Path -LiteralPath $rowDirectory) { throw "Matrix row directory is not fresh: '$rowDirectory'." } $metadataPath = Assert-MatrixContainedPath $rowDirectory ( Join-Path $rowDirectory "screenshots\$screenshotLeaf.metadata.json") $rowFailures = [Collections.Generic.List[string]]::new() $captureExitCode = -1 $metadata = $null $pack = $null $performance = $null $cpuSampleCount = $null $absoluteReceiverCpuSampleCount = $null $gpuSampleCount = $null $cpuP50 = $null $cpuP95 = $null $cpuP99 = $null $absoluteReceiverCpuP50 = $null $absoluteReceiverCpuP95 = $null $absoluteReceiverCpuP99 = $null $gpuP50 = $null $gpuP95 = $null $gpuP99 = $null $residentGpuBytes = $null $transientGpuBytes = $null $casterCount = $null $cascadeCount = $null $drawCalls = $null $dispatchCalls = $null $imageCount = $null $bufferCount = $null $effectiveQuality = $null $activationState = $null $failureReason = $null $availability = if ($preset -eq 'retail') { 'Retail' } else { 'Unknown' } $unavailableClassification = $null $metadataSchemaVersion = $null $packVersion = $null $activationGeneration = $null $topResidentGpuBytes = $null $topTransientGpuBytes = $null $classificationCalls = $null $passIds = @() $framebufferSha256 = $null $processEvidence = $null $adapterEvidence = $null $budget = if ($preset -in @('retail', 'auto')) { $null } else { $budgets[$preset] } $gpuBudgetApplies = $false try { $arguments = @( '-NoProfile', '-File', $pixelGate, '-Out', $rowDirectory, '-WarmupMs', "$WarmupMs", '-DayGroup', "$DayGroup", '-WorldDayFraction', (Format-Invariant $WorldDayFraction '0.################'), '-SkyPhaseSeconds', (Format-Invariant $SkyPhaseSeconds '0.################'), '-MsaaSamples', '0', '-RenderPackPreset', $preset, '-Resolution', $resolution, '-OrbitDistanceMeters', (Format-Invariant $OrbitDistanceMeters '0.################'), '-SkipBuild') if ($preset -ne 'retail') { $arguments += @( '-RequiredRenderPackSamples', '2048', '-RenderPackSampleTimeoutMs', '300000', '-AllowSafeRenderPackFallback') } if ($null -ne $OrbitYawDegrees) { $arguments += @( '-OrbitYawDegrees', (Format-Invariant ([double]$OrbitYawDegrees) '0.################')) } if ($null -ne $OrbitPitchDegrees) { $arguments += @( '-OrbitPitchDegrees', (Format-Invariant ([double]$OrbitPitchDegrees) '0.################')) } if ($pacing -eq 'uncapped') { $arguments += '-Uncapped' } & $powershellExecutable @arguments $captureExitCode = $LASTEXITCODE if ($captureExitCode -ne 0) { Add-Failure $rowFailures ( "offline capture exited with code $captureExitCode") } if (-not (Test-Path -LiteralPath $metadataPath)) { throw "screenshot metadata is missing at '$metadataPath'." } foreach ($capturedPath in @( $rowDirectory, (Join-Path $rowDirectory 'screenshots'), (Join-Path $rowDirectory 'isolated-state'), (Join-Path $rowDirectory 'isolated-state\cache'))) { Assert-ConnectedGateNoReparsePoint $capturedPath } $metadata = Get-Content -Raw -LiteralPath $metadataPath | ConvertFrom-Json $metadataSchemaVersion = [int](Get-RequiredProperty $metadata 'SchemaVersion' 'metadata') $strictEvidence = Test-AtmosphericPerformanceMetadataEvidence ` -MetadataPath $metadataPath -Preset $preset ` -ExpectedWidth $expectedWidth -ExpectedHeight $expectedHeight ` -AllowSafeFallback:($preset -ne 'retail') foreach ($strictFailure in @($strictEvidence.Failures)) { Add-Failure $rowFailures $strictFailure } $availability = [string]$strictEvidence.Outcome $unavailableClassification = $strictEvidence.UnavailableClassification $classificationCalls = $strictEvidence.CpuClassificationCalls $passIds = @($strictEvidence.PassIds) $actualWidth = [int](Get-RequiredProperty $metadata 'Width' 'metadata') $actualHeight = [int](Get-RequiredProperty $metadata 'Height' 'metadata') if ($actualWidth -ne $expectedWidth -or $actualHeight -ne $expectedHeight) { Add-Failure $rowFailures ( "capture extent was ${actualWidth}x${actualHeight}, expected $resolution") } $pack = Get-RequiredProperty $metadata 'RenderPack' 'metadata' $activationState = [int](Get-RequiredProperty $pack 'State' 'RenderPack') $actualPackId = [string](Get-RequiredProperty $pack 'PackId' 'RenderPack') $actualPresetId = [string](Get-RequiredProperty $pack 'PresetId' 'RenderPack') $packVersion = [string](Get-RequiredProperty $pack 'PackVersion' 'RenderPack') $activationGeneration = [int](Get-RequiredProperty $pack 'ActivationGeneration' 'RenderPack') $topResidentGpuBytes = [long](Get-RequiredProperty $pack 'RetainedGpuBytes' 'RenderPack') $topTransientGpuBytes = [long](Get-RequiredProperty $pack 'TransientGpuBytes' 'RenderPack') $effectiveQuality = [string]( Get-RequiredProperty $pack 'EffectiveQuality' 'RenderPack') if ($availability -eq 'Active' -and $preset -eq 'auto') { $budget = $budgets[$effectiveQuality] if ($null -eq $budget) { Add-Failure $rowFailures ( "Automatic resolved unknown effective quality '$effectiveQuality'") } } $gpuBudgetApplies = $availability -eq 'Active' -and $resolution -eq '1920x1080' $failureReason = Get-RequiredProperty $pack 'FailureReason' 'RenderPack' $expectedPackId = if ($preset -eq 'retail' -or $availability -eq 'Unavailable') { 'retail' } else { 'acdream.atmospheric' } $expectedPresetId = if ($preset -eq 'retail' -or $availability -eq 'Unavailable') { 'off' } else { $preset } $expectedState = if ($preset -eq 'retail') { 0 } elseif ($availability -eq 'Unavailable') { 3 } else { 2 } if ($actualPackId -cne $expectedPackId) { Add-Failure $rowFailures ( "pack was '$actualPackId', expected '$expectedPackId'") } if ($actualPresetId -cne $expectedPresetId) { Add-Failure $rowFailures ( "preset was '$actualPresetId', expected '$expectedPresetId'") } if ($activationState -ne $expectedState) { Add-Failure $rowFailures ( "activation state was $activationState, expected $expectedState") } if ($availability -ne 'Unavailable' -and -not [string]::IsNullOrWhiteSpace([string]$failureReason)) { Add-Failure $rowFailures "render-pack failure: $failureReason" } $casterCount = [int](Get-RequiredProperty $pack 'ShadowCasterCount' 'RenderPack') $cascadeCount = [int](Get-RequiredProperty $pack 'CascadeDrawCount' 'RenderPack') $drawCalls = [int](Get-RequiredProperty $pack 'DrawCalls' 'RenderPack') $dispatchCalls = [int](Get-RequiredProperty $pack 'DispatchCalls' 'RenderPack') $imageCount = [int](Get-RequiredProperty $pack 'ImageCount' 'RenderPack') $bufferCount = [int](Get-RequiredProperty $pack 'BufferCount' 'RenderPack') $performance = Get-RequiredProperty $pack 'Performance' 'RenderPack' # Consume only the post-audit metric names. The old absolute # CpuMilliseconds*/GpuMilliseconds* fields must never be used # to decide an incremental budget row. $cpuSampleCount = [int](Get-RequiredProperty ` $performance 'CpuSampleCount' 'RenderPack.Performance') $absoluteReceiverCpuSampleCount = [int](Get-RequiredProperty ` $performance 'AbsoluteReceiverCpuSampleCount' 'RenderPack.Performance') $gpuSampleCount = [int](Get-RequiredProperty ` $performance 'GpuSampleCount' 'RenderPack.Performance') $cpuP50 = [double](Get-RequiredProperty ` $performance 'IncrementalCpuMillisecondsP50' 'RenderPack.Performance') $cpuP95 = [double](Get-RequiredProperty ` $performance 'IncrementalCpuMillisecondsP95' 'RenderPack.Performance') $cpuP99 = [double](Get-RequiredProperty ` $performance 'IncrementalCpuMillisecondsP99' 'RenderPack.Performance') $absoluteReceiverCpuP50 = [double](Get-RequiredProperty ` $performance 'AbsoluteReceiverCpuMillisecondsP50' 'RenderPack.Performance') $absoluteReceiverCpuP95 = [double](Get-RequiredProperty ` $performance 'AbsoluteReceiverCpuMillisecondsP95' 'RenderPack.Performance') $absoluteReceiverCpuP99 = [double](Get-RequiredProperty ` $performance 'AbsoluteReceiverCpuMillisecondsP99' 'RenderPack.Performance') $gpuP50 = [double](Get-RequiredProperty ` $performance 'InclusiveGpuMillisecondsP50' 'RenderPack.Performance') $gpuP95 = [double](Get-RequiredProperty ` $performance 'InclusiveGpuMillisecondsP95' 'RenderPack.Performance') $gpuP99 = [double](Get-RequiredProperty ` $performance 'InclusiveGpuMillisecondsP99' 'RenderPack.Performance') $residentGpuBytes = [long](Get-RequiredProperty ` $performance 'ResidentGpuBytes' 'RenderPack.Performance') $transientGpuBytes = [long](Get-RequiredProperty ` $performance 'TransientGpuBytes' 'RenderPack.Performance') if ($availability -eq 'Active') { if ($null -eq $expectedCasterCount) { $expectedCasterCount = $casterCount } elseif ($casterCount -ne $expectedCasterCount) { Add-Failure $rowFailures ( "shadow caster membership $casterCount differs from matrix oracle $expectedCasterCount") } } $pngPath = Assert-MatrixContainedPath $rowDirectory ( Join-Path $rowDirectory "screenshots\$screenshotLeaf.png") $framebufferSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $pngPath).Hash.ToLowerInvariant() $processPath = Assert-MatrixContainedPath $rowDirectory ( Join-Path $rowDirectory 'capture-process.json') $processEvidence = Get-Content -Raw -LiteralPath $processPath | ConvertFrom-Json if ([int]$processEvidence.SchemaVersion -ne 1 -or [long]$processEvidence.WorkingSetBytes -le 0 -or [long]$processEvidence.PrivateMemoryBytes -le 0) { Add-Failure $rowFailures 'process-memory evidence is missing or invalid' } $capabilityPath = Assert-MatrixContainedPath $rowDirectory ( Join-Path $rowDirectory 'isolated-state\cache\diagnostics\graphical-capabilities-vulkan.json') $capability = Get-Content -Raw -LiteralPath $capabilityPath | ConvertFrom-Json $adapterEvidence = [pscustomobject][ordered]@{ DeviceName = [string]$capability.DeviceName DriverInfo = [string]$capability.DriverInfo DeviceType = [string]$capability.DeviceType SelectedDeviceIndex = [int]$capability.SelectedDeviceIndex DeviceApiVersion = [string]$capability.DeviceApiVersion } $adapterIdentity = "$($adapterEvidence.DeviceName)|$($adapterEvidence.DriverInfo)|$($adapterEvidence.SelectedDeviceIndex)" if ([string]::IsNullOrWhiteSpace($adapterEvidence.DeviceName)) { Add-Failure $rowFailures 'Vulkan adapter identity is missing' } elseif ($null -eq $expectedAdapterIdentity) { $expectedAdapterIdentity = $adapterIdentity } elseif ($adapterIdentity -cne $expectedAdapterIdentity) { Add-Failure $rowFailures 'Vulkan adapter identity changed between matrix rows' } if ($preset -eq 'retail') { if ($imageCount -ne 0 -or $bufferCount -ne 0 -or $drawCalls -ne 0 -or $dispatchCalls -ne 0 -or $casterCount -ne 0 -or $cascadeCount -ne 0 -or $residentGpuBytes -ne 0 -or $transientGpuBytes -ne 0) { Add-Failure $rowFailures ( 'retail row activated pack resources, submissions, casters, or memory') } } elseif ($availability -eq 'Unavailable') { # The strict metadata oracle already proved exact retail # identity, zero samples/work/resources, and an allow-listed # resource/capability reason. No enhanced budget applies to # a preset which never became active. } else { if ($cpuSampleCount -le 0 -or $gpuSampleCount -le 0) { Add-Failure $rowFailures ( "enhanced row has insufficient samples: cpu=$cpuSampleCount gpu=$gpuSampleCount") } if (-not [double]::IsFinite($cpuP50) -or $cpuP50 -lt 0 -or -not [double]::IsFinite($cpuP99) -or $cpuP99 -lt 0 -or -not [double]::IsFinite($gpuP50) -or $gpuP50 -lt 0 -or -not [double]::IsFinite($gpuP99) -or $gpuP99 -lt 0 -or $residentGpuBytes -lt 0) { Add-Failure $rowFailures 'performance measurements are non-finite or negative' } if ($cpuP50 -gt $budget.IncrementalCpuMillisecondsP50) { Add-Failure $rowFailures ( "incremental CPU p50 $(Format-Invariant $cpuP50) ms exceeds " + "$(Format-Invariant $budget.IncrementalCpuMillisecondsP50) ms") } if ($cpuP99 -gt $budget.IncrementalCpuMillisecondsP99) { Add-Failure $rowFailures ( "incremental CPU p99 $(Format-Invariant $cpuP99) ms exceeds " + "$(Format-Invariant $budget.IncrementalCpuMillisecondsP99) ms") } if ($residentGpuBytes -gt $budget.ResidentGpuBytes) { Add-Failure $rowFailures ( "resident GPU bytes $residentGpuBytes exceed $($budget.ResidentGpuBytes)") } if ($gpuBudgetApplies -and $gpuP50 -gt $budget.InclusiveGpuMillisecondsP50At1080p) { Add-Failure $rowFailures ( "inclusive GPU p50 $(Format-Invariant $gpuP50) ms exceeds the 1080p " + "ceiling $(Format-Invariant $budget.InclusiveGpuMillisecondsP50At1080p) ms") } if ($gpuBudgetApplies -and $gpuP99 -gt $budget.InclusiveGpuMillisecondsP99At1080p) { Add-Failure $rowFailures ( "inclusive GPU p99 $(Format-Invariant $gpuP99) ms exceeds the 1080p " + "ceiling $(Format-Invariant $budget.InclusiveGpuMillisecondsP99At1080p) ms") } } } catch { Add-Failure $rowFailures $_.Exception.Message } $passed = $rowFailures.Count -eq 0 $row = [pscustomobject][ordered]@{ Id = $rowId FramePacing = $pacing Preset = $preset Resolution = $resolution CaptureDirectory = $rowDirectory MetadataPath = $metadataPath CaptureExitCode = $captureExitCode Passed = $passed Failures = @($rowFailures) Activation = [pscustomobject][ordered]@{ MetadataSchemaVersion = $metadataSchemaVersion PackVersion = $packVersion State = $activationState Generation = $activationGeneration EffectiveQuality = $effectiveQuality FailureReason = $failureReason Availability = $availability UnavailableClassification = $unavailableClassification } FramebufferSha256 = $framebufferSha256 PairedDefaultFramebufferSha256 = $null PairedDefaultComparison = $null Process = $processEvidence Adapter = $adapterEvidence Samples = [pscustomobject][ordered]@{ IncrementalCpu = $cpuSampleCount AbsoluteReceiverCpu = $absoluteReceiverCpuSampleCount InclusiveGpu = $gpuSampleCount } PerformanceMilliseconds = [pscustomobject][ordered]@{ IncrementalCpuP50 = $cpuP50 IncrementalCpuP95 = $cpuP95 IncrementalCpuP99 = $cpuP99 AbsoluteReceiverCpuP50 = $absoluteReceiverCpuP50 AbsoluteReceiverCpuP95 = $absoluteReceiverCpuP95 AbsoluteReceiverCpuP99 = $absoluteReceiverCpuP99 InclusiveGpuP50 = $gpuP50 InclusiveGpuP95 = $gpuP95 InclusiveGpuP99 = $gpuP99 } Resources = [pscustomobject][ordered]@{ TopLevelResidentGpuBytes = $topResidentGpuBytes TopLevelTransientGpuBytes = $topTransientGpuBytes ResidentGpuBytes = $residentGpuBytes TransientGpuBytes = $transientGpuBytes Images = $imageCount Buffers = $bufferCount } Work = [pscustomobject][ordered]@{ ShadowCasters = $casterCount CascadeDraws = $cascadeCount DrawCalls = $drawCalls DispatchCalls = $dispatchCalls CpuClassificationCalls = $classificationCalls PassIds = @($passIds) } Budget = if ($null -eq $budget) { $null } else { [pscustomobject][ordered]@{ IncrementalCpuMillisecondsP50 = $budget.IncrementalCpuMillisecondsP50 IncrementalCpuMillisecondsP99 = $budget.IncrementalCpuMillisecondsP99 InclusiveGpuMillisecondsP50At1080p = $budget.InclusiveGpuMillisecondsP50At1080p InclusiveGpuMillisecondsP99At1080p = $budget.InclusiveGpuMillisecondsP99At1080p ResidentGpuBytes = $budget.ResidentGpuBytes GpuBudgetApplies = $gpuBudgetApplies } } } $null = $rows.Add($row) foreach ($failure in $rowFailures) { $null = $matrixFailures.Add("${rowId}: $failure") } } } } foreach ($row in @($rows | Where-Object { $_.Preset -ne 'retail' })) { $defaultRow = @($rows | Where-Object { $_.Preset -eq 'retail' -and $_.FramePacing -eq $row.FramePacing -and $_.Resolution -eq $row.Resolution }) if ($defaultRow.Count -ne 1 -or [string]::IsNullOrWhiteSpace([string]$defaultRow[0].FramebufferSha256)) { $message = "$($row.Id): paired default framebuffer digest is unavailable" $null = $matrixFailures.Add($message) $row.Passed = $false $row.Failures = @($row.Failures) + $message } else { $row.PairedDefaultFramebufferSha256 = $defaultRow[0].FramebufferSha256 if ($row.Activation.Availability -eq 'Unavailable') { $expectedPng = Assert-MatrixContainedPath $defaultRow[0].CaptureDirectory ( Join-Path $defaultRow[0].CaptureDirectory "screenshots\$screenshotLeaf.png") $actualPng = Assert-MatrixContainedPath $row.CaptureDirectory ( Join-Path $row.CaptureDirectory "screenshots\$screenshotLeaf.png") $comparisonReport = Assert-MatrixContainedPath $row.CaptureDirectory ( Join-Path $row.CaptureDirectory 'compare-paired-default.json') $comparisonMask = Assert-MatrixContainedPath $row.CaptureDirectory ( Join-Path $row.CaptureDirectory 'compare-paired-default-mask.png') try { $row.PairedDefaultComparison = Compare-MatrixFallbackFramebuffer ` -Expected $expectedPng ` -Actual $actualPng ` -ReportPath $comparisonReport ` -MaskPath $comparisonMask if (-not $row.PairedDefaultComparison.Passed) { $message = "$($row.Id): $($row.PairedDefaultComparison.Failure)" $null = $matrixFailures.Add($message) $row.Passed = $false $row.Failures = @($row.Failures) + $message } } catch { $message = "$($row.Id): fallback/default screenshot comparison failed: $($_.Exception.Message)" $null = $matrixFailures.Add($message) $row.Passed = $false $row.Failures = @($row.Failures) + $message } } } } $finishedUtc = [DateTime]::UtcNow $report = [pscustomobject][ordered]@{ SchemaVersion = 1 Scope = 'offline fixed-scene pack diagnostics; final receiver CPU authority requires connected identical pack-off/on A/B' Passed = $matrixFailures.Count -eq 0 StartedUtc = $startedUtc.ToString('O') FinishedUtc = $finishedUtc.ToString('O') SourceCommit = $sourceCommit TrackedSourceStatus = @($sourceStatus) BinaryProductVersion = $binaryIdentity.BinaryProductVersion BinaryCommit = $binaryIdentity.BinaryCommit BinaryMatchesSource = $binaryIdentity.BinaryMatchesSource SkipBuild = $binaryIdentity.SkipBuild FramePacing = $FramePacing Pins = [pscustomobject][ordered]@{ WarmupMs = $WarmupMs ExplicitPresetPerformanceWindowResetAfterWarmup = $true AutomaticPerformanceWindowPolicy = 'settled rolling window; diagnostic reset prohibited' RequiredEnhancedSamplesPerMetric = 2048 RenderPackSampleTimeoutMs = 300000 DayGroup = $DayGroup WorldDayFraction = $WorldDayFraction SkyPhaseSeconds = $SkyPhaseSeconds MsaaSamples = 0 OrbitDistanceMeters = $OrbitDistanceMeters OrbitYawDegrees = $OrbitYawDegrees OrbitPitchDegrees = $OrbitPitchDegrees Presets = $presets Resolutions = $resolutions } Summary = [pscustomobject][ordered]@{ TotalRows = $rows.Count PassedRows = @($rows | Where-Object Passed).Count ActiveEnhancedRows = @($rows | Where-Object { $_.Activation.Availability -eq 'Active' -and $_.Passed }).Count ResourceUnavailableRows = @($rows | Where-Object { $_.Activation.UnavailableClassification -eq 'ResourceUnavailable' -and $_.Passed }).Count CapabilityUnavailableRows = @($rows | Where-Object { $_.Activation.UnavailableClassification -eq 'CapabilityUnavailable' -and $_.Passed }).Count FailedRows = @($rows | Where-Object { -not $_.Passed }).Count } EvidenceOracle = [pscustomobject][ordered]@{ RequiredSamplesPerMetric = 2048 EqualEnhancedShadowCasterCount = $expectedCasterCount CascadeDraws = [pscustomobject][ordered]@{ Low = 2; Medium = 3; High = 4 } WarmedCpuClassificationCalls = 0 VulkanAdapterIdentity = $expectedAdapterIdentity } DeclaredBudgets = [pscustomobject][ordered]@{ Low = $budgets.low Medium = $budgets.medium High = $budgets.high } Rows = @($rows) Failures = @($matrixFailures) } $report | ConvertTo-Json -Depth 12 | Set-Content -Encoding utf8 -LiteralPath $jsonPath $markdown = [Text.StringBuilder]::new() $null = $markdown.AppendLine('# Atmospheric Rendering Performance Matrix') $null = $markdown.AppendLine() $null = $markdown.AppendLine('Scope: offline fixed-scene pack diagnostics. Final receiver CPU authority requires connected identical pack-off/on A/B.') $null = $markdown.AppendLine() $null = $markdown.AppendLine("- Result: **$(if ($report.Passed) { 'PASS' } else { 'FAIL' })**") $null = $markdown.AppendLine("- Source commit: ``$sourceCommit``") $null = $markdown.AppendLine("- Binary commit: ``$($binaryIdentity.BinaryCommit)`` (source match: $($binaryIdentity.BinaryMatchesSource))") $null = $markdown.AppendLine("- Vulkan adapter: ``$expectedAdapterIdentity``") $null = $markdown.AppendLine("- Frame pacing: ``$FramePacing``") $null = $markdown.AppendLine( "- Pins: warmup ${WarmupMs} ms; day group $DayGroup; world day fraction " + "$(Format-Invariant $WorldDayFraction '0.################'); sky phase " + "$(Format-Invariant $SkyPhaseSeconds '0.################') s; MSAA 0; orbit " + "$(Format-Invariant $OrbitDistanceMeters) m") $null = $markdown.AppendLine( "- Evidence window: explicit presets reset diagnostics after warmup; Auto preserves " + "its hysteresis-owned rolling window. Every active row waits for a complete 2048-sample " + "CPU / receiver / GPU window (300000 ms timeout).") $null = $markdown.AppendLine() $null = $markdown.AppendLine('## Declared ceilings') $null = $markdown.AppendLine() $null = $markdown.AppendLine('| Preset | CPU p50 / p99 (ms) | GPU p50 / p99 at 1080p (ms) | Resident MiB |') $null = $markdown.AppendLine('|---|---:|---:|---:|') foreach ($preset in @('low', 'medium', 'high')) { $budget = $budgets[$preset] $null = $markdown.AppendLine( "| $preset | $(Format-Invariant $budget.IncrementalCpuMillisecondsP50) / " + "$(Format-Invariant $budget.IncrementalCpuMillisecondsP99) | " + "$(Format-Invariant $budget.InclusiveGpuMillisecondsP50At1080p) / " + "$(Format-Invariant $budget.InclusiveGpuMillisecondsP99At1080p) | " + "$([Math]::Round($budget.ResidentGpuBytes / 1MB, 0)) |") } $null = $markdown.AppendLine() $null = $markdown.AppendLine('## Rows') $null = $markdown.AppendLine() $null = $markdown.AppendLine('| Pacing | Preset | Resolution | Availability | CPU / receiver / GPU samples | CPU p50 / p95 / p99 ms | Receiver p50 / p95 / p99 ms | GPU p50 / p95 / p99 ms | Resident MiB | Process WS / private MiB | Casters | Cascades | Draw / dispatch | Framebuffer / paired-default SHA-256 | Result |') $null = $markdown.AppendLine('|---|---|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|---|') foreach ($row in $rows) { $cpu = if ($null -eq $row.PerformanceMilliseconds.IncrementalCpuP50) { 'n/a' } else { "$(Format-Invariant $row.PerformanceMilliseconds.IncrementalCpuP50) / " + "$(Format-Invariant $row.PerformanceMilliseconds.IncrementalCpuP95) / " + "$(Format-Invariant $row.PerformanceMilliseconds.IncrementalCpuP99)" } $gpu = if ($null -eq $row.PerformanceMilliseconds.InclusiveGpuP50) { 'n/a' } else { "$(Format-Invariant $row.PerformanceMilliseconds.InclusiveGpuP50) / " + "$(Format-Invariant $row.PerformanceMilliseconds.InclusiveGpuP95) / " + "$(Format-Invariant $row.PerformanceMilliseconds.InclusiveGpuP99)" } $receiver = if ($null -eq $row.PerformanceMilliseconds.AbsoluteReceiverCpuP50) { 'n/a' } else { "$(Format-Invariant $row.PerformanceMilliseconds.AbsoluteReceiverCpuP50) / " + "$(Format-Invariant $row.PerformanceMilliseconds.AbsoluteReceiverCpuP95) / " + "$(Format-Invariant $row.PerformanceMilliseconds.AbsoluteReceiverCpuP99)" } $resident = if ($null -eq $row.Resources.ResidentGpuBytes) { 'n/a' } else { Format-Invariant ($row.Resources.ResidentGpuBytes / 1MB) } $processMemory = if ($null -eq $row.Process) { 'n/a' } else { "$(Format-Invariant ($row.Process.WorkingSetBytes / 1MB)) / " + "$(Format-Invariant ($row.Process.PrivateMemoryBytes / 1MB))" } $digest = if ($null -eq $row.FramebufferSha256) { 'n/a' } else { $row.FramebufferSha256 } $pairedDigest = if ($null -eq $row.PairedDefaultFramebufferSha256) { 'n/a' } else { $row.PairedDefaultFramebufferSha256 } $result = if ($row.Passed -and $row.Activation.Availability -eq 'Unavailable') { 'UNAVAILABLE: ' + $row.Activation.UnavailableClassification + ' - ' + (([string]$row.Activation.FailureReason) -replace '\|', '/') } elseif ($row.Passed) { 'PASS' } else { 'FAIL: ' + ((@($row.Failures) -join '; ') -replace '\|', '/') } $null = $markdown.AppendLine( "| $($row.FramePacing) | $($row.Preset) | $($row.Resolution) | $($row.Activation.Availability) | " + "$($row.Samples.IncrementalCpu) / $($row.Samples.AbsoluteReceiverCpu) / $($row.Samples.InclusiveGpu) | " + "$cpu | $receiver | $gpu | $resident | $processMemory | $($row.Work.ShadowCasters) | " + "$($row.Work.CascadeDraws) | $($row.Work.DrawCalls) / $($row.Work.DispatchCalls) | " + "$digest / $pairedDigest | $result |") } if ($matrixFailures.Count -ne 0) { $null = $markdown.AppendLine() $null = $markdown.AppendLine('## Failures') $null = $markdown.AppendLine() foreach ($failure in $matrixFailures) { $null = $markdown.AppendLine("- $failure") } } $markdown.ToString() | Set-Content -Encoding utf8 -LiteralPath $markdownPath Write-Output "JSON=$jsonPath" Write-Output "MARKDOWN=$markdownPath" Write-Output "RESULT=$(if ($report.Passed) { 'PASS' } else { 'FAIL' })" if (-not $report.Passed) { exit 1 }