From 01fa18a57b40ccbcd78ae9e5f3a35366e7cc7037 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 31 Jul 2024 16:53:48 -0400 Subject: [PATCH] [SPRIV] Allow vk-invert-y for MS shaders (#6839) Fixes #3154 --- tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 20 ++--------- tools/clang/lib/SPIRV/DeclResultIdMapper.h | 5 --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 23 +++++++++++-- tools/clang/lib/SPIRV/SpirvEmitter.h | 5 +++ .../test/CodeGenSPIRV/mesh.invert.y.hlsl | 34 +++++++++++++++++++ 5 files changed, 62 insertions(+), 25 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/mesh.invert.y.hlsl diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 5489b34db..06e6da0ac 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -3667,7 +3667,7 @@ bool DeclResultIdMapper::createStageVars(StageVarDataBundle &stageVarData, return true; // Negate SV_Position.y if requested if (semanticKind == hlsl::Semantic::Kind::Position) - *value = invertYIfRequested(*value, thisSemantic.loc); + *value = theEmitter.invertYIfRequested(*value, thisSemantic.loc); storeToShaderOutputVariable(varInstr, *value, stageVarData); } @@ -3856,7 +3856,7 @@ bool DeclResultIdMapper::writeBackOutputStream(const NamedDecl *decl, // Negate SV_Position.y if requested if (semanticInfo.semantic->GetKind() == hlsl::Semantic::Kind::Position) - value = invertYIfRequested(value, loc, range); + value = theEmitter.invertYIfRequested(value, loc, range); // Boolean stage output variables are represented as unsigned integers. if (isBooleanStageIOVar(decl, type, semanticInfo.semantic->GetKind(), @@ -3906,22 +3906,6 @@ bool DeclResultIdMapper::writeBackOutputStream(const NamedDecl *decl, return true; } -SpirvInstruction * -DeclResultIdMapper::invertYIfRequested(SpirvInstruction *position, - SourceLocation loc, SourceRange range) { - // Negate SV_Position.y if requested - if (spirvOptions.invertY) { - const auto oldY = spvBuilder.createCompositeExtract( - astContext.FloatTy, position, {1}, loc, range); - const auto newY = spvBuilder.createUnaryOp( - spv::Op::OpFNegate, astContext.FloatTy, oldY, loc, range); - position = spvBuilder.createCompositeInsert( - astContext.getExtVectorType(astContext.FloatTy, 4), position, {1}, newY, - loc, range); - } - return position; -} - SpirvInstruction * DeclResultIdMapper::invertWIfRequested(SpirvInstruction *position, SourceLocation loc) { diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.h b/tools/clang/lib/SPIRV/DeclResultIdMapper.h index caa480a40..41781c18d 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.h +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.h @@ -516,11 +516,6 @@ public: bool writeBackOutputStream(const NamedDecl *decl, QualType type, SpirvInstruction *value, SourceRange range = {}); - /// \brief Negates to get the additive inverse of SV_Position.y if requested. - SpirvInstruction *invertYIfRequested(SpirvInstruction *position, - SourceLocation loc, - SourceRange range = {}); - /// \brief Reciprocates to get the multiplicative inverse of SV_Position.w /// if requested. SpirvInstruction *invertWIfRequested(SpirvInstruction *position, diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index e00c0aeb1..acf1ec5d3 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -594,8 +594,8 @@ SpirvEmitter::SpirvEmitter(CompilerInstance &ci) emitError("unknown shader module: %0", {}) << shaderModel->GetName(); if (spirvOptions.invertY && !shaderModel->IsVS() && !shaderModel->IsDS() && - !shaderModel->IsGS()) - emitError("-fvk-invert-y can only be used in VS/DS/GS", {}); + !shaderModel->IsGS() && !shaderModel->IsMS()) + emitError("-fvk-invert-y can only be used in VS/DS/GS/MS", {}); if (spirvOptions.useGlLayout && spirvOptions.useDxLayout) emitError("cannot specify both -fvk-use-dx-layout and -fvk-use-gl-layout", @@ -7933,6 +7933,9 @@ void SpirvEmitter::assignToMSOutAttribute( valueType = astContext.UnsignedIntTy; } varInstr = spvBuilder.createAccessChain(valueType, varInstr, indices, loc); + if (semanticInfo.semantic->GetKind() == hlsl::Semantic::Kind::Position) + value = invertYIfRequested(value, semanticInfo.loc); + spvBuilder.createStore(varInstr, value, loc); } @@ -14327,6 +14330,22 @@ SpirvEmitter::createSpirvIntrInstExt(llvm::ArrayRef attrs, return retVal; } +SpirvInstruction *SpirvEmitter::invertYIfRequested(SpirvInstruction *position, + SourceLocation loc, + SourceRange range) { + // Negate SV_Position.y if requested + if (spirvOptions.invertY) { + const auto oldY = spvBuilder.createCompositeExtract( + astContext.FloatTy, position, {1}, loc, range); + const auto newY = spvBuilder.createUnaryOp( + spv::Op::OpFNegate, astContext.FloatTy, oldY, loc, range); + position = spvBuilder.createCompositeInsert( + astContext.getExtVectorType(astContext.FloatTy, 4), position, {1}, newY, + loc, range); + } + return position; +} + SpirvInstruction * SpirvEmitter::processSpvIntrinsicCallExpr(const CallExpr *expr) { const auto *funcDecl = expr->getDirectCallee(); diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.h b/tools/clang/lib/SPIRV/SpirvEmitter.h index 8ac93fdae..9a7daae34 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.h +++ b/tools/clang/lib/SPIRV/SpirvEmitter.h @@ -114,6 +114,11 @@ public: llvm::ArrayRef spvArgs, bool isInstr, SourceLocation loc); + /// \brief Negates to get the additive inverse of SV_Position.y if requested. + SpirvInstruction *invertYIfRequested(SpirvInstruction *position, + SourceLocation loc, + SourceRange range = {}); + private: void doFunctionDecl(const FunctionDecl *decl); void doVarDecl(const VarDecl *decl); diff --git a/tools/clang/test/CodeGenSPIRV/mesh.invert.y.hlsl b/tools/clang/test/CodeGenSPIRV/mesh.invert.y.hlsl new file mode 100644 index 000000000..7054a62b9 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/mesh.invert.y.hlsl @@ -0,0 +1,34 @@ +// RUN: %dxc -T ms_6_5 -E main -fcgl %s -spirv -fvk-invert-y | FileCheck %s -check-prefix=CHECK -check-prefix=INVERT +// RUN: %dxc -T ms_6_5 -E main -fcgl %s -spirv | FileCheck %s -check-prefix=CHECK -check-prefix=NINVERT + +struct MeshPerVertex { + float4 position : SV_Position; +}; + +#define NUM_THREADS 128 +#define MAX_VERT 256 +#define MAX_PRIM 256 + +// CHECK: [[v:%[0-9]+]] = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7 + +[outputtopology("point")] +[numthreads(NUM_THREADS, 1, 1)] +void main(out vertices MeshPerVertex verts[MAX_VERT], + out indices uint primitiveInd[MAX_PRIM], + in uint tid : SV_DispatchThreadID) +{ + + SetMeshOutputCounts(MAX_VERT, MAX_PRIM); + +// CHECK: [[glPosition:%[0-9]+]] = OpAccessChain %_ptr_Output_v4float %gl_Position %47 +// NINVERT: OpStore [[glPosition]] [[v]] + +// INVERT: [[vy:%[0-9]+]] = OpCompositeExtract %float [[v]] 1 +// INVERT: [[nvy:%[0-9]+]] = OpFNegate %float [[vy]] +// INVERT: [[nv:%[0-9]+]] = OpCompositeInsert %v4float [[nvy]] [[v]] 1 +// INVERT: OpStore [[glPosition]] [[nv]] + verts[tid].position = float4(4.0,5.0,6.0,7.0); + + primitiveInd[6] = 2; +} +