aboutsummaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-19 02:02:20 +0200
committerhachem <im@hachem.wtf>2026-08-19 02:02:20 +0200
commitf7e05555fb4ff6d8e51bdb5734db4dab1841d593 (patch)
tree353d350b19da7b84ca11e5801d33a921407a963e /Tools
parent5c5fc10d8938fd2da1922f01c638d42e70eb1ab1 (diff)
[feat]: migrate to slang from glsl
Diffstat (limited to 'Tools')
-rwxr-xr-xTools/compile-shaders.sh110
-rwxr-xr-xTools/fetch-slang.sh29
2 files changed, 139 insertions, 0 deletions
diff --git a/Tools/compile-shaders.sh b/Tools/compile-shaders.sh
new file mode 100755
index 0000000..ea1aa15
--- /dev/null
+++ b/Tools/compile-shaders.sh
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+#
+# Compiles every Assets/Shaders/*.slang to all backend targets, into
+# Assets/Shaders/generated/ (gitignored):
+#
+# OpenGL : <name>.glsl - combined "#type" GLSL 4.10 (Slang -> SPIR-V ->
+# SPIRV-Cross), macOS-4.1-core valid, loaded by
+# OpenGLShader.
+# Vulkan : <name>.<entry>.spv - SPIR-V per entry point.
+# Metal : <name>.metal - MSL, whole module.
+#
+# Entry points are auto-discovered from Slang [shader("stage")] attributes.
+# Override tool paths with SLANGC / SPIRV_CROSS.
+set -euo pipefail
+
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+SLANGC="${SLANGC:-$ROOT/Tools/slang/bin/slangc}"
+SPIRV_CROSS="${SPIRV_CROSS:-$(command -v spirv-cross || echo spirv-cross)}"
+SRC="$ROOT/Assets/Shaders"
+OUT="$SRC/generated"
+
+[ -x "$SLANGC" ] || { echo "compile-shaders: slangc not found at $SLANGC (run Tools/fetch-slang.sh)"; exit 1; }
+command -v "$SPIRV_CROSS" >/dev/null 2>&1 || { echo "compile-shaders: spirv-cross not found (brew install spirv-cross)"; exit 1; }
+
+mkdir -p "$OUT"
+shopt -s nullglob
+shaders=("$SRC"/*.slang)
+[ ${#shaders[@]} -gt 0 ] || { echo "compile-shaders: no .slang files in $SRC yet"; exit 0; }
+
+# Prints "stage entryName" for each [shader("stage")] entry point in a file.
+entry_points() {
+ awk '
+ /\[shader\(/ { if (match($0, /"[a-zA-Z]+"/)) { stage = substr($0, RSTART+1, RLENGTH-2); want = 1 } next }
+ want && $0 ~ /^[ \t]*\[/ { next } # skip further attributes
+ want && /\(/ {
+ sig = $0; sub(/\(.*/, "", sig)
+ n = split(sig, t, /[ \t*&]+/); name = t[n]
+ if (name != "") print stage, name
+ want = 0
+ }
+ ' "$1"
+}
+
+fail=0
+for f in "${shaders[@]}"; do
+ name="$(basename "$f" .slang)"
+ echo "== $name.slang =="
+
+ # Metal: whole module.
+ if "$SLANGC" "$f" -target metal -o "$OUT/$name.metal" 2>"$OUT/.err"; then
+ echo " metal -> $name.metal"
+ else echo " metal FAILED:"; sed 's/^/ /' "$OUT/.err"; fail=1; fi
+
+ # OpenGL + Vulkan: per entry point. Shaders that declare a ConstantBuffer keep
+ # real UBO blocks (the Engine binds them by name); the rest have Slang's
+ # $Globals flattened to loose uniforms so per-draw glUniform* calls still work.
+ if grep -q 'ConstantBuffer<' "$f"; then ubo=1; else ubo=0; fi
+ combined="$OUT/$name.glsl"; : > "$combined"
+ while read -r stage entry; do
+ [ -z "${stage:-}" ] && continue
+ spv="$OUT/$name.$entry.spv"
+
+ if ! "$SLANGC" "$f" -target spirv -entry "$entry" -stage "$stage" -o "$spv" 2>"$OUT/.err"; then
+ echo " spirv FAILED ($entry):"; sed 's/^/ /' "$OUT/.err"; fail=1; continue
+ fi
+ echo " spirv -> $name.$entry.spv ($stage)"
+
+ # SPIR-V -> classic GLSL 4.10 (combined samplers, no binding layouts).
+ xcopts="--version 410 --no-es --no-420pack-extension"
+ [ "$ubo" = 0 ] && xcopts="$xcopts --glsl-emit-ubo-as-plain-uniforms"
+
+ if "$SPIRV_CROSS" $xcopts "$spv" --output "$OUT/.stage.glsl" 2>"$OUT/.err"; then
+ if [ "$ubo" = 1 ]; then
+ # Real UBOs: strip SPIRV-Cross's "_std140" block-name suffix so the block
+ # names match glGetUniformBlockIndex("Camera") etc. in the Engine.
+ perl -i -pe 's/_std140//g' "$OUT/.stage.glsl"
+ else
+ # Flatten "struct S {..}; uniform S inst;" into loose "uniform TYPE NAME;"
+ # and strip the "inst." prefix, so uniforms keep their original names and
+ # the existing C++ SetMat4("u_X") / SetFloat("u_Y") calls work unchanged.
+ perl -0777 -i -pe '
+ while (/struct\s+(\w+)\s*\{(.*?)\}\s*;\s*uniform\s+\1\s+(\w+)\s*;/s) {
+ my ($s,$body,$inst)=($1,$2,$3); my @u;
+ while ($body =~ /([A-Za-z_]\w*)\s+([A-Za-z_]\w*(?:\[\d+\])?)\s*;/g) { push @u,"uniform $1 $2;"; }
+ my $loose=join("\n",@u);
+ s/struct\s+\Q$s\E\s*\{.*?\}\s*;\s*uniform\s+\Q$s\E\s+\Q$inst\E\s*;/$loose/s;
+ s/\b\Q$inst\E\.//g;
+ }
+ ' "$OUT/.stage.glsl"
+ fi
+ # SPIRV-Cross names inter-stage varyings per stage and relies on explicit
+ # locations, but macOS's GL linker matches varyings by NAME. Rename each
+ # varying to a location-canonical name (_v<loc>) so stages agree: rename
+ # `out` in vertex stages and `in` in fragment stages (never attributes).
+ case "$stage" in vertex) vdir=out ;; fragment) vdir=in ;; *) vdir="" ;; esac
+ if [ -n "$vdir" ]; then
+ DIR="$vdir" perl -0777 -i -pe '
+ my $d=$ENV{DIR}; my %m;
+ while (/layout\(location = (\d+)\)\s+\Q$d\E\s+\w+\s+(\w+)\s*;/g) { $m{$2}="_v$1"; }
+ for my $n (keys %m) { s/\b\Q$n\E\b/$m{$n}/g; }
+ ' "$OUT/.stage.glsl"
+ fi
+ { echo "#type $stage"; cat "$OUT/.stage.glsl"; echo; } >> "$combined"
+ echo " glsl -> $name.glsl (#type $stage)"
+ else echo " glsl FAILED ($entry):"; sed 's/^/ /' "$OUT/.err"; fail=1; fi
+ done < <(entry_points "$f")
+done
+
+rm -f "$OUT/.err" "$OUT/.stage.glsl"
+exit $fail
diff --git a/Tools/fetch-slang.sh b/Tools/fetch-slang.sh
new file mode 100755
index 0000000..5ee6de5
--- /dev/null
+++ b/Tools/fetch-slang.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+#
+# Fetches the Slang shader-compiler toolchain into Tools/slang (gitignored).
+# Slang is the single shader-authoring language for Donut; slangc cross-compiles
+# each Assets/Shaders/*.slang to GLSL (OpenGL), SPIR-V (Vulkan), and MSL (Metal).
+#
+# Re-run to (re)install. Pin the version here so builds are reproducible.
+set -euo pipefail
+
+VERSION="2026.14.1"
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+DEST="$ROOT/Tools/slang"
+
+case "$(uname -s)-$(uname -m)" in
+ Darwin-arm64|Darwin-aarch64) ASSET="macos-aarch64" ;;
+ Darwin-x86_64) ASSET="macos-x86_64" ;;
+ Linux-x86_64) ASSET="linux-x86_64" ;;
+ Linux-aarch64|Linux-arm64) ASSET="linux-aarch64" ;;
+ *) echo "fetch-slang: unsupported platform $(uname -s)-$(uname -m)"; exit 1 ;;
+esac
+
+URL="https://github.com/shader-slang/slang/releases/download/v${VERSION}/slang-${VERSION}-${ASSET}.tar.gz"
+
+echo "fetch-slang: downloading Slang ${VERSION} (${ASSET})..."
+rm -rf "$DEST"
+mkdir -p "$DEST"
+curl -fsSL "$URL" | tar -xz -C "$DEST"
+
+"$DEST/bin/slangc" -v >/dev/null 2>&1 && echo "fetch-slang: installed to $DEST (slangc $("$DEST/bin/slangc" -v))"