MGFX / MojoShader Format
The output of every ShadowDusk compile is a .mgfx binary — MonoGame's compiled-effect container, which its Effect class loads at runtime. ShadowDusk faithfully reproduces this format with the managed MgfxWriter (ShadowDusk.Core/MgfxWriter.cs).
What's in a .mgfx
The writer assembles, in order:
- a header — the
MGFXsignature and a format version (see below); - the constant buffers — cbuffer layouts with parameter offsets (from reflection);
- the shader blobs — the per-stage compiled code: GLSL text for OpenGL/WebGL, DXBC bytecode for DirectX;
- the parameters — names, types, and offsets;
- the techniques and passes — reconstructed from the FX9 pre-parser metadata, mapping to MonoGame's
Technique/ pass model; - the render states parsed from the effect's pass blocks.
MojoShader heritage (OpenGL)
For OpenGL effects the shader blob is GLSL in the MojoShader dialect — the uniform-naming and fragment-output convention MonoGame's OpenGL effect loader expects. ShadowDusk's GLSL dialect rewrite produces exactly that dialect so the bytes load and render like mgfxc's.
Format version: MGFX v10 (default), opt-in MGFX v11 / KNIFX v11
ShadowDusk produces MGFX v10 by default (CompilerOptions.MgfxVersion / CLI --mgfx-version, defaults to 10). v10 is the broadly compatible choice: it loads in MonoGame 3.8.x (DesktopGL and WindowsDX) and in KNI for both Reach (WebGL1) and HiDef (WebGL2 / GLSL ES 3.00). It is the seamless default and is never something a consumer must change to get correct output. ShadowDusk does not emit the older v9 (pre-3.8.2) format.
Two opt-in, additive newer containers are also available (the v10 default is unchanged): a faithful MonoGame MGFX v11 (MgfxVersion = 11; MonoGame 3.8.5+, which adds two per-shader diagnostic strings to the shader blob, render-proven in real MonoGame 3.8.5) and KNI's KNIFX v11 (a distinct KNIF-signed container; CompilerOptions.Container = EffectContainer.Knifx; KNI v4.02+, render-proven in real KNI). Both render identically to v10. See Parameters & Caveats.
One writer, two backends
The writer is backend-agnostic — there is no separate structural branch for DirectX vs OpenGL. It consumes the shared reflection contract and embeds whichever blob the backend produced, so the DirectX .mgfx is byte-compatible with the OpenGL writer's structure (only the embedded shader bytes differ).
Output is in-memory
The writer returns a byte[]. The CLI writes it to disk; the library returns it from CompileAsync as the Data array — no temp file, no child process. That is what enables the in-memory and in-browser paths.
Reproducibility, not byte-equality with
mgfxc. ShadowDusk is deterministic: same version + source + target → identical bytes. It is not byte-identical tomgfxc(a different compiler); equivalence is behavioral — theEffectloads and renders the same.