Skip to content

Commit 8898631

Browse files
committed
SDSL: infer array size from initializer for static const member arrays
`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.
1 parent 4647502 commit 8898631

3 files changed

Lines changed: 48 additions & 0 deletions

File tree

sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/ShaderElements.MethodOrMember.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ public override void ProcessSymbol(SymbolTable table, SpirvContext context)
225225

226226
// Constant: compile right away
227227
var constantValue = Value.CompileConstantValue(table, context, memberType);
228+
// Infer size for unsized arrays (e.g. `static const uint info[] = {...};`) from
229+
// the initializer; otherwise indexing the constant later allocates a temp variable
230+
// typed as runtime array, mismatching the OpSpecConstantComposite's sized OpTypeArray.
231+
if (memberType is ArrayType { Size: -1 } && Value.ValueType is ArrayType { Size: > 0 } inferred)
232+
memberType = inferred;
228233
context.SetName(constantValue.Id, Name);
229234
var constant = new Symbol(new(Name, SymbolKind.Constant), memberType, constantValue.Id, OwnerType: table.CurrentShader);
230235
table.CurrentFrame.Add(Name, constant);

sources/shaders/Stride.Shaders.Tests/RenderingTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,27 @@ public void DuplicateCBufferNameSurvivesMixerRename()
107107
Assert.DoesNotContain("cbuffer Settings_", hlsl2);
108108
}
109109

110+
[Fact]
111+
public void UnsizedConstArrayInfersSizeForIndexing()
112+
{
113+
// Regression: `static const uint info[] = {...};` was kept as ArrayType
114+
// with Size=-1 even after the initializer fixed the count, so indexing
115+
// `info[i]` allocated a Function temp typed as OpTypeRuntimeArray and
116+
// then OpStored the OpSpecConstantComposite of OpTypeArray<7> into it —
117+
// SPIR-V validation rejects the type mismatch.
118+
const string shaderName3 = "CSConstArrayInfer";
119+
var shaderMixer3 = new ShaderMixer(new ShaderLoader("./assets/SDSL/ComputeTests"));
120+
shaderMixer3.ShaderLoader.LoadExternalBuffer(shaderName3, [], out _, out _, out _);
121+
122+
var log3 = new Stride.Core.Diagnostics.LoggerResult();
123+
Assert.True(shaderMixer3.MergeSDSL(new ShaderClassSource(shaderName3), new ShaderMixer.Options(true), log3, out var bytecode3, out _, out _, out _),
124+
string.Join(Environment.NewLine, log3.Messages.Select(m => m.Text)));
125+
126+
File.WriteAllBytes($"{shaderName3}.spv", bytecode3);
127+
var validation = Spv.ValidateFile($"{shaderName3}.spv");
128+
Assert.True(validation.IsValid, validation.Output);
129+
}
130+
110131
[Fact]
111132
public void StructuredBufferEmitsStructuredBufferHlsl()
112133
{
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// PSMain(ExpectedResult=#00000000)
2+
3+
namespace Stride.Shaders.Tests;
4+
5+
// Regression: an unsized const array (size inferred from initializer) used as
6+
// the source of a dynamic indexing must yield a sized array temp, not a
7+
// runtime-array temp — otherwise OpStore on the materialization fails SPIR-V
8+
// validation with "OpStore Pointer's type does not match Object's type".
9+
shader CSConstArrayInfer
10+
{
11+
static const uint info[] = { 0, 1, 2, 3, 4, 5, 6 };
12+
13+
stage stream uint3 DispatchThreadId : SV_DispatchThreadID;
14+
RWStructuredBuffer<uint> Out;
15+
16+
[numthreads(1, 1, 1)]
17+
void CSMain()
18+
{
19+
uint idx = streams.DispatchThreadId.x;
20+
Out[idx] = info[idx];
21+
}
22+
};

0 commit comments

Comments
 (0)