Choosing a Target

When you compile a .fx, the choice that changes the output bytes is mostly which graphics backend the result must run on — with one framework-level exception: FNA, which loads a different effect format entirely. GraphicsProfile (Reach / HiDef) feels like it should matter too, but it doesn't. This page untangles the three axes so you can pick the right target with confidence (e.g. when offering shader downloads from a tool like XnaFiddle).

Quick answer

Most of the time, picking a target is one question: which graphics backend does the game run?

  • MonoGame or KNI on DirectX (WindowsDX) → PlatformTarget.DirectX
  • MonoGame or KNI on OpenGL (DesktopGL), WebGL, or AndroidPlatformTarget.OpenGL
  • FNAPlatformTarget.Fna

That covers the common cases. GraphicsProfile (Reach vs HiDef) never changes the target. The rest of this page explains why, plus KNI's newer container and one-shot capability profiles.

The three axes (which ones change the file)

Axis Examples Changes the compiled output?
1. Framework MonoGame, KNI, FNA Mostly no — MonoGame and KNI read the same MGFX container. FNA is the exception: it loads the legacy D3D9 fx_2_0 .fxb, so it gets its own output (see below).
2. Graphics backend / API DirectX 11, DirectX 12, OpenGL/DesktopGL, WebGL, Metal, Vulkan YES — for MonoGame/KNI this is the axis that picks the bytes
3. GraphicsProfile Reach, HiDef No — a runtime setting, not a compile target

For MonoGame/KNI the bytes are dictated by axis 2. A DirectX .mgfx contains DXBC GPU bytecode; an OpenGL .mgfx contains GLSL source text. They are not interchangeable — MonoGame's Effect loader reads a profile byte in the header and routes to a completely different code path. So for MonoGame/KNI the one thing you must know to pick a target is which graphics backend the consuming game runs. For FNA, axis 1 decides it: pick PlatformTarget.Fna and you get the .fxb FNA loads — one file serves every backend FNA itself runs on (FNA translates at load time).

Axis 1 — Framework compatibility

Framework Status
MonoGame ✅ Supported (DesktopGL and WindowsDX, validated in the real runtime).
KNI ✅ Supported — KNI reads the same MGFX format as MonoGame (its loader accepts MGFX v10), the default. Validated in real KNI WebGL and on a current KNI v4.02 desktop runtime. KNI's newer KNIFX v11 container is also available as an opt-in (CompilerOptions.Container = EffectContainer.Knifx, KNI v4.02+); the default v10 needs no KNI-specific output.
FNA Supported — but a different output format. FNA's effect path differs from MonoGame's: it loads legacy D3D9 fx_2_0 shader bytecode via MojoShader at runtime, not the MGFX container. So ShadowDusk does not hand FNA a .mgfx — it emits the .fxb FNA actually loads (new Effect(gd, bytes)). Select it with PlatformTarget.Fna / CLI /Profile:FNA (D3D9-style .fx, SM ≤ 3). Validated against fxc /T fx_2_0 in real FNA. Shaders needing SM4+ features fail loudly with a clear diagnostic.
Classic Microsoft XNA 4.0 Out of scope. XNA's effect .xnb wraps legacy D3D9 bytecode produced by fxc — a different instruction set our pipeline does not emit, on a Windows-only framework abandoned in ~2013. There is no "reach" win (nothing to compile where mgfxc can't) and no fidelity oracle. (Note: "XnaFiddle" is named for the lineage — the runtime it ships is KNI/MonoGame, which is supported.)

Axis 2 — Graphics backend (the real matrix)

Select the backend with Target (library) or /Profile: (CLI). The defaults differ — see Parameters & Caveats.

Target CompilerOptions.Target CLI /Profile: Output Status
OpenGL / DesktopGL / WebGL PlatformTarget.OpenGL OpenGL .mgfx, GLSL text (MojoShader dialect) ✅ Validated
DirectX 11 (WindowsDX) PlatformTarget.DirectX DirectX_11 .mgfx, DXBC binary (SM5) ✅ Validated
FNA PlatformTarget.Fna FNA .fxb, D3D9 fx_2_0 (SM ≤ 3) ✅ Validated
Metal PlatformTarget.Metal MSL ❌ Not implemented (future)
Vulkan PlatformTarget.Vulkan Vulkan .mgfx, SPIR-V ✅ Validated (MonoGame DesktopVK only — KNI has no Vulkan platform; see Vulkan)
DirectX 12 PlatformTarget.DirectX12 DirectX_12 .mgfx, DXIL (SM6) ✅ Validated (MonoGame WindowsDX12 only — KNI has no DirectX 12 platform; see DirectX 12)

For the MonoGame/KNI targets, the on-disk profile byte in the MGFX header encodes the backend choice (OpenGL = 0, DirectX11 = 1, DirectX12 = 2, Vulkan = 80). The runtime reads it to pick the shader path, so the target must be chosen at compile time — there is no universal .mgfx that serves both DirectX and OpenGL. A DirectX .mgfx is useless to a DesktopGL game and vice versa. FNA is selected differently (it's a whole separate format, .fxb — see Axis 1) and is not byte-compatible with the .mgfx targets.

Practical rule for shader downloads: first ask which framework — if it's FNA, emit the .fxb (PlatformTarget.Fna) and you're done (one file, all FNA backends). For MonoGame/KNI, the only remaining question is "DirectX (WindowsDX) or OpenGL/DesktopGL/Web?" — offer one .mgfx per backend. GraphicsProfile never matters.

All three targets can also be compiled in the browser via ShadowDusk.Wasm, byte-identical to a desktop compile — OpenGL renders live in KNI WebGL, while DirectX and FNA are export targets (a browser cannot render DXBC/D3D9 bytecode). See DirectX & FNA in the Browser.

One-shot selection: capability profiles (Profile / --target-runtime)

Instead of setting the backend (Target), container (Container), and version (MgfxVersion) separately, you can name the whole (runtime, format) contract with a single capability profile. A profile fully specifies the output, including the backend, so picking one is all you need:

Profile (CapabilityProfile.*) CLI --target-runtime Output
MonoGameGL_3_8_2 monogame-gl OpenGL, MGFX v10
MonoGameDX_SM5 monogame-dx DirectX, MGFX v10
MonoGameGL_3_8_5 monogame-gl-v11 OpenGL, MGFX v11 (MonoGame 3.8.5+)
KniGL_4_02 kni-knifx OpenGL, KNIFX v11 (KNI 4.02+)
Fna_Fx2 fna FNA, fx_2_0

Set it on the library with CompilerOptions.Profile = CapabilityProfile.KniGL_4_02, or on the CLI with --target-runtime kni-knifx. A set profile overrides Target / Container / MgfxVersion. The set is closed — it holds only render-proven contracts, so you can never request an untested combination.

Auto-detecting the runtime. For an in-app runtime compile, RuntimeProfileDetector.Recommend(typeof(Game).Assembly, target) classifies the loaded framework (MonoGame / KNI / FNA) and returns the proven profile to pass to CompilerOptions.Profile. It is conservative: it returns the universally-loadable MGFX v10 (or fx_2_0 for FNA) and never silently upgrades a consumer to a newer container — the newer formats stay an explicit opt-in.

Axis 3 — Reach vs HiDef (a runtime concept, not a target)

GraphicsProfile.Reach and GraphicsProfile.HiDef are runtime settings, not compile-time targets. mgfxc has no "Reach profile" vs "HiDef profile" — only OpenGL and DirectX_11. So you do not compile twice for Reach vs HiDef.

For the OpenGL/WebGL path specifically:

  • GraphicsProfile.Reach → WebGL1 / GLSL ES 1.00
  • GraphicsProfile.HiDef → WebGL2 / GLSL ES 3.00

ShadowDusk emits one OpenGL .mgfx (legacy GLSL dialect), and KNI's runtime converts it to ES 3.00 at load time for HiDef/WebGL2. One file serves both. See KNI HiDef / WebGL2.

.mgfx vs .xnb

For the MonoGame/KNI targets, ShadowDusk's compiled effect is a raw .mgfx blob (FNA's equivalent is the raw .fxb). The .xnb is a different layer — and ShadowDusk can produce both:

.mgfx .xnb
What it is the compiled effect itself the Content Pipeline container that wraps a .mgfx (and every other content type)
Loaded via new Effect(graphicsDevice, mgfxBytes) Content.Load<Effect>("name")
Produced by ShadowDusk (and mgfxc) ShadowDusk (CompiledShader.ToXnb() / an .xnb CLI output path), MGCB, or the MGCB plugin

If a consuming project loads effects with new Effect(gd, bytes), hand it the raw .mgfx — done. If it uses Content.Load<Effect>, it needs an .xnb, and there are two ShadowDusk routes: direct output — name an .xnb output on the CLI or call result.Value.ToXnb(), drop the file in the content directory, and no MGCB is involved at all (see Drop-in mgfxc); or, for a build that already uses MGCB for other content, the ShadowDusk.MgcbPlugin content processor (see the MGCB Content Pipeline guide). See also Parameters & Caveats → .mgfx vs .xnb.