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

  1. Reach mgfxc can't. Compile .fx where MonoGame's own toolchain cannot: on Linux/macOS (no Wine, no Windows SDK) and at runtime / in-browser via WASM. Matching mgfxc only on Windows-at-build-time would be pointless — the reach is the reason to exist.
  2. 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 .mgfx container); for FNA it is fxc /T fx_2_0 (the D3D9 .fxb).

"Same .mgfx as mgfxc" means behaviorally equivalent and Effect-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 with mgfxc (they are different compilers).

The product and its delivery shapes

Shape Package / Tool Use
Library (the product) ShadowDusk.CompilerEffectCompiler : IShaderCompiler Add the package, call CompileAsync(fx), get .mgfx bytes in-memory.
CLI tool ShadowDusk.Clidotnet 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.MgcbPluginShadowDuskEffectImporter / 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.WasmWasmShaderCompiler : 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+) and Container = 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 as SD0214) 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