Skip to content

Commit 2034cde

Browse files
authored
Triangle subdivision geometry shader test (#1223)
Adds a geometry shader test that exercises one-triangle-in / many-triangles-out expansion together with `RestartStrip()`. The GS subdivides the input triangle into four sub-triangles by joining the edge midpoints (three corner triangles + one inverted central triangle), emitting each as its own strip via `RestartStrip()`. Because the four sub-triangles exactly tile the parent, the rasterized coverage of the expanded output must equal that of the original triangle — every pixel inside the parent is covered by exactly one sub-triangle.
1 parent 8a68c02 commit 2034cde

1 file changed

Lines changed: 124 additions & 0 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#--- vertex.hlsl
2+
struct VSOutput {
3+
float4 position : SV_POSITION;
4+
};
5+
6+
VSOutput main(float4 position : POSITION) {
7+
VSOutput o;
8+
o.position = position;
9+
return o;
10+
}
11+
12+
#--- geometry.hlsl
13+
struct GSInput {
14+
float4 position : SV_POSITION;
15+
};
16+
17+
struct GSOutput {
18+
float4 position : SV_POSITION;
19+
};
20+
21+
// Subdivide the input triangle into four sub-triangles by joining the
22+
// edge midpoints (three corner triangles + one inverted central one).
23+
// Their union exactly tiles the parent triangle, so the rasterized
24+
// coverage of the subdivided primitive must equal that of the original —
25+
// every pixel inside the parent triangle is covered by exactly one
26+
// sub-triangle.
27+
[maxvertexcount(12)]
28+
void main(triangle GSInput input[3], inout TriangleStream<GSOutput> stream) {
29+
float4 v0 = input[0].position;
30+
float4 v1 = input[1].position;
31+
float4 v2 = input[2].position;
32+
float4 m01 = 0.5 * (v0 + v1);
33+
float4 m12 = 0.5 * (v1 + v2);
34+
float4 m02 = 0.5 * (v0 + v2);
35+
36+
GSOutput o;
37+
38+
// Corner triangle at v0.
39+
o.position = v0; stream.Append(o);
40+
o.position = m01; stream.Append(o);
41+
o.position = m02; stream.Append(o);
42+
stream.RestartStrip();
43+
44+
// Corner triangle at v1.
45+
o.position = m01; stream.Append(o);
46+
o.position = v1; stream.Append(o);
47+
o.position = m12; stream.Append(o);
48+
stream.RestartStrip();
49+
50+
// Corner triangle at v2.
51+
o.position = m02; stream.Append(o);
52+
o.position = m12; stream.Append(o);
53+
o.position = v2; stream.Append(o);
54+
stream.RestartStrip();
55+
56+
// Central triangle.
57+
o.position = m01; stream.Append(o);
58+
o.position = m12; stream.Append(o);
59+
o.position = m02; stream.Append(o);
60+
}
61+
62+
#--- pixel.hlsl
63+
struct PSInput {
64+
float4 position : SV_POSITION;
65+
};
66+
67+
float4 main(PSInput input) : SV_TARGET {
68+
return float4(1.0, 0.0, 0.0, 1.0);
69+
}
70+
71+
#--- pipeline.yaml
72+
---
73+
Shaders:
74+
- Stage: Vertex
75+
Entry: main
76+
- Stage: Geometry
77+
Entry: main
78+
- Stage: Pixel
79+
Entry: main
80+
Buffers:
81+
# One oversized triangle that covers the full 2x2 viewport in clip space.
82+
- Name: VertexData
83+
Format: Float32
84+
Stride: 16 # 3 vertices, 16 bytes each
85+
Data: [ -1.0, -1.0, 0.0, 1.0,
86+
3.0, -1.0, 0.0, 1.0,
87+
-1.0, 3.0, 0.0, 1.0 ]
88+
- Name: Output
89+
Format: Float32
90+
Channels: 4
91+
FillSize: 64 # 2x2 @ 16 bytes per pixel
92+
OutputProps:
93+
Height: 2
94+
Width: 2
95+
Depth: 1
96+
Bindings:
97+
VertexBuffer: VertexData
98+
VertexAttributes:
99+
- Format: Float32
100+
Channels: 4
101+
Offset: 0
102+
Name: POSITION
103+
RenderTarget: Output
104+
DescriptorSets: []
105+
...
106+
#--- end
107+
108+
# Metal has no native geometry shader stage.
109+
# UNSUPPORTED: Metal
110+
111+
# Clang's HLSL frontend does not yet support geometry shader stream types.
112+
# Tracked upstream: https://github.com/llvm/llvm-project/issues/136963
113+
# XFAIL: Clang
114+
115+
# RUN: split-file %s %t
116+
# RUN: %dxc_target -T vs_6_0 -Fo %t-vertex.o %t/vertex.hlsl
117+
# RUN: %dxc_target -T gs_6_0 -Fo %t-geometry.o %t/geometry.hlsl
118+
# RUN: %dxc_target -T ps_6_0 -Fo %t-pixel.o %t/pixel.hlsl
119+
# RUN: %offloader %t/pipeline.yaml %t-vertex.o %t-geometry.o %t-pixel.o | FileCheck %s
120+
121+
# All 4 pixels of the 2x2 render target must be opaque red — the union of the
122+
# four sub-triangles equals the parent.
123+
# CHECK: Name: Output
124+
# CHECK: Data: [ 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1 ]

0 commit comments

Comments
 (0)