Table of Contents

Namespace ShadowDusk.Core

Classes

AnnotationInfo

A single FX annotation (a <key = value;> attached to a parameter or technique), as the MgfxWriter serializes it. Exactly one of the typed value fields is populated, selected by Type.

CapabilityProfile

A named, render-proven runtime contract: a validated point in ShadowDusk's capability space (the effect EffectContainer + MgfxVersion "format" axis and the GL ShaderDialect; later, allowed GL features). The closed set spans every (runtime, format) cell ShadowDusk targets, so one profile names a full contract.

CompiledShader

The successful output of CompileAsync(string, CompilerOptions, CancellationToken): the compiled effect bytes together with the platform they were produced for. For MonoGame/KNI targets the bytes are a .mgfx effect; for Fna they are the D3D9 fx_2_0 effects binary (.fxb). Either way they can be written to a file or fed directly to the consumer runtime's Effect constructor.

CompiledShaderBlob

One compiled shader within an effect: its platform bytecode (Bytes) and the stage it belongs to (Stage), plus the per-shader tables the effect writers serialize (samplers, constant-buffer indices, vertex attributes, shader model).

CompilerOptions

Settings that control a single CompileAsync(string, CompilerOptions, CancellationToken) call: the target backend, how #include directives are resolved, debug output, the MGFX container version, and (for DirectX) which DXBC backend to use.

ConstantBufferInfo

One effect constant buffer as the MGFX writer serializes it: its name, byte size, and the effect parameters it contains (by index into the effect's flattened parameter list) with each parameter's byte offset within the buffer.

D3d9BytecodePatcher

Post-pass over vkd3d's D3D9 SM2/SM3 token streams that canonicalizes the two instruction forms MojoShader rejects but vkd3d 1.17 emits (found by the Phase 39 rung-3/4 FNA harness — real FNA load failures where the fxc oracle loads fine):

  1. texkill with a partial destination writemask (vkd3d writes e.g. .x; fxc always writes .xyzw and MojoShader hard-fails anything else: "TEXKILL writemask must be .xyzw").
  2. texld whose coordinate source MojoShader rejects: a swizzle below SM3 ("TEXLD src0 must not swizzle" for ps_1_x/ps_2_x; SM3 allows it), or a source modifier at ANY SM2+ major ("TEXLD src0 must have no modifiers").
  3. def float literals with |f| ≥ 2³² — vkd3d's discard sentinel is −2³² (0xCF800000), and MojoShader's MOJOSHADER_printFloat converts the magnitude through a 32-bit unsigned long on Windows (LLP64), overflowing to ±0.0 in the translated source — so texkill's < 0 test never fires (Dissolve rendered un-discarded). Clamped in place to the same-signed largest float BELOW 2³² (±4294967040.0, 0x4F7FFFFF), which MojoShader prints exactly; the sentinel's only observable property is its sign. fxc's largest def literals are ±1, so the oracle never trips this. Empirically proven pixel-identical in real FNA by the rung-4 harness's clamped-Dissolve experiment.

The rewrite is semantics-preserving, not a blind mask/swizzle flip: the offending operand is routed through a fresh temporary — mov rK, reg.<replicated-masked-components> followed by the canonical texkill rK.xyzw (each tested lane now holds one of the originally-tested values), or mov rK, src0.<swizzle> followed by texld dst, rK, s#. Blindly widening the texkill mask would test garbage lanes; this never does.

D3D9 SM2+ instruction tokens carry an explicit operand-count field and the format has no byte-offset branches, so inserting instructions is purely mechanical; comment blocks (the CTAB) pass through byte-identical. Streams below SM2 are returned unchanged: MojoShader's ps_1_x rules differ wholesale (and ps_1_x tokens carry no instruction-length fields to walk), and the FNA pipeline rejects literal SM1 profiles upstream (SD0300), so this pass never has to reason about them.

Applied ONLY on the FNA path — the DirectX SM5 path never sees this code, and the blob handed to the fx_2_0 writer stays exactly what MojoShader will consume.

EffectParameterInfo

One .mgfx parameter record. MonoGame 3.8.2's Effect.ReadParameters reads Elements (array elements) and Members (struct members) as RECURSIVE parameter collections — elements first, then members, each a full nested parameter record (mirroring mgfxc's EffectObject.WriteParameter). A value-typed leaf (Scalar/Vector/Matrix with no elements/members) additionally carries a raw default-value blob of RowCountColumnCount4 bytes.

Fx2EffectDesc

The input IR for Fx2EffectWriter — everything needed to author a D3D9 Effects Framework binary ("fx_2_0", token 0xFEFF0901) for FNA. This is deliberately a separate shape from ShaderIR: the fx_2_0 container carries typed effect parameters with default values and sampler-state blocks that MGFX has no analog for. Field encodings follow docs/fx2-binary-format.md (MojoShader's parser is the spec).

Fx2EffectWriter

Emits the D3D9 Effects Framework binary ("fx_2_0", version token 0xFEFF0901) that FNA consumes via FNA3D/MojoShader — the FNA analog of MgfxWriter. There is no public spec for this format; the byte layout implemented here follows MojoShader's parser as documented field-by-field in docs/fx2-binary-format.md, cross-checked against real fxc /T fx_2_0 output (tests/fixtures/golden/FNA/).

Layout recap: 8-byte header (token + pool size), then a "data pool" holding every typedef/string/value blob addressed by offsets relative to file offset 8, then the structured stream (counts → parameter records → technique/pass/state records → small / large object sections). MojoShader performs no bounds checking on pool offsets, so this writer is solely responsible for their validity.

Fx2Parameter

One fx_2_0 effect parameter. Three kinds share this record, distinguished by Class/Type (raw D3DXPARAMETER / MojoShader symbol values, see docs/fx2-binary-format.md §6.1): numerics (class 0–3, type bool/int/float), textures (class 4, type 5–9), and samplers (class 4, type 10–14, carrying SamplerStates).

Fx2Pass

One fx_2_0 pass. Shader indices of -1 mean the stage is absent — the writer then omits the VertexShader/PixelShader state entirely (MojoShader keeps the previously bound shader; emitting a "NULL shader" state is the unresolved F4 ambiguity).

Fx2RenderState

One pass render-state assignment. Operation is the MojoShader renderStateType file value (NOT a D3DRS number); Value carries the raw dword (D3D9-domain enum value, 0/1 bool, or IEEE-754 bits when IsFloat). The writer restricts ops to the set FNA's runtime honors — anything else makes FNA throw at load time.

Fx2SamplerState

One sampler-state assignment inside a sampler parameter's value blob. Exactly one of TextureParameterName (op 164/Texture), FloatValue, or IntValue is set.

Fx2Shader

One compiled SM1–3 shader blob (bare D3D9 token stream with CTAB).

Fx2Technique

One fx_2_0 technique.

KnifxWriter

Serializes a ShadowDusk ShaderIR into KNI's KNIFX v11 effect container, the additive newer format KNI v4.02+ loads (signature "KNIF"). This is the KNIFX analogue of MgfxWriter: it carries the same MojoShader-dialect GLSL body ShadowDusk already produces for MGFX v10 (KNIFX is a container over a still-MojoShader body), re-serialized into KNIFX's binary layout.

Byte format reverse-engineered from KNI's own KNIFXWriter11 + the runtime Effect reader (full spec: plan/PHASE-35-appendix/knifx-format-spec.md). The headline deltas vs MGFX v10:

  • A multi-backend directory header (one .knifx can carry several backend bodies; the runtime picks the match). This writer emits one backend.
  • Counts and most indices are written as packed ints (zigzag + 7-bit).
  • New fields: a per-shader ShaderVersion, a Stage byte (with a compute slot), and a columnsActual byte on parameters.
The pass render-state blocks are byte-identical to v10, so MgfxWriter's writers are reused verbatim. Default product output stays MGFX v10; KNIFX is additive.
KnifxWriterOptions

Options for KnifxWriter.

MgfxPassInfo

One pass within a technique: its name, FX annotations, the vertex/pixel shader it binds (by index into the effect's shader list, or -1 when absent), and its render state.

MgfxSamplerInfo

One entry in a shader's sampler table, as MonoGame's Shader reader expects it. Name must match the sampler uniform's name in the emitted GLSL (e.g. ps_s0) so MonoGame's GL backend can bind it. Parameter indexes the texture parameter in the effect's global parameter table. State carries the baked sampler_state { MinFilter = …; AddressU = …; } members (Phase 43, F9); when null the record is written with hasState = 0 and MonoGame uses GraphicsDevice.SamplerStates instead.

MgfxSamplerStateInfo

A baked sampler state, field-for-field as MonoGame 3.8.2's Shader reader consumes it (AddressU/V/W, BorderColor RGBA, Filter, MaxAnisotropy, MaxMipLevel, MipMapLevelOfDetailBias) and as mgfxc's ShaderData.writer.cs emits it. Byte values are MonoGame enum ordinals (TextureAddressMode / TextureFilter).

MgfxSamplerStateResolver

Resolves parsed sampler_state { … } members into the baked MgfxSamplerStateInfo mgfxc writes into the .mgfx sampler record (Phase 43, F9). Mirrors mgfxc v3.8.2's TPGParser/SamplerStateInfo exactly:

  • State is only present (hasState = 1) when at least one recognized state member is set — a block containing only Texture = <…> resolves to null.
  • Defaults are MonoGame's SamplerState constructor values: Wrap addressing, white border color, MaxAnisotropy 4, MaxMipLevel 0, LOD bias 0.
  • The separate Min/Mag/Mip filter members combine into ONE MonoGame TextureFilter via mgfxc's UpdateSamplerState if-chain ("None" treated like "Point"); MipFilter = None additionally forces MipMapLevelOfDetailBias = -16 (mgfxc's only mip-disable mechanism).
  • Unrecognized KEYS are ignored (the parser accepted them; fxc tolerates many D3D9 states MonoGame has no analog for), but a recognized key with an unparseable VALUE fails loudly (SD0024) — mgfxc's grammar would reject it, so silently dropping it would diverge from the mgfxc build.
MgfxTechniqueInfo

One effect technique as the MGFX writer serializes it: its name, any FX annotations, and its ordered passes.

MgfxVertexAttributeInfo

One vertex-attribute table entry (GL profile only) mapping a GLSL attribute to a VertexElementUsage+index, as MonoGame's Shader reader expects for a vertex shader.

MgfxWriter

Serializes a fully assembled ShaderIR into the binary MGFX container MonoGame/KNI's Effect loads (the "MGFX" header, constant buffers, shader blobs, parameters, and techniques). Counts and sizes that the format stores in a single byte or int16 are guarded so an oversized effect fails loudly (SD002x) rather than silently truncating into a corrupt file. The emitted version is controlled via MgfxWriterOptions (default v10, the most backwards-compatible choice).

MgfxWriterOptions

Settings for the MgfxWriter: the backend MgfxProfile to stamp into the header and the MGFX container version to emit.

RenderStateBlock

The render states declared inside a single FX pass, parsed from the source by RenderStateParser. Every state is nullable so a state left unset in the source stays absent (rather than defaulting), which lets the MgfxWriter decide via the Has* gates whether to emit each of the three optional MGFX state-object headers. The FNA-only states (and KnownFnaThrowingStates) are consumed solely by the FNA fx_2_0 path and are deliberately kept out of the Has* gates so they never alter MGFX v10 output.

RenderStateParser

Parses the render-state assignments inside an FX pass block into a typed RenderStateBlock. Recognized states map to nullable fields (left unset when absent in the source); states fxc accepts but FNA's runtime would throw on are recorded in KnownFnaThrowingStates so the FNA path can fail loudly while the MGFX paths preserve fxc/mgfxc's silent-ignore behavior.

RuntimeProfileDetector

The runtime-detection advisory (Phase 35 auto-select seam 6): given a consumer's loaded XNA framework assembly, recommend the CapabilityProfile to compile for. This is the "auto-detect the runtime, give the newest proven experience" helper the consumer's game calls; the resulting profile is passed to Profile.

ShaderError

A single diagnostic produced during compilation, carrying the source location and the underlying compiler's message verbatim. Errors are returned (never swallowed or reformatted) so callers can surface the exact file, line, column, and message.

ShaderFeatureSupport

The single source of truth for which ShaderFeatures a shipping runtime is render-proven to consume, and the guard that enforces ShadowDusk's hard rule: never emit bytes no runtime can load. Requesting a feature with no downstream support is rejected loudly (SD0201) rather than silently compiled into unloadable output.

ShaderIR

ShadowDusk's backend-neutral intermediate representation of a whole effect, sitting between the parsed/reflected HLSL and the final MGFX emission: the constant buffers, per-pass compiled shader blobs, flattened effect parameters, and techniques the MgfxWriter serializes. It carries no platform-specific bytecode shape, so the same IR drives every MGFX-targeting backend.

Structs

GlslSource

A small wrapper around a GLSL source string produced by the transpiler.

Result<T, TError>

A lightweight discriminated union representing either a success value of type T or an error of type TError. ShadowDusk uses this instead of exception-as-control-flow: compilation outcomes are returned, not thrown.

Unit

A type with exactly one value, used as the success type of a Result<T, TError> when an operation has no meaningful return value but can still fail (the functional equivalent of void).

Interfaces

IShaderCompiler

The core consumer contract: compiles HLSL .fx source into a compiled effect entirely in memory, with no fxc.exe, mgfxc, Wine, or Windows SDK required. For the MonoGame/KNI targets the output is a .mgfx effect; for Fna it is the D3D9 fx_2_0 effects binary (.fxb) FNA loads. This is the product's public entry point — add the library to a project and call CompileAsync(string, CompilerOptions, CancellationToken) at runtime or build time.

Enums

BlendFunctionValue

How source and destination blend terms are combined (mirrors MonoGame's BlendFunction ordinals).

BlendValue

A blend factor applied to a source or destination color (mirrors MonoGame's Blend ordinals).

CompareFunctionValue

A depth- or stencil-test comparison function (mirrors MonoGame's CompareFunction ordinals).

CullModeValue

Which triangle faces are culled (mirrors MonoGame's CullMode ordinals).

DetectedRuntime

The XNA-reimplementation runtime a consumer's game is running on, classified from the loaded framework assembly's simple name (all three share the Microsoft.Xna.Framework namespace, so the assembly name is the only reliable fork discriminator). Used by RuntimeProfileDetector to recommend a CapabilityProfile.

DxbcBackend

Selects which backend compiles HLSL to SM5 DXBC for the DirectX target.

EffectContainer

Which effect container ShadowDusk serializes the compiled effect into.

Mgfx (the default) is the MGFX container, the universally loadable format every MonoGame and KNI runtime accepts (version controlled by MgfxVersion, default v10). This is the seamless product default and is never something a consumer must change to get correct output.

Knifx emits KNI's newer KNIFX v11 container (additive, opt-in) so consumers on KNI v4.02+ can use the newer container's features. It is an escape hatch / additive target, not a replacement for the v10 default. Ignored for Fna, whose output is always the D3D9 fx_2_0 container.

FillModeValue

How triangles are rasterized (mirrors MonoGame's FillMode ordinals).

KnifxBackend

The KNI graphics backend a KNIFX body targets. The value IS the on-disk GraphicsBackend enum integer KNI's runtime matches against its adapter (verified from Xna.Framework.Graphics/Graphics/GraphicsBackend.cs @ KNI main). Desktop SDL2.GL reports OpenGL; the browser reports WebGL.

MgfxProfile

The profile byte written into the MGFX binary header, identifying the shader backend an effect was compiled for. These byte values are deliberately NOT the same as PlatformTarget ordinals (PlatformTarget.DirectX=0, OpenGL=1 vs MgfxProfile.OpenGL=0, DirectX11=1) — always use these values when writing the format's profile byte.

PlatformTarget

The consumer runtime/loader an effect is compiled for. Each target is a distinct emitted artifact loaded by a different runtime path, so a shader must be compiled (and validated) per target.

ShaderDialect

How GLSL is emitted for an OpenGL-family target. This is the "dialect" capability axis of a CapabilityProfile: it selects whether ShadowDusk down-converts SPIR-V/GLSL into the MonoGame/KNI MojoShader dialect that every shipping GL runtime consumes today, or emits the un-down-converted modern GLSL a future runtime might consume. Non-GL targets (DirectX DXBC, FNA fx_2_0) carry NotApplicable.

ShaderErrorKind

Categorizes the kind of failure a ShaderError represents.

ShaderErrorSeverity

The severity level of a ShaderError.

ShaderFeatures

GL shader capabilities that ShadowDusk's MojoShader-dialect down-convert rejects today (every shipping MonoGame/KNI GL runtime is MojoShader-capped at SM2-3). A CapabilityProfile declares which it permits via AllowedFeatures, but a feature is only honored once a runtime is render-proven to consume it: ShaderFeatureSupport rejects any feature no shipping runtime supports, so ShadowDusk never emits bytes no runtime can load. As of 2026-06 NONE of these are runtime-supported (KNI's GL backend is still MojoShader), so every proven profile declares None.

ShaderStage

Which programmable shader stage a single compile request targets. The ordinals are stable (Vertex = 0, Pixel = 1) and are used to pick the matching shader profile/entry point when invoking the backend compiler.

StencilOperationValue

What happens to a stencil value on a test outcome (mirrors MonoGame's StencilOperation ordinals).