From 2c9f81fbf1abec2228569bb5d672aad76b5f1d8e Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 10 Jun 2026 21:30:49 +0100 Subject: [PATCH] Add HLSL SPIR-V tool scripts --- .gitignore | 1 + README.md | 16 ++++++++++ tools/compile-hlsl-spirv.ps1 | 58 ++++++++++++++++++++++++++++++++++++ tools/get-dxc.ps1 | 42 ++++++++++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 tools/compile-hlsl-spirv.ps1 create mode 100644 tools/get-dxc.ps1 diff --git a/.gitignore b/.gitignore index 6eae439..5ae20c8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ obj/ **/obj/ target/ **/target/ +.tools/ diff --git a/README.md b/README.md index ef69df8..7627b77 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,22 @@ cargo test --manifest-path native/cultmath-core/Cargo.toml cargo build --release --manifest-path native/cultmath-core/Cargo.toml ``` +## Shader Tooling + +CultMath keeps portable DXC outside git under `.tools/`: + +```powershell +.\tools\get-dxc.ps1 +.\tools\compile-hlsl-spirv.ps1 ` + -ShaderPath E:\Projects\Odin\crates\muninn-move-tracker\shaders\MoveSphereCandidate.comp.hlsl ` + -OutputPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.spv ` + -IncludePath E:\Projects\CultMath\shaders +``` + +DXC emits Vulkan SPIR-V with `-spirv`. `-TargetEnv vulkan1.2` is exposed by the +script, but the current Windows DXC release compiled this shader successfully +with DXC's default Vulkan target while rejecting the dotted target-env value. + ## Doctrine The goal is mechanical sympathy between CPU-side authoring, native kernels, and diff --git a/tools/compile-hlsl-spirv.ps1 b/tools/compile-hlsl-spirv.ps1 new file mode 100644 index 0000000..98270cb --- /dev/null +++ b/tools/compile-hlsl-spirv.ps1 @@ -0,0 +1,58 @@ +param( + [Parameter(Mandatory = $true)] + [string]$ShaderPath, + + [Parameter(Mandatory = $true)] + [string]$OutputPath, + + [string]$EntryPoint = "main", + [string]$Profile = "cs_6_0", + [string[]]$IncludePath = @(), + [string]$TargetEnv = "", + [string]$DxcPath = "" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +if (-not $DxcPath) { + $DxcPath = Join-Path $repoRoot ".tools\dxc\current\bin\x64\dxc.exe" +} + +if (-not (Test-Path $DxcPath)) { + throw "DXC not found at '$DxcPath'. Run tools\get-dxc.ps1 first or pass -DxcPath." +} + +$resolvedShader = Resolve-Path $ShaderPath +$resolvedIncludes = @((Join-Path $repoRoot "shaders")) +foreach ($path in $IncludePath) { + $resolvedIncludes += (Resolve-Path $path) +} + +$outputDirectory = Split-Path -Parent $OutputPath +if ($outputDirectory) { + New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null +} + +$arguments = @( + "-T", $Profile, + "-E", $EntryPoint, + "-spirv" +) + +if ($TargetEnv) { + $arguments += "-fspv-target-env=$TargetEnv" +} + +foreach ($include in $resolvedIncludes) { + $arguments += @("-I", $include) +} + +$arguments += @($resolvedShader, "-Fo", $OutputPath) + +& $DxcPath @arguments +if ($LASTEXITCODE -ne 0) { + throw "dxc.exe failed with exit code $LASTEXITCODE." +} + +Get-Item -LiteralPath $OutputPath diff --git a/tools/get-dxc.ps1 b/tools/get-dxc.ps1 new file mode 100644 index 0000000..2f3363f --- /dev/null +++ b/tools/get-dxc.ps1 @@ -0,0 +1,42 @@ +param( + [string]$InstallRoot = ".tools\dxc" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$installPath = Join-Path $repoRoot $InstallRoot +New-Item -ItemType Directory -Force -Path $installPath | Out-Null + +$release = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/microsoft/DirectXShaderCompiler/releases/latest" ` + -Headers @{ "User-Agent" = "CultMath-DXC-Bootstrap" } + +$asset = $release.assets | + Where-Object { $_.name -like "dxc_*.zip" } | + Select-Object -First 1 + +if (-not $asset) { + throw "No Windows dxc_*.zip asset found on the latest DirectXShaderCompiler release." +} + +$zipPath = Join-Path $installPath $asset.name +Remove-Item -LiteralPath $zipPath -Force -ErrorAction SilentlyContinue + +& curl.exe -L --retry 5 --retry-delay 2 --fail -o $zipPath $asset.browser_download_url +if ($LASTEXITCODE -ne 0) { + throw "curl.exe failed with exit code $LASTEXITCODE." +} + +$currentPath = Join-Path $installPath "current" +Remove-Item -LiteralPath $currentPath -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $currentPath | Out-Null +Expand-Archive -LiteralPath $zipPath -DestinationPath $currentPath -Force + +$dxcPath = Join-Path $currentPath "bin\x64\dxc.exe" +if (-not (Test-Path $dxcPath)) { + throw "DXC x64 executable was not found after extraction." +} + +& $dxcPath --version +Write-Host "DXC installed at $dxcPath"