rhi: d3d12: Use IDxcCompiler for SM 6.0+
Only when available at build time (dxcapi.h) and at run time (dxcompiler.dll, ideally with dxil.dll). The catch is that the latter will not be true in a typical Windows system. Unlike the legacy d3dcompiler_47.dll the dxc stuff is just not there. It is unclear what we can do about it. In the meantime one needs to go to https://github.com/microsoft/DirectXShaderCompiler/releases and get the DLLs. Fixes: QTBUG-114773 Change-Id: I6e68fdd1e47505187036b47d6f3e7fe9cc4ee8dc Reviewed-by: Andy Nichols <andy.nichols@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
e7405dc14a
commit
5a6f51a322
@ -4828,9 +4828,14 @@ QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(const QD3D1
|
||||
return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
|
||||
}
|
||||
|
||||
// For now we mirror exactly what's done in the D3D11 backend, meaning we use
|
||||
// the old shader compiler (so like fxc, not dxc) to generate shader model 5.0
|
||||
// output. Some day this should be moved to the new compiler and DXIL.
|
||||
// For shader model < 6.0 we do the same as the D3D11 backend: use the old
|
||||
// compiler (D3DCompile) to generate DXBC, just as qsb does (when -c is passed)
|
||||
// by invoking fxc, not dxc. For SM >= 6.0 we have to use the new compiler and
|
||||
// work with DXIL. And that involves IDxcCompiler and needs the presence of
|
||||
// dxcompiler.dll and dxil.dll at runtime. Plus there's a chance we have
|
||||
// ancient SDK headers when not using MSVC. So this is heavily optional,
|
||||
// meaning support for dxc can be disabled both at build time (no dxcapi.h) and
|
||||
// at run time (no DLLs).
|
||||
|
||||
static inline void makeHlslTargetString(char target[7], const char stage[3], int version)
|
||||
{
|
||||
@ -4845,6 +4850,108 @@ static inline void makeHlslTargetString(char target[7], const char stage[3], int
|
||||
target[6] = '\0';
|
||||
}
|
||||
|
||||
static QByteArray legacyCompile(const QShaderCode &hlslSource, const char *target, UINT flags, QString *error)
|
||||
{
|
||||
static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
|
||||
if (!d3dCompile) {
|
||||
qWarning("Unable to resolve function D3DCompile()");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
ID3DBlob *bytecode = nullptr;
|
||||
ID3DBlob *errors = nullptr;
|
||||
HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
|
||||
nullptr, nullptr, nullptr,
|
||||
hlslSource.entryPoint().constData(), target, flags, 0, &bytecode, &errors);
|
||||
if (FAILED(hr) || !bytecode) {
|
||||
qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
|
||||
if (errors) {
|
||||
*error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
|
||||
int(errors->GetBufferSize()));
|
||||
errors->Release();
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray result;
|
||||
result.resize(int(bytecode->GetBufferSize()));
|
||||
memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
|
||||
bytecode->Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef QRHI_D3D12_HAS_DXC
|
||||
static QByteArray dxcCompile(const QShaderCode &hlslSource, const char *target, UINT flags, QString *error)
|
||||
{
|
||||
static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
|
||||
IDxcCompiler *compiler = dxc.first;
|
||||
if (!compiler) {
|
||||
qWarning("Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
|
||||
"Bundling these are out of scope for Qt. Try https://github.com/microsoft/DirectXShaderCompiler/releases");
|
||||
return QByteArray();
|
||||
}
|
||||
IDxcLibrary *library = dxc.second;
|
||||
if (!library)
|
||||
return QByteArray();
|
||||
|
||||
IDxcBlobEncoding *sourceBlob = nullptr;
|
||||
HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
|
||||
UINT32(hlslSource.shader().size()),
|
||||
DXC_CP_UTF8,
|
||||
&sourceBlob);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to create source blob for dxc: 0x%x (%s)",
|
||||
uint(hr),
|
||||
qPrintable(QSystemError::windowsComString(hr)));
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
|
||||
const QString targetStr = QString::fromLatin1(target);
|
||||
|
||||
IDxcOperationResult *result = nullptr;
|
||||
hr = compiler->Compile(sourceBlob,
|
||||
nullptr,
|
||||
reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
|
||||
reinterpret_cast<LPCWSTR>(targetStr.utf16()),
|
||||
nullptr, 0, nullptr, 0, nullptr,
|
||||
&result);
|
||||
sourceBlob->Release();
|
||||
if (SUCCEEDED(hr))
|
||||
result->GetStatus(&hr);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("HLSL shader compilation failed: 0x%x (%s)",
|
||||
uint(hr),
|
||||
qPrintable(QSystemError::windowsComString(hr)));
|
||||
if (result) {
|
||||
IDxcBlobEncoding *errorsBlob = nullptr;
|
||||
if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
|
||||
if (errorsBlob) {
|
||||
*error = QString::fromUtf8(static_cast<const char *>(errorsBlob->GetBufferPointer()),
|
||||
int(errorsBlob->GetBufferSize()));
|
||||
errorsBlob->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
IDxcBlob *bytecode = nullptr;
|
||||
if FAILED(result->GetResult(&bytecode)) {
|
||||
qWarning("No result from IDxcCompiler: 0x%x (%s)",
|
||||
uint(hr),
|
||||
qPrintable(QSystemError::windowsComString(hr)));
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray ba;
|
||||
ba.resize(int(bytecode->GetBufferSize()));
|
||||
memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
|
||||
bytecode->Release();
|
||||
return ba;
|
||||
}
|
||||
#endif
|
||||
|
||||
static QByteArray compileHlslShaderSource(const QShader &shader,
|
||||
QShader::Variant shaderVariant,
|
||||
UINT flags,
|
||||
@ -4904,33 +5011,17 @@ static QByteArray compileHlslShaderSource(const QShader &shader,
|
||||
break;
|
||||
}
|
||||
|
||||
static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
|
||||
if (!d3dCompile) {
|
||||
qWarning("Unable to resolve function D3DCompile()");
|
||||
return QByteArray();
|
||||
if (key.sourceVersion().version() >= 60) {
|
||||
#ifdef QRHI_D3D12_HAS_DXC
|
||||
return dxcCompile(hlslSource, target, flags, error);
|
||||
#else
|
||||
qWarning("Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
|
||||
"but the Qt build has no support for DXC. "
|
||||
"Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
|
||||
#endif
|
||||
}
|
||||
|
||||
ID3DBlob *bytecode = nullptr;
|
||||
ID3DBlob *errors = nullptr;
|
||||
HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
|
||||
nullptr, nullptr, nullptr,
|
||||
hlslSource.entryPoint().constData(), target, flags, 0, &bytecode, &errors);
|
||||
if (FAILED(hr) || !bytecode) {
|
||||
qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
|
||||
if (errors) {
|
||||
*error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
|
||||
int(errors->GetBufferSize()));
|
||||
errors->Release();
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray result;
|
||||
result.resize(int(bytecode->GetBufferSize()));
|
||||
memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
|
||||
bytecode->Release();
|
||||
|
||||
return result;
|
||||
return legacyCompile(hlslSource, target, flags, error);
|
||||
}
|
||||
|
||||
static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
|
||||
@ -5229,7 +5320,7 @@ bool QD3D12GraphicsPipeline::create()
|
||||
&error,
|
||||
&shaderKey);
|
||||
if (bytecode.isEmpty()) {
|
||||
qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
|
||||
qWarning("HLSL graphics shader compilation failed: %s", qPrintable(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,11 @@
|
||||
#include <dcomp.h>
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
#if __has_include(<dxcapi.h>)
|
||||
#include <dxcapi.h>
|
||||
#define QRHI_D3D12_HAS_DXC
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QRhiD3D {
|
||||
@ -32,6 +37,8 @@ inline pD3DCompile resolveD3DCompile()
|
||||
if (library.load()) {
|
||||
if (auto symbol = library.resolve("D3DCompile"))
|
||||
return reinterpret_cast<pD3DCompile>(symbol);
|
||||
} else {
|
||||
qWarning("Failed to load D3DCompiler_47/43.dll");
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@ -53,13 +60,45 @@ inline IDCompositionDevice *createDirectCompositionDevice()
|
||||
IDCompositionDevice *device = nullptr;
|
||||
HRESULT hr = func(nullptr, __uuidof(IDCompositionDevice), reinterpret_cast<void **>(&device));
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to Direct Composition device: %s",
|
||||
qWarning("Failed to create Direct Composition device: %s",
|
||||
qPrintable(QSystemError::windowsComString(hr)));
|
||||
return nullptr;
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
#ifdef QRHI_D3D12_HAS_DXC
|
||||
inline std::pair<IDxcCompiler *, IDxcLibrary *> createDxcCompiler()
|
||||
{
|
||||
QSystemLibrary dxclib(QStringLiteral("dxcompiler"));
|
||||
// this will not be in the system library location, hence onlySystemDirectory==false
|
||||
if (!dxclib.load(false)) {
|
||||
qWarning("Failed to load dxcompiler.dll");
|
||||
return {};
|
||||
}
|
||||
DxcCreateInstanceProc func = reinterpret_cast<DxcCreateInstanceProc>(dxclib.resolve("DxcCreateInstance"));
|
||||
if (!func) {
|
||||
qWarning("Unable to resolve DxcCreateInstance");
|
||||
return {};
|
||||
}
|
||||
IDxcCompiler *compiler = nullptr;
|
||||
HRESULT hr = func(CLSID_DxcCompiler, __uuidof(IDxcCompiler), reinterpret_cast<void**>(&compiler));
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to create dxc compiler instance: %s",
|
||||
qPrintable(QSystemError::windowsComString(hr)));
|
||||
return {};
|
||||
}
|
||||
IDxcLibrary *library = nullptr;
|
||||
hr = func(CLSID_DxcLibrary, __uuidof(IDxcLibrary), reinterpret_cast<void**>(&library));
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to create dxc library instance: %s",
|
||||
qPrintable(QSystemError::windowsComString(hr)));
|
||||
return {};
|
||||
}
|
||||
return { compiler, library };
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
Loading…
x
Reference in New Issue
Block a user