Vulkan 高级着色语言对比
扩展
在 GLSL 中,需要使用 #extension
指令显式启用扩展。这在 HLSL 中是不需要的。编译器将根据着色器隐式选择合适的 SPIR-V 扩展。如果需要,可以使用 -fspv-extension
参数显式选择扩展。
数据类型
类型在 GLSL 和 HLSL 中的工作方式类似。但是,GLSL 例如具有显式的向量或矩阵类型,而 HLSL 使用基本类型。另一方面,HLSL 提供了高级类型功能,如 C++ 模板。本段包含一个基本摘要,并附带一些示例,以显示两种语言之间的类型差异。 |
GLSL | HLSL | 示例 |
---|---|---|
vecn |
floatn |
vec4 → float4 |
ivecn |
intn |
ivec3 -→ int3 |
matnxm 或简写 matn |
floatnxm |
mat4 → float4x4 |
类型转换的语法也不同
GLSL
mat4x3 mat = mat4x3(ubo.view);
HLSL
float4x3 mat = (float4x3)(ubo.view);
一个重要的区别:GLSL 中的矩阵是列主序的,而 HLSL 中的矩阵是行主序的。这会影响诸如矩阵构造之类的事情。 |
隐式 vk 命名空间
对于 DirectX 中不可用的 Vulkan 概念,已添加一个隐式命名空间,用于标记 Vulkan 特定功能。
SPIR-V 宏
当使用 DXC 将 HLSL 编译为 SPIR-V 时,可以使用 __spirv__
宏来表示 Vulkan 特定代码。如果 HLSL 着色器需要同时使用 Vulkan 和 D3D,这很有用
#ifdef __spirv__
[[vk::binding(0, 1)]]
#endif
ConstantBuffer<Node> node : register(b0, space1);
SPIR-V 内置函数
DXC 支持具有 GL_EXT_spirv_intrinsics
扩展的 SPIR-V 内置函数。这增加了对在 GLSL 中间嵌入任意 SPIR-V 的支持,以实现 DirectX 中不可用的功能。为此,向 vk
命名空间添加了新的关键字,用于映射 SPIR-V 操作码,包括 vk::ext_extension
、vk::ext_capability
、vk::ext_builtin_input
、vk::ext_execution_mode
和 vk::ext_instruction
。
在 HLSL 中使用模板导出 SPIR-V 扩展的示例
[[vk::ext_capability(/* StencilExportEXT */ 5013)]]
[[vk::ext_extension("SPV_EXT_shader_stencil_export")]]
vk::ext_execution_mode(/* StencilRefReplacingEXT */ 5027);
设置内置函数以访问光线追踪中顶点位置的示例
[[vk::ext_extension("SPV_KHR_ray_tracing_position_fetch")]]
[[vk::ext_capability(RayTracingPositionFetchKHR)]]
[[vk::ext_builtin_input(HitTriangleVertexPositionsKHR)]]
const static float3 gl_HitTriangleVertexPositions[3];
内置函数与语义
虽然 GLSL 大量使用内置于语言中的输入和输出变量(称为“内置变量”),但在 HLSL 中没有这样的概念。HLSL 而是使用语义,即附加到输入或包含有关该变量预期用途信息的字符串。它们以 |
示例
从顶点着色器写入位置
GLSL
layout (location = 0) in vec4 inPos;
void main() {
// The vertex output position is written to the gl_Position built-in
gl_Position = ubo.projectionMatrix * ubo.viewMatrix * ubo.modelMatrix * inPos.xyz;
}
HLSL
struct VSOutput
{
// The SV_POSITION semantic declares the Pos member as the vertex output position
float4 Pos : SV_POSITION;
};
VSOutput main(VSInput input)
{
VSOutput output = (VSOutput)0;
output.Pos = mul(ubo.projectionMatrix, mul(ubo.viewMatrix, mul(ubo.modelMatrix, input.Pos)));
return output;
}
读取顶点索引
GLSL
void main()
{
// The vertex index is stored in the gl_VertexIndex built-in
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
}
HLSL
struct VSInput
{
// The SV_VertexID semantic declares the VertexIndex member as the vertex index input
uint VertexIndex : SV_VertexID
};
VSOutput main(VSInput input)
{
VSOutput output = (VSOutput)0;
output.UV = float2((input.VertexIndex << 1) & 2, input.VertexIndex & 2);
return output;
}
着色器接口
GLSL 和 HLSL 之间的着色器接口差异很大。 |
描述符绑定
GLSL
layout (set = <set-index>, binding = <binding-index>) uniform <type> <name>
在使用 Vulkan 时,有两种选项可以在 HLSL 中定义描述符集和绑定索引。
HLSL 方式
<type> <name> : register(<register-type><binding-index>, space<set-index>)
使用此语法,描述符集和绑定索引将从集合和绑定索引隐式分配。
Vulkan 命名空间
[[vk::binding(binding-index, set-index)]]
<type> <name>
使用此选项,描述符集和绑定索引使用 vk::binding
显式设置。
可以对一个描述符同时使用 |
Uniform 变量
GLSL
layout (set = <set-index>, binding = <binding-index>) uniform <type> <name>
示例
// Uniform buffer
layout (set = 0, binding = 0) uniform UBO
{
mat4 projection;
} ubo;
// Combined image sampler
layout (set = 0, binding = 1) uniform sampler2D samplerColor;
HLSL
<type> <name> : register(<register-type><binding-index>, space<set-index>)
或
[[vk::binding(binding-index, set-index)]]
<type> <name>
示例
// Uniform buffer
struct UBO
{
float4x4 projection;
};
ConstantBuffer<UBO> ubo : register(b0, space0);
// Combined image sampler
Texture2D textureColor : register(t1);
SamplerState samplerColor : register(s1);
如果使用 HLSL 描述符绑定语法,则 <register type>
可以是
类型 | 寄存器描述 | Vulkan 资源 |
---|---|---|
b |
常量缓冲区 |
Uniform 缓冲区 |
t |
纹理和纹理缓冲区 |
Uniform 纹理元素缓冲区和只读着色器存储缓冲区 |
c |
缓冲区偏移 |
|
s |
采样器 |
相同 |
u |
无序访问视图 |
着色器存储缓冲区、存储图像和存储纹理元素缓冲区 |
着色器输入
GLSL
layout (location = <location-index>) in <type> <name>;
示例
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inUV0;
layout (location = 3) in vec2 inUV1;
HLSL
[[vk::location(<location-index>)]] <type> <name> : <semantic-type>;
示例
struct VSInput
{
[[vk::location(0)]] float3 Pos : POSITION;
[[vk::location(1)]] float3 Normal : NORMAL;
[[vk::location(2)]] float2 UV0 : TEXCOORD0;
[[vk::location(3)]] float2 UV1 : TEXCOORD1;
};
VSOutput main(VSInput input) {
}
<semantic type>
可以是
语义 | 描述 | 类型 |
---|---|---|
BINORMAL[n] |
副法线 |
float4 |
BLENDINDICES[n] |
混合索引 |
uint |
BLENDWEIGHT[n] |
混合权重 |
float |
COLOR[n] |
漫反射和镜面反射颜色 |
float4 |
NORMAL[n] |
法线向量 |
float4 |
POSITION[n] |
对象空间中的顶点位置。 |
float4 |
POSITIONT |
转换后的顶点位置 |
float4 |
PSIZE[n] |
点大小 |
float |
TANGENT[n] |
切线 |
float4 |
TEXCOORD[n] |
纹理坐标 |
float4 |
n
是一个可选整数,介于 0 和支持的资源数量之间。(来源)
着色器输出
在阶段之间传递数据
例如,对于顶点着色器和细分着色器。
GLSL
layout (location = <location-index>) out/in <type> <name>;
示例
layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor;
layout (location = 2) out vec2 outUV;
layout (location = 3) out vec3 outViewVec;
void main() {
gl_Position = vec4(inPos, 1.0);
outNormal = inNormal;
}
HLSL
[[vk::location(<location-index>)]] <type> <name> : <semantic-type>;
示例
struct VSOutput
{
float4 Pos : SV_POSITION;
[[vk::location(0)]] float3 Normal : NORMAL;
[[vk::location(1)]] float3 Color : COLOR;
[[vk::location(2)]] float2 UV : TEXCOORD0;
[[vk::location(3)]] float3 ViewVec : TEXCOORD1;
}
VSOutput main(VSInput input) {
VSOutput output = (VSOutput)0;
output.Pos = float4(input.Pos.xyz, 1.0);
output.Normal = input.Normal;
return output;
}
推送常量
推送常量必须通过 D3D 中的根签名来处理。 |
特化常量
特化常量仅在 Vulkan 中可用,D3D 不提供任何类似的东西。 |
子过程
纹理读取
当 GLSL 使用全局函数访问图像时,HLSL 使用纹理对象的成员函数。 |
示例
GLSL
layout (binding = 0, set = 0) uniform sampler2D sampler0;
void main() {
vec4 color = texture(sampler0, inUV);
}
HLSL
Texture2D texture0 : register(t0, space0);
SamplerState sampler0 : register(s0, space0);
float4 main(VSOutput input) : SV_TARGET {
float4 color = texture0.Sample(sampler0, input.UV);
}
GLSL | HLSL |
---|---|
texture |
Sample |
textureGrad |
SampleGrad |
textureLod |
SampleLevel |
textureSize |
GetDimensions |
textureProj |
不适用,需要手动透视除法 |
texelFetch |
Load |
sparseTexelsResidentARB |
CheckAccessFullyMapped |
内置变量和函数映射
缓冲区设备地址
目前,HLSL 仅支持 |
光线追踪
着色器阶段选择
当 GLSL 通过文件扩展名(或通过编译器参数显式)隐式检测着色器阶段(用于光线追踪)时,对于 HLSL 光线追踪着色器,需要使用 [shader("stage")]
语义进行标记
示例
[shader("closesthit")]
void main(inout RayPayload rayPayload, in float2 attribs) {
}
阶段名称与 GLSL 匹配:raygeneration
、intersection
、anyhit
、closesthit
、miss
、callable
内置变量
GLSL | HLSL | 注意 |
---|---|---|
accelerationStructureEXT |
RaytracingAccelerationStructure |
|
executeCallableEXT |
CallShader |
|
ignoreIntersectionEXT |
IgnoreHit |
|
reportIntersectionEXT |
ReportHit |
|
terminateRayEXT |
AcceptHitAndEndSearch |
|
traceRayEXT |
TraceRay |
|
rayPayloadEXT (存储限定符) |
TraceRay 的最后一个参数 |
|
rayPayloadInEXT (存储限定符) |
任何命中、最近命中和未命中阶段的主要入口的第一个参数 |
|
hitAttributeEXT (存储限定符) |
ReportHit 的最后一个参数 |
|
callableDataEXT (存储限定符) |
CallShader 的最后一个参数 |
|
callableDataInEXT (存储限定符) |
可调用阶段的主要入口的第一个参数 |
|
gl_LaunchIDEXT |
DispatchRaysIndex |
|
gl_LaunchSizeEXT |
DispatchRaysDimensions |
|
gl_PrimitiveID |
PrimitiveIndex |
|
gl_InstanceID |
InstanceIndex |
|
gl_InstanceCustomIndexEXT |
InstanceID |
|
gl_GeometryIndexEXT |
GeometryIndex |
|
gl_VertexIndex |
SV_VertexID |
|
gl_WorldRayOriginEXT |
WorldRayOrigin |
|
gl_WorldRayDirectionEXT |
WorldRayDirection |
|
gl_ObjectRayOriginEXT |
ObjectRayOrigin |
|
gl_ObjectRayDirectionEXT |
ObjectRayDirection |
|
gl_RayTminEXT |
RayTMin |
|
gl_RayTmaxEXT |
RayTCurrent |
|
gl_IncomingRayFlagsEXT |
RayFlags |
|
gl_HitTEXT |
RayTCurrent |
|
gl_HitKindEXT |
HitKind |
|
gl_ObjectToWorldEXT |
ObjectToWorld4x3 |
|
gl_WorldToObjectEXT |
WorldToObject4x3 |
|
gl_WorldToObject3x4EXT |
WorldToObject3x4 |
|
gl_ObjectToWorld3x4EXT |
ObjectToWorld3x4 |
|
gl_RayFlagsNoneEXT |
RAY_FLAG_NONE |
|
gl_RayFlagsOpaqueEXT |
RAY_FLAG_FORCE_OPAQUE |
|
gl_RayFlagsNoOpaqueEXT |
AY_FLAG_FORCE_NON_OPAQUE |
|
gl_RayFlagsTerminateOnFirstHitEXT |
RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH |
|
gl_RayFlagsSkipClosestHitShaderEXT |
RAY_FLAG_SKIP_CLOSEST_HIT_SHADER |
|
gl_RayFlagsCullBackFacingTrianglesEXT |
RAY_FLAG_CULL_BACK_FACING_TRIANGLES |
|
gl_RayFlagsCullFrontFacingTrianglesEXT |
RAY_FLAG_CULL_FRONT_FACING_TRIANGLES |
|
gl_RayFlagsCullOpaqueEXT |
RAY_FLAG_CULL_OPAQUE |
|
gl_RayFlagsCullNoOpaqueEXT |
RAY_FLAG_CULL_NON_OPAQUE |
需要 |
gl_RayFlagsSkipTrianglesEXT |
RAY_FLAG_SKIP_TRIANGLES |
需要 |
gl_RayFlagsSkipAABBEXT |
RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |
|
gl_HitKindFrontFacingTriangleEXT |
HIT_KIND_TRIANGLE_FRONT_FACE |
|
gl_HitKindBackFacingTriangleEXT |
HIT_KIND_TRIANGLE_BACK_FACE |
|
gl_HitTriangleVertexPositionsEXT |
需要 SPIR-V 内置函数
|
需要 |
计算
本地工作组大小
内置变量
GLSL | HLSL |
---|---|
gl_GlobalInvocationID |
SV_DispatchThreadID |
gl_LocalInvocationID |
SV_GroupThreadID |
gl_WorkGroupID |
SV_GroupID |
gl_LocalInvocationIndex |
SV_GroupIndex |
gl_NumWorkGroups |
不适用 |
gl_WorkGroupSize |
不适用 |
屏障
GLSL 和 HLSL 之间的屏障差异很大。除一个例外,没有直接的映射。要在 GLSL 中匹配 HLSL,通常需要在 glsl 中调用多个不同的屏障类型。 |
示例
GLSL
groupMemoryBarrier();
barrier();
for (int j = 0; j < 256; j++) {
doSomething;
}
groupMemoryBarrier();
barrier();
HLSL
GroupMemoryBarrierWithGroupSync();
for (int j = 0; j < 256; j++) {
doSomething;
}
GroupMemoryBarrierWithGroupSync();
GLSL |
HLSL |
groupMemoryBarrier |
GroupMemoryBarrier |
groupMemoryBarrier + barrier |
GroupMemoryBarrierWithGroupSync |
memoryBarrier + memoryBarrierImage + memoryBarrierImage |
DeviceMemoryBarrier |
memoryBarrier + memoryBarrierImage + memoryBarrierImage + barrier |
DeviceMemoryBarrierWithGroupSync |
以上所有屏障 + barrier |
AllMemoryBarrierWithGroupSync |
以上所有屏障 |
AllMemoryBarrier |
memoryBarrierShared(仅限) |
不适用 |
网格、任务(放大)和几何着色器
这些着色器阶段共享多个函数和内置变量
GLSL | HLSL |
---|---|
EmitMeshTasksEXT |
DispatchMesh |
SetMeshOutputsEXT |
SetMeshOutputCounts |
EmitVertex |
StreamType<Name>.Append(例如,{TriangleStream<MSOutput>}) |
EndPrimitive |
StreamType<Name>.RestartStrip |
gl_PrimitiveShadingRateEXT |
SV_ShadingRate |
gl_CullPrimitiveEXT |
SV_CullPrimitive |
gl_in |
主入口的数组参数(例如,{triangle VSInput input[3]}) |
细分着色器
GLSL | HLSL |
---|---|
gl_InvocationID |
SV_OutputControlPointID |
gl_TessLevelInner |
SV_InsideTessFactor |
gl_TessLevelOuter |
SV_TessFactor |
gl_TessCoord |
SV_DomainLocation |
子组
GLSL | HLSL |
---|---|
gl_HelperInvocation |
WaveIsHelperLane |
不适用 |
WaveOnce |
readFirstInvocationARB |
WaveReadFirstLane |
readInvocationARB |
WaveReadLaneAt |
anyInvocationARB |
WaveAnyTrue |
allInvocationsARB |
WaveAllTrue |
allInvocationsEqualARB |
WaveAllEqual |
ballotARB |
WaveBallot |
gl_NumSubgroups |
NumSubgroups 修饰的 OpVariable |
gl_SubgroupID |
SubgroupId 修饰的 OpVariable |
gl_SubgroupSize |
WaveGetLaneCount |
gl_SubgroupInvocationID |
WaveGetLaneIndex |
gl_SubgroupEqMask |
不适用 |
gl_SubgroupGeMask |
不适用 |
gl_SubgroupGtMask |
不适用 |
gl_SubgroupLeMask |
不适用 |
gl_SubgroupLtMask |
SubgroupLtMask 修饰的 OpVariable |
subgroupElect |
WaveIsFirstLane |
subgroupAny |
WaveActiveAnyTrue |
subgroupAll |
WaveActiveAllTrue |
subgroupBallot |
WaveActiveBallot |
subgroupAllEqual |
WaveActiveAllEqual |
subgroupBallotBitCount |
WaveActiveCountBits |
subgroupAnd |
WaveActiveBitAdd |
subgroupOr |
WaveActiveBitOr |
subgroupXor |
WaveActiveBitXor |
subgroupAdd |
WaveActiveSum |
subgroupMul |
WaveActiveProduct |
subgroupMin |
WaveActiveMin |
subgroupMax |
WaveActiveMax |
subgroupExclusiveAdd |
WavePrefixSum |
subgroupExclusiveMul |
WavePrefixProduct |
subgroupBallotExclusiveBitCount |
WavePrefixCountBits |
subgroupBroadcast |
WaveReadLaneAt |
subgroupBroadcastFirst |
WaveReadLaneFirst |
subgroupQuadSwapHorizontal |
QuadReadAcrossX |
subgroupQuadSwapVertical |
QuadReadAcrossY |
subgroupQuadSwapDiagonal |
QuadReadAcrossDiagonal |
subgroupQuadBroadcast |
QuadReadLaneAt |
其他
GLSL | HLSL | 注意 |
---|---|---|
gl_PointSize |
[[vk::builtin("PointSize")]] |
仅限 Vulkan,没有直接的 HLSL 等效项 |
gl_BaseVertexARB |
[[vk::builtin("BaseVertex")]] |
仅限 Vulkan,没有直接的 HLSL 等效项 |
gl_BaseInstanceARB |
[[vk::builtin("BaseInstance")]] |
仅限 Vulkan,没有直接的 HLSL 等效项 |
gl_DrawID |
[[vk::builtin("DrawIndex")]] |
仅限 Vulkan,没有直接的 HLSL 等效项 |
gl_DeviceIndex |
[[vk::builtin("DeviceIndex")]] |
仅限 Vulkan,没有直接的 HLSL 等效项 |
gl_ViewportMask |
[[vk::builtin("ViewportMaskNV")]] |
仅限 Vulkan,没有直接的 HLSL 等效项 |
gl_FragCoord |
SV_Position |
|
gl_FragDepth |
SV_Depth |
|
gl_FrontFacing |
SV_IsFrontFace |
|
gl_InstanceIndex |
SV_InstanceID |
|
gl_ViewIndex |
SV_ViewID |
|
gl_ClipDistance |
SV_ClipDistance |
|
gl_CullDistance |
SV_CullDistance |
|
gl_PointCoord |
SV_Position |
|
gl_Position |
SV_Position |
|
gl_PrimitiveID |
SV_PrimitiveID |
|
gl_ViewportIndex |
SV_ViewportArrayIndex |
|
gl_Layer |
SV_RenderTargetArrayIndex |
|
gl_SampleID |
SV_SampleIndex |
|
gl_SamplePosition |
EvaluateAttributeAtSample |
|
subpassLoad |
<SubPassInput>.SubpassLoad |
|
imageLoad |
RWTexture1D/2D/3D<T>[] |
|
imageStore |
RWTexture1D/2D/3D<T>[] |
|
atomicAdd |
InterlockedAdd |
|
atomicCompSwap |
InterlockedCompareExchange |
|
imageAtomicExchange |
InterlockedExchange |
|
nonuniformEXT |
NonUniformResourceIndex |
|
gl_BaryCoordEXT |
SV_Barycentrics |
|
gl_BaryCoordNoPerspEXT |
带有 noperspective 的 SV_Barycentrics |