From 96c5c0ad17712dc54fbed99eafaa0c54331656f4 Mon Sep 17 00:00:00 2001 From: Ehsan Date: Wed, 25 Oct 2017 16:02:23 -0400 Subject: [PATCH] [spirv] Execution modes for GS primitive types. (#734) --- docs/SPIR-V.rst | 22 +++++++++++++ tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 17 +++++++++- tools/clang/lib/SPIRV/SPIRVEmitter.cpp | 32 +++++++++++++++++++ .../test/CodeGenSPIRV/primitive.error.gs.hlsl | 6 ++++ .../test/CodeGenSPIRV/primitive.line.gs.hlsl | 6 ++++ .../CodeGenSPIRV/primitive.lineadj.gs.hlsl | 6 ++++ .../test/CodeGenSPIRV/primitive.point.gs.hlsl | 6 ++++ .../CodeGenSPIRV/primitive.triangle.gs.hlsl | 6 ++++ .../primitive.triangleadj.gs.hlsl | 6 ++++ .../unittests/SPIRV/CodeGenSPIRVTest.cpp | 16 ++++++++++ 10 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 tools/clang/test/CodeGenSPIRV/primitive.error.gs.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/primitive.line.gs.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/primitive.lineadj.gs.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/primitive.point.gs.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/primitive.triangle.gs.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/primitive.triangleadj.gs.hlsl diff --git a/docs/SPIR-V.rst b/docs/SPIR-V.rst index c62151649..66750d6dc 100644 --- a/docs/SPIR-V.rst +++ b/docs/SPIR-V.rst @@ -1843,6 +1843,28 @@ and is translated to SPIR-V execution mode as follows: |``maxvertexcount`` | ``n`` | ``OutputVertices n`` | +-------------------------+---------------------+--------------------------+ +Translation for Primitive Types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Geometry shader vertex inputs may be qualified with primitive types. Only one primitive type +is allowed to be used in a given geometry shader. The following table shows the SPIR-V execution +mode that is used in order to represent the given primitive type. + +.. table:: Mapping from geometry shader primitive type to SPIR-V execution mode + ++---------------------+-----------------------------+ +| HLSL Primitive Type | SPIR-V Execution Mode | ++=====================+=============================+ +|``point`` | ``InputPoints`` | ++---------------------+-----------------------------+ +|``line`` | ``InputLines`` | ++---------------------+-----------------------------+ +|``triangle`` | ``Triangles`` | ++---------------------+-----------------------------+ +|``lineadj`` | ``InputLinesAdjacency`` | ++---------------------+-----------------------------+ +|``triangleadj`` | ``InputTrianglesAdjacency`` | ++---------------------+-----------------------------+ + TODO: Describe more details about how geometry shaders are translated. e.g. OutputStreams, etc. Vulkan Command-line Options diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 9e648edce..bd68ab0d2 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -54,6 +54,15 @@ ResourceVar::Category getResourceCategory(QualType type) { return ResourceVar::Category::Other; } +/// \brief Returns true if the given declaration has a primitive type qualifier. +/// Returns false otherwise. +bool hasGSPrimitiveTypeQualifier(const Decl *decl) { + return (decl->hasAttr() || + decl->hasAttr() || + decl->hasAttr() || decl->hasAttr() || + decl->hasAttr()); +} + } // anonymous namespace bool DeclResultIdMapper::createStageOutputVar(const DeclaratorDecl *decl, @@ -684,8 +693,14 @@ bool DeclResultIdMapper::createStageVars(const DeclaratorDecl *decl, // Found semantic attached directly to this Decl. This means we need to // map this decl to a single stage variable. - const hlsl::DxilParamInputQual qual = + hlsl::DxilParamInputQual qual = asInput ? hlsl::DxilParamInputQual::In : hlsl::DxilParamInputQual::Out; + + // The inputs to the geometry shader that have a primitive type qualifier + // must use 'InputPrimitive'. + if (asInput && shaderModel.IsGS() && hasGSPrimitiveTypeQualifier(decl)) + qual = hlsl::DxilParamInputQual::InputPrimitive; + const hlsl::SigPoint *sigPoint = hlsl::SigPoint::GetSigPoint(hlsl::SigPointFromInputQual( qual, shaderModel.GetKind(), isPatchConstant)); diff --git a/tools/clang/lib/SPIRV/SPIRVEmitter.cpp b/tools/clang/lib/SPIRV/SPIRVEmitter.cpp index dace7c5cd..20b780caa 100644 --- a/tools/clang/lib/SPIRV/SPIRVEmitter.cpp +++ b/tools/clang/lib/SPIRV/SPIRVEmitter.cpp @@ -5142,6 +5142,38 @@ bool SPIRVEmitter::processGeometryShaderAttributes(const FunctionDecl *decl) { spv::ExecutionMode::OutputVertices, {static_cast(vcAttr->getCount())}); } + + // Only one primitive type is permitted for the geometry shader. + uint32_t primitiveTypes = 0; + for (const auto *param : decl->params()) { + if (param->hasAttr()) { + ++primitiveTypes; + theBuilder.addExecutionMode(entryFunctionId, + spv::ExecutionMode::Triangles, {}); + } else if (param->hasAttr()) { + ++primitiveTypes; + theBuilder.addExecutionMode( + entryFunctionId, spv::ExecutionMode::InputTrianglesAdjacency, {}); + } else if (param->hasAttr()) { + ++primitiveTypes; + theBuilder.addExecutionMode(entryFunctionId, + spv::ExecutionMode::InputPoints, {}); + } else if (param->hasAttr()) { + ++primitiveTypes; + theBuilder.addExecutionMode(entryFunctionId, + spv::ExecutionMode::InputLinesAdjacency, {}); + } else if (param->hasAttr()) { + ++primitiveTypes; + theBuilder.addExecutionMode(entryFunctionId, + spv::ExecutionMode::InputLines, {}); + } + } + if (primitiveTypes > 1) { + emitError( + "only one primitive type can be specified in the geometry shader"); + return false; + } + return true; } diff --git a/tools/clang/test/CodeGenSPIRV/primitive.error.gs.hlsl b/tools/clang/test/CodeGenSPIRV/primitive.error.gs.hlsl new file mode 100644 index 000000000..7f5a38fc2 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/primitive.error.gs.hlsl @@ -0,0 +1,6 @@ +// Run: %dxc -T gs_6_0 -E main + +[maxvertexcount(3)] +void main(triangle in uint i[3] : TriangleVertexID, line in uint j[2] : LineVertexID) {} + +// CHECK: error: only one primitive type can be specified in the geometry shader \ No newline at end of file diff --git a/tools/clang/test/CodeGenSPIRV/primitive.line.gs.hlsl b/tools/clang/test/CodeGenSPIRV/primitive.line.gs.hlsl new file mode 100644 index 000000000..23623f581 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/primitive.line.gs.hlsl @@ -0,0 +1,6 @@ +// Run: %dxc -T gs_6_0 -E main + +// CHECK: OpExecutionMode %main InputLines + +[maxvertexcount(3)] +void main(line in uint id[2] : VertexID) {} diff --git a/tools/clang/test/CodeGenSPIRV/primitive.lineadj.gs.hlsl b/tools/clang/test/CodeGenSPIRV/primitive.lineadj.gs.hlsl new file mode 100644 index 000000000..87a9b6c9f --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/primitive.lineadj.gs.hlsl @@ -0,0 +1,6 @@ +// Run: %dxc -T gs_6_0 -E main + +// CHECK: OpExecutionMode %main InputLinesAdjacency + +[maxvertexcount(3)] +void main(lineadj in uint id[4] : VertexID) {} diff --git a/tools/clang/test/CodeGenSPIRV/primitive.point.gs.hlsl b/tools/clang/test/CodeGenSPIRV/primitive.point.gs.hlsl new file mode 100644 index 000000000..dcf60506c --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/primitive.point.gs.hlsl @@ -0,0 +1,6 @@ +// Run: %dxc -T gs_6_0 -E main + +// CHECK: OpExecutionMode %main InputPoints + +[maxvertexcount(3)] +void main(point in uint id[1] : VertexID) {} diff --git a/tools/clang/test/CodeGenSPIRV/primitive.triangle.gs.hlsl b/tools/clang/test/CodeGenSPIRV/primitive.triangle.gs.hlsl new file mode 100644 index 000000000..795f7e0ea --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/primitive.triangle.gs.hlsl @@ -0,0 +1,6 @@ +// Run: %dxc -T gs_6_0 -E main + +// CHECK: OpExecutionMode %main Triangles + +[maxvertexcount(3)] +void main(triangle in uint i[3] : VertexID) {} diff --git a/tools/clang/test/CodeGenSPIRV/primitive.triangleadj.gs.hlsl b/tools/clang/test/CodeGenSPIRV/primitive.triangleadj.gs.hlsl new file mode 100644 index 000000000..69c5722db --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/primitive.triangleadj.gs.hlsl @@ -0,0 +1,6 @@ +// Run: %dxc -T gs_6_0 -E main + +// CHECK: OpExecutionMode %main InputTrianglesAdjacency + +[maxvertexcount(3)] +void main(triangleadj in uint id[6] : VertexID) {} diff --git a/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp b/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp index b303daf71..feba33dbf 100644 --- a/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp +++ b/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp @@ -683,6 +683,22 @@ TEST_F(FileTest, AttributeMaxVertexCount) { runFileTest("attribute.max-vertex-count.hlsl"); } +// For geometry shader primitive types +TEST_F(FileTest, PrimitivePointGS) { runFileTest("primitive.point.gs.hlsl"); } +TEST_F(FileTest, PrimitiveLineGS) { runFileTest("primitive.line.gs.hlsl"); } +TEST_F(FileTest, PrimitiveTriangleGS) { + runFileTest("primitive.triangle.gs.hlsl"); +} +TEST_F(FileTest, PrimitiveLineAdjGS) { + runFileTest("primitive.lineadj.gs.hlsl"); +} +TEST_F(FileTest, PrimitiveTriangleAdjGS) { + runFileTest("primitive.triangleadj.gs.hlsl"); +} +TEST_F(FileTest, PrimitiveErrorGS) { + runFileTest("primitive.error.gs.hlsl", /*expectSuccess*/ false); +} + // Vulkan/SPIR-V specific TEST_F(FileTest, SpirvStorageClass) { runFileTest("spirv.storage-class.hlsl"); }