Mapping_between_HLSL_and_GLSL
(2022-06-04 11:06:10)
标签:
it |
分类: 技术 |
It's 2016 and we're still stuck with various shading languages
- the current contenders being HLSL for Direct3D, and GLSL for
OpenGL and as the “default” front-end language to generate SPIR-V
for Vulkan. SPIR-V may become eventually the IL of choice for
everything, but that will take a while, so right now, you need to
convert HLSL to GLSL or vice versa if you want to target both
APIs.
I won't dig into the various cross-compilers today - that's a
huge topic - and focus on the language similarities instead. Did
you ever ask yourself how your SV_Position input is called in GLSL?
Then this post is for you!
Note
This is by no means complete. It's meant as a starting point
when you're looking to port some shaders between GLSL to HLSL. I’m
omitting functions which are the same for instance.
System values & built-in inputs
Direct3D specifies a couple of system values, GLSL has the
concept of built-in variables. The mapping is as following:
HLSL GLSL
SV_ClipDistance gl_ClipDistance
SV_CullDistance gl_CullDistance if ARB_cull_distance is
present
SV_Coverage gl_SampleMaskIn & gl_SampleMask
SV_Depth gl_FragDepth
SV_DepthGreaterEqual layout (depth_greater) out float
gl_FragDepth;
SV_DepthLessEqual layout (depth_less) out float
gl_FragDepth;
SV_DispatchThreadID gl_GlobalInvocationID
SV_DomainLocation gl_TessCord
SV_GroupID gl_WorkGroupID
SV_GroupIndex gl_LocalInvocationIndex
SV_GroupThreadID gl_LocalInvocationID
SV_GSInstanceID gl_InvocationID
SV_InsideTessFactor gl_TessLevelInner
SV_InstanceID gl_InstanceID & gl_InstanceIndex (latter in
Vulkan with different semantics)
SV_IsFrontFace gl_FrontFacing
SV_OutputControlPointID gl_InvocationID
N/A gl_PatchVerticesIn
SV_Position gl_Position in a vertex shader, gl_FragCoord in a
fragment shader
SV_PrimitiveID gl_PrimitiveID
SV_RenderTargetArrayIndex gl_Layer
SV_SampleIndex gl_SampleID
The equivalent functionality is available through
EvaluateAttributeAtSample gl_SamplePosition
SV_StencilRef gl_FragStencilRef if ARB_shader_stencil_export
is present
SV_Target layout(location=N) out your_var_name;
SV_TessFactor gl_TessLevelOuter
SV_VertexID gl_VertexID & gl_VertexIndex (latter Vulkan
with different semantics)
SV_ViewportArrayIndex gl_ViewportIndex
This table is sourced from the OpenGL wiki, the HLSL semantic
documentation and the GL_KHR_vulkan_glsl extension
specification.
Atomic operations
These map fairly easily. Interlocked becomes atomic. So
InterlockedAdd becomes atomicAdd, and so on. The only difference is
InterlockedCompareExchange which turns into atomicCompSwap.
Shared/local memory
groupshared memory in HLSL is shared memory in GLSL. That's
it.
Barriers
HLSL GLSL
GroupMemoryBarrierWithGroupSync groupMemoryBarrier and
barrier
GroupMemoryBarrier groupMemoryBarrier
DeviceMemoryBarrierWithGroupSync memoryBarrier,
memoryBarrierImage, memoryBarrierImage and barrier
DeviceMemoryBarrier memoryBarrier, memoryBarrierImage,
memoryBarrierImage
AllMemoryBarrierWithGroupSync All of the barriers above and
barrier
AllMemoryBarrier All of the barriers above
N/A memoryBarrierShared
Texture access
Before Vulkan, this is bundled and not trivial to emulate.
Fortunately, this changes with Vulkan, where the semantics are the
same as in HLSL. The main difference is that in HLSL, the access
method is part of the “texture object”, while in GLSL, they are
free functions. In HLSL, you’ll sample a texture called Texture
with a sampler called Sampler like this:
Texture.Sample (Sampler, coordinate)
In GLSL, you need to specify the type of the texture and the
sampler, but otherwise, it's similar:
texture (sampler2D(Texture, Sampler), coordinate)
HLSL GLSL
CalculateLevelOfDetail & CalculateLevelOfDetailUnclamped
textureQueryLod
Load texelFetch and texelFetchOffset
GetDimensions textureSize, textureQueryLevels and
textureSamples
Gather textureGather, textureGatherOffset,
textureGatherOffsets
Sample, SampleBias texture, textureOffset
SampleCmp samplerShadow
SampleGrad textureGrad, textureGradOffset
SampleLevel textureLod, textureLodOffset
N/A textureProj
General math
GLSL and HLSL differ in their default matrix interpretation.
GLSL assumes column-major, and multiplication on the right (that
is, you apply M * vM∗v) and HLSL assumes multiplication from left
(v * Mv∗M) While you can usually ignore that - you can override the
order, and multiply from whatever side you want in both - it does
change the meaning of m[0] with m being a matrix. In HLSL, this
will return the first row, in GLSL, the first column. That also
extends to the constructors, which initialize the members in the
“natural” order.
Various functions
HLSL GLSL
atan2(y,x) atan
ddx dFdx
ddx_coarse dFdxCoarse
ddx_fine dFdxFine
ddy dFdy
ddy_coarse dFdyCoarse
ddy_fine dFdyFine
EvaluateAttributeAtCentroid interpolateAtCentroid
EvaluateAttributeAtSample interpolateAtSample
EvaluateAttributeSnapped interpolateAtOffset
frac fract
lerp mix
mad fma
saturate clamp(x, 0.0, 1.0)
前一篇:十年
后一篇:人生缘何不快乐,只因未读苏东坡