CLI Reference (ShadowDuskCLI)

ShadowDusk's CLI is a drop-in replacement for MonoGame's mgfxc: same positional arguments, same .mgfx output format, same exit codes, and MGCB-parseable diagnostics on stderr. Install it as a global tool:

dotnet tool install --global ShadowDusk.Cli

Usage

ShadowDuskCLI <SourceFile> <OutputFile> [options]

Arguments are positional<SourceFile> then <OutputFile>. There is no /Output: flag (output is the second positional argument).

ShadowDuskCLI MyShader.fx MyShader.mgfx /Profile:OpenGL

Options

Option Description Default
/Profile:<Platform> Target platform. Valid: DirectX_11, DirectX_12 (SM6 DXIL for MonoGame WindowsDX12 — real mgfxc's own registration name), OpenGL, Vulkan, FNA (the D3D9 fx_2_0 .fxb target — additive, not an mgfxc profile). DirectX_11
/Debug Include debug information in the output. off
/I <path> Additional include search path (repeatable). Also accepts /I:<path>. none
/Defines:<name=value;...> Preprocessor macros, matching mgfxc (MGCB's EffectProcessor forwards its Defines property in exactly this form). Entries are ;-separated (, also tolerated); a bare NAME defines 1; the flag is repeatable and entries accumulate. Applies on every target, including FNA. The library equivalent is Defines. none
/DxbcBackend:<Backend> DXBC backend for DirectX_11: vkd3d (cross-platform) or d3dcompiler (the Windows-only correctness oracle). Never required for correct output. vkd3d
--mgfx-version <10\|11> MGFX container version (opt-in escape hatch). 10 (default) loads on every MonoGame 3.8.1.263+ and KNI runtime — leave it unset for correct output everywhere. 11 emits a faithful MonoGame MGFX v11 container (MonoGame 3.8.5+, opt-in/experimental; renders identically to v10). 10
--target-runtime <name> Pick the output target (backend and container/version) with one name: monogame-gl, monogame-dx, monogame-gl-v11 (MGFX v11), kni-knifx (KNI's KNIFX v11), fna. Overrides /Profile and --mgfx-version. Also accepts /target-runtime:<name>. (use /Profile)
--input-format <auto\|fx\|glsl\|slang> Input language. auto detects a ShaderToy / plain-GLSL image shader — by extension (.glsl/.frag/.fs/.glslf) or content — or a Slang source (.slang) and converts it to .fx before compiling. Never required for correct output; the explicit values are the escape hatch for genuinely ambiguous input. The Slang route is the HLSL-compatible subset of Slang (entry points via [shader("...")] attributes, technique synthesized, body compiled by the same pipeline as any .fx — nothing to install); Slang-only language features are rejected with a named SD0600. auto
--print-uniforms Print the converted shader's drivable effect parameters (iTime, iChannel0, custom uniforms) to stderr. Only affects ShaderToy/GLSL input. off

Unknown flags are silently ignored (not consuming a following value) so that future mgfxc flags MGCB may pass don't break existing pipelines. A known flag that is missing its required value is a different case and fails loudly with X0009 rather than silently compiling with the default.

Unsupported platforms

/Profile: values PlayStation4, XboxOne, and Switch are rejected and exit with code 1 (a portable tool can't produce console bytecode). An unknown profile name also fails loudly.

The default-profile caveat

The CLI default profile is DirectX_11 (matching MonoGame's mgfxc), but the library default — Target — is OpenGL:

Surface Default target
CLI — ShadowDuskCLI /Profile DirectX_11
Library — CompilerOptions.Target OpenGL

So ShadowDuskCLI MyShader.fx out.mgfx (no /Profile) compiles for DirectX_11, while the equivalent library call with no Target compiles for OpenGL. Always pass the target explicitly. (See the In-Memory Quickstart.)

Examples

# OpenGL / DesktopGL
ShadowDuskCLI effects/Blur.fx Content/Blur.mgfx /Profile:OpenGL

# DirectX 11 (the CLI default — /Profile optional)
ShadowDuskCLI effects/Blur.fx Content/Blur.mgfx /Profile:DirectX_11

# With include paths and debug info
ShadowDuskCLI effects/Lit.fx Content/Lit.mgfx /Profile:OpenGL /I shaders/common /I shaders/lighting /Debug

# Pick backend + format together by name (KNI's KNIFX v11 container)
ShadowDuskCLI effects/Cube.fx Content/Cube.knifx --target-runtime kni-knifx

# ShaderToy / GLSL fragment shader — auto-detected, converted to .fx, then compiled
ShadowDuskCLI shadertoy/Plasma.glsl Content/Plasma.mgfx /Profile:OpenGL --print-uniforms

The ShaderToy/GLSL conversion is the same front-end the optional ShadowDusk.ShaderToy package exposes as a library — see Installation.

Exit codes & diagnostics

  • 0 — success. Note that a successful compile can still write to stderr: warnings are reported there and do not fail the build. Treat the exit code, not the presence of stderr output, as the pass/fail signal — a CI step that fails on any stderr will trip over warnings.
  • non-zero — failure; diagnostics are written to stderr in mgfxc-compatible file(line,col-col): severity CODE: message form, which MGCB parses. Diagnostics that apply to a whole file rather than one line (the GL portability warnings, for example) drop the line/column and read file: severity CODE: message.

Warnings use the same parseable format with warning as the severity:

Bloom.fx: warning SD0401: The pass has no vertex shader, and pixel shader 'MainPS' reads vTexCoord1 (TEXCOORD1) — interpolants SpriteBatch's built-in vertex shader never writes ...

When the underlying compiler says more than the one-line summary — leading warnings, a source echo with a caret — its complete output follows the parseable line, indented, so nothing it told us is hidden from you. There is no verbosity flag to discover: the compiler's own words are shown by default.

Every code is listed in the Diagnostic Codes registry.

Using it alongside MGCB

MGCB will not call this CLI for you. It was documented until 2026-07-28 that exposing ShadowDusk under the name mgfxc on PATH would make MGCB use it; measurement against dotnet mgcb 3.8.2.1105, 3.8.4.1, and 3.8.5 showed MGCB compiles .fx in-process and launches no external mgfxc.

For MGCB, add the ShadowDusk.MgcbPlugin content-processor package and /reference: it from your .mgcb — MGCB then compiles .fx → .xnb through ShadowDusk in its own process, and the .mgfx inside that .xnb is byte-for-byte what this CLI emits. If you would rather not use the plugin, invoke this CLI directly and have the content project /copy: the resulting .mgfx. Both routes are in MGCB Content Pipeline; Drop-in mgfxc covers the flag compatibility.