Skip to content

Commit

Permalink
Emit OpExecutionMode SpacingEqual for Domain stage (shader-slang#5696)
Browse files Browse the repository at this point in the history
Domain stage should emit one more `OpExecutionMode` with
`SpacingEqual`, similary to how Hull stage does.

Currently Hull stage emits four OpExecutionMode as following:
  OpExecutionMode %hullMain SpacingEqual
  OpExecutionMode %hullMain OutputVertices 4
  OpExecutionMode %hullMain VertexOrderCw
  OpExecutionMode %hullMain Quads

And Domain stage emits only one OpExecutionMode:
  OpExecutionMode %domainMain Quads

This commit adds the following instruction for Domain stage:
  OpExecutionMode %domainMain SpacingEqual

It is because the Vulkan Validation Layer prints error when the
Domain shader didn't have `OpeExecutionMode SpacingEqual`.

`SpacingEqual` corresponds to an attribute, `[partitioning("integer")]`,
given to the Hull stage.  Although Domain stage is not marked with
same attribute, it is assumed to use the same value used for
matching Hull Stage.

The error message from VVL is following:
```
vkCreateShadersEXT(): pCreateInfos[2].stage is VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
but spacing is not specified. The Vulkan spec states: If codeType is VK_SHADER_CODE_TYPE_SPIRV_EXT,
and stage is VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, pCode must contain an OpExecutionMode
instruction specifying the spacing of segments on the edges of tessellated primitives
(https://vulkan.lunarg.com/doc/view/1.3.283.0/windows/1.3-extensions/vkspec.html#VUID-VkShaderCreateInfoEXT-codeType-08874)
```

Co-authored-by: Ellie Hermaszewska <ellieh@nvidia.com>
  • Loading branch information
jkwak-work and expipiplus1 authored Nov 29, 2024
1 parent 0b92e1d commit c005fe9
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 19 deletions.
4 changes: 1 addition & 3 deletions source/slang/slang-emit-spirv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4267,6 +4267,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_mesh_shader"));
break;
case Stage::Hull:
case Stage::Domain:
{
requireSPIRVCapability(SpvCapabilityTessellation);

Expand All @@ -4288,10 +4289,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
arg);
}
requireSPIRVExecutionMode(nullptr, getIRInstSpvID(entryPoint), mode);
break;
}
case Stage::Domain:
requireSPIRVCapability(SpvCapabilityTessellation);
break;
default:
break;
Expand Down
65 changes: 49 additions & 16 deletions tests/spirv/tessellation.slang
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
//TEST:SIMPLE(filecheck=CHECK): -target spirv
//TEST:SIMPLE(filecheck=HULL): -target spirv -stage hull -entry hullMain
//TEST:SIMPLE(filecheck=DOMAIN): -target spirv -stage domain -entry domainMain

// CHECK-DAG: OpExecutionMode %main SpacingEqual
// HULL-DAG: OpExecutionMode %hullMain SpacingEqual
// HULL-DAG: OpExecutionMode %hullMain OutputVertices 4
// HULL-DAG: OpExecutionMode %hullMain VertexOrderCw
// HULL-DAG: OpExecutionMode %hullMain Quads

// CHECK-DAG: OpExecutionMode %main OutputVertices 4
// HULL: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
// HULL: OpDecorate %gl_TessLevelOuter Patch
// HULL: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
// HULL: OpDecorate %gl_TessLevelInner Patch

// CHECK-DAG: OpExecutionMode %main VertexOrderCw
// HULL: OpControlBarrier %uint_2 %uint_4 %uint_0

// CHECK-DAG: OpExecutionMode %main Quads
// HULL: OpStore %gl_TessLevelOuter
// HULL: OpStore %gl_TessLevelInner

// CHECK: OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
// CHECK: OpDecorate %gl_TessLevelOuter Patch
// CHECK: OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
// CHECK: OpDecorate %gl_TessLevelInner Patch

// CHECK: OpControlBarrier %uint_2 %uint_4 %uint_0

// CHECK: OpStore %gl_TessLevelOuter
// CHECK: OpStore %gl_TessLevelInner
// DOMAIN-DAG: OpExecutionMode %domainMain SpacingEqual
// DOMAIN-DAG: OpExecutionMode %domainMain Quads

struct VS_OUT
{
Expand All @@ -34,13 +35,18 @@ struct HSC_OUT
float InsideTessFactor[2] : SV_InsideTessFactor;
};

struct DS_OUT
{
float4 position : SV_Position;
};

// Hull Shader (HS)
[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("constants")]
HS_OUT main(InputPatch<VS_OUT, 4> patch, uint i : SV_OutputControlPointID)
HS_OUT hullMain(InputPatch<VS_OUT, 4> patch, uint i : SV_OutputControlPointID)
{
HS_OUT o;
o.position = patch[i].position;
Expand All @@ -62,4 +68,31 @@ HSC_OUT constants(InputPatch<VS_OUT, 4> patch)
o.InsideTessFactor[0] = lerp(o.EdgeTessFactor[1], o.EdgeTessFactor[3], 0.5);
o.InsideTessFactor[1] = lerp(o.EdgeTessFactor[0], o.EdgeTessFactor[2], 0.5);
return o;
}
}

[domain("quad")]
DS_OUT domainMain(
float2 uv : SV_DomainLocation, // Tessellated coordinates (u, v)
const OutputPatch<HS_OUT, 4> patch, // Control points from the hull shader
const HSC_OUT patchConstants // Patch constants calculated by the hull shader
)
{
DS_OUT o;

// Interpolate the position of the tessellated point within the patch
float3 p0 = patch[0].position;
float3 p1 = patch[1].position;
float3 p2 = patch[2].position;
float3 p3 = patch[3].position;

// Bilinear interpolation of the position in the quad
float3 interpolatedPosition =
p0 * (1 - uv.x) * (1 - uv.y)
+ p1 * uv.x * (1 - uv.y)
+ p3 * uv.x * uv.y
+ p2 * (1 - uv.x) * uv.y;

// Output final position in clip space
o.position = float4(interpolatedPosition, 1.0);
return o;
}

0 comments on commit c005fe9

Please sign in to comment.