Skip to content

Commit 73a8d74

Browse files
jkwak-workcsyonghe
andauthored
Legalize array size of SV_TessFactor and SV_InsideTessFactor (#6409)
* Legalize array size of SV_TessFactor and SV_InsideTessFactor When targeting SPIR-V or GLSL, the type for SV_TessFactor must be float[4]; note that it is not a vector but an array. Similarly the type of SV_InsideTessFactor has to be an array of float[2]. When the user shader declare them as arrays smaller than the required size, Slang will legalize them to the required sizes. Note that it is not the user mistake to declare floar[3] when the hull mode is in "tri", as an example. The unused components are expected to be ignored. Note also that HLSL allows the type to be float[2|3|4] whereas GLSL and SPIR-V requires it to be always float[4]. * Change from "quad" domain mode to "tri" * Handle error case --------- Co-authored-by: Yong He <[email protected]>
1 parent 9e465c7 commit 73a8d74

4 files changed

+180
-0
lines changed

source/slang/slang-diagnostic-defs.h

+5
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,11 @@ DIAGNOSTIC(30019, Error, typeMismatch, "expected an expression of type '$0', got
606606
DIAGNOSTIC(30021, Error, noApplicationFunction, "$0: no overload takes arguments ($1)")
607607
DIAGNOSTIC(30022, Error, invalidTypeCast, "invalid type cast between \"$0\" and \"$1\".")
608608
DIAGNOSTIC(30023, Error, typeHasNoPublicMemberOfName, "\"$0\" does not have public member \"$1\".")
609+
DIAGNOSTIC(
610+
30024,
611+
Error,
612+
cannotConvertArrayOfSmallerToLargerSize,
613+
"Cannot convert array of size $0 to array of size $1 as this would truncate data")
609614
DIAGNOSTIC(30025, Error, invalidArraySize, "array size must be larger than zero.")
610615
DIAGNOSTIC(
611616
30026,

source/slang/slang-ir-glsl-legalize.cpp

+73
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,43 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
15281528

15291529
val = ScalarizedVal::typeAdapter(typeAdapter);
15301530
}
1531+
1532+
if (auto requiredArrayType = as<IRArrayTypeBase>(systemValueInfo->requiredType))
1533+
{
1534+
// Find first array declarator and handle size mismatch
1535+
for (auto dd = declarator; dd; dd = dd->next)
1536+
{
1537+
if (dd->flavor != GlobalVaryingDeclarator::Flavor::array)
1538+
continue;
1539+
1540+
// Compare the array size
1541+
auto declaredArraySize = dd->elementCount;
1542+
auto requiredArraySize = requiredArrayType->getElementCount();
1543+
if (declaredArraySize == requiredArraySize)
1544+
break;
1545+
1546+
auto toSize = getIntVal(requiredArraySize);
1547+
auto fromSize = getIntVal(declaredArraySize);
1548+
if (toSize < fromSize)
1549+
{
1550+
context->getSink()->diagnose(
1551+
inVarLayout,
1552+
Diagnostics::cannotConvertArrayOfSmallerToLargerSize,
1553+
fromSize,
1554+
toSize);
1555+
}
1556+
1557+
// Array sizes differ, need type adapter
1558+
RefPtr<ScalarizedTypeAdapterValImpl> typeAdapter =
1559+
new ScalarizedTypeAdapterValImpl;
1560+
typeAdapter->actualType = systemValueInfo->requiredType;
1561+
typeAdapter->pretendType = builder->getArrayType(inType, declaredArraySize);
1562+
typeAdapter->val = val;
1563+
1564+
val = ScalarizedVal::typeAdapter(typeAdapter);
1565+
break;
1566+
}
1567+
}
15311568
}
15321569
}
15331570
else
@@ -1971,6 +2008,42 @@ ScalarizedVal adaptType(IRBuilder* builder, IRInst* val, IRType* toType, IRType*
19712008
val,
19722009
builder->getIntValue(builder->getIntType(), 0));
19732010
}
2011+
else if (auto toArray = as<IRArrayTypeBase>(toType))
2012+
{
2013+
// If array sizes differ, we need to reshape the array
2014+
if (fromArray->getElementCount() != toArray->getElementCount())
2015+
{
2016+
List<IRInst*> elements;
2017+
2018+
// Get array sizes once
2019+
auto fromSize = getIntVal(fromArray->getElementCount());
2020+
auto toSize = getIntVal(toArray->getElementCount());
2021+
SLANG_ASSERT(fromSize <= toSize);
2022+
2023+
// Extract elements one at a time up to the source array size
2024+
for (Index i = 0; i < fromSize; i++)
2025+
{
2026+
auto element = builder->emitElementExtract(
2027+
fromArray->getElementType(),
2028+
val,
2029+
builder->getIntValue(builder->getIntType(), i));
2030+
elements.add(element);
2031+
}
2032+
2033+
if (fromSize < toSize)
2034+
{
2035+
// Fill remaining elements with default value up to target size
2036+
auto elementType = toArray->getElementType();
2037+
auto defaultValue = builder->emitDefaultConstruct(elementType);
2038+
for (Index i = fromSize; i < toSize; i++)
2039+
{
2040+
elements.add(defaultValue);
2041+
}
2042+
}
2043+
2044+
val = builder->emitMakeArray(toType, elements.getCount(), elements.getBuffer());
2045+
}
2046+
}
19742047
}
19752048
// TODO: actually consider what needs to go on here...
19762049
return ScalarizedVal::value(builder->emitCast(toType, val));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//TEST:SIMPLE(filecheck=CHK):-target glsl -entry hullMain -stage hull -allow-glsl
2+
//TEST:SIMPLE(filecheck=CHK):-target spirv-asm -entry hullMain -stage hull -allow-glsl
3+
4+
// Tessllation outsie factor must be an array of size 4 or less
5+
// Tessllation inside factor must be an array of size 2 or less
6+
7+
struct HsOut
8+
{
9+
float2 pos;
10+
float2 hm;
11+
};
12+
13+
struct HscOut
14+
{
15+
//CHK: error 30024: Cannot convert array of size 5 to array of size 4 as this would truncate data
16+
float EdgeTessFactor[5] : SV_TessFactor;
17+
18+
//CHK: error 30024: Cannot convert array of size 3 to array of size 2 as this would truncate data
19+
float InsideTessFactor[3] : SV_InsideTessFactor;
20+
};
21+
22+
[domain("tri")]
23+
[partitioning("integer")]
24+
[outputtopology("triangle_ccw")]
25+
[outputcontrolpoints(4)]
26+
[patchconstantfunc("constants")]
27+
HsOut hullMain()
28+
{
29+
HsOut o;
30+
o.pos = 1;
31+
o.hm = 2;
32+
return o;
33+
}
34+
35+
HscOut constants()
36+
{
37+
HscOut o;
38+
o.EdgeTessFactor[0] = 1;
39+
o.EdgeTessFactor[1] = 2;
40+
o.EdgeTessFactor[2] = 3;
41+
o.EdgeTessFactor[3] = 4;
42+
o.EdgeTessFactor[4] = 5;
43+
o.InsideTessFactor[0] = 0.5;
44+
o.InsideTessFactor[1] = 0.3;
45+
o.InsideTessFactor[2] = 0.2;
46+
return o;
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//TEST:SIMPLE(filecheck=GLSL):-target glsl -entry hullMain -stage hull -allow-glsl
2+
//TEST:SIMPLE(filecheck=SPIRV):-target spirv -entry hullMain -stage hull -allow-glsl
3+
4+
// When targeting SPIRV, the tessellation factors should be an array with size 4 or 2.
5+
6+
// GLSL: gl_TessLevelOuter[3] = 0.0;
7+
// GLSL: gl_TessLevelInner[1] = 0.0;
8+
9+
// SPIRV: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
10+
// SPIRV: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
11+
12+
// SPIRV-DAG: OpStore %gl_TessLevelOuter %[[OuterOpCompositeConstruct:[1-9][0-9]*]]
13+
// SPIRV-DAG: %[[OuterOpCompositeConstruct]] = OpCompositeConstruct %[[OuterOpTypeArray:[a-zA-Z_0-9]*]]
14+
// SPIRV-DAG: %[[OuterOpTypeArray]] = OpTypeArray %{{[^ ]*}} %[[OuterOpConstant:[a-zA-Z_0-9]*]]
15+
// SPIRV-DAG: %[[OuterOpConstant]] = OpConstant %{{[^ ]*}} 4
16+
17+
// SPIRV-DAG: OpStore %gl_TessLevelInner %[[InnerOpCompositeConstruct:[1-9][0-9]*]]
18+
// SPIRV-DAG: %[[InnerOpCompositeConstruct]] = OpCompositeConstruct %[[InnerOpTypeArray:[a-zA-Z_0-9]*]]
19+
// SPIRV-DAG: %[[InnerOpTypeArray]] = OpTypeArray %{{[^ ]*}} %[[InnerOpConstant:[a-zA-Z_0-9]*]]
20+
// SPIRV-DAG: %[[InnerOpConstant]] = OpConstant %{{[^ ]*}} 2
21+
22+
struct HsOut
23+
{
24+
float2 pos;
25+
float2 hm;
26+
};
27+
28+
struct HscOut
29+
{
30+
float EdgeTessFactor[3] : SV_TessFactor; // Should be legalized to float[4]
31+
float InsideTessFactor[1] : SV_InsideTessFactor; // Should be legalized to float[2]
32+
};
33+
34+
[domain("tri")]
35+
[partitioning("integer")]
36+
[outputtopology("triangle_ccw")]
37+
[outputcontrolpoints(4)]
38+
[patchconstantfunc("constants")]
39+
HsOut hullMain()
40+
{
41+
HsOut o;
42+
o.pos = 1;
43+
o.hm = 2;
44+
return o;
45+
}
46+
47+
HscOut constants()
48+
{
49+
HscOut o;
50+
o.EdgeTessFactor[0] = 1;
51+
o.EdgeTessFactor[1] = 2;
52+
o.EdgeTessFactor[2] = 3;
53+
o.InsideTessFactor[0] = 0.5;
54+
return o;
55+
}

0 commit comments

Comments
 (0)