Skip to content

Commit 50f534e

Browse files
authored
[HLSL][SPIR-V] Handle SV_Position builtin in PS (#141759)
This commit is using the same mechanism as vk::ext_builtin_input to implement the SV_Position semantic input. The HLSL signature is not yet ready for DXIL, hence this commit only implements the SPIR-V side. This is incomplete as it doesn't allow the semantic on hull/domain and other shaders, but it's a first step to validate the overall input/output semantic logic. Fixes #136969
1 parent 33fee56 commit 50f534e

File tree

11 files changed

+119
-10
lines changed

11 files changed

+119
-10
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4901,6 +4901,13 @@ def HLSLResourceBinding: InheritableAttr {
49014901
}];
49024902
}
49034903

4904+
def HLSLSV_Position : HLSLAnnotationAttr {
4905+
let Spellings = [HLSLAnnotation<"sv_position">];
4906+
let Subjects = SubjectList<[ParmVar, Field]>;
4907+
let LangOpts = [HLSL];
4908+
let Documentation = [HLSLSV_PositionDocs];
4909+
}
4910+
49044911
def HLSLPackOffset: HLSLAnnotationAttr {
49054912
let Spellings = [HLSLAnnotation<"packoffset">];
49064913
let LangOpts = [HLSL];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8529,6 +8529,20 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
85298529
}];
85308530
}
85318531

8532+
def HLSLSV_PositionDocs : Documentation {
8533+
let Category = DocCatFunction;
8534+
let Content = [{
8535+
The ``SV_Position`` semantic, when applied to an input parameter in a pixel
8536+
shader, contains the location of the pixel center (x, y) in screen space.
8537+
This semantic can be applied to the parameter, or a field in a struct used
8538+
as an input parameter.
8539+
This attribute is supported as an input in pixel, hull, domain and mesh shaders.
8540+
This attribute is supported as an output in vertex, geometry and domain shaders.
8541+
8542+
The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics
8543+
}];
8544+
}
8545+
85328546
def HLSLGroupSharedAddressSpaceDocs : Documentation {
85338547
let Category = DocCatVariable;
85348548
let Content = [{

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class SemaHLSL : public SemaBase {
125125
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
126126
void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
127127
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
128+
void handleSV_PositionAttr(Decl *D, const ParsedAttr &AL);
128129
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
129130
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
130131
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
@@ -146,6 +147,7 @@ class SemaHLSL : public SemaBase {
146147

147148
// Diagnose whether the input ID is uint/unit2/uint3 type.
148149
bool diagnoseInputIDType(QualType T, const ParsedAttr &AL);
150+
bool diagnosePositionType(QualType T, const ParsedAttr &AL);
149151

150152
bool CanPerformScalarCast(QualType SrcTy, QualType DestTy);
151153
bool ContainsBitField(QualType BaseTy);

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,30 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
384384
return B.CreateCall(F, {B.getInt32(0)});
385385
}
386386

387+
static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV,
388+
unsigned BuiltIn) {
389+
LLVMContext &Ctx = GV->getContext();
390+
IRBuilder<> B(GV->getContext());
391+
MDNode *Operands = MDNode::get(
392+
Ctx,
393+
{ConstantAsMetadata::get(B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)),
394+
ConstantAsMetadata::get(B.getInt32(BuiltIn))});
395+
MDNode *Decoration = MDNode::get(Ctx, {Operands});
396+
GV->addMetadata("spirv.Decorations", *Decoration);
397+
}
398+
399+
static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
400+
llvm::Type *Ty, const Twine &Name,
401+
unsigned BuiltInID) {
402+
auto *GV = new llvm::GlobalVariable(
403+
M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
404+
/* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
405+
llvm::GlobalVariable::GeneralDynamicTLSModel,
406+
/* AddressSpace */ 7, /* isExternallyInitialized= */ true);
407+
addSPIRVBuiltinDecoration(GV, BuiltInID);
408+
return B.CreateLoad(Ty, GV);
409+
}
410+
387411
llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
388412
const ParmVarDecl &D,
389413
llvm::Type *Ty) {
@@ -407,6 +431,12 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
407431
llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic());
408432
return buildVectorInput(B, GroupIDIntrinsic, Ty);
409433
}
434+
if (D.hasAttr<HLSLSV_PositionAttr>()) {
435+
if (getArch() == llvm::Triple::spirv)
436+
return createSPIRVBuiltinLoad(B, CGM.getModule(), Ty, "sv_position",
437+
/* BuiltIn::Position */ 0);
438+
llvm_unreachable("SV_Position semantic not implemented for this target.");
439+
}
410440
assert(false && "Unhandled parameter attribute");
411441
return nullptr;
412442
}
@@ -626,16 +656,8 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
626656

627657
void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
628658
llvm::GlobalVariable *GV) {
629-
if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>()) {
630-
LLVMContext &Ctx = GV->getContext();
631-
IRBuilder<> B(GV->getContext());
632-
MDNode *Operands = MDNode::get(
633-
Ctx, {ConstantAsMetadata::get(
634-
B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)),
635-
ConstantAsMetadata::get(B.getInt32(Attr->getBuiltIn()))});
636-
MDNode *Decoration = MDNode::get(Ctx, {Operands});
637-
GV->addMetadata("spirv.Decorations", *Decoration);
638-
}
659+
if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
660+
addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
639661
}
640662

641663
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {

clang/lib/Parse/ParseHLSL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
289289
case ParsedAttr::AT_HLSLSV_GroupID:
290290
case ParsedAttr::AT_HLSLSV_GroupIndex:
291291
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
292+
case ParsedAttr::AT_HLSLSV_Position:
292293
break;
293294
default:
294295
llvm_unreachable("invalid HLSL Annotation");

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7588,6 +7588,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
75887588
case ParsedAttr::AT_HLSLWaveSize:
75897589
S.HLSL().handleWaveSizeAttr(D, AL);
75907590
break;
7591+
case ParsedAttr::AT_HLSLSV_Position:
7592+
S.HLSL().handleSV_PositionAttr(D, AL);
7593+
break;
75917594
case ParsedAttr::AT_HLSLVkExtBuiltinInput:
75927595
S.HLSL().handleVkExtBuiltinInputAttr(D, AL);
75937596
break;

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,13 @@ void SemaHLSL::CheckSemanticAnnotation(
764764
return;
765765
DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute});
766766
break;
767+
case attr::HLSLSV_Position:
768+
// TODO(#143523): allow use on other shader types & output once the overall
769+
// semantic logic is implemented.
770+
if (ST == llvm::Triple::Pixel)
771+
return;
772+
DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel});
773+
break;
767774
default:
768775
llvm_unreachable("Unknown HLSLAnnotationAttr");
769776
}
@@ -1147,6 +1154,26 @@ void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
11471154
HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
11481155
}
11491156

1157+
bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) {
1158+
const auto *VT = T->getAs<VectorType>();
1159+
1160+
if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
1161+
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1162+
<< AL << "float/float1/float2/float3/float4";
1163+
return false;
1164+
}
1165+
1166+
return true;
1167+
}
1168+
1169+
void SemaHLSL::handleSV_PositionAttr(Decl *D, const ParsedAttr &AL) {
1170+
auto *VD = cast<ValueDecl>(D);
1171+
if (!diagnosePositionType(VD->getType(), AL))
1172+
return;
1173+
1174+
D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL));
1175+
}
1176+
11501177
void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) {
11511178
auto *VD = cast<ValueDecl>(D);
11521179
if (!diagnoseInputIDType(VD->getType(), AL))
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
2+
3+
// CHECK: @sv_position = external thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0
4+
5+
// CHECK: define void @main() {{.*}} {
6+
float4 main(float4 p : SV_Position) {
7+
// CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @sv_position, align 16
8+
// CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
9+
return p;
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s
2+
3+
float4 main(float4 a : SV_Position) {
4+
// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)'
5+
// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 a 'float4':'vector<float, 4>'
6+
// CHECK-NEXT: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}>
7+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected
2+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected
3+
4+
// expected-error@+1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}}
5+
void main(vector<float, 5> a : SV_Position) {
6+
}
7+
8+
// expected-error@+1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}}
9+
void main(int2 a : SV_Position) {
10+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -finclude-default-header -o - %s -verify
2+
3+
// expected-error@+1 {{attribute 'SV_Position' is unsupported in 'vertex' shaders, requires pixel}}
4+
float4 main(float4 a : SV_Position) {
5+
return a;
6+
}

0 commit comments

Comments
 (0)