summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarren Wihandi <65404740+fairywreath@users.noreply.github.com>2025-05-19 14:21:25 -0400
committerGitHub <noreply@github.com>2025-05-19 11:21:25 -0700
commit634e3960c2bc322bbd51fccc7ff395d9f24e35dc (patch)
treed7cc501d74a1e4e5fb7fa7d5dcf6c6d515603678
parent31d80c767865d360afba39e5248ab709c587792f (diff)
Map `SV_VertexID` to `gl_VertexIndex-gl_BaseVertex`, add `SV_Vulkan*ID` semantics (#7150)
* Map SV_VertexID to `gl_VertexIndex - gl_BaseVertex`, provide SV_Vulkan* SV semantics * Fix docs * Regenerate toc * Fix affected pointer-2 test * Add tests --------- Co-authored-by: Yong He <yonghe@outlook.com>
-rw-r--r--docs/user-guide/a2-01-spirv-target-specific.md19
-rw-r--r--docs/user-guide/a2-02-metal-target-specific.md2
-rw-r--r--docs/user-guide/a2-03-wgsl-target-specific.md4
-rw-r--r--docs/user-guide/toc.html2
-rw-r--r--source/slang/glsl.meta.slang31
-rw-r--r--source/slang/slang-emit-c-like.cpp4
-rw-r--r--source/slang/slang-emit-spirv.cpp9
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp54
-rw-r--r--source/slang/slang-ir-insts.h3
-rw-r--r--source/slang/slang-ir-legalize-varying-params.cpp4
-rw-r--r--source/slang/slang-ir-legalize-varying-params.h2
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp2
-rw-r--r--tests/spirv/pointer-2.slang2
-rw-r--r--tests/spirv/sv-vertex-id.slang16
-rw-r--r--tests/spirv/sv-vulkan-instance-vertex-id.slang42
15 files changed, 177 insertions, 19 deletions
diff --git a/docs/user-guide/a2-01-spirv-target-specific.md b/docs/user-guide/a2-01-spirv-target-specific.md
index 1ab143cb0..dee19cd28 100644
--- a/docs/user-guide/a2-01-spirv-target-specific.md
+++ b/docs/user-guide/a2-01-spirv-target-specific.md
@@ -72,7 +72,7 @@ The system-value semantics are translated to the following SPIR-V code.
| `SV_GroupThreadID` | `BuiltIn LocalInvocationId` |
| `SV_InnerCoverage` | `BuiltIn FullyCoveredEXT` |
| `SV_InsideTessFactor` | `BuiltIn TessLevelInner` |
-| `SV_InstanceID`<sup>**</sup> | `BuiltIn InstanceIndex` |
+| `SV_InstanceID`<sup>**</sup> | `BuiltIn InstanceIndex` - `Builtin BaseInstance` |
| `SV_IntersectionAttributes` | *Not supported* |
| `SV_IsFrontFace` | `BuiltIn FrontFacing` |
| `SV_OutputControlPointID` | `BuiltIn InvocationId` |
@@ -88,20 +88,25 @@ The system-value semantics are translated to the following SPIR-V code.
| `SV_StencilRef` | `BuiltIn FragStencilRefEXT` |
| `SV_Target<N>` | `Location` |
| `SV_TessFactor` | `BuiltIn TessLevelOuter` |
-| `SV_VertexID` | `BuiltIn VertexIndex` |
+| `SV_VertexID`<sup>**</sup> | `BuiltIn VertexIndex` - `Builtin BaseVertex` |
| `SV_ViewID` | `BuiltIn ViewIndex` |
| `SV_ViewportArrayIndex` | `BuiltIn ViewportIndex` |
+| `SV_VulkanInstanceID` | `BuiltIn InstanceIndex` |
+| `SV_VulkanVertexID` | `BuiltIn VertexIndex` |
*Note* that `SV_DrawIndex`, `SV_PointSize` and `SV_PointCoord` are Slang-specific semantics that are not defined in HLSL.
-Also *Note* that `SV_InstanceID` counts all instances in a draw call, unlike how `InstanceIndex` is relative to `BaseInstance`. See [Using SV_InstanceID with SPIR-V target](#using-sv_instanceid-with-spir-v-target)
+Also *Note* that `SV_InstanceID`/`SV_VertexID` counts all instances/vertices in a draw call, unlike how `InstanceIndex`/`VertexIndex` is relative to `BaseInstance`/`BaseVertex`.
+See [Using SV_InstanceID/SV_VertexID with SPIR-V target](#using-sv_instanceid-and-sv_vertexid-with-spir-v-target)
-Using SV_InstanceID with SPIR-V target
+Using SV_InstanceID and SV_VertexID with SPIR-V target
--------------------------------------
-When using `SV_InstanceID` with SPIR-V target, it is equivalent to the difference between the `InstanceIndex` and `BaseInstance` builtins.
-This matches the behavior of D3D where `SV_InstanceID` starts from zero for each draw call, while in SPIR-V, `InstanceIndex` includes the base instance.
+When using `SV_InstanceID` and `SV_VertexID` with SPIR-V target, it is equivalent to the difference between the index and base builtins.
+This matches the behavior of D3D where `SV_InstanceID` and `SV_VertexID` starts from zero for each draw call, while in SPIR-V,
+`InstanceIndex` and `VertexIndex` includes the base instance.
-If you need direct access to the `InstanceIndex` value, you can use parameters with `SV_InstanceID` and `SV_StartInstanceLocation` semantics:
+If you need direct access to `InstanceIndex` and `VertexIndex` values, use `SV_VulkanInstanceID` and `SV_VulkanVertexID` semantic names. These are supported for all targets except HLSL.
+Alternatively you can use parameters with `SV_InstanceID`(or `SV_VertexID`) and `SV_StartInstanceLocation`(or `SV_StartVertexLocation`) semantics:
```slang
void myVertexShader(
diff --git a/docs/user-guide/a2-02-metal-target-specific.md b/docs/user-guide/a2-02-metal-target-specific.md
index 8d69a5975..c0360efda 100644
--- a/docs/user-guide/a2-02-metal-target-specific.md
+++ b/docs/user-guide/a2-02-metal-target-specific.md
@@ -44,6 +44,8 @@ The system-value semantics are translated to the following Metal attributes:
| `SV_ViewportArrayIndex` | `[[viewport_array_index]]` |
| `SV_StartVertexLocation` | `[[base_vertex]]` |
| `SV_StartInstanceLocation` | `[[base_instance]]` |
+| `SV_VulkanInstanceID` | `[[instance_id]]` |
+| `SV_VulkanVertexID` | `[[vertex_id]]` |
Custom semantics are mapped to user attributes:
diff --git a/docs/user-guide/a2-03-wgsl-target-specific.md b/docs/user-guide/a2-03-wgsl-target-specific.md
index cf28d4b49..e8a918dc8 100644
--- a/docs/user-guide/a2-03-wgsl-target-specific.md
+++ b/docs/user-guide/a2-03-wgsl-target-specific.md
@@ -50,6 +50,8 @@ The system-value semantics are translated to the following WGSL code.
| SV_VertexID | `@builtin(vertex_index)` |
| SV_ViewID | *Not supported* |
| SV_ViewportArrayIndex | *Not supported* |
+| SV_VulkanInstanceID | `@builtin(instance_index)` |
+| SV_VulkanVertexID | `@builtin(vertex_index)` |
Supported HLSL features when targeting WGSL
@@ -179,4 +181,4 @@ Translates to:
```wgsl
@id(7) override a : i32 = 2;
-``` \ No newline at end of file
+```
diff --git a/docs/user-guide/toc.html b/docs/user-guide/toc.html
index ace7da1d0..47e0c05ad 100644
--- a/docs/user-guide/toc.html
+++ b/docs/user-guide/toc.html
@@ -195,7 +195,7 @@
<li data-link="spirv-target-specific#memory-model"><span>Memory model</span></li>
<li data-link="spirv-target-specific#combined-texture-sampler"><span>Combined texture sampler</span></li>
<li data-link="spirv-target-specific#system-value-semantics"><span>System-Value semantics</span></li>
-<li data-link="spirv-target-specific#using-sv_instanceid-with-spir-v-target"><span>Using SV_InstanceID with SPIR-V target</span></li>
+<li data-link="spirv-target-specific#using-sv_instanceid-and-sv_vertexid-with-spir-v-target"><span>Using SV_InstanceID and SV_VertexID with SPIR-V target</span></li>
<li data-link="spirv-target-specific#behavior-of-discard-after-spir-v-16"><span>Behavior of `discard` after SPIR-V 1.6</span></li>
<li data-link="spirv-target-specific#supported-hlsl-features-when-targeting-spir-v"><span>Supported HLSL features when targeting SPIR-V</span></li>
<li data-link="spirv-target-specific#unsupported-glsl-keywords-when-targeting-spir-v"><span>Unsupported GLSL keywords when targeting SPIR-V</span></li>
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang
index 2d9078855..588396251 100644
--- a/source/slang/glsl.meta.slang
+++ b/source/slang/glsl.meta.slang
@@ -159,6 +159,9 @@ public property uint3 gl_WorkGroupSize
public in int gl_InvocationID : SV_GSInstanceID;
internal in int __sv_InstanceIndex : SV_InstanceID;
+internal in int __sv_VertexIndex : SV_VertexID;
+internal in int __sv_VulkanInstanceIndex : SV_VulkanInstanceID;
+internal in int __sv_VulkanVertexIndex : SV_VulkanVertexID;
// SPIRV InstanceIndex builtin for vertex shader
public property int gl_InstanceIndex
@@ -168,24 +171,42 @@ public property int gl_InstanceIndex
{
__target_switch
{
+ case glsl:
+ case spirv:
+ case metal:
+ case wgsl:
+ return __sv_VulkanInstanceIndex;
default:
return __sv_InstanceIndex;
+ }
+ }
+}
+
+// SPIRV VertexIndex builtin for vertex shader
+public property int gl_VertexIndex
+{
+ [require(vertex)]
+ get
+ {
+ __target_switch
+ {
case glsl:
- __intrinsic_asm "gl_InstanceIndex";
case spirv:
- return spirv_asm {
- result:$$int = OpLoad builtin(InstanceIndex:int);
- };
+ case metal:
+ case wgsl:
+ return __sv_VulkanVertexIndex;
+ default:
+ return __sv_VertexIndex;
}
}
}
+
public in bool gl_FrontFacing : SV_IsFrontFace;
// TODO: define overload for geometry stage.
public in int gl_Layer : SV_RenderTargetArrayIndex;
public in int gl_SampleID : SV_SampleIndex;
-public in int gl_VertexIndex : SV_VertexID;
public in int gl_ViewIndex : SV_ViewID;
public in int gl_ViewportIndex : SV_ViewportArrayIndex;
public in int gl_BaseVertex : SV_StartVertexLocation;
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index b2dc9b014..26b964d6e 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -351,6 +351,10 @@ String CLikeSourceEmitter::getTargetBuiltinVarName(IRInst* inst, IRTargetBuiltin
return "gl_InstanceIndex";
case IRTargetBuiltinVarName::SpvBaseInstance:
return "gl_BaseInstance";
+ case IRTargetBuiltinVarName::SpvVertexIndex:
+ return "gl_VertexIndex";
+ case IRTargetBuiltinVarName::SpvBaseVertex:
+ return "gl_BaseVertex";
}
if (auto linkage = inst->findDecoration<IRLinkageDecoration>())
return linkage->getMangledName();
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 5c1ccaf36..5dfa1c76c 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -5856,6 +5856,11 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
case IRTargetBuiltinVarName::SpvBaseInstance:
requireSPIRVCapability(SpvCapabilityDrawParameters);
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInBaseInstance, inst);
+ case IRTargetBuiltinVarName::SpvVertexIndex:
+ return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInVertexIndex, inst);
+ case IRTargetBuiltinVarName::SpvBaseVertex:
+ requireSPIRVCapability(SpvCapabilityDrawParameters);
+ return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInBaseVertex, inst);
}
}
if (auto layout = getVarLayout(inst))
@@ -5948,7 +5953,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
{
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInInvocationId, inst);
}
- else if (semanticName == "sv_instanceid")
+ else if (semanticName == "sv_vulkaninstanceid")
{
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInInstanceIndex, inst);
}
@@ -6046,7 +6051,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
requireSPIRVCapability(SpvCapabilityTessellation);
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInTessLevelInner, inst);
}
- else if (semanticName == "sv_vertexid")
+ else if (semanticName == "sv_vulkanvertexid")
{
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInVertexIndex, inst);
}
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index 1223ea91c..c9791880f 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -630,6 +630,13 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
context->requireGLSLVersion(ProfileVersion::GLSL_460);
context->requireGLSLExtension(toSlice("GL_ARB_shader_draw_parameters"));
}
+ else if (semanticName == "sv_vulkaninstanceid")
+ {
+ // https://docs.microsoft.com/en-us/windows/desktop/direct3d11/d3d10-graphics-programming-guide-input-assembler-stage-using#instanceid
+ // uint in hlsl, int in glsl
+ requiredType = builder->getBasicType(BaseType::Int);
+ name = "gl_InstanceIndex";
+ }
else if (semanticName == "sv_isfrontface")
{
// bool in hlsl & glsl
@@ -778,6 +785,16 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
// uint in hlsl, int in glsl (https://www.khronos.org/opengl/wiki/Built-in_Variable_(GLSL))
requiredType = builder->getBasicType(BaseType::Int);
name = "gl_VertexIndex";
+ targetVarName = IRTargetBuiltinVarName::HlslVertexID;
+ context->requireSPIRVVersion(SemanticVersion(1, 3));
+ context->requireGLSLVersion(ProfileVersion::GLSL_460);
+ context->requireGLSLExtension(toSlice("GL_ARB_shader_draw_parameters"));
+ }
+ else if (semanticName == "sv_vulkanvertexid")
+ {
+ // uint in hlsl, int in glsl (https://www.khronos.org/opengl/wiki/Built-in_Variable_(GLSL))
+ requiredType = builder->getBasicType(BaseType::Int);
+ name = "gl_VertexIndex";
}
else if (semanticName == "sv_viewid")
{
@@ -1251,6 +1268,12 @@ void invokePathConstantFuncInHullShader(
fixUpFuncType(constantFunc);
}
+static bool targetBuiltinRequiresLegalization(IRTargetBuiltinVarName builtinVarName)
+{
+ return (builtinVarName == IRTargetBuiltinVarName::HlslInstanceID) ||
+ (builtinVarName == IRTargetBuiltinVarName::HlslVertexID);
+}
+
ScalarizedVal createSimpleGLSLGlobalVarying(
GLSLLegalizationContext* context,
CodeGenContext* codeGenContext,
@@ -1284,7 +1307,7 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
// Validate the system value, convert to a regular parameter if this is not a valid system
// value for a given target.
if (systemSemantic && systemValueInfo && isSPIRV(codeGenContext->getTargetFormat()) &&
- systemValueInfo->targetVarName == IRTargetBuiltinVarName::HlslInstanceID &&
+ targetBuiltinRequiresLegalization(systemValueInfo->targetVarName) &&
((stage == Stage::Fragment) ||
(stage == Stage::Vertex &&
inVarLayout->usesResourceKind(LayoutResourceKind::VaryingOutput))))
@@ -3918,12 +3941,13 @@ ScalarizedVal legalizeEntryPointReturnValueForGLSL(
return result;
}
+
void legalizeTargetBuiltinVar(GLSLLegalizationContext& context)
{
List<KeyValuePair<IRTargetBuiltinVarName, IRInst*>> workItems;
for (auto [builtinVarName, varInst] : context.builtinVarMap)
{
- if (builtinVarName == IRTargetBuiltinVarName::HlslInstanceID)
+ if (targetBuiltinRequiresLegalization(builtinVarName))
{
workItems.add(KeyValuePair(builtinVarName, varInst));
}
@@ -3970,6 +3994,32 @@ void legalizeTargetBuiltinVar(GLSLLegalizationContext& context)
}
});
}
+ // Repalce SV_VertexID with gl_VertexIndex - gl_BaseVertex.
+ else if (builtinVarName == IRTargetBuiltinVarName::HlslVertexID)
+ {
+ auto vertexIndex = getOrCreateBuiltinVar(
+ IRTargetBuiltinVarName::SpvVertexIndex,
+ varInst->getDataType());
+ auto baseVertex = getOrCreateBuiltinVar(
+ IRTargetBuiltinVarName::SpvBaseVertex,
+ varInst->getDataType());
+ traverseUses(
+ varInst,
+ [&](IRUse* use)
+ {
+ auto user = use->getUser();
+ if (user->getOp() == kIROp_Load)
+ {
+ IRBuilder builder(use->getUser());
+ builder.setInsertBefore(use->getUser());
+ auto sub = builder.emitSub(
+ tryGetPointedToType(&builder, varInst->getDataType()),
+ builder.emitLoad(vertexIndex),
+ builder.emitLoad(baseVertex));
+ user->replaceUsesWith(sub);
+ }
+ });
+ }
}
}
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index c188b1eff..2ab4db980 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -203,8 +203,11 @@ enum class IRTargetBuiltinVarName
{
Unknown,
HlslInstanceID,
+ HlslVertexID,
SpvInstanceIndex,
SpvBaseInstance,
+ SpvVertexIndex,
+ SpvBaseVertex,
};
struct IRInterpolationModeDecoration : IRDecoration
diff --git a/source/slang/slang-ir-legalize-varying-params.cpp b/source/slang/slang-ir-legalize-varying-params.cpp
index 180d8eaa7..f8a9839d2 100644
--- a/source/slang/slang-ir-legalize-varying-params.cpp
+++ b/source/slang/slang-ir-legalize-varying-params.cpp
@@ -3189,6 +3189,7 @@ protected:
break;
}
case SystemValueSemanticName::InstanceID:
+ case SystemValueSemanticName::VulkanInstanceID:
{
result.systemValueName = toSlice("instance_id");
result.permittedTypes.add(builder.getBasicType(BaseType::UInt));
@@ -3252,6 +3253,7 @@ protected:
break;
}
case SystemValueSemanticName::VertexID:
+ case SystemValueSemanticName::VulkanVertexID:
{
result.systemValueName = toSlice("vertex_id");
result.permittedTypes.add(builder.getBasicType(BaseType::UInt));
@@ -3855,6 +3857,7 @@ protected:
break;
case SystemValueSemanticName::InstanceID:
+ case SystemValueSemanticName::VulkanInstanceID:
{
result.systemValueName = toSlice("instance_index");
result.permittedTypes.add(builder.getUIntType());
@@ -3908,6 +3911,7 @@ protected:
}
case SystemValueSemanticName::VertexID:
+ case SystemValueSemanticName::VulkanVertexID:
{
result.systemValueName = toSlice("vertex_index");
result.permittedTypes.add(builder.getUIntType());
diff --git a/source/slang/slang-ir-legalize-varying-params.h b/source/slang/slang-ir-legalize-varying-params.h
index 21674cd9e..233acaf94 100644
--- a/source/slang/slang-ir-legalize-varying-params.h
+++ b/source/slang/slang-ir-legalize-varying-params.h
@@ -72,6 +72,8 @@ void depointerizeInputParams(IRFunc* entryPoint);
M(WaveLaneCount, SV_WaveLaneCount) \
M(WaveLaneIndex, SV_WaveLaneIndex) \
M(QuadLaneIndex, SV_QuadLaneIndex) \
+ M(VulkanVertexID, SV_VulkanVertexID) \
+ M(VulkanInstanceID, SV_VulkanInstanceID) \
/* end */
/// A known system-value semantic name that can be applied to a parameter
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index 87a6cc4b9..20b7f795f 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -636,6 +636,8 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
{
case IRTargetBuiltinVarName::SpvInstanceIndex:
case IRTargetBuiltinVarName::SpvBaseInstance:
+ case IRTargetBuiltinVarName::SpvVertexIndex:
+ case IRTargetBuiltinVarName::SpvBaseVertex:
return AddressSpace::BuiltinInput;
}
}
diff --git a/tests/spirv/pointer-2.slang b/tests/spirv/pointer-2.slang
index 201d97001..1f2b2d0ea 100644
--- a/tests/spirv/pointer-2.slang
+++ b/tests/spirv/pointer-2.slang
@@ -44,7 +44,7 @@ ConstantBuffer<PushConstants> constantBuffer;
// CHECK_SPV_VIA_GLSL: OpTypePointer PhysicalStorageBuffer
[shader("vertex")]
-VSOutput vertexMain(int vertexIndex: SV_VertexID)
+VSOutput vertexMain(int vertexIndex: SV_VulkanVertexID)
{
//
// Test field access chains.
diff --git a/tests/spirv/sv-vertex-id.slang b/tests/spirv/sv-vertex-id.slang
new file mode 100644
index 000000000..c92f0351e
--- /dev/null
+++ b/tests/spirv/sv-vertex-id.slang
@@ -0,0 +1,16 @@
+//TEST:SIMPLE(filecheck=GLSL): -target glsl -entry vertMain -stage vertex
+//TEST:SIMPLE(filecheck=CHECK): -target spirv
+//TEST:SIMPLE(filecheck=CHECK): -target spirv -emit-spirv-via-glsl
+
+// CHECK-DAG: %[[BASE_VERTEX:[0-9]+|[a-zA-Z_][a-zA-Z0-9_]*]] = OpVariable {{.*}} BuiltIn BaseVertex
+// CHECK-DAG: %[[REG1:[0-9a-zA-Z_]+]] = OpLoad %int %[[BASE_VERTEX]]
+// CHECK-DAG: %[[REG2:[0-9a-zA-Z_]+]] = OpLoad %int %gl_VertexIndex
+// CHECK-DAG: OpISub %int %[[REG2]] %[[REG1]]
+
+// GLSL: gl_VertexIndex - gl_BaseVertex
+
+[shader("vertex")]
+float4 vertMain(int i : SV_VertexID) : SV_Position
+{
+ return i;
+}
diff --git a/tests/spirv/sv-vulkan-instance-vertex-id.slang b/tests/spirv/sv-vulkan-instance-vertex-id.slang
new file mode 100644
index 000000000..c8654c857
--- /dev/null
+++ b/tests/spirv/sv-vulkan-instance-vertex-id.slang
@@ -0,0 +1,42 @@
+//TEST:SIMPLE(filecheck=SPIRV): -entry main -stage vertex -target spirv -emit-spirv-directly
+//TEST:SIMPLE(filecheck=GLSL): -entry main -stage vertex -target glsl
+//TEST:SIMPLE(filecheck=METAL): -entry main -stage vertex -target metal
+//TEST:SIMPLE(filecheck=WGSL): -entry main -stage vertex -target wgsl
+
+struct VSInput
+{
+ uint vertexID : SV_VulkanVertexID;
+ uint instanceID : SV_VulkanInstanceID;
+};
+
+struct VSOutput
+{
+ float4 position : SV_POSITION;
+};
+
+[shader("vertex")]
+VSOutput main(VSInput input)
+{
+ VSOutput output;
+ output.position = float4(input.vertexID + input.instanceID);
+
+ // SPIRV-DAG: BuiltIn InstanceIndex
+ // SPIRV-DAG: BuiltIn VertexIndex
+ // SPIRV-NOT: BuiltIn BaseInstance
+ // SPIRV-NOT: BuiltIn BaseVertex
+
+ // GLSL-NOT: GL_ARB_shader_draw_parameters
+ // GLSL-DAG: gl_VertexIndex
+ // GLSL-NOT: gl_BaseVertex
+ // GLSL-DAG: gl_InstanceIndex
+ // GLSL-NOT: gl_BaseInstance
+
+ // METAL-DAG: vertex_id
+ // METAL-DAG: instance_id
+
+ // WGSL-DAG: vertex_index
+ // WGSL-DAG: instance_index
+
+ return output;
+}
+