Skip to content

Commit eda82cb

Browse files
author
Tim Foley
authored
Fix a regression in geometry shader cross-compilation (shader-slang#794)
The underlying problem here was that legalization of entry point parameters for GLSL eliminates all the parameters to `main()`, but we still left a dangling reference to one of those parameters if it was a geometry shader output stream. The un-parented parameter would lead to an infinite loop in a later IR step, because it would never be reached by the transformation, and thus could never change its status to the one for "visited" instructions. The fix here is to simply replace any refernces to the GS input stream parameter with an `undefined` instruction in the IR, and then rely on the fact that the downstream GLSL emit logic wouldn't actually reference that value anyway (hence why the danlging reference wasn't originally an issue). I included a basic cross-compilation test case for geometry shaders to try to avoid subsequent regressions like this (Vulkan GS support is one of the most commonly recurring regressions we've had). The comment I put into the IR legalization logic makes it clear that the strategy used there isn't 100% rock-solid anyway (it only works in all the `EmitVertex()` calls come from the shader entry point function, and not subroutines. Adding a better (more robust) translation strategy for geometry shaders would be a nice bit of future work.
1 parent 968d7b4 commit eda82cb

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed

source/slang/ir-glsl-legalize.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,23 @@ void legalizeEntryPointParameterForGLSL(
12381238
}
12391239
}
12401240

1241+
// We will still have references to the parameter coming
1242+
// from the `EmitVertex` calls, so we need to replace it
1243+
// with something. There isn't anything reasonable to
1244+
// replace it with that would have the right type, so
1245+
// we will replace it with an undefined value, knowing
1246+
// that the emitted code will not actually reference it.
1247+
//
1248+
// TODO: This approach to generating geometry shader code
1249+
// is not ideal, and we should strive to find a better
1250+
// approach that involes coding the `EmitVertex` operation
1251+
// directly in the stdlib, similar to how ray-tracing
1252+
// operations like `TraceRay` are handled.
1253+
//
1254+
builder->setInsertBefore(func->getFirstBlock()->getFirstOrdinaryInst());
1255+
auto undefinedVal = builder->emitUndefined(pp->getFullType());
1256+
pp->replaceUsesWith(undefinedVal);
1257+
12411258
return;
12421259
}
12431260
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// geometry-shader.slang
2+
3+
//TEST:CROSS_COMPILE: -profile sm_5_0 -stage geometry -entry main -target spirv-assembly
4+
5+
struct CoarseVertex
6+
{
7+
float4 position : POSITION;
8+
float3 color : COLOR;
9+
uint id : ID;
10+
}
11+
12+
struct RasterVertex
13+
{
14+
float4 position : POSITION;
15+
float3 color : COLOR;
16+
uint id : SV_RenderTargetArrayIndex;
17+
}
18+
19+
[maxvertexcount(3)]
20+
void main(
21+
triangle CoarseVertex coarseVertices[3],
22+
inout TriangleStream<RasterVertex> outputStream)
23+
{
24+
for(int ii = 0; ii < 3; ++ii)
25+
{
26+
CoarseVertex coarseVertex = coarseVertices[ii];
27+
RasterVertex rasterVertex;
28+
rasterVertex.position = coarseVertex.position;
29+
rasterVertex.color = coarseVertex.color;
30+
rasterVertex.id = coarseVertex.id;
31+
outputStream.Append(rasterVertex);
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#version 450
2+
// geometry-shader.slang.glsl
3+
//TEST_IGNORE_FILE:
4+
5+
#define RasterVertex RasterVertex_0
6+
#define CoarseVertex CoarseVertex_0
7+
8+
#define input_position _S1
9+
#define input_color _S2
10+
#define input_id _S3
11+
#define output_position _S4
12+
#define output_color _S5
13+
14+
layout(row_major) uniform;
15+
layout(row_major) buffer;
16+
17+
layout(location = 0)
18+
in vec4 input_position[3];
19+
20+
layout(location = 1)
21+
in vec3 input_color[3];
22+
23+
layout(location = 2)
24+
in uint input_id[3];
25+
26+
layout(location = 0)
27+
out vec4 output_position;
28+
29+
layout(location = 1)
30+
out vec3 output_color;
31+
32+
struct RasterVertex
33+
{
34+
vec4 position_0;
35+
vec3 color_0;
36+
uint id_0;
37+
};
38+
39+
struct CoarseVertex
40+
{
41+
vec4 position_1;
42+
vec3 color_1;
43+
uint id_1;
44+
};
45+
46+
47+
layout(max_vertices = 3) out;
48+
layout(triangles) in;
49+
layout(triangle_strip) out;
50+
51+
void main()
52+
{
53+
int ii_0;
54+
55+
// TODO: Having to make this copy to transpose things is unfortunate.
56+
//
57+
// The front-end should be able to generate code using aggregate
58+
// types for the input, and/or eliminate the redundant temporary
59+
// by indexing directly into the sub-arrays.
60+
//
61+
CoarseVertex_0 _S6[3] = {
62+
CoarseVertex_0(input_position[0], input_color[0], input_id[0]),
63+
CoarseVertex_0(input_position[1], input_color[1], input_id[1]),
64+
CoarseVertex_0(input_position[2], input_color[2], input_id[2])
65+
};
66+
67+
ii_0 = 0;
68+
for(;;)
69+
{
70+
if(ii_0 < 3)
71+
{}
72+
else
73+
{
74+
break;
75+
}
76+
77+
CoarseVertex_0 coarseVertex_0 = _S6[ii_0];
78+
79+
RasterVertex_0 rasterVertex_0;
80+
rasterVertex_0.position_0 = coarseVertex_0.position_1;
81+
rasterVertex_0.color_0 = coarseVertex_0.color_1;
82+
rasterVertex_0.id_0 = coarseVertex_0.id_1;
83+
84+
RasterVertex_0 _S7 = rasterVertex_0;
85+
86+
output_position = _S7.position_0;
87+
output_color = _S7.color_0;
88+
gl_Layer = int(_S7.id_0);
89+
90+
EmitVertex();
91+
92+
ii_0 = ii_0 + 1;
93+
}
94+
95+
return;
96+
}

0 commit comments

Comments
 (0)