Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/DXIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2888,6 +2888,9 @@ Modules and Linking
===================

HLSL has linking capabilities to enable third-party libraries. The linking step happens before shader DXIL is given to the driver compilers.
Experimental library generation is added in DXIL1.1. A library could be created by compile with lib_6_1 profile.
A library is a dxil container like the compile result of other shader profiles. The difference is library will keep information for linking like resource link info and entry function signatures.
Library support is not part of DXIL spec. Only requirement is linked shader must be valid DXIL.

Additional Notes
================
Expand Down
6 changes: 6 additions & 0 deletions tools/clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,12 @@ def HLSLGloballyCoherent : InheritableAttr {
let Documentation = [Undocumented];
}

def HLSLShader : InheritableAttr {
let Spellings = [CXX11<"", "shader", 2017>];
let Args = [StringArgument<"profile">]; // one of tri, quad, isoline
let Documentation = [Undocumented];
}

// HLSL Change Ends

def C11NoReturn : InheritableAttr {
Expand Down
46 changes: 38 additions & 8 deletions tools/clang/lib/CodeGen/CGHLSLMS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1053,10 +1053,47 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
if (isEntry)
EntryFunc = F;

DiagnosticsEngine &Diags = CGM.getDiags();

std::unique_ptr<DxilFunctionProps> funcProps =
llvm::make_unique<DxilFunctionProps>();
// TODO: add attribute to mark shader entry.
funcProps->shaderKind = DXIL::ShaderKind::Invalid;
bool isCS = false;
bool isGS = false;
bool isHS = false;
bool isDS = false;
bool isVS = false;
bool isPS = false;
if (const HLSLShaderAttr *Attr = FD->getAttr<HLSLShaderAttr>()) {
const ShaderModel *pSM =
ShaderModel::GetByName(Attr->getProfile().str().c_str());
funcProps->shaderKind = pSM->GetKind();
switch (funcProps->shaderKind) {
case DXIL::ShaderKind::Compute:
isCS = true;
break;
case DXIL::ShaderKind::Vertex:
isVS = true;
break;
case DXIL::ShaderKind::Hull:
isHS = true;
break;
case DXIL::ShaderKind::Domain:
isDS = true;
break;
case DXIL::ShaderKind::Geometry:
isGS = true;
break;
case DXIL::ShaderKind::Pixel:
isPS = true;
break;
default: {
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error, "Invalid profile for shader attribute");
Diags.Report(Attr->getLocation(), DiagID);
} break;
}
}

// Save patch constant function to patchConstantFunctionMap.
bool isPatchConstantFunction = false;
Expand Down Expand Up @@ -1097,9 +1134,7 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
funcProps->shaderKind = SM->GetKind();
}

DiagnosticsEngine &Diags = CGM.getDiags();
// Geometry shader.
bool isGS = false;
if (const HLSLMaxVertexCountAttr *Attr =
FD->getAttr<HLSLMaxVertexCountAttr>()) {
isGS = true;
Expand Down Expand Up @@ -1132,7 +1167,6 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
}

// Computer shader.
bool isCS = false;
if (const HLSLNumThreadsAttr *Attr = FD->getAttr<HLSLNumThreadsAttr>()) {
isCS = true;
funcProps->shaderKind = DXIL::ShaderKind::Compute;
Expand All @@ -1150,7 +1184,6 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
}

// Hull shader.
bool isHS = false;
if (const HLSLPatchConstantFuncAttr *Attr =
FD->getAttr<HLSLPatchConstantFuncAttr>()) {
if (isEntry && !SM->IsHS()) {
Expand Down Expand Up @@ -1256,7 +1289,6 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
}

// Hull or domain shader.
bool isDS = false;
if (const HLSLDomainAttr *Attr = FD->getAttr<HLSLDomainAttr>()) {
if (isEntry && !SM->IsHS() && !SM->IsDS()) {
unsigned DiagID =
Expand All @@ -1278,7 +1310,6 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
}

// Vertex shader.
bool isVS = false;
if (const HLSLClipPlanesAttr *Attr = FD->getAttr<HLSLClipPlanesAttr>()) {
if (isEntry && !SM->IsVS()) {
unsigned DiagID = Diags.getCustomDiagID(
Expand All @@ -1294,7 +1325,6 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
}

// Pixel shader.
bool isPS = false;
if (const HLSLEarlyDepthStencilAttr *Attr =
FD->getAttr<HLSLEarlyDepthStencilAttr>()) {
if (isEntry && !SM->IsPS()) {
Expand Down
1 change: 1 addition & 0 deletions tools/clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
case AttributeList::AT_HLSLLoop:
case AttributeList::AT_HLSLMaxTessFactor:
case AttributeList::AT_HLSLNumThreads:
case AttributeList::AT_HLSLShader:
case AttributeList::AT_HLSLRootSignature:
case AttributeList::AT_HLSLOutputControlPoints:
case AttributeList::AT_HLSLOutputTopology:
Expand Down
17 changes: 17 additions & 0 deletions tools/clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10005,6 +10005,14 @@ void hlsl::HandleDeclAttributeForHLSL(Sema &S, Decl *D, const AttributeList &A,
declAttr = ::new (S.Context) HLSLPatchConstantFuncAttr(A.getRange(), S.Context,
ValidateAttributeStringArg(S, A, nullptr), A.getAttributeSpellingListIndex());
break;
case AttributeList::AT_HLSLShader:
declAttr = ::new (S.Context) HLSLShaderAttr(
A.getRange(), S.Context,
ValidateAttributeStringArg(S, A,
"cs_6_0,cs_6_1,ps_6_0,ps_6_1,vs_6_0,vs_6_1, "
"hs_6_0,hs_6_1,ds_6_0,ds_6_1,gs_6_0,gs_6_1"),
A.getAttributeSpellingListIndex());
break;
case AttributeList::AT_HLSLMaxVertexCount:
declAttr = ::new (S.Context) HLSLMaxVertexCountAttr(A.getRange(), S.Context,
ValidateAttributeIntArg(S, A), A.getAttributeSpellingListIndex());
Expand Down Expand Up @@ -11003,6 +11011,15 @@ void hlsl::CustomPrintHLSLAttr(const clang::Attr *A, llvm::raw_ostream &Out, con
Out << "[patchconstantfunc(\"" << ACast->getFunctionName() << "\")]\n";
break;
}

case clang::attr::HLSLShader:
{
Attr * noconst = const_cast<Attr*>(A);
HLSLShaderAttr *ACast = static_cast<HLSLShaderAttr*>(noconst);
Indent(Indentation, Out);
Out << "[shader(\"" << ACast->getProfile() << "\")]\n";
break;
}

case clang::attr::HLSLMaxVertexCount:
{
Expand Down
197 changes: 197 additions & 0 deletions tools/clang/test/CodeGenHLSL/lib_entries2.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// RUN: %dxc -T lib_6_1 %s | FileCheck %s

// Make sure entry function exist.
// CHECK: @cs_main()
// Make sure signatures are lowered.
// CHECK: dx.op.threadId
// CHECK: dx.op.groupId

// Make sure entry function exist.
// CHECK: @gs_main()
// Make sure signatures are lowered.
// CHECK: dx.op.loadInput
// CHECK: dx.op.storeOutput
// CHECK: dx.op.emitStream
// CHECK: dx.op.cutStream

// Make sure entry function exist.
// CHECK: @ds_main()
// Make sure signatures are lowered.
// CHECK: dx.op.loadPatchConstant
// CHECK: dx.op.domainLocation
// CHECK: dx.op.loadInput
// CHECK: dx.op.storeOutput

// Make sure patch constant function exist.
// CHECK: HSPerPatchFunc
// Make sure signatures are lowered.
// CHECK: dx.op.storePatchConstant

// Make sure entry function exist.
// CHECK: @hs_main()
// Make sure signatures are lowered.
// CHECK: dx.op.outputControlPointID
// CHECK: dx.op.loadInput
// CHECK: dx.op.storeOutput

// Make sure entry function exist.
// CHECK: @vs_main()
// Make sure signatures are lowered.
// CHECK: dx.op.loadInput
// CHECK: dx.op.storeOutput

// Make sure entry function exist.
// CHECK: @ps_main()
// Make sure signatures are lowered.
// CHECK: dx.op.loadInput
// CHECK: dx.op.storeOutput
// Finish ps_main
// CHECK: ret void

// Make sure cloned function signatures are not lowered.
// CHECK-NOT: call float @dx.op.loadInput
// CHECK-NOT: call void @dx.op.storeOutput


// Make sure cloned function exist.
// CHECK: @"\01?ps_main


// Make sure function entrys exist.
// CHECK: dx.func.signatures
// Make sure cs don't have signature.
// CHECK: @cs_main, null

void StoreCSOutput(uint2 tid, uint2 gid);

[shader("cs_6_1")]
[numthreads(8,8,1)]
void cs_main( uint2 tid : SV_DispatchThreadID, uint2 gid : SV_GroupID, uint2 gtid : SV_GroupThreadID, uint gidx : SV_GroupIndex )
{
StoreCSOutput(tid, gid);
}

// GS

struct GSOut {
float2 uv : TEXCOORD0;
float4 pos : SV_Position;
};

// geometry shader that outputs 3 vertices from a point
[shader("gs_6_1")]
[maxvertexcount(3)]
[instance(24)]
void gs_main(InputPatch<GSOut, 2>points, inout PointStream<GSOut> stream) {

stream.Append(points[0]);

stream.RestartStrip();
}

// DS
struct PSSceneIn {
float4 pos : SV_Position;
float2 tex : TEXCOORD0;
float3 norm : NORMAL;

uint RTIndex : SV_RenderTargetArrayIndex;
};

struct HSPerVertexData {
// This is just the original vertex verbatim. In many real life cases this would be a
// control point instead
PSSceneIn v;
};

struct HSPerPatchData {
// We at least have to specify tess factors per patch
// As we're tesselating triangles, there will be 4 tess factors
// In real life case this might contain face normal, for example
float edges[3] : SV_TessFactor;
float inside : SV_InsideTessFactor;
};

// domain shader that actually outputs the triangle vertices
[shader("ds_6_1")]
[domain("tri")] PSSceneIn ds_main(const float3 bary
: SV_DomainLocation,
const OutputPatch<HSPerVertexData, 3> patch,
const HSPerPatchData perPatchData) {
PSSceneIn v;

// Compute interpolated coordinates
v.pos = patch[0].v.pos * bary.x + patch[1].v.pos * bary.y + patch[2].v.pos * bary.z + perPatchData.edges[1];
v.tex = patch[0].v.tex * bary.x + patch[1].v.tex * bary.y + patch[2].v.tex * bary.z + perPatchData.edges[0];
v.norm = patch[0].v.norm * bary.x + patch[1].v.norm * bary.y + patch[2].v.norm * bary.z + perPatchData.inside;
v.RTIndex = 0;
return v;
}

// HS

HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points, OutputPatch<HSPerVertexData, 3> outp)
{
HSPerPatchData d;

d.edges[ 0 ] = 1;
d.edges[ 1 ] = 1;
d.edges[ 2 ] = 1;
d.inside = 1;

return d;
}

// hull per-control point shader
[shader("hs_6_1")]
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[patchconstantfunc("HSPerPatchFunc")]
[outputcontrolpoints(3)]
HSPerVertexData hs_main( const uint id : SV_OutputControlPointID,
const InputPatch< PSSceneIn, 3 > points)
{
HSPerVertexData v;

// Just forward the vertex
v.v = points[ id ];

return v;
}

// VS

struct VS_INPUT
{
float3 vPosition : POSITION;
float3 vNormal : NORMAL;
float2 vTexcoord : TEXCOORD0;
};

struct VS_OUTPUT
{
float3 vNormal : NORMAL;
float2 vTexcoord : TEXCOORD0;
float4 vPosition : SV_POSITION;
};


[shader("vs_6_1")]
VS_OUTPUT vs_main(VS_INPUT Input)
{
VS_OUTPUT Output;

Output.vPosition = float4( Input.vPosition, 1.0 );
Output.vNormal = Input.vNormal;
Output.vTexcoord = Input.vTexcoord;

return Output;
}

// PS
[shader("ps_6_1")]
float4 ps_main(float4 a : A) : SV_TARGET
{
return a;
}
9 changes: 9 additions & 0 deletions tools/clang/test/CodeGenHLSL/shader_attr.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %dxc -T lib_6_1 %s | FileCheck %s

// CHECK:attribute 'shader' must have one of these values: cs_6_0,cs_6_1,ps_6_0,ps_6_1,vs_6_0,vs_6_1, hs_6_0,hs_6_1,ds_6_0,ds_6_1,gs_6_0,gs_6_1

[shader("lib_6_1")]
float4 ps_main(float4 a : A) : SV_TARGET
{
return a;
}
Loading