summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-03-11 14:52:16 -0700
committerGitHub <noreply@github.com>2024-03-11 14:52:16 -0700
commit7c7fbd572874bdbb3e6f965da3abb918013e1ac8 (patch)
tree47b09522ec72b4ab651127d67e7ebc6020bac376
parent1bbcf25af514a9ae24f7006747177f2d1b3b7c0d (diff)
Add `-fvk-use-dx-position-w` and fix ExecutionMode ordering for geometry shaders. (#3731)
* Add `-fvk-use-dx-position-w`. * Fix ordering of OutputVertices and output primitive type decoration in spirv. * Fix. * fix * Fix. * Move test around.
-rw-r--r--docs/user-guide/08-compiling.md1
-rw-r--r--slang.h1
-rw-r--r--source/slang/slang-compiler-options.cpp1
-rw-r--r--source/slang/slang-emit-spirv.cpp58
-rw-r--r--source/slang/slang-emit.cpp2
-rw-r--r--source/slang/slang-hlsl-to-vulkan-layout-options.cpp3
-rw-r--r--source/slang/slang-hlsl-to-vulkan-layout-options.h8
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp5
-rw-r--r--source/slang/slang-ir-inst-defs.h3
-rw-r--r--source/slang/slang-ir-insts.h10
-rw-r--r--source/slang/slang-ir-vk-invert-y.cpp32
-rw-r--r--source/slang/slang-ir-vk-invert-y.h1
-rw-r--r--source/slang/slang-options.cpp2
-rw-r--r--tests/spirv/geometry-decoration-ordering.slang17
-rw-r--r--tests/spirv/rcp-w-fragment.slang7
15 files changed, 122 insertions, 29 deletions
diff --git a/docs/user-guide/08-compiling.md b/docs/user-guide/08-compiling.md
index fb9d8de6c..ba772d620 100644
--- a/docs/user-guide/08-compiling.md
+++ b/docs/user-guide/08-compiling.md
@@ -660,6 +660,7 @@ meanings of their `CompilerOptionValue` encodings.
| VulkanBindShift | Specifies the `-fvk-bind-shift` option. `intValue0` (higher 8 bits): kind, `intValue0` (lower bits): set; `intValue1`: shift. |
| VulkanBindGlobals | Specifies the `-fvk-bind-globals` option. `intValue0`: index, `intValue`: set. |
| VulkanInvertY | Specifies the `-fvk-invert-y` option. `intValue0` specifies a bool value for the setting. |
+| VulkanUseDxPositionW | Specifies the `-fvk-use-dx-position-w` option. `intValue0` specifies a bool value for the setting. |
| VulkanUseEntryPointName | When set, will keep the original name of entrypoints as they are defined in the source instead of renaming them to `main`. `intValue0` specifies a bool value for the setting. |
| VulkanUseGLLayout | When set, will use std430 layout instead of D3D buffer layout for raw buffer load/stores. `intValue0` specifies a bool value for the setting. |
| VulkanEmitReflection | Specifies the `-fspv-reflect` option. When set will include additional reflection instructions in the output SPIRV. `intValue0` specifies a bool value for the setting. |
diff --git a/slang.h b/slang.h
index fc242dbf1..28835f713 100644
--- a/slang.h
+++ b/slang.h
@@ -874,6 +874,7 @@ extern "C"
VulkanBindShift, // intValue0 (higher 8 bits): kind; intValue0(lower bits): set; intValue1: shift
VulkanBindGlobals, // intValue0: index; intValue1: set
VulkanInvertY, // bool
+ VulkanUseDxPositionW, // bool
VulkanUseEntryPointName, // bool
VulkanUseGLLayout, // bool
VulkanEmitReflection, // bool
diff --git a/source/slang/slang-compiler-options.cpp b/source/slang/slang-compiler-options.cpp
index 100a5719f..974fbaaaa 100644
--- a/source/slang/slang-compiler-options.cpp
+++ b/source/slang/slang-compiler-options.cpp
@@ -113,6 +113,7 @@ namespace Slang
case CompilerOptionName::MatrixLayoutRow:
case CompilerOptionName::MatrixLayoutColumn:
case CompilerOptionName::VulkanInvertY:
+ case CompilerOptionName::VulkanUseDxPositionW:
case CompilerOptionName::VulkanUseEntryPointName:
case CompilerOptionName::VulkanUseGLLayout:
case CompilerOptionName::VulkanEmitReflection:
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 2f318c464..8063975e2 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -3074,16 +3074,9 @@ struct SPIRVEmitContext
}
break;
case kIROp_MaxVertexCountDecoration:
- {
- auto section = getSection(SpvLogicalSectionID::ExecutionModes);
- auto maxVertexCount = cast<IRMaxVertexCountDecoration>(decoration);
- emitOpExecutionModeOutputVertices(
- section,
- decoration,
- dstID,
- SpvLiteralInteger::from32(int32_t(getIntVal(maxVertexCount->getCount())))
- );
- }
+ // Don't do anything here, instead wait until we see OutputTopologyDecoration
+ // and emit them together to ensure MaxVertexCount always appears before OutputTopology,
+ // which seemed to be required by SPIRV.
break;
case kIROp_InstanceDecoration:
{
@@ -3094,22 +3087,49 @@ struct SPIRVEmitContext
}
break;
case kIROp_TriangleInputPrimitiveTypeDecoration:
- emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeTriangles);
- break;
case kIROp_LineInputPrimitiveTypeDecoration:
- emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeInputLines);
- break;
case kIROp_LineAdjInputPrimitiveTypeDecoration:
- emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeInputLinesAdjacency);
- break;
case kIROp_PointInputPrimitiveTypeDecoration:
- emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeInputPoints);
- break;
case kIROp_TriangleAdjInputPrimitiveTypeDecoration:
- emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeInputTrianglesAdjacency);
+ // Defer this until we see kIROp_StreamOutputTypeDecoration because the driver wants to see
+ // them before the output.
break;
case kIROp_StreamOutputTypeDecoration:
{
+ for (auto inputDecor : decoration->getParent()->getDecorations())
+ {
+ switch (inputDecor->getOp())
+ {
+ case kIROp_TriangleInputPrimitiveTypeDecoration:
+ emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeTriangles);
+ break;
+ case kIROp_LineInputPrimitiveTypeDecoration:
+ emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputLines);
+ break;
+ case kIROp_LineAdjInputPrimitiveTypeDecoration:
+ emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputLinesAdjacency);
+ break;
+ case kIROp_PointInputPrimitiveTypeDecoration:
+ emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputPoints);
+ break;
+ case kIROp_TriangleAdjInputPrimitiveTypeDecoration:
+ emitOpExecutionMode(getSection(SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputTrianglesAdjacency);
+ break;
+ }
+ }
+ // SPIRV requires MaxVertexCount decoration to appear before OutputTopologyDecoration,
+ // so we emit them here.
+ if (auto maxVertexCount = decoration->getParent()->findDecoration<IRMaxVertexCountDecoration>())
+ {
+ auto section = getSection(SpvLogicalSectionID::ExecutionModes);
+ emitOpExecutionModeOutputVertices(
+ section,
+ maxVertexCount,
+ dstID,
+ SpvLiteralInteger::from32(int32_t(getIntVal(maxVertexCount->getCount())))
+ );
+ }
+
auto decor = as<IRStreamOutputTypeDecoration>(decoration);
IRType* type = decor->getStreamType();
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 5ec6fa62a..0ec9b0c1a 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -934,6 +934,8 @@ Result linkAndOptimizeIR(
legalizeUniformBufferLoad(irModule);
if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::VulkanInvertY))
invertYOfPositionOutput(irModule);
+ if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::VulkanUseDxPositionW))
+ rcpWOfPositionInput(irModule);
}
// Lower sizeof/alignof
diff --git a/source/slang/slang-hlsl-to-vulkan-layout-options.cpp b/source/slang/slang-hlsl-to-vulkan-layout-options.cpp
index 0e6f70294..4246b7b39 100644
--- a/source/slang/slang-hlsl-to-vulkan-layout-options.cpp
+++ b/source/slang/slang-hlsl-to-vulkan-layout-options.cpp
@@ -53,7 +53,6 @@ void HLSLToVulkanLayoutOptions::loadFromOptionSet(CompilerOptionSet& optionSet)
m_globalsBinding.set = (*bindGlobals)[0].intValue2;
}
}
- m_invertY = optionSet.getBoolOption(CompilerOptionName::VulkanInvertY);
m_useGLLayout = optionSet.getBoolOption(CompilerOptionName::VulkanUseGLLayout);
m_useOriginalEntryPointName = optionSet.getBoolOption(CompilerOptionName::VulkanUseEntryPointName);
@@ -123,7 +122,7 @@ Index HLSLToVulkanLayoutOptions::getShift(Kind kind, Index set) const
bool HLSLToVulkanLayoutOptions::hasState() const
{
- return canInferBindings() || hasGlobalsBinding() || shouldInvertY() || getUseOriginalEntryPointName()
+ return canInferBindings() || hasGlobalsBinding() || getUseOriginalEntryPointName()
|| shouldUseGLLayout() || shouldEmitSPIRVReflectionInfo();
}
diff --git a/source/slang/slang-hlsl-to-vulkan-layout-options.h b/source/slang/slang-hlsl-to-vulkan-layout-options.h
index 2b8ec973c..1b7daf330 100644
--- a/source/slang/slang-hlsl-to-vulkan-layout-options.h
+++ b/source/slang/slang-hlsl-to-vulkan-layout-options.h
@@ -119,9 +119,6 @@ public:
/// True if can infer a binding for a kind
bool canInferBindingForKind(Kind kind) const { return (m_kindShiftEnabledFlags & getKindFlag(kind)) != 0; }
- /// True if the compiler should invert the Y coordinate of any SV_Position output.
- bool shouldInvertY() const { return m_invertY; }
-
bool shouldUseGLLayout() const { return m_useGLLayout; }
bool shouldEmitSPIRVReflectionInfo() const { return m_emitSPIRVReflectionInfo; }
@@ -152,8 +149,6 @@ public:
/// Get the globals binding
const Binding& getGlobalsBinding() const { return m_globalsBinding; }
- void setInvertY(bool value) { m_invertY = value; }
-
void setUseOriginalEntryPointName(bool value) { m_useOriginalEntryPointName = value; }
void setUseGLLayout(bool value) { m_useGLLayout = value; }
@@ -186,9 +181,6 @@ protected:
/// Maps a key to the amount of shift
Dictionary<Key, Index> m_shifts;
- /// Whether to invert the Y coordinate of SV_Position output.
- bool m_invertY = false;
-
/// If set, will use the original entry point name in the generated SPIRV instead of "main".
bool m_useOriginalEntryPointName = false;
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index d2d09f45a..e40dc33ff 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -335,6 +335,7 @@ enum GLSLSystemValueKind
{
General,
PositionOutput,
+ PositionInput,
};
struct GLSLSystemValueInfo
@@ -569,6 +570,7 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
&& kind == LayoutResourceKind::VaryingInput )
{
name = "gl_FragCoord";
+ systemValueKind = GLSLSystemValueKind::PositionInput;
}
else if( stage == Stage::Geometry
&& kind == LayoutResourceKind::VaryingInput )
@@ -1008,6 +1010,9 @@ void createVarLayoutForLegalizedGlobalParam(
case GLSLSystemValueKind::PositionOutput:
builder->addGLPositionOutputDecoration(globalParam);
break;
+ case GLSLSystemValueKind::PositionInput:
+ builder->addGLPositionInputDecoration(globalParam);
+ break;
default:
break;
}
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index cd79f05a6..26e0ebd69 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -859,6 +859,9 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
INST(GLSLPrimitivesRateDecoration, perprimitive, 0, 0)
// Marks an inst that represents the gl_Position output.
INST(GLPositionOutputDecoration, PositionOutput, 0, 0)
+ // Marks an inst that represents the gl_Position input.
+ INST(GLPositionInputDecoration, PositionInput, 0, 0)
+
/* StageAccessDecoration */
INST(StageReadAccessDecoration, stageReadAccess, 0, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 6fbccab5c..0a7f8c33b 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -1366,6 +1366,11 @@ struct IRGLPositionOutputDecoration : public IRDecoration
IR_LEAF_ISA(GLPositionOutputDecoration)
};
+struct IRGLPositionInputDecoration : public IRDecoration
+{
+ IR_LEAF_ISA(GLPositionInputDecoration)
+};
+
struct IRMeshOutputRef : public IRInst
{
enum { kOp = kIROp_MeshOutputRef };
@@ -4297,6 +4302,11 @@ public:
addDecoration(value, kIROp_GLPositionOutputDecoration);
}
+ void addGLPositionInputDecoration(IRInst* value)
+ {
+ addDecoration(value, kIROp_GLPositionInputDecoration);
+ }
+
void addInterpolationModeDecoration(IRInst* value, IRInterpolationMode mode)
{
addDecoration(value, kIROp_InterpolationModeDecoration, getIntValue(getIntType(), IRIntegerValue(mode)));
diff --git a/source/slang/slang-ir-vk-invert-y.cpp b/source/slang/slang-ir-vk-invert-y.cpp
index 5c21fee95..5e2dfcf2e 100644
--- a/source/slang/slang-ir-vk-invert-y.cpp
+++ b/source/slang/slang-ir-vk-invert-y.cpp
@@ -56,4 +56,36 @@ void invertYOfPositionOutput(IRModule* module)
}
}
+
+static IRInst* _invertWOfVector(IRBuilder& builder, IRInst* originalVector)
+{
+ auto vectorType = as<IRVectorType>(originalVector->getDataType());
+ SLANG_ASSERT(vectorType);
+ UInt elementIndexW = 3;
+ auto originalW = builder.emitSwizzle(vectorType->getElementType(), originalVector, 1, &elementIndexW);
+ auto rcpW = builder.emitDiv(originalW->getDataType(), builder.getFloatValue(originalW->getDataType(), 1.0), originalW);
+ auto newVal = builder.emitSwizzleSet(originalVector->getDataType(), originalVector, rcpW, 1, &elementIndexW);
+ return newVal;
+}
+
+// Find inputs of SV_Position and rcp the w coordinates of it right after the read.
+void rcpWOfPositionInput(IRModule* module)
+{
+ for (auto globalInst : module->getGlobalInsts())
+ {
+ if (globalInst->findDecoration<IRGLPositionInputDecoration>())
+ {
+ // Find all loads and replace them with reciprocals.
+ IRBuilder builder(module);
+ traverseUses(globalInst, [&](IRUse* use)
+ {
+ // Get the inverted vector.
+ builder.setInsertBefore(use->getUser());
+ auto invertedVal = _invertWOfVector(builder, globalInst);
+ // Replace original uses with the invertex vector.
+ builder.replaceOperand(use, invertedVal);
+ });
+ }
+ }
+}
}
diff --git a/source/slang/slang-ir-vk-invert-y.h b/source/slang/slang-ir-vk-invert-y.h
index b6b1e4a4c..4fc007169 100644
--- a/source/slang/slang-ir-vk-invert-y.h
+++ b/source/slang/slang-ir-vk-invert-y.h
@@ -5,6 +5,7 @@ namespace Slang
{
struct IRModule;
void invertYOfPositionOutput(IRModule* module);
+ void rcpWOfPositionInput(IRModule* module);
}
#endif
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index 42eb66517..3d0b22edd 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -399,6 +399,7 @@ void initCommandOptions(CommandOptions& options)
{ OptionKind::VulkanBindGlobals, "-fvk-bind-globals", "-fvk-bind-globals <N> <descriptor-set>",
"Places the $Globals cbuffer at descriptor set <descriptor-set> and binding <N>."},
{ OptionKind::VulkanInvertY, "-fvk-invert-y", nullptr, "Negates (additively inverts) SV_Position.y before writing to stage output."},
+ { OptionKind::VulkanUseDxPositionW, "-fvk-use-dx-position-w", nullptr, "Reciprocates (multiplicatively inverts) SV_Position.w after reading from stage input. For use in fragment shaders only."},
{ OptionKind::VulkanUseEntryPointName, "-fvk-use-entrypoint-name", nullptr, "Uses the entrypoint name from the source instead of 'main' in the spirv output."},
{ OptionKind::VulkanUseGLLayout, "-fvk-use-gl-layout", nullptr, "Use std430 layout instead of D3D buffer layout for raw buffer load/stores."},
{ OptionKind::VulkanEmitReflection, "-fspv-reflect", nullptr, "Include reflection decorations in the resulting SPIRV for shader parameters."},
@@ -1681,6 +1682,7 @@ SlangResult OptionsParser::_parse(
case OptionKind::ValidateIr:
case OptionKind::DumpIr:
case OptionKind::VulkanInvertY:
+ case OptionKind::VulkanUseDxPositionW:
case OptionKind::VulkanUseEntryPointName:
case OptionKind::VulkanUseGLLayout:
case OptionKind::VulkanEmitReflection:
diff --git a/tests/spirv/geometry-decoration-ordering.slang b/tests/spirv/geometry-decoration-ordering.slang
new file mode 100644
index 000000000..be6eee878
--- /dev/null
+++ b/tests/spirv/geometry-decoration-ordering.slang
@@ -0,0 +1,17 @@
+//TEST:SIMPLE(filecheck=CHECK):-target spirv -emit-spirv-directly -entry main -stage geometry
+
+// Make sure InputPoints always appears before OutputVertices and OutputTriangleStrip,
+// otherwise, the shader won't work correctly.
+
+// CHECK: OpExecutionMode {{.*}} InputPoints
+// CHECK: OpExecutionMode {{.*}} OutputVertices 4
+// CHECK: OpExecutionMode {{.*}} OutputTriangleStrip
+
+[maxvertexcount(4)]
+void main( point float4 input[1], inout TriangleStream<float4> OutputStream )
+{
+ OutputStream.Append(float4(0));
+ OutputStream.Append(float4(1));
+ OutputStream.Append(float4(2));
+ OutputStream.Append(float4(3));
+} \ No newline at end of file
diff --git a/tests/spirv/rcp-w-fragment.slang b/tests/spirv/rcp-w-fragment.slang
new file mode 100644
index 000000000..1cd1b8ee8
--- /dev/null
+++ b/tests/spirv/rcp-w-fragment.slang
@@ -0,0 +1,7 @@
+//TEST:SIMPLE(filecheck=CHECK): -target spirv -entry main -stage fragment -fvk-use-dx-position-w -emit-spirv-directly
+
+// CHECK: OpFDiv
+float4 main(float4 pos : SV_Position) : SV_Target
+{
+ return pos;
+} \ No newline at end of file