-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[DXIL] Add support for root signature flag element in DXContainer #123147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 53 commits
8adb678
ba78f21
0a54559
557075f
e0d3dcd
80587dd
be3764d
7582ca6
6aaa0a5
916b2f1
d9bce0a
e7676ed
a0cee57
1e7a1fe
0ed658a
932062e
628937c
1378c9f
e3206c9
f93d42d
25e3f37
751cbdc
44532d6
ca21878
987901c
0fbe900
b771aea
aabdfe7
4f6f941
a7f7784
bf3b2e0
16b4d03
e043370
57bf935
1f8c0a5
0905b83
77e8544
1351fb0
09e645a
5a44b62
d1a79b3
9f8e512
5c7ed7e
93f7c4c
5aac761
47b01f7
486ab88
852ac25
74f7226
7a82fa9
c67d039
e80ef33
ef1ce8a
b7f2716
83b0979
b175b65
01b49a7
7bba9d3
2809c2f
023dcb8
aedb446
39e60c0
3b135c6
ae3d03f
3d19f8b
5a3be7c
f64c608
a5a2093
5b3fedc
605f225
e4bca2b
825673f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -9,9 +9,9 @@ | |||||
#include "llvm/Object/DXContainer.h" | ||||||
#include "llvm/BinaryFormat/DXContainer.h" | ||||||
#include "llvm/Object/Error.h" | ||||||
#include "llvm/Support/FormatVariadic.h" | ||||||
#include "llvm/Support/Alignment.h" | ||||||
#include "llvm/Support/Endian.h" | ||||||
#include "llvm/Support/FormatVariadic.h" | ||||||
bogner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
using namespace llvm; | ||||||
using namespace llvm::object; | ||||||
|
@@ -254,11 +254,9 @@ Error DirectX::RootSignature::parse(StringRef Data) { | |||||
support::endian::read<uint32_t, llvm::endianness::little>(Current); | ||||||
Current += sizeof(uint32_t); | ||||||
|
||||||
Expected<uint32_t> MaybeVersion = | ||||||
dxbc::RootSignatureValidations::validateVersion(VValue); | ||||||
if (Error E = MaybeVersion.takeError()) | ||||||
return E; | ||||||
Version = MaybeVersion.get(); | ||||||
if (dxbc::RootSignatureValidations::validateVersion(VValue)) | ||||||
return make_error<GenericBinaryError>("Invalid Root Signature Version"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These error strings are what get printed by LLVM if we ever hit this error condition. This message doesn't tell me what the actual error is. Maybe something like (needs proper formatting):
Suggested change
|
||||||
Version = VValue; | ||||||
|
||||||
NumParameters = | ||||||
support::endian::read<uint32_t, llvm::endianness::little>(Current); | ||||||
|
@@ -280,11 +278,9 @@ Error DirectX::RootSignature::parse(StringRef Data) { | |||||
support::endian::read<uint32_t, llvm::endianness::little>(Current); | ||||||
Current += sizeof(uint32_t); | ||||||
|
||||||
Expected<uint32_t> MaybeFlag = | ||||||
dxbc::RootSignatureValidations::validateRootFlag(FValue); | ||||||
if (Error E = MaybeFlag.takeError()) | ||||||
return E; | ||||||
Flags = MaybeFlag.get(); | ||||||
if (dxbc::RootSignatureValidations::validateRootFlag(FValue)) | ||||||
return make_error<GenericBinaryError>("Invalid Root Signature flag"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same feedback as above, we can make this a useful error. |
||||||
Flags = FValue; | ||||||
|
||||||
return Error::success(); | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ add_llvm_target(DirectXCodeGen | |
DXILResourceAccess.cpp | ||
DXILShaderFlags.cpp | ||
DXILTranslateMetadata.cpp | ||
|
||
DXILRootSignature.cpp | ||
LINK_COMPONENTS | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please keep the blank line between the sources and the LINK_COMPONENTS line - it makes this easier to read. |
||
Analysis | ||
AsmPrinter | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "DXILRootSignature.h" | ||
#include "DXILShaderFlags.h" | ||
#include "DirectX.h" | ||
#include "llvm/ADT/SmallVector.h" | ||
|
@@ -23,6 +24,7 @@ | |
#include "llvm/IR/Module.h" | ||
#include "llvm/InitializePasses.h" | ||
#include "llvm/MC/DXContainerPSVInfo.h" | ||
#include "llvm/MC/DXContainerRootSignature.h" | ||
#include "llvm/Pass.h" | ||
#include "llvm/Support/MD5.h" | ||
#include "llvm/Transforms/Utils/ModuleUtils.h" | ||
|
@@ -41,6 +43,7 @@ class DXContainerGlobals : public llvm::ModulePass { | |
GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name, | ||
StringRef SectionName); | ||
void addSignature(Module &M, SmallVector<GlobalValue *> &Globals); | ||
void addRootSignature(Module &M, SmallVector<GlobalValue *> &Globals); | ||
void addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV); | ||
void addPipelineStateValidationInfo(Module &M, | ||
SmallVector<GlobalValue *> &Globals); | ||
|
@@ -60,6 +63,7 @@ class DXContainerGlobals : public llvm::ModulePass { | |
void getAnalysisUsage(AnalysisUsage &AU) const override { | ||
AU.setPreservesAll(); | ||
AU.addRequired<ShaderFlagsAnalysisWrapper>(); | ||
AU.addRequired<RootSignatureAnalysisWrapper>(); | ||
AU.addRequired<DXILMetadataAnalysisWrapperPass>(); | ||
AU.addRequired<DXILResourceTypeWrapperPass>(); | ||
AU.addRequired<DXILResourceBindingWrapperPass>(); | ||
|
@@ -73,6 +77,7 @@ bool DXContainerGlobals::runOnModule(Module &M) { | |
Globals.push_back(getFeatureFlags(M)); | ||
Globals.push_back(computeShaderHash(M)); | ||
addSignature(M, Globals); | ||
addRootSignature(M, Globals); | ||
addPipelineStateValidationInfo(M, Globals); | ||
appendToCompilerUsed(M, Globals); | ||
return true; | ||
|
@@ -144,6 +149,29 @@ void DXContainerGlobals::addSignature(Module &M, | |
Globals.emplace_back(buildSignature(M, OutputSig, "dx.osg1", "OSG1")); | ||
} | ||
|
||
void DXContainerGlobals::addRootSignature(Module &M, | ||
SmallVector<GlobalValue *> &Globals) { | ||
|
||
auto &RSA = getAnalysis<RootSignatureAnalysisWrapper>(); | ||
|
||
if (!RSA.hasRootSignature()) | ||
return; | ||
|
||
ModuleRootSignature MRS = RSA.getRootSignature(); | ||
|
||
SmallString<256> Data; | ||
raw_svector_ostream OS(Data); | ||
|
||
RootSignatureHeader RSH; | ||
RSH.Flags = MRS.Flags; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we have an auxilliary structure that we simply copy through here? Could RootSignatureAnalysis just provide us with a aside: Both |
||
|
||
RSH.write(OS); | ||
|
||
Constant *Constant = | ||
ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false); | ||
Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.rts0", "RTS0")); | ||
} | ||
|
||
void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) { | ||
const DXILBindingMap &DBM = | ||
getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap(); | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,196 @@ | ||||||
//===- DXILRootSignature.cpp - DXIL Root Signature helper objects ----===// | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I counted this right
Suggested change
|
||||||
// | ||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||||
// See https://llvm.org/LICENSE.txt for license information. | ||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
// | ||||||
//===----------------------------------------------------------------------===// | ||||||
/// | ||||||
/// \file This file contains helper objects and APIs for working with DXIL | ||||||
/// Root Signatures. | ||||||
/// | ||||||
//===----------------------------------------------------------------------===// | ||||||
#include "DXILRootSignature.h" | ||||||
#include "DirectX.h" | ||||||
#include "llvm/ADT/StringSwitch.h" | ||||||
#include "llvm/ADT/Twine.h" | ||||||
#include "llvm/Analysis/DXILMetadataAnalysis.h" | ||||||
#include "llvm/BinaryFormat/DXContainer.h" | ||||||
#include "llvm/IR/Constants.h" | ||||||
#include "llvm/IR/DiagnosticInfo.h" | ||||||
#include "llvm/IR/Function.h" | ||||||
#include "llvm/IR/LLVMContext.h" | ||||||
#include "llvm/IR/Module.h" | ||||||
#include "llvm/InitializePasses.h" | ||||||
#include "llvm/Pass.h" | ||||||
#include "llvm/Support/Error.h" | ||||||
#include <optional> | ||||||
|
||||||
using namespace llvm; | ||||||
using namespace llvm::dxil; | ||||||
|
||||||
bool ModuleRootSignature::reportError(Twine Message, | ||||||
DiagnosticSeverity Severity) { | ||||||
Ctx->diagnose(DiagnosticInfoGeneric(Message, Severity)); | ||||||
return true; | ||||||
} | ||||||
|
||||||
bool ModuleRootSignature::parseRootFlags(MDNode *RootFlagNode) { | ||||||
|
||||||
if (RootFlagNode->getNumOperands() != 2) | ||||||
return reportError("Invalid format for RootFlag Element"); | ||||||
|
||||||
auto *Flag = mdconst::extract<ConstantInt>(RootFlagNode->getOperand(1)); | ||||||
this->Flags = Flag->getZExtValue(); | ||||||
|
||||||
return false; | ||||||
} | ||||||
|
||||||
bool ModuleRootSignature::parseRootSignatureElement(MDNode *Element) { | ||||||
MDString *ElementText = cast<MDString>(Element->getOperand(0)); | ||||||
if (ElementText == nullptr) | ||||||
return reportError("Invalid format for Root Element"); | ||||||
|
||||||
RootSignatureElementKind ElementKind = | ||||||
StringSwitch<RootSignatureElementKind>(ElementText->getString()) | ||||||
.Case("RootFlags", RootSignatureElementKind::RootFlags) | ||||||
.Case("RootConstants", RootSignatureElementKind::RootConstants) | ||||||
.Case("RootCBV", RootSignatureElementKind::RootDescriptor) | ||||||
.Case("RootSRV", RootSignatureElementKind::RootDescriptor) | ||||||
.Case("RootUAV", RootSignatureElementKind::RootDescriptor) | ||||||
.Case("Sampler", RootSignatureElementKind::RootDescriptor) | ||||||
.Case("DescriptorTable", RootSignatureElementKind::DescriptorTable) | ||||||
.Case("StaticSampler", RootSignatureElementKind::StaticSampler) | ||||||
.Default(RootSignatureElementKind::None); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should |
||||||
|
||||||
switch (ElementKind) { | ||||||
|
||||||
case RootSignatureElementKind::RootFlags: { | ||||||
return parseRootFlags(Element); | ||||||
break; | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
|
||||||
case RootSignatureElementKind::RootConstants: | ||||||
case RootSignatureElementKind::RootDescriptor: | ||||||
case RootSignatureElementKind::DescriptorTable: | ||||||
case RootSignatureElementKind::StaticSampler: | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
case RootSignatureElementKind::None: | ||||||
return reportError("Invalid Root Element: " + ElementText->getString()); | ||||||
break; | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
|
||||||
return true; | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
|
||||||
bool ModuleRootSignature::parse(NamedMDNode *Root, const Function *EF) { | ||||||
bool HasError = false; | ||||||
|
||||||
/** Root Signature are specified as following in the metadata: | ||||||
|
||||||
!dx.rootsignatures = !{!2} ; list of function/root signature pairs | ||||||
!2 = !{ ptr @main, !3 } ; function, root signature | ||||||
!3 = !{ !4, !5, !6, !7 } ; list of root signature elements | ||||||
|
||||||
So for each MDNode inside dx.rootsignatures NamedMDNode | ||||||
(the Root parameter of this function), the parsing process needs | ||||||
to loop through each of it's operand and process the pairs function | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
signature pair. | ||||||
*/ | ||||||
|
||||||
for (const MDNode *Node : Root->operands()) { | ||||||
if (Node->getNumOperands() != 2) | ||||||
return reportError("Invalid format for Root Signature Definition. Pairs " | ||||||
"of function, root signature expected."); | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
ValueAsMetadata *VAM = | ||||||
llvm::dyn_cast<ValueAsMetadata>(Node->getOperand(0).get()); | ||||||
if (VAM == nullptr) | ||||||
return reportError("First element of root signature is not a value"); | ||||||
|
||||||
Function *F = dyn_cast<Function>(VAM->getValue()); | ||||||
if (F == nullptr) | ||||||
return reportError("First element of root signature is not a function"); | ||||||
|
||||||
if (F != EF) | ||||||
continue; | ||||||
|
||||||
// Get the Root Signature Description from the function signature pair. | ||||||
MDNode *RS = dyn_cast<MDNode>(Node->getOperand(1).get()); | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
if (RS == nullptr) | ||||||
return reportError("Missing Root Element List Metadata node."); | ||||||
|
||||||
// Loop through the Root Elements of the root signature. | ||||||
for (unsigned int Eid = 0; Eid < RS->getNumOperands(); Eid++) { | ||||||
MDNode *Element = dyn_cast<MDNode>(RS->getOperand(Eid)); | ||||||
bogner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
if (Element == nullptr) | ||||||
return reportError("Missing Root Element Metadata Node."); | ||||||
|
||||||
HasError = HasError || parseRootSignatureElement(Element); | ||||||
} | ||||||
} | ||||||
return HasError; | ||||||
} | ||||||
|
||||||
bool ModuleRootSignature::validate() { | ||||||
if (dxbc::RootSignatureValidations::validateRootFlag(Flags)) { | ||||||
return reportError("Invalid Root Signature flag value"); | ||||||
} | ||||||
return false; | ||||||
} | ||||||
|
||||||
OptionalRootSignature ModuleRootSignature::analyzeModule(Module &M, | ||||||
const Function *F) { | ||||||
ModuleRootSignature MRS(&M.getContext()); | ||||||
|
||||||
NamedMDNode *RootSignatureNode = M.getNamedMetadata("dx.rootsignatures"); | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
if (RootSignatureNode == nullptr || MRS.parse(RootSignatureNode, F) || | ||||||
MRS.validate()) | ||||||
return std::nullopt; | ||||||
|
||||||
return MRS; | ||||||
} | ||||||
|
||||||
AnalysisKey RootSignatureAnalysis::Key; | ||||||
|
||||||
OptionalRootSignature RootSignatureAnalysis::run(Module &M, | ||||||
ModuleAnalysisManager &AM) { | ||||||
auto MMI = AM.getResult<DXILMetadataAnalysis>(M); | ||||||
|
||||||
if (MMI.ShaderProfile == Triple::Library) | ||||||
return std::nullopt; | ||||||
|
||||||
assert(MMI.EntryPropertyVec.size() == 1); | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
const Function *EntryFunction = MMI.EntryPropertyVec[0].Entry; | ||||||
return ModuleRootSignature::analyzeModule(M, EntryFunction); | ||||||
} | ||||||
|
||||||
//===----------------------------------------------------------------------===// | ||||||
bool RootSignatureAnalysisWrapper::runOnModule(Module &M) { | ||||||
|
||||||
dxil::ModuleMetadataInfo &MMI = | ||||||
getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata(); | ||||||
|
||||||
if (MMI.ShaderProfile == Triple::Library) | ||||||
return false; | ||||||
assert(MMI.EntryPropertyVec.size() == 1); | ||||||
|
||||||
const Function *EntryFunction = MMI.EntryPropertyVec[0].Entry; | ||||||
MRS = ModuleRootSignature::analyzeModule(M, EntryFunction); | ||||||
return false; | ||||||
} | ||||||
|
||||||
void RootSignatureAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const { | ||||||
AU.setPreservesAll(); | ||||||
AU.addRequired<DXILMetadataAnalysisWrapperPass>(); | ||||||
} | ||||||
|
||||||
char RootSignatureAnalysisWrapper::ID = 0; | ||||||
damyanp marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
INITIALIZE_PASS_BEGIN(RootSignatureAnalysisWrapper, | ||||||
"dx-root-signature-analysis", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be called |
||||||
"DXIL Root Signature Analysis", true, true) | ||||||
INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass) | ||||||
INITIALIZE_PASS_END(RootSignatureAnalysisWrapper, "dx-root-signature-analysis", | ||||||
"DXIL Root Signature Analysis", true, true) |
Uh oh!
There was an error while loading. Please reload this page.