ShadowDusk
A cross-platform HLSL shader compiler for MonoGame, KNI, and FNA. Compile .fx shaders to .mgfx (MonoGame/KNI) or .fxb (FNA) on Linux, macOS, or Windows — no Wine, no Windows SDK, no fxc.exe, no DirectX install required.
The "XNA-likes." Throughout these docs, MonoGame, KNI, and FNA — the XNA-derived runtimes ShadowDusk targets — are collectively the XNA-likes. Classic Microsoft XNA 4.0 itself is out of scope (a different, abandoned, Windows-only toolchain). The three share a heritage but not one effect format: MonoGame and KNI load the
.mgfx(MGFX) container, while FNA loads the legacy D3D9 fx_2_0.fxb— so where the output format matters, the docs name the runtime explicitly rather than say "XNA-likes."
The product is the in-memory
IShaderCompilerlibrary (theShadowDusk.CompilerNuGet package): add the package and callCompileAsync(fx)to get the compiled effect bytes (.mgfx, or.fxbfor FNA) — nothing else to install. The CLI (theShadowDuskCLIdotnet tool), the MGCB content-processor plugin (ShadowDusk.MgcbPlugin, which a.mgcb/reference:s so MonoGame's Content Builder compiles through ShadowDusk in its own process), and direct.xnboutput (CompiledShader.ToXnb(), or an.xnboutput path on the CLI —Content.Load<Effect>ready with no MGCB and no consumer code change) are delivery shapes of the same library for build-time use, and emit the same bytes. The in-browser shader fiddle is only a sample of reach — not a separate product.
What it does
MonoGame's stock content pipeline compiles shaders with the same engine as mgfxc, which depends on fxc.exe from the DirectX SDK and only runs on Windows. ShadowDusk replaces that step with one portable pipeline whose output a real XNA-like Effect — MonoGame, KNI, or FNA — loads and renders like the reference compiler's (mgfxc for MonoGame/KNI, fxc for FNA):
OpenGL / WebGL (MonoGame, KNI):
HLSL (.fx)
→ DXC (via Vortice.Dxc) → SPIR-V
→ SPIRV-Cross → GLSL (+ MojoShader-dialect rewrite)
→ .mgfx binary → MonoGame / KNI Effect loader
DirectX (DX11) (MonoGame, KNI):
HLSL (.fx)
→ vkd3d-shader → DXBC (SM5)
→ .mgfx binary → MonoGame / KNI Effect loader
FNA (D3D9 fx_2_0):
HLSL (.fx)
→ vkd3d-shader → D3D9 fx_2_0 bytecode (SM ≤ 3)
→ .fxb binary → FNA Effect loader (MojoShader)
OpenGL / WebGL is fully cross-platform and self-contained (DXC + SPIRV-Cross ride inside the package). For DirectX (DX11), ShadowDusk produces DXBC in-process via two backends behind IDxbcShaderCompiler, chosen by CompilerOptions.DxbcBackend: the default, cross-platform vkd3d-shader (DxbcBackend.Vkd3d), whose per-RID natives ship inside the package and run on Linux/macOS/Windows, and the opt-in d3dcompiler_47 (Microsoft's HLSL compiler — a Windows-only system DLL; the most fxc-faithful correctness oracle). DXC is not used for DX11 (it emits DXIL/SM6, not the DXBC/SM ≤ 5 the DX11 runtime loads). See The Faithful Pipeline and DirectX DXBC (vkd3d) Path.
Supported backends
| Backend | Output | Status |
|---|---|---|
| OpenGL / DesktopGL | GLSL | Validated end-to-end |
| DirectX (DX11) | DXBC (SM5) via vkd3d-shader (default, cross-platform) / d3dcompiler_47 (Windows-only oracle, opt-in) |
Validated end-to-end |
| WebGL (XNA Fiddle / KNI browser) | GLSL ES | Validated end-to-end |
| Android on-device (MonoGame, KNI) | GLSL | Validated end-to-end (byte-identical to the desktop build) |
FNA (/Profile:FNA → .fxb) |
D3D9 fx_2_0 via vkd3d-shader | Validated end-to-end |
| Metal (macOS / iOS) | MSL | Not yet implemented (future) |
| Vulkan | SPIR-V | Validated end-to-end (MonoGame DesktopVK only — KNI has no Vulkan platform) |
DirectX 12 (MonoGame WindowsDX12) |
DXIL (SM6) | Validated end-to-end (MonoGame WindowsDX12 only — KNI has no DirectX 12 platform) |
Validated end-to-end means rendered in the real engine and compared against the reference compiler's output — Validation & the Evidence Ladder has the per-target proof detail.
The table above is the graphics-backend axis — the one that decides the output bytes for MonoGame/KNI. Framework is a separate axis: MonoGame and KNI read the same MGFX format (both supported); FNA is also supported, but via a different effect path — ShadowDusk emits the legacy D3D9 fx_2_0 .fxb (MojoShader) FNA loads, not the MGFX container; classic Microsoft XNA 4.0 is out of scope. New to picking a target, or building a shader-download feature? See Choosing a Target — it covers the framework / backend / GraphicsProfile axes and the .mgfx-vs-.xnb distinction.
"Same
.mgfxasmgfxc" means behaviorally equivalent andEffect-loadable — it renders the same pixels in the real runtime. Byte-identity is only ShadowDusk's own reproducibility (same version + source + target → same bytes), never byte-equality withmgfxc.
Output container. The default is MGFX v10 — it loads on every MonoGame 3.8.1.263+ (the measured floor) and KNI runtime, so you never set a flag for correct output. Opt-in/experimental MGFX v11 (
CompilerOptions.MgfxVersion = 11, MonoGame 3.8.5+) and KNIFX v11 (CompilerOptions.Container = EffectContainer.Knifx, KNI v4.02+) containers are additionally available, both render-proven in their real engines. See Parameters & Caveats.
Quick links
- New here? Start with Overview → Installation → In-Memory Quickstart.
- Using the content pipeline? Drop-in
mgfxcand MGCB Content Pipeline. - Compiling in the browser? In-Browser (KNI/Blazor WASM).
- Coming from ShaderToy? The optional
ShadowDusk.ShaderToypackage converts ShaderToy / plain-GLSL fragment shaders to.fx, and the CLI auto-detects.glslinput — see Installation. - Compiling on-device on Android? Runtime Compilation on Android.
- How it works: the Architecture section.
- API: the API Reference (generated from the code's own XML doc-comments).
- CLI: the
ShadowDuskCLICLI Reference.
In-memory in five lines
using ShadowDusk.Compiler;
using ShadowDusk.Core;
var compiler = new EffectCompiler();
Result<CompiledShader, ShaderError[]> result =
await compiler.CompileAsync(hlslSource, new CompilerOptions { Target = PlatformTarget.OpenGL });
if (result.IsSuccess)
{
byte[] mgfx = result.Value.Data; // .mgfx, ready for new Effect(graphicsDevice, mgfx)
}
See the In-Memory Quickstart for the full walkthrough (and the default-target caveat between the library and the CLI).
Design principles
- No Windows / Wine requirement. Every native binary has Linux + macOS builds; the pieces the pipeline needs ride inside the package.
- Drop-in replacement. Same CLI flags, same
.mgfxoutput format, same exit codes and error format asmgfxc. A build step that invokesmgfxccan invoke it instead. MGCB itself compiles in-process, so it is integrated through the MGCB content-processor plugin rather than aPATHoverride. - Deterministic output. Same source + same target = byte-identical
.mgfx, given the same compiler version (ShadowDusk's own reproducibility). - Fail loudly. Shader errors surface the source file, line, column, and message exactly as the underlying compiler emitted them.
- Result-typed errors. No exceptions for expected shader failures — the API returns
Result<CompiledShader, ShaderError[]>.
The repository README.md is the front door and stays the source of truth for the project summary, the backend matrix, and acknowledgements; this site documents the product, its delivery shapes, samples, and API in depth.