in tools/clang/tools/dxcompiler/dxcompilerobj.cpp [615:1253]
HRESULT STDMETHODCALLTYPE Compile(
_In_ const DxcBuffer *pSource, // Source text to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, buffer, and errors
) override {
if (pSource == nullptr || ppResult == nullptr ||
(argCount > 0 && pArguments == nullptr))
return E_INVALIDARG;
if (!(IsEqualIID(riid, __uuidof(IDxcResult)) ||
IsEqualIID(riid, __uuidof(IDxcOperationResult))))
return E_INVALIDARG;
*ppResult = nullptr;
HRESULT hr = S_OK;
CComPtr<IDxcBlobUtf8> utf8Source;
CComPtr<AbstractMemoryStream> pOutputStream;
CComPtr<IDxcOperationResult> pDxcOperationResult;
bool bCompileStarted = false;
bool bPreprocessStarted = false;
DxilShaderHash ShaderHashContent;
DxcThreadMalloc TM(m_pMalloc);
try {
DefaultFPEnvScope fpEnvScope;
IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
// Parse command-line options into DxcOpts
int argCountInt;
IFT(UIntToInt(argCount, &argCountInt));
hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
hlsl::options::DxcOpts opts;
std::string warnings;
raw_string_ostream w(warnings);
{
bool finished = false;
CComPtr<AbstractMemoryStream> pOptionErrorStream;
IFT(CreateMemoryStream(m_pMalloc, &pOptionErrorStream));
dxcutil::ReadOptsAndValidate(mainArgs, opts, pOptionErrorStream, &pDxcOperationResult, finished);
if (finished) {
IFT(pDxcOperationResult->QueryInterface(riid, ppResult));
hr = S_OK;
goto Cleanup;
}
if (pOptionErrorStream->GetPtrSize() > 0) {
w << StringRef((const char*)pOptionErrorStream->GetPtr(), (size_t)pOptionErrorStream->GetPtrSize());
}
}
bool isPreprocessing = !opts.Preprocess.empty();
if (isPreprocessing) {
DxcEtw_DXCompilerPreprocess_Start();
bPreprocessStarted = true;
} else {
DxcEtw_DXCompilerCompile_Start();
bCompileStarted = true;
}
CComPtr<DxcResult> pResult = DxcResult::Alloc(m_pMalloc);
IFT(pResult->SetEncoding(opts.DefaultTextCodePage));
DxcOutputObject primaryOutput;
// Formerly API values.
const char *pUtf8SourceName = opts.InputFile.empty() ? "hlsl.hlsl" : opts.InputFile.data();
CA2W pUtf16SourceName(pUtf8SourceName, CP_UTF8);
const char *pUtf8EntryPoint = opts.EntryPoint.empty() ? "main" : opts.EntryPoint.data();
const char *pUtf8OutputName = isPreprocessing
? opts.Preprocess.data()
: opts.OutputObject.empty()
? "" : opts.OutputObject.data();
CA2W pUtf16OutputName(isPreprocessing ?
opts.Preprocess.data() : pUtf8OutputName,
CP_UTF8);
LPCWSTR pObjectName = (!isPreprocessing && opts.OutputObject.empty()) ?
nullptr : pUtf16OutputName.m_psz;
IFT(primaryOutput.SetName(pObjectName));
// Wrap source in blob
CComPtr<IDxcBlobEncoding> pSourceEncoding;
IFT(hlsl::DxcCreateBlob(pSource->Ptr, pSource->Size,
true, false, pSource->Encoding != 0, pSource->Encoding,
nullptr, &pSourceEncoding));
#ifdef ENABLE_SPIRV_CODEGEN
// We want to embed the preprocessed source code in the final SPIR-V if
// debug information is enabled. Therefore, we invoke Preprocess() here
// first for such case. Then we invoke the compilation process over the
// preprocessed source code, so that line numbers are consistent with the
// embedded source code.
if (!isPreprocessing && opts.GenSPIRV && opts.DebugInfo &&
!opts.SpirvOptions.debugInfoVulkan) {
CComPtr<IDxcResult> pSrcCodeResult;
std::vector<LPCWSTR> PreprocessArgs;
PreprocessArgs.reserve(argCount + 1);
PreprocessArgs.assign(pArguments, pArguments + argCount);
PreprocessArgs.push_back(L"-P");
PreprocessArgs.push_back(L"preprocessed.hlsl");
IFT(Compile(pSource, PreprocessArgs.data(), PreprocessArgs.size(), pIncludeHandler, IID_PPV_ARGS(&pSrcCodeResult)));
HRESULT status;
IFT(pSrcCodeResult->GetStatus(&status));
if (SUCCEEDED(status)) {
pSourceEncoding.Release();
IFT(pSrcCodeResult->GetOutput(DXC_OUT_HLSL, IID_PPV_ARGS(&pSourceEncoding), nullptr));
}
}
#endif // ENABLE_SPIRV_CODEGEN
// Convert source code encoding
IFC(hlsl::DxcGetBlobAsUtf8(pSourceEncoding, m_pMalloc, &utf8Source,
opts.DefaultTextCodePage));
CComPtr<IDxcBlob> pOutputBlob;
dxcutil::DxcArgsFileSystem *msfPtr = dxcutil::CreateDxcArgsFileSystem(
utf8Source, pUtf16SourceName.m_psz, pIncludeHandler,
opts.DefaultTextCodePage);
std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
IFTLLVM(pts.error_code());
IFT(pOutputStream.QueryInterface(&pOutputBlob));
primaryOutput.kind = DXC_OUT_OBJECT;
if (opts.AstDump || opts.OptDump || opts.DumpDependencies)
primaryOutput.kind = DXC_OUT_TEXT;
else if (isPreprocessing)
primaryOutput.kind = DXC_OUT_HLSL;
IFT(pResult->SetOutputName(DXC_OUT_REFLECTION, opts.OutputReflectionFile));
IFT(pResult->SetOutputName(DXC_OUT_SHADER_HASH, opts.OutputShaderHashFile));
IFT(pResult->SetOutputName(DXC_OUT_ERRORS, opts.OutputWarningsFile));
IFT(pResult->SetOutputName(DXC_OUT_ROOT_SIGNATURE, opts.OutputRootSigFile));
if (opts.DisplayIncludeProcess)
msfPtr->EnableDisplayIncludeProcess();
IFT(msfPtr->RegisterOutputStream(L"output.bc", pOutputStream));
IFT(msfPtr->CreateStdStreams(m_pMalloc));
StringRef Data(utf8Source->GetStringPointer(),
utf8Source->GetStringLength());
// Not very efficient but also not very important.
std::vector<std::string> defines;
CreateDefineStrings(opts.Defines.data(), opts.Defines.size(), defines);
// Setup a compiler instance.
raw_stream_ostream outStream(pOutputStream.p);
llvm::LLVMContext llvmContext; // LLVMContext should outlive CompilerInstance
std::unique_ptr<llvm::Module> debugModule;
CComPtr<AbstractMemoryStream> pReflectionStream;
CompilerInstance compiler;
std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
llvm::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
SetupCompilerForCompile(compiler, &m_langExtensionsHelper, pUtf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
msfPtr->SetupForCompilerInstance(compiler);
// The clang entry point (cc1_main) would now create a compiler invocation
// from arguments, but depending on the Preprocess option, we either compile
// to LLVM bitcode and then package that into a DXBC blob, or preprocess to
// HLSL text.
//
// With the compiler invocation built from command line arguments, the
// next step is to call ExecuteCompilerInvocation, which creates a
// FrontendAction* of EmitBCAction, which is a CodeGenAction, which is an
// ASTFrontendAction. That sets up a BackendConsumer as the ASTConsumer.
compiler.getFrontendOpts().OutputFile = "output.bc";
compiler.WriteDefaultOutputDirectly = true;
compiler.setOutStream(&outStream);
unsigned rootSigMajor = 0;
unsigned rootSigMinor = 0;
// NOTE: this calls the validation component from dxil.dll; the built-in
// validator can be used as a fallback.
bool produceFullContainer = false;
bool needsValidation = false;
bool validateRootSigContainer = false;
if (isPreprocessing) {
// These settings are back-compatible with fxc.
clang::PreprocessorOutputOptions &PPOutOpts =
compiler.getPreprocessorOutputOpts();
PPOutOpts.ShowCPP = 1; // Print normal preprocessed output.
PPOutOpts.ShowComments = 0; // Show comments.
PPOutOpts.ShowLineMarkers = 1; // Show \#line markers.
PPOutOpts.UseLineDirectives = 1; // Use \#line instead of GCC-style \# N.
PPOutOpts.ShowMacroComments = 0; // Show comments, even in macros.
PPOutOpts.ShowMacros = 0; // Print macro definitions.
PPOutOpts.RewriteIncludes = 0; // Preprocess include directives only.
FrontendInputFile file(pUtf8SourceName, IK_HLSL);
clang::PrintPreprocessedAction action;
if (action.BeginSourceFile(compiler, file)) {
action.Execute();
action.EndSourceFile();
}
outStream.flush();
} else {
compiler.getLangOpts().HLSLEntryFunction =
compiler.getCodeGenOpts().HLSLEntryFunction = pUtf8EntryPoint;
compiler.getLangOpts().HLSLProfile =
compiler.getCodeGenOpts().HLSLProfile = opts.TargetProfile;
// Parse and apply
if (opts.BindingTableDefine.size()) {
// Just pas the define for now because preprocessor is not available yet.
struct BindingTableParserImpl : public CodeGenOptions::BindingTableParserType {
CompilerInstance &compiler;
std::string define;
BindingTableParserImpl(CompilerInstance &compiler, StringRef define)
:compiler(compiler), define(define.str())
{}
bool Parse(llvm::raw_ostream &os, hlsl::DxcBindingTable *outBindingTable) override {
Preprocessor &pp = compiler.getPreprocessor();
MacroInfo *macro = MacroExpander::FindMacroInfo(pp, define);
if (!macro) {
os << Twine("Binding table define'") + define + "' not found.";
os.flush();
return false;
}
std::string bindingTableStr;
// Combine tokens into single string
MacroExpander expander(pp, MacroExpander::STRIP_QUOTES);
if (!expander.ExpandMacro(macro, &bindingTableStr)) {
os << Twine("Binding table define'") + define + "' failed to expand.";
os.flush();
return false;
}
return hlsl::ParseBindingTable(
define, StringRef(bindingTableStr),
os, outBindingTable);
}
};
compiler.getCodeGenOpts().BindingTableParser.reset(new BindingTableParserImpl(compiler, opts.BindingTableDefine));
}
else if (opts.ImportBindingTable.size()) {
hlsl::options::StringRefUtf16 wstrRef(opts.ImportBindingTable);
CComPtr<IDxcBlob> pBlob;
std::string error;
llvm::raw_string_ostream os(error);
if (!pIncludeHandler) {
os << Twine("Binding table binding file '") + opts.ImportBindingTable + "' specified, but no include handler was given.";
os.flush();
return ErrorWithString(error, riid, ppResult);
}
else if (SUCCEEDED(pIncludeHandler->LoadSource(wstrRef, &pBlob))) {
bool succ = hlsl::ParseBindingTable(
opts.ImportBindingTable,
StringRef((const char *)pBlob->GetBufferPointer(), pBlob->GetBufferSize()),
os, &compiler.getCodeGenOpts().HLSLBindingTable);
if (!succ) {
os.flush();
return ErrorWithString(error, riid, ppResult);
}
}
else {
os << Twine("Could not load binding table file '") + opts.ImportBindingTable + "'.";
os.flush();
return ErrorWithString(error, riid, ppResult);
}
}
if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_1") {
rootSigMajor = 1;
rootSigMinor = 1;
} else if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_0") {
rootSigMajor = 1;
rootSigMinor = 0;
}
compiler.getLangOpts().IsHLSLLibrary = opts.IsLibraryProfile();
// Clear entry function if library target
if (compiler.getLangOpts().IsHLSLLibrary)
compiler.getLangOpts().HLSLEntryFunction =
compiler.getCodeGenOpts().HLSLEntryFunction = "";
// NOTE: this calls the validation component from dxil.dll; the built-in
// validator can be used as a fallback.
produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump &&
!opts.OptDump && rootSigMajor == 0 &&
!opts.DumpDependencies;
needsValidation = produceFullContainer && !opts.DisableValidation;
if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_x") {
// Currently do not support stripping reflection from offline linking target.
opts.KeepReflectionInDxil = true;
}
if (opts.ValVerMajor != UINT_MAX) {
// user-specified validator version override
compiler.getCodeGenOpts().HLSLValidatorMajorVer = opts.ValVerMajor;
compiler.getCodeGenOpts().HLSLValidatorMinorVer = opts.ValVerMinor;
} else {
// Version from dxil.dll, or internal validator if unavailable
dxcutil::GetValidatorVersion(&compiler.getCodeGenOpts().HLSLValidatorMajorVer,
&compiler.getCodeGenOpts().HLSLValidatorMinorVer);
}
// Root signature-only container validation is only supported on 1.5 and above.
validateRootSigContainer = DXIL::CompareVersions(
compiler.getCodeGenOpts().HLSLValidatorMajorVer,
compiler.getCodeGenOpts().HLSLValidatorMinorVer,
1, 5) >= 0;
}
if (opts.AstDump) {
clang::ASTDumpAction dumpAction;
// Consider - ASTDumpFilter, ASTDumpLookups
compiler.getFrontendOpts().ASTDumpDecls = true;
FrontendInputFile file(pUtf8SourceName, IK_HLSL);
dumpAction.BeginSourceFile(compiler, file);
dumpAction.Execute();
dumpAction.EndSourceFile();
outStream.flush();
} else if (opts.DumpDependencies) {
auto dependencyCollector = std::make_shared<DependencyCollector>();
compiler.addDependencyCollector(dependencyCollector);
compiler.createPreprocessor(clang::TranslationUnitKind::TU_Complete);
clang::PreprocessOnlyAction preprocessAction;
FrontendInputFile file(pUtf8SourceName, IK_HLSL);
preprocessAction.BeginSourceFile(compiler, file);
preprocessAction.Execute();
preprocessAction.EndSourceFile();
outStream << (opts.OutputObject.empty() ? opts.InputFile
: opts.OutputObject);
bool firstDependency = true;
for (auto &dependency : dependencyCollector->getDependencies()) {
if (firstDependency) {
outStream << ": " << dependency;
firstDependency = false;
continue;
}
outStream << " \\\n " << dependency;
}
outStream << "\n";
outStream.flush();
} else if (opts.OptDump) {
EmitOptDumpAction action(&llvmContext);
FrontendInputFile file(pUtf8SourceName, IK_HLSL);
action.BeginSourceFile(compiler, file);
action.Execute();
action.EndSourceFile();
outStream.flush();
} else if (rootSigMajor) {
HLSLRootSignatureAction action(
compiler.getCodeGenOpts().HLSLEntryFunction, rootSigMajor,
rootSigMinor);
FrontendInputFile file(pUtf8SourceName, IK_HLSL);
action.BeginSourceFile(compiler, file);
action.Execute();
action.EndSourceFile();
outStream.flush();
// Don't do work to put in a container if an error has occurred
bool compileOK = !compiler.getDiagnostics().hasErrorOccurred();
if (compileOK) {
auto rootSigHandle = action.takeRootSigHandle();
CComPtr<AbstractMemoryStream> pContainerStream;
IFT(CreateMemoryStream(m_pMalloc, &pContainerStream));
SerializeDxilContainerForRootSignature(rootSigHandle.get(),
pContainerStream);
pOutputBlob.Release();
IFT(pContainerStream.QueryInterface(&pOutputBlob));
if (validateRootSigContainer && !opts.DisableValidation) {
CComPtr<IDxcBlobEncoding> pValErrors;
// Validation failure communicated through diagnostic error
dxcutil::ValidateRootSignatureInContainer(
pOutputBlob, &compiler.getDiagnostics());
}
}
}
// SPIRV change starts
#ifdef ENABLE_SPIRV_CODEGEN
else if (!isPreprocessing && opts.GenSPIRV) {
// Since SpirvOptions is passed to the SPIR-V CodeGen as a whole
// structure, we need to copy a few non-spirv-specific options into the
// structure.
opts.SpirvOptions.enable16BitTypes = opts.Enable16BitTypes;
opts.SpirvOptions.codeGenHighLevel = opts.CodeGenHighLevel;
opts.SpirvOptions.defaultRowMajor = opts.DefaultRowMajor;
opts.SpirvOptions.disableValidation = opts.DisableValidation;
// Store a string representation of command line options.
if (opts.DebugInfo)
for (auto opt : mainArgs.getArrayRef())
opts.SpirvOptions.clOptions += " " + std::string(opt);
compiler.getCodeGenOpts().SpirvOptions = opts.SpirvOptions;
clang::EmitSpirvAction action;
FrontendInputFile file(pUtf8SourceName, IK_HLSL);
action.BeginSourceFile(compiler, file);
action.Execute();
action.EndSourceFile();
outStream.flush();
}
#endif
// SPIRV change ends
else if (!isPreprocessing) {
EmitBCAction action(&llvmContext);
FrontendInputFile file(pUtf8SourceName, IK_HLSL);
bool compileOK;
if (action.BeginSourceFile(compiler, file)) {
action.Execute();
action.EndSourceFile();
compileOK = !compiler.getDiagnostics().hasErrorOccurred();
}
else {
compileOK = false;
}
outStream.flush();
SerializeDxilFlags SerializeFlags = SerializeDxilFlags::None;
if (opts.EmbedPDBName()) {
SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
}
// If -Qembed_debug specified, embed the debug info.
// Or, if there is no output pointer for the debug blob (such as when called by Compile()),
// embed the debug info and emit a note.
if (opts.EmbedDebugInfo()) {
SerializeFlags |= SerializeDxilFlags::IncludeDebugInfoPart;
}
if (opts.DebugNameForSource) {
// Implies name part
SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
SerializeFlags |= SerializeDxilFlags::DebugNameDependOnSource;
} else if (opts.DebugNameForBinary) {
// Implies name part
SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
}
if (!opts.KeepReflectionInDxil) {
SerializeFlags |= SerializeDxilFlags::StripReflectionFromDxilPart;
}
if (!opts.StripReflection) {
SerializeFlags |= SerializeDxilFlags::IncludeReflectionPart;
}
if (opts.StripRootSignature) {
SerializeFlags |= SerializeDxilFlags::StripRootSignature;
}
// Don't do work to put in a container if an error has occurred
// Do not create a container when there is only a a high-level representation in the module.
if (compileOK && !opts.CodeGenHighLevel) {
HRESULT valHR = S_OK;
CComPtr<AbstractMemoryStream> pRootSigStream;
IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pReflectionStream));
IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pRootSigStream));
std::unique_ptr<llvm::Module> serializeModule( action.takeModule() );
// Clone and save the copy.
if (opts.GenerateFullDebugInfo()) {
debugModule.reset(llvm::CloneModule(serializeModule.get()));
}
dxcutil::AssembleInputs inputs(
std::move(serializeModule), pOutputBlob, m_pMalloc, SerializeFlags,
pOutputStream,
opts.GetPDBName(), &compiler.getDiagnostics(),
&ShaderHashContent, pReflectionStream, pRootSigStream);
if (needsValidation) {
valHR = dxcutil::ValidateAndAssembleToContainer(inputs);
} else {
dxcutil::AssembleToContainer(inputs);
}
// Callback after valid DXIL is produced
if (SUCCEEDED(valHR)) {
CComPtr<IDxcBlob> pTargetBlob;
if (m_pDxcContainerEventsHandler != nullptr) {
HRESULT hr = m_pDxcContainerEventsHandler->OnDxilContainerBuilt(pOutputBlob, &pTargetBlob);
if (SUCCEEDED(hr) && pTargetBlob != nullptr) {
std::swap(pOutputBlob, pTargetBlob);
}
}
if (pOutputBlob && produceFullContainer && (SerializeFlags & SerializeDxilFlags::IncludeDebugNamePart) != 0) {
const DxilContainerHeader *pContainer = reinterpret_cast<DxilContainerHeader *>(pOutputBlob->GetBufferPointer());
DXASSERT(IsValidDxilContainer(pContainer, pOutputBlob->GetBufferSize()), "else invalid container generated");
auto it = std::find_if(begin(pContainer), end(pContainer), DxilPartIsType(DFCC_ShaderDebugName));
if (it != end(pContainer)) {
const char *pDebugName;
if (GetDxilShaderDebugName(*it, &pDebugName, nullptr) && pDebugName && *pDebugName) {
IFT(pResult->SetOutputName(DXC_OUT_PDB, pDebugName));
}
}
}
if (pReflectionStream && pReflectionStream->GetPtrSize()) {
CComPtr<IDxcBlob> pReflection;
IFT(pReflectionStream->QueryInterface(&pReflection));
IFT(pResult->SetOutputObject(DXC_OUT_REFLECTION, pReflection));
}
if (pRootSigStream && pRootSigStream->GetPtrSize()) {
CComPtr<IDxcBlob> pRootSignature;
IFT(pRootSigStream->QueryInterface(&pRootSignature));
if (validateRootSigContainer && needsValidation) {
CComPtr<IDxcBlobEncoding> pValErrors;
// Validation failure communicated through diagnostic error
dxcutil::ValidateRootSignatureInContainer(pRootSignature, &compiler.getDiagnostics());
}
IFT(pResult->SetOutputObject(DXC_OUT_ROOT_SIGNATURE, pRootSignature));
}
CComPtr<IDxcBlob> pHashBlob;
IFT(hlsl::DxcCreateBlobOnHeapCopy(&ShaderHashContent, (UINT32)sizeof(ShaderHashContent), &pHashBlob));
IFT(pResult->SetOutputObject(DXC_OUT_SHADER_HASH, pHashBlob));
} // SUCCEEDED(valHR)
} // compileOK && !opts.CodeGenHighLevel
}
// Add std err to warnings.
msfPtr->WriteStdErrToStream(w);
CComPtr<IStream> pErrorStream;
msfPtr->GetStdOutpuHandleStream(&pErrorStream);
CComPtr<IDxcBlob> pErrorBlob;
IFT(pErrorStream.QueryInterface(&pErrorBlob));
if (IsBlobNullOrEmpty(pErrorBlob)) {
IFT(pResult->SetOutputString(DXC_OUT_ERRORS, warnings.c_str(), warnings.size()));
} else {
IFT(pResult->SetOutputObject(DXC_OUT_ERRORS, pErrorBlob));
}
bool hasErrorOccurred = compiler.getDiagnostics().hasErrorOccurred();
bool writePDB = opts.GeneratePDB() && produceFullContainer;
// SPIRV change starts
#if defined(ENABLE_SPIRV_CODEGEN)
writePDB &= !opts.GenSPIRV;
#endif
// SPIRV change ends
if (!hasErrorOccurred && writePDB) {
CComPtr<IDxcBlob> pStrippedContainer;
{
// Create the shader source information for PDB
hlsl::SourceInfoWriter debugSourceInfoWriter;
const hlsl::DxilSourceInfo *pSourceInfo = nullptr;
if (!opts.SourceInDebugModule) { // If we are using old PDB format where sources are in debug module, do not generate source info at all
debugSourceInfoWriter.Write(opts.TargetProfile, opts.EntryPoint, compiler.getCodeGenOpts(), compiler.getSourceManager());
pSourceInfo = debugSourceInfoWriter.GetPart();
}
CComPtr<IDxcBlob> pDebugProgramBlob;
CComPtr<AbstractMemoryStream> pReflectionInPdb;
// Don't include the debug part if using source only PDB
if (opts.SourceOnlyDebug) {
assert(pSourceInfo);
pReflectionInPdb = pReflectionStream;
}
else {
if (!opts.SourceInDebugModule) {
// Strip out the source related metadata
debugModule->GetOrCreateDxilModule()
.StripShaderSourcesAndCompileOptions(/* bReplaceWithDummyData */ true);
}
CComPtr<AbstractMemoryStream> pDebugBlobStorage;
IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pDebugBlobStorage));
raw_stream_ostream outStream(pDebugBlobStorage.p);
WriteBitcodeToFile(debugModule.get(), outStream, true);
outStream.flush();
IFT(pDebugBlobStorage.QueryInterface(&pDebugProgramBlob));
}
IFT(CreateContainerForPDB(
m_pMalloc,
pOutputBlob, pDebugProgramBlob,
static_cast<IDxcVersionInfo *>(this), pSourceInfo,
pReflectionInPdb,
&pStrippedContainer));
}
// Create the final PDB Blob
CComPtr<IDxcBlob> pPdbBlob;
IFT(hlsl::pdb::WriteDxilPDB(m_pMalloc, pStrippedContainer, ShaderHashContent.Digest, &pPdbBlob));
IFT(pResult->SetOutputObject(DXC_OUT_PDB, pPdbBlob));
// If option Qpdb_in_private given, add the PDB to the DXC_OUT_OBJECT container output as a
// DFCC_PrivateData part.
if (opts.PdbInPrivate) {
CComPtr<IDxcBlobEncoding> pContainerBlob;
hlsl::DxcCreateBlobWithEncodingFromPinned(pOutputBlob->GetBufferPointer(), pOutputBlob->GetBufferSize(), CP_ACP, &pContainerBlob);
CComPtr<IDxcContainerBuilder> pContainerBuilder;
DxcCreateInstance2(this->m_pMalloc, CLSID_DxcContainerBuilder, IID_PPV_ARGS(&pContainerBuilder));
IFT(pContainerBuilder->Load(pOutputBlob));
IFT(pContainerBuilder->AddPart(hlsl::DFCC_PrivateData, pPdbBlob));
CComPtr<IDxcOperationResult> pReserializeResult;
IFT(pContainerBuilder->SerializeContainer(&pReserializeResult));
CComPtr<IDxcBlob> pNewOutput;
IFT(pReserializeResult->GetResult(&pNewOutput));
pOutputBlob = pNewOutput;
} // PDB in private
} // Write PDB
IFT(primaryOutput.SetObject(pOutputBlob, opts.DefaultTextCodePage));
IFT(pResult->SetOutput(primaryOutput));
IFT(pResult->SetStatusAndPrimaryResult(hasErrorOccurred ? E_FAIL : S_OK, primaryOutput.kind));
IFT(pResult->QueryInterface(riid, ppResult));
hr = S_OK;
} catch (std::bad_alloc &) {
hr = E_OUTOFMEMORY;
} catch (hlsl::Exception &e) {
_Analysis_assume_(DXC_FAILED(e.hr));
CComPtr<IDxcResult> pResult;
hr = e.hr;
std::string msg("Internal Compiler error: ");
msg += e.msg;
if (SUCCEEDED(DxcResult::Create(e.hr, DXC_OUT_NONE, {
DxcOutputObject::ErrorOutput(CP_UTF8,
msg.c_str(), msg.size())
}, &pResult)) &&
SUCCEEDED(pResult->QueryInterface(riid, ppResult))) {
hr = S_OK;
}
} catch (...) {
hr = E_FAIL;
}
Cleanup:
if (bPreprocessStarted) {
DxcEtw_DXCompilerPreprocess_Stop(hr);
}
if (bCompileStarted) {
DxcEtw_DXCompilerCompile_Stop(hr);
}
return hr;
}