Overview
ShadowDusk is a self-contained, in-memory HLSL shader compiler for MonoGame, KNI, and FNA. It compiles .fx shaders into the format each runtime loads (.mgfx for MonoGame/KNI, the D3D9 .fxb for FNA) on Linux, macOS, or Windows. Nothing extra to install: no Wine, no Windows SDK, no fxc.exe, no separate toolchain. (Classic Microsoft XNA 4.0 is out of scope.)
The problem it solves
MonoGame's stock content pipeline (MGCB) compiles .fx with the same effect compiler mgfxc wraps, which depends on fxc.exe from the DirectX SDK and therefore only runs on Windows. That makes shader compilation a Windows-only build step: it cannot run on Linux or macOS, and it cannot run at runtime or in a browser at all. (FNA's equivalent path leans on fxc and has the same Windows-only constraint.)
ShadowDusk replaces that step with one portable, faithful pipeline whose output a real MonoGame, KNI, or FNA Effect loads and renders like the reference compiler's (mgfxc for MonoGame/KNI, fxc for FNA).
What success means — two axes, both required
- Reach
mgfxccan't. Compile.fxwhere MonoGame's own toolchain cannot: on Linux/macOS (no Wine, no Windows SDK) and at runtime / in-browser via WASM. Matchingmgfxconly on Windows-at-build-time would be pointless — the reach is the reason to exist. - Output the reference compiler would. The compiled effect, loaded into the real runtime, renders the same image as the reference-compiled version — zero code or content-pipeline changes. For MonoGame/KNI the reference is
mgfxc(the.mgfxcontainer); for FNA it isfxc /T fx_2_0(the D3D9.fxb).
"Same
.mgfxasmgfxc" means behaviorally equivalent andEffect-loadable — the same pixels in the real runtime. Byte-identity is only ShadowDusk's own reproducibility (same compiler version + source + target → same bytes); it is never byte-equality withmgfxc(they are different compilers).
The product and its delivery shapes
| Shape | Package / Tool | Use |
|---|---|---|
| Library (the product) | ShadowDusk.Compiler — EffectCompiler : IShaderCompiler |
Add the package, call CompileAsync(fx), get .mgfx bytes in-memory. |
| CLI tool | ShadowDusk.Cli — dotnet tool named ShadowDuskCLI |
The same library for build-time use from build scripts, CI steps, or a terminal (see Drop-in mgfxc). |
| MGCB plugin | ShadowDusk.MgcbPlugin — ShadowDuskEffectImporter / ShadowDuskEffectProcessor |
The same library as a MonoGame Content Builder content processor. /reference: it in your .mgcb and MGCB compiles .fx → .xnb through ShadowDusk in its own process — the native MGCB route, since MGCB compiles in-process and cannot be redirected by a PATH override (see MGCB Content Pipeline). |
Direct .xnb output |
CompiledShader.ToXnb() on the library, or an .xnb output path on the CLI |
ShadowDusk writes the content-pipeline .xnb itself, so Content.Load<Effect>("Foo") keeps working with no consumer code change and MGCB out of the picture entirely. The XNB platform byte is derived from the target — nothing to select — and the payload inside is byte-for-byte the .mgfx the same call emits. Proven with a real ContentManager loading and rendering pixel-identically to the mgfxc-built file. |
| WASM library | ShadowDusk.Wasm — WasmShaderCompiler : IShaderCompiler |
The same pipeline inside .NET WASM for in-browser runtime compilation. |
Every shape implements the same IShaderCompiler interface and runs the same faithful pipeline — no substitute compilers. The in-browser ShaderFiddle.Web is a sample of the WASM reach, not a separate product.
Supported backends
| Backend | Output | Status |
|---|---|---|
| OpenGL / DesktopGL | GLSL .mgfx |
Supported |
| DirectX 11 | DXBC .mgfx |
Supported |
| WebGL (KNI browser) | GLSL .mgfx |
Supported |
| Android (on-device) | GLSL .mgfx |
Supported (byte-identical to the desktop build) |
| FNA | D3D9 .fxb |
Supported |
| Metal (macOS / iOS) | MSL | Not yet |
| Vulkan | SPIR-V .mgfx |
Supported (MonoGame DesktopVK only — KNI has no Vulkan platform) |
DirectX 12 (MonoGame WindowsDX12) |
DXIL .mgfx |
Supported (MonoGame WindowsDX12 only — KNI has no DirectX 12 platform) |
Supported targets are tested end-to-end against the reference compiler and render identically (on-device Android via byte-identity: its output is byte-identical to the desktop build, whose renders are proven — the on-device pixel diff is a tracked follow-up). See Validation for how that's proven, and Choosing a Target to pick one.
Output format. The default is MGFX v10, which loads on MonoGame 3.8.1.263 (the measured floor) and every newer MonoGame, plus KNI — you never set a flag for correct output. Targeting a newer runtime?
MgfxVersion = 11(MonoGame 3.8.5+) andContainer = EffectContainer.Knifx(KNI v4.02+) are optional and load and render just like v10. See Parameters & Caveats.
Cross-platform. Every target compiles on Windows, macOS, and Linux, and OpenGL, DirectX 11, and FNA produce the same bytes on every OS — ShadowDusk bundles its own native pieces, and the full test suite runs green on all three in CI.
Two carve-outs. Build DirectX 12 content on Windows: DXIL validation and signing run through the Windows-only
dxil.dll, so a non-Windows DX12 compile still succeeds but emits unsigned DXIL (warned asSD0214) that retail D3D12 rejects at pipeline-state creation — see DirectX 12. And a small family of advanced-texture intrinsics (tex3D,tex2Dlod,tex2Dgrad) currently fails to compile on the Linux/macOS DXC builds — see Parameters & Caveats.
Next steps
- Installation — add the package / install the tool.
- In-Memory Quickstart — compile a shader in C# in a few lines.
- The Faithful Pipeline — how a
.fxbecomes a.mgfx. - Glossary — quick definitions of the shader and compiler terms.