<# .SYNOPSIS Campaign V slice V6c: compile acdream's GLSL to the committed SPIR-V the Vulkan backend loads at startup. .DESCRIPTION Plan §4.6 rules out runtime shader compilation: it would add a native dependency and a startup cost for shaders that never change at runtime, and CI runners have no Vulkan SDK. So the .spv artifacts are committed, this script regenerates them, and an App test re-hashes the GLSL sources against the manifest this writes so a source edit that never got recompiled fails a test rather than shipping a stale binary. Two compilers are supported, in this order: 1. glslc from a Vulkan SDK, if one is on PATH or under $VULKAN_SDK. This is the reference implementation and is what the plan names. 2. tools/ShaderCompiler, a small .NET tool over Silk.NET.Shaderc — the same shaderc library glslc is built on, through the already-pinned Silk.NET 2.23.0 family. It exists because neither the development machine nor CI has an SDK installed, and requiring one to build acdream would put a 500 MB manual install between a contributor and a working checkout. Both paths inject the same Vulkan preamble (see tools/ShaderCompiler/VulkanGlslPreamble.cs) so the GLSL sources stay the single source of truth for both backends. .PARAMETER ShadersDirectory Source directory. Defaults to src/AcDream.App/Rendering/Shaders. .PARAMETER OutputDirectory Where .spv and shaders.manifest.json are written. Defaults to src/AcDream.App/Rendering/Shaders/spv. .PARAMETER PreferSdk Use glslc when available. On by default; pass -PreferSdk:$false to force the managed path, which is what a comparison between the two wants. .EXAMPLE tools/compile-shaders.ps1 #> [CmdletBinding()] param( [string]$ShadersDirectory, [string]$OutputDirectory, [bool]$PreferSdk = $true ) $ErrorActionPreference = 'Stop' $repo = Split-Path -Parent $PSScriptRoot # Campaign V slice V9: every path below is composed one segment at a time rather # than from an embedded 'a\b\c' literal. A backslash is a path separator on # Windows and an ordinary filename character everywhere else, so the embedded # form silently produced one long nonexistent file name on the Linux CI runner # that this slice's lavapipe job introduced. if (-not $ShadersDirectory) { $ShadersDirectory = [System.IO.Path]::Combine( $repo, 'src', 'AcDream.App', 'Rendering', 'Shaders') } if (-not $OutputDirectory) { $OutputDirectory = Join-Path $ShadersDirectory 'spv' } function Write-Step($message) { Write-Host "[shaders] $message" } New-Item -ItemType Directory -Force -Path $OutputDirectory | Out-Null # --- 1. Locate glslc, if the machine has a Vulkan SDK ------------------------- $glslc = $null if ($PreferSdk) { $onPath = Get-Command glslc -ErrorAction SilentlyContinue if ($onPath) { $glslc = $onPath.Source } elseif ($env:VULKAN_SDK) { # 'Bin/glslc.exe' on Windows, 'bin/glslc' on the SDK's Linux layout. $candidates = @( [System.IO.Path]::Combine($env:VULKAN_SDK, 'Bin', 'glslc.exe'), [System.IO.Path]::Combine($env:VULKAN_SDK, 'bin', 'glslc') ) foreach ($candidate in $candidates) { if (Test-Path $candidate) { $glslc = $candidate; break } } } } # --- 2. Compile --------------------------------------------------------------- # Even with glslc present the managed tool does the work: it owns the preamble # injection and the manifest, and running the same transform through two # code paths is exactly how the two would drift. glslc's presence is reported so # a future slice can add a cross-check between them. if ($glslc) { Write-Step "a Vulkan SDK glslc was found at $glslc (recorded; the managed compiler still runs)" } else { Write-Step 'no Vulkan SDK glslc found; using the managed Silk.NET.Shaderc compiler' } $tool = [System.IO.Path]::Combine( $repo, 'tools', 'ShaderCompiler', 'ShaderCompiler.csproj') # Campaign V slice V9 follow-up: the tool is PUBLISHED for the host runtime # identifier rather than built portable. A portable `dotnet build` leaves # shaderc's native module under runtimes//native/ and makes loading it the # job of Silk.NET's probing chain, which reaches it on some hosts and not # others - it resolved on Ubuntu 24.04 locally and failed on the ubuntu-24.04 # CI runner with "Could not load from any of the possible library names!". # Publishing with an explicit RID flattens the native next to the assembly, # where AppContext.BaseDirectory - the first candidate Silk.NET tries - always # finds it. Same managed code, same pinned shaderc 2.23.0; only the lookup # changes. $architecture = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture $ridArchitecture = switch ($architecture) { 'X64' { 'x64' } 'Arm64' { 'arm64' } 'X86' { 'x86' } default { throw "No shaderc native is published for processor architecture $architecture." } } # $IsWindows and friends only exist in PowerShell 6+; 5.1 is Windows by # definition, and -or short-circuits before touching the undefined variable. $ridOs = if ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows) { 'win' } elseif ($IsMacOS) { 'osx' } elseif ($IsLinux) { 'linux' } else { throw 'Unrecognised operating system; cannot choose a shaderc native.' } $rid = "$ridOs-$ridArchitecture" $toolDirectory = [System.IO.Path]::Combine( $repo, 'tools', 'ShaderCompiler', 'bin', 'publish', $rid) Write-Step "publishing the shader compiler for $rid" & dotnet publish $tool -c Release -r $rid --self-contained false -o $toolDirectory --nologo -v q | Out-Null if ($LASTEXITCODE -ne 0) { throw "Shader compiler publish failed with exit code $LASTEXITCODE." } $binary = Join-Path $toolDirectory 'AcDream.Tools.ShaderCompiler.dll' if (-not (Test-Path $binary)) { throw "Shader compiler not found at $binary." } # Name the missing file rather than letting Silk.NET report the generic # "could not load from any of the possible library names" three steps later. $nativeName = if ($ridOs -eq 'win') { 'shaderc_shared.dll' } elseif ($ridOs -eq 'osx') { 'libshaderc_shared.dylib' } else { 'libshaderc_shared.so' } $native = Join-Path $toolDirectory $nativeName if (-not (Test-Path $native)) { throw ("The shaderc native $nativeName is not beside the shader compiler at " + "$toolDirectory. The Silk.NET.Shaderc.Native package did not publish a " + "$rid asset.") } Write-Step "shaderc native: $native" Write-Step "compiling $ShadersDirectory -> $OutputDirectory" & dotnet $binary $ShadersDirectory $OutputDirectory if ($LASTEXITCODE -ne 0) { throw "Shader compilation failed with exit code $LASTEXITCODE." } Write-Step 'done'