Skip to content

fix: ignore [numthreads] on non-entry compute methods (match HLSL) - #3304

Open
sasvdw wants to merge 2 commits into
stride3d:masterfrom
LazyWorksZA:fix/sdsl-numthreads-non-entry
Open

fix: ignore [numthreads] on non-entry compute methods (match HLSL)#3304
sasvdw wants to merge 2 commits into
stride3d:masterfrom
LazyWorksZA:fix/sdsl-numthreads-non-entry

Conversation

@sasvdw

@sasvdw sasvdw commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

PR Details

Summary — a compute shader with [numthreads] on a non-entry method (e.g. override void Compute()) emitted invalid SPIR-V and failed to compile on Direct3D11; this ignores the mis-placed
attribute (as HLSL does) and warns.

Description — the [numthreads] OpExecutionMode LocalSize was emitted on the attribute-bearing
method, but the compute entry point is a generated CSMain_Wrapper, so the mode was stranded on a
non-entry function → invalid SPIR-V → LegalizeForHlsl failed with a bare spvOptimizerRun InternalError. HLSL/FXC/DXC treat [numthreads] on a non-entry function as legal and silently ignored
(size comes only from the entry point). Match that:

  • MethodOrMember.cs — emit LocalSize only when the attribute is on the compute entry
    (EntryPoint == ComputeShader); otherwise skip it (valid SPIR-V) and warn, pointing to
    ThreadNumberX/Y/Z.
  • ShaderMixer.cs — drain SymbolTable.Warnings to log.Warning in MergeSDSL (only errors were
    before), so the warning reaches the user.
  • EffectCompiler.cs — when LegalizeForHlsl throws, validate the module and surface the real
    instruction instead of a bare InternalError.
  • ComputeEffectShader.cs — clarify the XML docs: ThreadNumbers sets the compute shader's thread
    group size (its [numthreads]); ThreadGroupCounts is the dispatch count.

Not a regression (the classic ≤4.3 path also dropped it).

Motivation and context — see #3303. Repro: https://github.com/sasvdw/stride-spirv-legalize-repro

Related Issue

Fixes #3303.

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.

Validation status (honest):

  • Tests: StrideShaderTests.NumThreadsOnNonEntryMethodIsIgnoredWithWarning +
    CompilerTests/CSNumThreadsOnNonEntry.sdsl — compiles, valid SPIR-V, warning emitted; verified
    red/green.
  • Build: Stride.Shaders.Parsers/Compilers clean; StrideShaderTests 13/13. CI pending.
  • Editor: outstanding (the mandatory personal-testing step).
  • Docs: improved the ComputeEffectShader.ThreadNumbers/ThreadGroupCounts XML docs (flow to the API
    reference). The manual has no compute-shader guide — tracked as a separate stride-docs follow-up.

sasvdw and others added 2 commits July 29, 2026 10:54
[numthreads] on a method other than the compute entry point (CSMain) was
emitted as an OpExecutionMode LocalSize on that method's own function id, but
the SPIR-V entry point is a generated CSMain_Wrapper. The mode was left stranded
on a non-entry function, producing invalid SPIR-V that failed SPIRV-Cross HLSL
legalization with a bare spvOptimizerRun InternalError (Direct3D11 path).

HLSL/FXC/DXC treat [numthreads] on a non-entry function as legal and silently
ignored; the thread group size comes only from the entry point. Match that: skip
the LocalSize on a non-entry compute method and warn, pointing to
ThreadNumberX/Y/Z (C#-overridable via ComputeEffectShader.ThreadNumbers, which
also drives dispatch). Drain SymbolTable.Warnings to the log in MergeSDSL so the
warning reaches the user. Also validate the module when LegalizeForHlsl throws,
surfacing the real invalid instruction instead of a bare InternalError.

Adds a regression test (compiles + valid SPIR-V + warning; verified red/green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ThreadNumbers sets the compute shader's thread group size (its [numthreads],
via the ThreadNumberX/Y/Z macros on CSMain); ThreadGroupCounts is the dispatch
count. Documenting this points users at the supported mechanism rather than a
literal [numthreads] in the shader body (which is ignored on non-entry methods).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Draft PR — automatic CI is skipped to save runner minutes.

  • Mark the PR ready for review to run the full automatic CI — or add a ci-run-on-draft label to run it now without leaving draft.
  • Or arm a specific opt-in suite: ci-enduser, ci-editor, ci-ios, ci-android.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[numthreads] on a non-entry compute method emits invalid SPIR-V (D3D11 compile fails with a bare InternalError)

2 participants