Repository: shader-slang/slang (2025-07-08T22:42:49Z)

Issue:
Invalid SPIR-V generated for hull shader using outputtopology("point")
spirv-val gives an error when validating a hull shader using outputtopology("point") :

```
struct Out {
    float x;
};

struct PatchConst {
    float EdgeTessFactor[4] : SV_TessFactor;
    float InsideTessFactor[2] : SV_InsideTessFactor;
};

PatchConst patchConst() {
    PatchConst o;
    o.EdgeTessFactor[0] = 1;
    o.EdgeTessFactor[1] = 1;
    o.EdgeTessFactor[2] = 1;
    o.EdgeTessFactor[3] = 1;
    o.InsideTessFactor[0] = 1;
    o.InsideTessFactor[1] = 1;
    return o;
}

[domain("quad")]
[partitioning("integer")]
[outputtopology("point")]
[outputcontrolpoints(4)]
[patchconstantfunc("patchConst")]
Out hullMain_point() {
    Out o;
    o.x = 0;
    return o;
}
```


```
error: line 7: Operand 2 of ExecutionMode requires one of these capabilities: Geometry MeshShadingNV MeshShadingEXT
  OpExecutionMode %hullMain_point OutputPoints
```


Slang should generate OpExecutionMode PointMode instead of OutputPoints.



Discussion:

Patch:
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 7f6202a7f3..28862f5b8a 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -5312,6 +5312,8 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
                             m = SpvExecutionModeVertexOrderCw;
                         else if (topologyType == OutputTopologyType::TriangleCCW)
                             m = SpvExecutionModeVertexOrderCcw;
+                        else if (topologyType == OutputTopologyType::Point)
+                            m = SpvExecutionModePointMode;
                         break;
                     }
                 }


Test patch:
diff --git a/tests/spirv/hull-shader-outputtopology.slang b/tests/spirv/hull-shader-outputtopology.slang
new file mode 100644
index 0000000000..63c279528a
--- /dev/null
+++ b/tests/spirv/hull-shader-outputtopology.slang
@@ -0,0 +1,60 @@
+//TEST:SIMPLE(filecheck=SPIRV_POINT):-target spirv -stage hull -entry hullMain_point
+//TEST:SIMPLE(filecheck=SPIRV_TRICW):-target spirv -stage hull -entry hullMain_triangle_cw
+//TEST:SIMPLE(filecheck=SPIRV_TRICCW):-target spirv -stage hull -entry hullMain_triangle_ccw
+
+// SPIRV_POINT: OpExecutionMode %hullMain_point PointMode
+// SPIRV_TRICW: OpExecutionMode %hullMain_triangle_cw VertexOrderCw
+// SPIRV_TRICCW: OpExecutionMode %hullMain_triangle_ccw VertexOrderCcw
+
+struct Out {
+    float x;
+};
+
+struct PatchConst {
+    float EdgeTessFactor[4] : SV_TessFactor;
+    float InsideTessFactor[2] : SV_InsideTessFactor;
+};
+
+PatchConst patchConst() {
+    PatchConst o;
+    o.EdgeTessFactor[0] = 1;
+    o.EdgeTessFactor[1] = 1;
+    o.EdgeTessFactor[2] = 1;
+    o.EdgeTessFactor[3] = 1;
+    o.InsideTessFactor[0] = 1;
+    o.InsideTessFactor[1] = 1;
+    return o;
+}
+
+[domain("quad")]
+[partitioning("integer")]
+[outputtopology("point")]
+[outputcontrolpoints(4)]
+[patchconstantfunc("patchConst")]
+Out hullMain_point() {
+    Out o;
+    o.x = 0;
+    return o;
+}
+
+[domain("quad")]
+[partitioning("integer")]
+[outputtopology("triangle_cw")]
+[outputcontrolpoints(4)]
+[patchconstantfunc("patchConst")]
+Out hullMain_triangle_cw() {
+    Out o;
+    o.x = 0;
+    return o;
+}
+
+[domain("quad")]
+[partitioning("integer")]
+[outputtopology("triangle_ccw")]
+[outputcontrolpoints(4)]
+[patchconstantfunc("patchConst")]
+Out hullMain_triangle_ccw() {
+    Out o;
+    o.x = 0;
+    return o;
+}