Skip to content

kaltinril/ShadowDusk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

167 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ShadowDusk

ShadowDusk

A cross-platform HLSL shader compiler for MonoGame and KNI. Compile .fx shaders on Linux, macOS, or Windows — no Wine, no Windows SDK, no DirectX install required.

What it is

The product is a self-contained, in-memory, cross-platform compiler library (the ShadowDusk.Compiler NuGet package): a developer adds the package and calls IShaderCompiler.CompileAsync(fx) to get .mgfx bytes on Linux, macOS, or Windows — needing nothing else (no fxc.exe, no mgfxc, no Wine, no Windows SDK, no native toolchain to install separately; the native pieces ride inside the package). The CLI (mgfxc dotnet tool) and the MGCB plugin are delivery shapes of the same library for build-time use. The in-browser shader fiddle is only a sample of reach — not a separate product.

What it does

MonoGame's stock content pipeline shells out to mgfxc, a Windows-only tool that depends on fxc.exe from the DirectX SDK. ShadowDusk replaces that step with one portable pipeline that produces output a real MonoGame/KNI Effect loads and renders like mgfxc's:

OpenGL / WebGL:
  HLSL (.fx)
    → DXC (via Vortice.Dxc)  →  SPIR-V
    → SPIRV-Cross             →  GLSL (+ MojoShader-dialect rewrite)
    → .mgfx binary            →  MonoGame Effect loader

DirectX (DX11):
  HLSL (.fx)
    → vkd3d-shader            →  DXBC (SM5)
    → .mgfx binary            →  MonoGame Effect loader

OpenGL / WebGL is fully cross-platform and self-contained — DXC + SPIRV-Cross ride inside the package, so it compiles on Linux, macOS, and Windows with nothing to install.

DirectX (DX11) produces DXBC in-process (no fxc.exe/mgfxc) via two backends behind IDxbcShaderCompiler, chosen by CompilerOptions.DxbcBackend: the default is d3dcompiler_47 — Microsoft's HLSL compiler, a system DLL already present on Windows (not a dependency you install), giving the most fxc-faithful output; vkd3d-shader is the opt-in, cross-platform backend (DxbcBackend.Vkd3d) for compiling DX shaders on Linux/macOS. DXC is not used for DX11 (it emits DXIL/SM6, not the DXBC/SM ≤ 5 the DX11 runtime loads); its ps_6_0/vs_6_0 output is retained only for the DX12/KNI path.

Supported MonoGame backends:

Backend Output Status
OpenGL / DesktopGL GLSL Validated end-to-end (10/10 in real MonoGame DesktopGL)
DirectX (Windows, DX11) DXBC (SM5) via vkd3d-shader Validated end-to-end (10/10 in real MonoGame WindowsDX)
WebGL (XNA Fiddle / KNI browser) GLSL ES Validated end-to-end (10/10 in real headless KNI WebGL)
Metal (macOS / iOS) MSL Not yet implemented
Vulkan SPIR-V Future

KNI HiDef / WebGL2 note. A single ShadowDusk .mgfx loads in both KNI Reach (WebGL1) and HiDef (WebGL2 / GLSL ES 3.00) — no profile flag and no separate build. KNI converts the legacy GLSL to ES 3.00 at load time, and ShadowDusk emits the #define-aliased fragment output that converter expects (GitHub #7). HiDef shader loading needs KNI ≥ v3.14.9001 (the release that added KNI's runtime converter — any recent KNI qualifies); Reach and desktop GL have no version requirement. After upgrading ShadowDusk to pick up this fix, recompile your .fx — a .mgfx built by an older ShadowDusk keeps the old output and won't load under HiDef.

Drop-in mgfxc replacement

ShadowDusk is a transparent substitute for MonoGame's mgfxc. Same CLI flags, same .mgfx output format, same exit codes, same MGCB-compatible error messages on stderr. Games using the MonoGame Content Pipeline require zero code changes to switch.

Delivery shapes

Library (ShadowDusk.Compiler, type EffectCompiler : IShaderCompiler) — the product. Add the package, call CompileAsync(fx), get .mgfx bytes in-memory:

var compiler = new EffectCompiler();
Result<CompiledShader, ShaderError[]> result =
    await compiler.CompileAsync(hlslSource, new CompilerOptions(/* … */));

CLI tool (dotnet tool named ShadowDuskCLI) — the same library wrapped for build-time use from MGCB, scripts, or the terminal:

ShadowDuskCLI MyShader.fx MyShader.mgfx /Profile:OpenGL

WASM library (ShadowDusk.Wasm, type WasmShaderCompiler : IShaderCompiler) — the same pipeline running inside .NET WASM for in-browser runtime compilation (the faithful pinned-DXC→WASM + SPIRV-Cross-WASM frontend). Returns .mgfx bytes in-memory with no server roundtrip. The in-browser shader fiddle (samples/ShaderFiddle.Web) is a sample of this reach, not a separate product. See docs/HOWTO-WASM-KNI.md for the KNI/Blazor walkthrough.

Every shape shares the same IShaderCompiler interface. "Same .mgfx output" means behaviorally equivalent and Effect-loadable — byte-identity is ShadowDusk's own reproducibility (same version + source + target → same bytes), never byte-equality with mgfxc.

Getting started

Prerequisites

DXC binaries come from the Vortice.Dxc NuGet package automatically. SPIRV-Cross native binaries are downloaded by tools/restore.ps1 / tools/restore.sh:

./tools/restore.sh        # Linux / macOS
.\tools\restore.ps1       # Windows

Build

dotnet build ShadowDusk.slnx

Test

# Unit tests
dotnet test ShadowDusk.slnx --filter "Category!=Integration"

# Integration tests (requires native library restore first)
dotnet test ShadowDusk.slnx --filter "Category=Integration"

Repository layout

ShadowDusk/
├── src/
│   ├── ShadowDusk.Core/         # Core types: IShaderCompiler, Result<T,E>, ShaderError,
│   │                            #   CompilerOptions, CompiledShader, ShaderIR, DxbcBackend, SpirvReflector
│   ├── ShadowDusk.HLSL/         # FX9 pre-parser, preprocessor, DXC integration, reflection,
│   │                            #   vkd3d-shader + d3dcompiler DXBC backends
│   ├── ShadowDusk.GLSL/         # SPIR-V → GLSL via SPIRV-Cross + MonoGameGlslRewriter
│   ├── ShadowDusk.Metal/        # SPIR-V → MSL (stub — not yet implemented)
│   ├── ShadowDusk.Compiler/     # EffectCompiler : IShaderCompiler — the consumer-facing product NuGet
│   ├── ShadowDusk.Cli/          # dotnet tool entry point (mgfxc)
│   ├── ShadowDusk.MgcbPlugin/   # MGCB content processor plugin (scaffold)
│   └── ShadowDusk.Wasm/         # In-browser WASM compiler (WasmShaderCompiler), [JSImport] DXC + SPIRV-Cross
├── samples/
│   ├── ShaderFiddle.Web/        # KNI Blazor-WASM in-browser fiddle (sample of reach)
│   ├── ShaderViewer/            # Desktop shader viewer
│   └── mgcb/                    # MGCB content-pipeline sample
├── tests/
│   ├── ShadowDusk.Core.Tests/
│   ├── ShadowDusk.HLSL.Tests/
│   ├── ShadowDusk.GLSL.Tests/
│   ├── ShadowDusk.Integration.Tests/
│   └── fixtures/
│       ├── shaders/             # Canonical .fx test shaders
│       └── golden/              # Reference .mgfx outputs (DirectX_11/ and OpenGL/)
├── tools/                       # Native binary restore scripts
└── docs/                        # Architecture docs and research (incl. HOWTO-WASM-KNI.md)

Tech stack

  • C# 12 / .NET 8
  • Vortice.Dxc — managed DXC wrapper (cross-platform, no Windows SDK required)
  • SPIRV-Cross — SPIR-V → GLSL transpilation via P/Invoke
  • vkd3d-shader — cross-platform HLSL → DXBC (SM5) for the DirectX backend
  • xUnit + FluentAssertions

Design principles

  • No Windows / Wine requirement. Every native binary has Linux + macOS builds.
  • Drop-in replacement. Same CLI flags, same .mgfx output, same exit codes and error format as MonoGame's mgfxc. Zero changes to existing content pipelines.
  • Deterministic output. Same source + same target = byte-identical .mgfx, given the same compiler version.
  • Fail loudly. Shader errors surface the source file, line, column, and message exactly as the underlying compiler emitted them.
  • Result-typed errors. No exceptions for expected shader failures — the API returns Result<CompiledShader, ShaderError[]>.

Acknowledgements

ShadowDusk stands on a lot of excellent prior work. The faithful compilation pipeline is built around — and ships pieces of — these projects:

  • DirectX Shader Compiler (DXC) (Microsoft) — the HLSL → SPIR-V frontend, used on desktop via Vortice and compiled to WebAssembly for the in-browser path. The single faithful frontend everywhere.
  • Vortice.Windows (Amer Koleci) — managed Vortice.Dxc / Vortice.D3DCompiler bindings that let us drive DXC and d3dcompiler_47 without the Windows SDK.
  • SPIRV-Cross (The Khronos Group) — SPIR-V → GLSL transpilation, via P/Invoke on desktop and WebAssembly in the browser; the native package is provided through Silk.NET.
  • vkd3d / vkd3d-shader (the Wine project) — the cross-platform HLSL → DXBC backend that makes the DirectX path compilable where mgfxc can't run.
  • MonoGame — the runtime we target and the mgfxc/.mgfx format we faithfully reproduce.
  • KNI (nkast) — the WebAssembly/WebGL-capable MonoGame fork the in-browser sample runs on.
  • MojoShader (Ryan C. Gordon) — the OpenGL GLSL dialect / shader-bytecode heritage that MonoGame's .mgfx OpenGL effects use, which our GLSL rewrite matches.
  • Emscripten — used to compile DXC and SPIRV-Cross to WebAssembly.
  • Slang (shader-slang) — used only in the in-browser sample as an early spike frontend; it is not part of the product pipeline (which uses faithful DXC everywhere).
  • DocFX (the .NET Foundation) — planned to generate the documentation site.
  • xUnit and FluentAssertions — the test suite.

The test-shader corpus is derived from community MonoGame/HLSL examples, with thanks to:

See docs/test-shader-corpus.md for per-shader provenance.

License & contributing

See CLAUDE.md for coding conventions and agent guidance.

About

Monogame Shader cross platform and web compiler

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors