Add --hlsl-dx-position-w option

This reciprocates the w component of SV_Position in HLSL fragment shaders
to provide DirectX compatibility for HLSL shaders in Vulkan.

Fixes #2244
This commit is contained in:
Greg Fischer 2021-11-16 18:42:12 -07:00
parent 8a7860e4cb
commit e9564feb55
9 changed files with 323 additions and 2 deletions

View File

@ -177,6 +177,7 @@ const char* shaderStageName = nullptr;
const char* variableName = nullptr;
bool HlslEnable16BitTypes = false;
bool HlslDX9compatible = false;
bool HlslDxPositionW = false;
bool DumpBuiltinSymbols = false;
std::vector<std::string> IncludeDirectoryList;
@ -662,6 +663,8 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
HlslEnable16BitTypes = true;
} else if (lowerword == "hlsl-dx9-compatible") {
HlslDX9compatible = true;
} else if (lowerword == "hlsl-dx-position-w") {
HlslDxPositionW = true;
} else if (lowerword == "auto-sampled-textures") {
autoSampledTextures = true;
} else if (lowerword == "invert-y" || // synonyms
@ -1284,6 +1287,9 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
if (Options & EOptionInvertY)
shader->setInvertY(true);
if (HlslDxPositionW)
shader->setDxPositionW(true);
// Set up the environment, some subsettings take precedence over earlier
// ways of setting things.
if (Options & EOptionSpv) {
@ -1847,6 +1853,8 @@ void usage()
" --hlsl-dx9-compatible interprets sampler declarations as a\n"
" texture/sampler combo like DirectX9 would,\n"
" and recognizes DirectX9-specific semantics\n"
" --hlsl-dx-position-w W component of SV_Position in HLSL fragment\n"
" shaders compatible with DirectX\n"
" --invert-y | --iy invert position.Y output in vertex shader\n"
" --keep-uncalled | --ku don't eliminate uncalled functions\n"
" --nan-clamp favor non-NaN operand in min, max, and clamp\n"

View File

@ -0,0 +1,268 @@
hlsl.w-recip.frag
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:5 Function Definition: @main(vf4; ( temp 4-component vector of float)
0:5 Function Parameters:
0:5 'vpos' ( in 4-component vector of float)
0:? Sequence
0:6 Sequence
0:6 move second child to first child ( temp 4-component vector of float)
0:6 'vpos_t' ( temp 4-component vector of float)
0:6 Construct vec4 ( temp 4-component vector of float)
0:6 vector swizzle ( temp 3-component vector of float)
0:6 'vpos' ( in 4-component vector of float)
0:6 Sequence
0:6 Constant:
0:6 0 (const int)
0:6 Constant:
0:6 1 (const int)
0:6 Constant:
0:6 2 (const int)
0:6 divide ( temp float)
0:6 Constant:
0:6 1.000000
0:6 direct index ( temp float)
0:6 'vpos' ( in 4-component vector of float)
0:6 Constant:
0:6 3 (const int)
0:7 Test condition and select ( temp void)
0:7 Condition
0:7 Compare Less Than ( temp bool)
0:7 direct index ( temp float)
0:7 'vpos_t' ( temp 4-component vector of float)
0:7 Constant:
0:7 0 (const int)
0:7 Constant:
0:7 400.000000
0:7 true case
0:8 Branch: Return with expression
0:8 AmbientColor: direct index for structure ( uniform 4-component vector of float)
0:8 'anon@0' (layout( row_major std140) uniform block{ uniform 4-component vector of float AmbientColor, uniform 4-component vector of float AmbientColor2})
0:8 Constant:
0:8 0 (const uint)
0:7 false case
0:10 Branch: Return with expression
0:10 AmbientColor2: direct index for structure ( uniform 4-component vector of float)
0:10 'anon@0' (layout( row_major std140) uniform block{ uniform 4-component vector of float AmbientColor, uniform 4-component vector of float AmbientColor2})
0:10 Constant:
0:10 1 (const uint)
0:5 Function Definition: main( ( temp void)
0:5 Function Parameters:
0:? Sequence
0:5 move second child to first child ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:5 Construct vec4 ( temp 4-component vector of float)
0:5 vector swizzle ( temp 3-component vector of float)
0:? 'vpos' ( in 4-component vector of float FragCoord)
0:5 Sequence
0:5 Constant:
0:5 0 (const int)
0:5 Constant:
0:5 1 (const int)
0:5 Constant:
0:5 2 (const int)
0:5 divide ( temp float)
0:5 Constant:
0:5 1.000000
0:5 direct index ( temp float)
0:? 'vpos' ( in 4-component vector of float FragCoord)
0:5 Constant:
0:5 3 (const int)
0:5 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:5 Function Call: @main(vf4; ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? Linker Objects
0:? 'anon@0' (layout( row_major std140) uniform block{ uniform 4-component vector of float AmbientColor, uniform 4-component vector of float AmbientColor2})
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'vpos' ( in 4-component vector of float FragCoord)
Linked fragment stage:
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:5 Function Definition: @main(vf4; ( temp 4-component vector of float)
0:5 Function Parameters:
0:5 'vpos' ( in 4-component vector of float)
0:? Sequence
0:6 Sequence
0:6 move second child to first child ( temp 4-component vector of float)
0:6 'vpos_t' ( temp 4-component vector of float)
0:6 Construct vec4 ( temp 4-component vector of float)
0:6 vector swizzle ( temp 3-component vector of float)
0:6 'vpos' ( in 4-component vector of float)
0:6 Sequence
0:6 Constant:
0:6 0 (const int)
0:6 Constant:
0:6 1 (const int)
0:6 Constant:
0:6 2 (const int)
0:6 divide ( temp float)
0:6 Constant:
0:6 1.000000
0:6 direct index ( temp float)
0:6 'vpos' ( in 4-component vector of float)
0:6 Constant:
0:6 3 (const int)
0:7 Test condition and select ( temp void)
0:7 Condition
0:7 Compare Less Than ( temp bool)
0:7 direct index ( temp float)
0:7 'vpos_t' ( temp 4-component vector of float)
0:7 Constant:
0:7 0 (const int)
0:7 Constant:
0:7 400.000000
0:7 true case
0:8 Branch: Return with expression
0:8 AmbientColor: direct index for structure ( uniform 4-component vector of float)
0:8 'anon@0' (layout( row_major std140) uniform block{ uniform 4-component vector of float AmbientColor, uniform 4-component vector of float AmbientColor2})
0:8 Constant:
0:8 0 (const uint)
0:7 false case
0:10 Branch: Return with expression
0:10 AmbientColor2: direct index for structure ( uniform 4-component vector of float)
0:10 'anon@0' (layout( row_major std140) uniform block{ uniform 4-component vector of float AmbientColor, uniform 4-component vector of float AmbientColor2})
0:10 Constant:
0:10 1 (const uint)
0:5 Function Definition: main( ( temp void)
0:5 Function Parameters:
0:? Sequence
0:5 move second child to first child ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:5 Construct vec4 ( temp 4-component vector of float)
0:5 vector swizzle ( temp 3-component vector of float)
0:? 'vpos' ( in 4-component vector of float FragCoord)
0:5 Sequence
0:5 Constant:
0:5 0 (const int)
0:5 Constant:
0:5 1 (const int)
0:5 Constant:
0:5 2 (const int)
0:5 divide ( temp float)
0:5 Constant:
0:5 1.000000
0:5 direct index ( temp float)
0:? 'vpos' ( in 4-component vector of float FragCoord)
0:5 Constant:
0:5 3 (const int)
0:5 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:5 Function Call: @main(vf4; ( temp 4-component vector of float)
0:? 'vpos' ( temp 4-component vector of float)
0:? Linker Objects
0:? 'anon@0' (layout( row_major std140) uniform block{ uniform 4-component vector of float AmbientColor, uniform 4-component vector of float AmbientColor2})
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'vpos' ( in 4-component vector of float FragCoord)
// Module Version 10000
// Generated by (magic number): 8000a
// Id's are bound by 69
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 53 65
ExecutionMode 4 OriginUpperLeft
Source HLSL 500
Name 4 "main"
Name 11 "@main(vf4;"
Name 10 "vpos"
Name 13 "vpos_t"
Name 36 "$Global"
MemberName 36($Global) 0 "AmbientColor"
MemberName 36($Global) 1 "AmbientColor2"
Name 38 ""
Name 51 "vpos"
Name 53 "vpos"
Name 65 "@entryPointOutput"
Name 66 "param"
MemberDecorate 36($Global) 0 Offset 0
MemberDecorate 36($Global) 1 Offset 16
Decorate 36($Global) Block
Decorate 38 DescriptorSet 0
Decorate 38 Binding 0
Decorate 53(vpos) BuiltIn FragCoord
Decorate 65(@entryPointOutput) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 4
8: TypePointer Function 7(fvec4)
9: TypeFunction 7(fvec4) 8(ptr)
14: TypeVector 6(float) 3
17: 6(float) Constant 1065353216
18: TypeInt 32 0
19: 18(int) Constant 3
20: TypePointer Function 6(float)
28: 18(int) Constant 0
31: 6(float) Constant 1137180672
32: TypeBool
36($Global): TypeStruct 7(fvec4) 7(fvec4)
37: TypePointer Uniform 36($Global)
38: 37(ptr) Variable Uniform
39: TypeInt 32 1
40: 39(int) Constant 0
41: TypePointer Uniform 7(fvec4)
46: 39(int) Constant 1
52: TypePointer Input 7(fvec4)
53(vpos): 52(ptr) Variable Input
56: TypePointer Input 6(float)
64: TypePointer Output 7(fvec4)
65(@entryPointOutput): 64(ptr) Variable Output
4(main): 2 Function None 3
5: Label
51(vpos): 8(ptr) Variable Function
66(param): 8(ptr) Variable Function
54: 7(fvec4) Load 53(vpos)
55: 14(fvec3) VectorShuffle 54 54 0 1 2
57: 56(ptr) AccessChain 53(vpos) 19
58: 6(float) Load 57
59: 6(float) FDiv 17 58
60: 6(float) CompositeExtract 55 0
61: 6(float) CompositeExtract 55 1
62: 6(float) CompositeExtract 55 2
63: 7(fvec4) CompositeConstruct 60 61 62 59
Store 51(vpos) 63
67: 7(fvec4) Load 51(vpos)
Store 66(param) 67
68: 7(fvec4) FunctionCall 11(@main(vf4;) 66(param)
Store 65(@entryPointOutput) 68
Return
FunctionEnd
11(@main(vf4;): 7(fvec4) Function None 9
10(vpos): 8(ptr) FunctionParameter
12: Label
13(vpos_t): 8(ptr) Variable Function
15: 7(fvec4) Load 10(vpos)
16: 14(fvec3) VectorShuffle 15 15 0 1 2
21: 20(ptr) AccessChain 10(vpos) 19
22: 6(float) Load 21
23: 6(float) FDiv 17 22
24: 6(float) CompositeExtract 16 0
25: 6(float) CompositeExtract 16 1
26: 6(float) CompositeExtract 16 2
27: 7(fvec4) CompositeConstruct 24 25 26 23
Store 13(vpos_t) 27
29: 20(ptr) AccessChain 13(vpos_t) 28
30: 6(float) Load 29
33: 32(bool) FOrdLessThan 30 31
SelectionMerge 35 None
BranchConditional 33 34 45
34: Label
42: 41(ptr) AccessChain 38 40
43: 7(fvec4) Load 42
ReturnValue 43
45: Label
47: 41(ptr) AccessChain 38 46
48: 7(fvec4) Load 47
ReturnValue 48
35: Label
Unreachable
FunctionEnd

12
Test/hlsl.w-recip.frag Normal file
View File

@ -0,0 +1,12 @@
float4 AmbientColor = float4(1, 0.5, 0, 1);
float4 AmbientColor2 = float4(0.5, 1, 0, 0);
float4 main(float4 vpos : SV_POSITION) : SV_TARGET
{
float4 vpos_t = float4(vpos.xyz, 1 / vpos.w);
if (vpos_t.x < 400)
return AmbientColor;
else
return AmbientColor2;
}

View File

@ -254,6 +254,13 @@ diff -b $BASEDIR/hlsl.y-negate-2.vert.out $TARGETDIR/hlsl.y-negate-2.vert.out ||
run -H -e main -V -D -Od -H -i --invert-y hlsl.y-negate-3.vert > $TARGETDIR/hlsl.y-negate-3.vert.out
diff -b $BASEDIR/hlsl.y-negate-3.vert.out $TARGETDIR/hlsl.y-negate-3.vert.out || HASERROR=1
#
# Testing position W reciprocal
#
echo "Testing position W reciprocal"
run -H -e main -V -D -Od -H -i --hlsl-dx-position-w hlsl.w-recip.frag > $TARGETDIR/hlsl.w-recip.frag.out
diff -b $BASEDIR/hlsl.w-recip.frag.out $TARGETDIR/hlsl.w-recip.frag.out || HASERROR=1
#
# Testing hlsl_functionality1
#

View File

@ -2167,8 +2167,21 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
TIntermSymbol* arg = intermediate.addSymbol(*argVars.back());
handleFunctionArgument(&callee, callingArgs, arg);
if (param.type->getQualifier().isParamInput()) {
intermediate.growAggregate(synthBody, handleAssign(loc, EOpAssign, arg,
intermediate.addSymbol(**inputIt)));
TIntermTyped* input = intermediate.addSymbol(**inputIt);
if (input->getType().getQualifier().builtIn == EbvFragCoord && intermediate.getDxPositionW()) {
// Replace FragCoord W with reciprocal
auto pos_xyz = handleDotDereference(loc, input, "xyz");
auto pos_w = handleDotDereference(loc, input, "w");
auto one = intermediate.addConstantUnion(1.0, EbtFloat, loc);
auto recip_w = intermediate.addBinaryMath(EOpDiv, one, pos_w, loc);
TIntermAggregate* dst = new TIntermAggregate(EOpConstructVec4);
dst->getSequence().push_back(pos_xyz);
dst->getSequence().push_back(recip_w);
dst->setType(TType(EbtFloat, EvqTemporary, 4));
dst->setLoc(loc);
input = dst;
}
intermediate.growAggregate(synthBody, handleAssign(loc, EOpAssign, arg, input));
inputIt++;
}
if (param.type->getQualifier().storage == EvqUniform) {

View File

@ -1829,6 +1829,7 @@ void TShader::setUniqueId(unsigned long long id)
}
void TShader::setInvertY(bool invert) { intermediate->setInvertY(invert); }
void TShader::setDxPositionW(bool invert) { intermediate->setDxPositionW(invert); }
void TShader::setNanMinMaxClamp(bool useNonNan) { intermediate->setNanMinMaxClamp(useNonNan); }
#ifndef GLSLANG_WEB

View File

@ -312,6 +312,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
MERGE_TRUE(autoMapBindings);
MERGE_TRUE(autoMapLocations);
MERGE_TRUE(invertY);
MERGE_TRUE(dxPositionW);
MERGE_TRUE(flattenUniformArrays);
MERGE_TRUE(useUnknownFormat);
MERGE_TRUE(hlslOffsets);

View File

@ -290,6 +290,7 @@ public:
resources(TBuiltInResource{}),
numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
invertY(false),
dxPositionW(false),
useStorageBuffer(false),
invariantAll(false),
nanMinMaxClamp(false),
@ -460,6 +461,14 @@ public:
}
bool getInvertY() const { return invertY; }
void setDxPositionW(bool dxPosW)
{
dxPositionW = dxPosW;
if (dxPositionW)
processes.addProcess("dx-position-w");
}
bool getDxPositionW() const { return dxPositionW; }
#ifdef ENABLE_HLSL
void setSource(EShSource s) { source = s; }
EShSource getSource() const { return source; }
@ -1070,6 +1079,7 @@ protected:
int numPushConstants;
bool recursive;
bool invertY;
bool dxPositionW;
bool useStorageBuffer;
bool invariantAll;
bool nanMinMaxClamp; // true if desiring min/max/clamp to favor non-NaN over NaN

View File

@ -485,6 +485,7 @@ public:
GLSLANG_EXPORT void addUniformLocationOverride(const char* name, int loc);
GLSLANG_EXPORT void setUniformLocationBase(int base);
GLSLANG_EXPORT void setInvertY(bool invert);
GLSLANG_EXPORT void setDxPositionW(bool dxPosW);
#ifdef ENABLE_HLSL
GLSLANG_EXPORT void setHlslIoMapping(bool hlslIoMap);
GLSLANG_EXPORT void setFlattenUniformArrays(bool flatten);