Skip to content

SDSL rewrite#3134

Open
xen2 wants to merge 1200 commits intostride3d:masterfrom
xen2:sdsl-rewrite
Open

SDSL rewrite#3134
xen2 wants to merge 1200 commits intostride3d:masterfrom
xen2:sdsl-rewrite

Conversation

@xen2
Copy link
Copy Markdown
Member

@xen2 xen2 commented Apr 14, 2026

PR Details

WIP (created as non-draft for CI testing)

Related Issue

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My change requires a change to the documentation.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have built and run the editor to try this change out.

xen2 added 30 commits March 13, 2026 23:43
Replaces 125-line switch expression with a single instruction + opcode
patch, matching the existing pattern used by CompileFloatUnaryCall and
CompileInterlockedCall.
Adds BaseDimension, CoordinateDimension, and SizeQueryDimension to
TextureType, replacing 4 duplicated switch expressions across
Expression.cs and TextureMethodsImplementations.cs.
Uniform variables with initializers (e.g. stage float x = 2.0f) are now
compiled as constants instead of wrapper functions. This avoids illegal
stores to cbuffer members in the generated HLSL/SPIR-V, and allows
extracting DefaultValue for EffectReflection.
…is shared. Also added ShaderSource in C# format in meta.hlsl
Generic parameters of resource types (Texture2D, Buffer, StructuredBuffer,
ByteAddressBuffer) need the same PointerType wrapping as member variables,
otherwise code accessing them fails with a cast exception.
xen2 added 2 commits April 24, 2026 16:55
Drop D3D12 spirv_to_dxil and Vulkan from the legalization step — they
consume raw SPIR-V directly and don't need the HLSL-oriented rewrite.
Limit LegalizeForHlsl to the SPIRV-Cross → FXC path where it's needed
to prevent SPIRV-Cross emitting if(true)-style dead branches (from
generic-template constants) and FXC's 'argument pulled into unrelated
predicate' on shaders with Prepare/Compute helpers over a static
stream struct.
xen2 added 2 commits April 25, 2026 01:58
# Conflicts:
#	sources/sdk/Stride.Build.Sdk.Tests/Sdk/Sdk.targets
Stage-scoped StructuredBuffer<T> declarations in ShaderMember.Compile
already emit these decorations so SPIRV-Cross maps them to the correct
HLSL type. The rgroup path forgot to, leaving rgroup-declared read-only
StructuredBuffer<T> (e.g. TransformationInstancing.InstanceWorld) to
drop through SPIRV-Cross as RWByteAddressBuffer on a UAV register.
Regression-tested via CSStructuredBuffer + rgroup.
xen2 added 22 commits April 25, 2026 10:17
…s.targets

Mirrors the fix on Stride.Build.Sdk.Tests/Sdk/Sdk.targets so test
projects routed through the legacy targets path don't propagate
StrideSkipAutoPack=true into CompilerApp — without packing,
AssetCompiler can't resolve the test's package graph at runtime.
… path

When a shader class declares two cbuffers with the same name (e.g.
Transformation.PerDraw split across two blocks) RenameCBufferVariables
suffixes them as `.0` / `.1`. ShaderMixer.MergeCBuffers groups them
back by GetCBufferRealName but the count==1 branch — taken when one
of the duplicates was DCE'd before the merge — only updated the in-
memory Names dict; the OpName instruction in the buffer kept the
suffixed name and the surviving struct type kept its `type.X_1` name.

SPIRV-Cross derives the HLSL cbuffer name from the struct type
(`type.X` → `cbuffer X`), so the rendered HLSL ended up with
`cbuffer PerDraw_1 : register(b0)` while EffectReflection looked up
`PerDraw`, throwing 'No matching element' at
ShaderCompiler.UpdateReflection (DecalShader and similar effects).

Use SetName for the variable's OpName and rename the surviving struct
type back to the unsuffixed form. Regression-tested via CSCBufferRename.
TryGetConstantValue switch fell through to NotImplementedException
when a SpecConstant chain reinterpret-cast bits between scalar types
(e.g. int↔uint, float↔int via asfloat/asuint pattern in a constant
context). Reinterpret via BitConverter on the underlying 32-bit pattern
and dispatch on the result type's scalar.
`static const uint info[] = {...};` left the symbol's type as
ArrayType(Size=-1) even though the initializer fixed the count, so
indexing the constant later allocated a Function temp typed as
OpTypeRuntimeArray and then OpStored the OpSpecConstantComposite (of
sized OpTypeArray<N>) into it — SPIR-V validation rejected the type
mismatch (e.g. SinglePassWireframeShader's infoA/infoB lookup tables).

Mirror the inference logic from local DeclareStatement: after compiling
the initializer, swap the unsized member type for the value's inferred
sized type before registering the symbol.
No C# code launches glslangValidator — the binary was only being copied
into output by the legacy Stride.Shaders.Compiler.csproj and the active
Stride.Shaders.Compilers.csproj. Drop both <StrideNativeLib> entries,
the deps/glslang/ payload, the test-linux-game cleanup line that
deleted it from outputs, and update the leftover comment in
RestoreHelper that named it as an example.
The light-probe Z-prepass binds DSV only and was reusing
StrideForwardShadingEffect.ShadowMapCaster, which works but is
semantically a shadow caster. Add a dedicated ZPrepass mixin child
(same alpha-discard branching as ShadowMapCaster) and switch the
GBuffer render stage in DefaultGraphicsCompositorLevel10 to it.

Also move the ShadowMapCaster*/ZPrepass child declarations before
mixin StrideLighting in StrideForwardShadingEffect: depth-only
sub-effects don't need lighting, so the alpha-discard variants no
longer drag the lighting compose chain through base.PSMain().
ShadowMapCasterAlphaDiscard / ShadowMapCasterAlphaDithered used to
chain through base.PSMain(), which writes streams.ColorTarget — that
declared SV_Target0 in the PS output signature. Since shadow casting
and the light-probe Z prepass bind only a depth target, every draw
on those shaders would emit the D3D11 "PS expects RT View bound to
slot 0, but none is bound" warning.

Refactor both shaders to call this.Shading() directly to populate
streams.shadingColorAlpha through the material surface chain, then
clip without ever touching ColorTarget. The merged-effect Shading()
override (MaterialSurfacePixelStageCompositor) runs the layered
material chain identically to the regular pass, so per-layer
contributions to the alpha are preserved.

InterfaceProcessor previously dropped the Fragment entry point when
nothing wrote SV_Target/SV_Depth, which would silently strip these
shaders' PS entirely (clip never runs, transparent cutout pixels
write depth). Detect "empty PSMain" by inspecting the SPIR-V function
body instead — only the no-op PS case (e.g. ShadowMapCasterNoPixelShader)
is dropped, preserving the depth-only fast path. Any side-effecting
body (clip()/discard, stores, calls) keeps the PS bound.
Mini-dumps don't include the managed heap, so post-mortem analysis of
shader-compiler AVs can't dereference any of the captured pointers.
Switch all three Windows test crash-dump paths to full memory:

- DOTNET_DbgMiniDumpType: 1 (Normal) -> 4 (FullMemory)
- WER LocalDumps DumpType: 1 (Mini) -> 2 (Full)
- Stride FirstChance SEH: add MiniDumpWithFullMemory and
  MiniDumpWithHandleData to the previous flag set (the existing
  MiniDumpWithFullMemoryInfo only captures region descriptors, not
  pages)

Linux test workflow has no dump env vars set, so it's unchanged.
These were written next to the source by the old custom MSBuild tool;
they are now produced by the Roslyn source generator into obj/. The
on-disk siblings are dead weight (excluded from build but still in
source trees and version control).

The 4.3 -> 4.4 step in StridePackageUpgrader:
- Renames .sdsl.cs / .sdfx.cs to .bak in the project tree (skipping
  obj/ and bin/) so users can recover without git.
- Strips leftover csproj item nodes referencing those paths.
- Strips obsolete <Generator> / <LastGenOutput> metadata from .sdsl
  and .sdfx items.

Drop the now-unnecessary <Compile Remove> rules from
Stride.Shaders.Compilers.targets. The <None Remove> rules for .sdsl
and .sdfx source files stay -- they keep source files out of the
default <None> glob.
CompileSincos was passing the sincos function's FunctionType to the
GLSL Sin/Cos helpers, which take their result type from
functionType.ReturnType. sincos returns void, so the emitted SPIR-V
was OpExtInst %void Sin %x -- rejected by spirv-val with
"GLSL.std.450 Sin: expected Result Type to be a 16 or 32-bit scalar
or vector float type".

Synthesize a function type whose ReturnType is x's float type and use
that for the Sin/Cos extinsts.
…nctionType

The static intrinsic helpers (CompileFloatUnaryCall,
CompileGLSLFloatUnaryCall, CompileGLSLFloatBinaryCall,
CompileBitcastCall, MultiplyConstant, CompileBoolToScalarBoolCall)
took FunctionType only to read functionType.ReturnType. That coupled
the result-type decision to the intrinsic's declared return type,
which is wrong for void-returning intrinsics like sincos and forced a
"functionType with { ReturnType = ... }" workaround at the call site.

Take SymbolType resultType directly so the result-type intent is
local to each call site. CompileSincos can now pass the float type
without synthesizing a function type.

CompileInterlockedCall, CompileMemoryBarrierCall and
CompileControlBarrierCall never used FunctionType at all -- drop the
parameter.
# Conflicts:
#	.github/workflows/test-linux-game.yml
#	.github/workflows/test-linux-simple.yml
#	.github/workflows/test-windows-game.yml
#	.github/workflows/test-windows-simple.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants