summaryrefslogtreecommitdiffstats
path: root/Graphics
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2020-08-25 01:56:42 +0000
committerazhirnov <zh1dron@gmail.com>2020-08-25 01:56:42 +0000
commit1313de1ab167fe67d14fa2a848946f442491ca11 (patch)
treea87dad429e9a639b5403d0c923ca2d35b610479c /Graphics
parentadded AdapterId to Vulkan backend (diff)
downloadDiligentCore-1313de1ab167fe67d14fa2a848946f442491ca11.tar.gz
DiligentCore-1313de1ab167fe67d14fa2a848946f442491ca11.zip
added HLSLTools, HLSL shader compiler refactoring
added ShaderCompiler field to ShaderCreateInfo, fixed tests that doesn't compile on DXC, added dxc/WinAdapter.h to fix compilation on linux
Diffstat (limited to 'Graphics')
-rw-r--r--Graphics/CMakeLists.txt4
-rw-r--r--Graphics/GLSLTools/CMakeLists.txt2
-rw-r--r--Graphics/GraphicsEngine/interface/Shader.h25
-rw-r--r--Graphics/GraphicsEngineD3D11/CMakeLists.txt1
-rw-r--r--Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/CMakeLists.txt1
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp4
-rw-r--r--Graphics/GraphicsEngineD3DBase/CMakeLists.txt1
-rw-r--r--Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp10
-rw-r--r--Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp307
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp4
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt1
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp48
-rw-r--r--Graphics/HLSLTools/CMakeLists.txt49
-rw-r--r--Graphics/HLSLTools/include/DXILUtils.hpp76
-rw-r--r--Graphics/HLSLTools/src/DXILUtils.cpp552
17 files changed, 800 insertions, 289 deletions
diff --git a/Graphics/CMakeLists.txt b/Graphics/CMakeLists.txt
index 89e851db..077d3b10 100644
--- a/Graphics/CMakeLists.txt
+++ b/Graphics/CMakeLists.txt
@@ -36,6 +36,10 @@ if(GL_SUPPORTED OR GLES_SUPPORTED OR VULKAN_SUPPORTED)
add_subdirectory(GLSLTools)
endif()
+if(D3D12_SUPPORTED OR VULKAN_SUPPORTED)
+ add_subdirectory(HLSLTools)
+endif()
+
if(VULKAN_SUPPORTED)
add_subdirectory(GraphicsEngineVulkan)
endif()
diff --git a/Graphics/GLSLTools/CMakeLists.txt b/Graphics/GLSLTools/CMakeLists.txt
index f08ce304..d9bc011a 100644
--- a/Graphics/GLSLTools/CMakeLists.txt
+++ b/Graphics/GLSLTools/CMakeLists.txt
@@ -13,11 +13,9 @@ set(SOURCE
if(VULKAN_SUPPORTED)
list(APPEND SOURCE
src/SPIRVShaderResources.cpp
- src/DXILUtils.cpp
)
list(APPEND INCLUDE
include/SPIRVShaderResources.hpp
- include/DXILUtils.hpp
)
if (NOT ${DILIGENT_NO_GLSLANG})
diff --git a/Graphics/GraphicsEngine/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h
index 8c8d0879..f3d9b198 100644
--- a/Graphics/GraphicsEngine/interface/Shader.h
+++ b/Graphics/GraphicsEngine/interface/Shader.h
@@ -80,6 +80,28 @@ DILIGENT_TYPED_ENUM(SHADER_SOURCE_LANGUAGE, Uint32)
SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM
};
+/// Describes shader compiler
+DILIGENT_TYPED_ENUM(SHADER_COMPILER, Uint32)
+{
+ /// Default compiler for specific language and API:
+ /// for Direct3D11 - external FXC
+ /// for Direct3D12 - external DXC
+ /// for OpenGL(ES) GLSL - native compiler
+ /// for OpenGL(ES) HLSL - HLSL2GLSL and native compiler
+ /// for Vulkan GLSL - builtin glslang
+ /// for Vulkan HLSL - builtin glslang (with limitted support for Shader Model 6.x)
+ SHADER_COMPILER_DEFAULT = 0,
+
+ /// Builtin glslang compiler for GLSL and HLSL.
+ SHADER_COMPILER_GLSLANG,
+
+ /// External HLSL compiler for Direct3D12 and Vulkan with Shader Model 6.x support.
+ SHADER_COMPILER_DXC,
+
+ /// External HLSL compiler for Direct3D11 and Direct3D12 before Shader Model 6.
+ SHADER_COMPILER_FXC,
+};
+
/// Describes the flags that can be passed over to IShaderSourceInputStreamFactory::CreateInputStream2() function.
DILIGENT_TYPED_ENUM(CREATE_SHADER_SOURCE_INPUT_STREAM_FLAGS, Uint32)
{
@@ -258,6 +280,9 @@ struct ShaderCreateInfo
/// Shader source language. See Diligent::SHADER_SOURCE_LANGUAGE.
SHADER_SOURCE_LANGUAGE SourceLanguage DEFAULT_INITIALIZER(SHADER_SOURCE_LANGUAGE_DEFAULT);
+ /// Shader compiler. See Diligent::SHADER_COMPILER.
+ SHADER_COMPILER ShaderCompiler DEFAULT_INITIALIZER(SHADER_COMPILER_DEFAULT);
+
/// HLSL shader model to use when compiling the shader. When default value
/// is given (0, 0), the engine will attempt to use the highest HLSL shader model
/// supported by the device. If the shader is created from the byte code, this value
diff --git a/Graphics/GraphicsEngineD3D11/CMakeLists.txt b/Graphics/GraphicsEngineD3D11/CMakeLists.txt
index ba6aeb46..7a9ac2a5 100644
--- a/Graphics/GraphicsEngineD3D11/CMakeLists.txt
+++ b/Graphics/GraphicsEngineD3D11/CMakeLists.txt
@@ -119,6 +119,7 @@ PRIVATE
Diligent-GraphicsEngineD3DBase
Diligent-TargetPlatform
Diligent-Common
+ Diligent-HLSLTools
dxgi.lib
d3d11.lib
d3dcompiler.lib
diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp
index eb63485c..3b6edc0e 100644
--- a/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp
+++ b/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp
@@ -95,7 +95,7 @@ ShaderD3D11Impl::ShaderD3D11Impl(IReferenceCounters* pRefCounters,
pRenderDeviceD3D11,
ShaderCI.Desc
},
- ShaderD3DBase{ShaderCI, GetD3D11ShaderModel(pRenderDeviceD3D11->GetD3D11Device(), ShaderCI.HLSLVersion)}
+ ShaderD3DBase{ShaderCI, GetD3D11ShaderModel(pRenderDeviceD3D11->GetD3D11Device(), ShaderCI.HLSLVersion), false}
// clang-format on
{
auto* pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device();
diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt
index 00ce6a91..b5e85ad4 100644
--- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt
+++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt
@@ -157,6 +157,7 @@ PRIVATE
Diligent-GraphicsEngineD3DBase
Diligent-GraphicsEngineNextGenBase
Diligent-TargetPlatform
+ Diligent-HLSLTools
dxgi.lib
d3dcompiler.lib
PUBLIC
diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp
index 768983da..3c740b29 100644
--- a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp
@@ -59,7 +59,7 @@ ShaderD3D12Impl::ShaderD3D12Impl(IReferenceCounters* pRefCounters,
pRenderDeviceD3D12,
ShaderCI.Desc
},
- ShaderD3DBase{ShaderCI, GetD3D12ShaderModel(pRenderDeviceD3D12, ShaderCI.HLSLVersion)}
+ ShaderD3DBase{ShaderCI, GetD3D12ShaderModel(pRenderDeviceD3D12, ShaderCI.HLSLVersion), true}
// clang-format on
{
// Load shader resources
diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp
index e2093eaa..f7488afe 100644
--- a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp
@@ -31,6 +31,8 @@
#include "ShaderResourcesD3D12.hpp"
#include "ShaderD3DBase.hpp"
#include "ShaderBase.hpp"
+#include "DXILUtils.hpp"
+#include "dxc/dxcapi.h"
namespace Diligent
{
@@ -61,7 +63,7 @@ ShaderResourcesD3D12::ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, bool isDXI
const uint32_t DFCC_DXIL = uint32_t('D') | (uint32_t('X') << 8) | (uint32_t('I') << 16) | (uint32_t('L') << 24);
CComPtr<IDxcContainerReflection> pReflection;
UINT32 shaderIdx;
- hr = DXILCreateInstance(CLSID_DxcContainerReflection, IID_PPV_ARGS(&pReflection));
+ hr = D3D12DxcCreateInstance(CLSID_DxcContainerReflection, IID_PPV_ARGS(&pReflection));
CHECK_D3D_RESULT_THROW(hr, "Failed to create shader reflection instance");
hr = pReflection->Load(reinterpret_cast<IDxcBlob*>(pShaderBytecode));
CHECK_D3D_RESULT_THROW(hr, "Failed to load shader reflection from bytecode");
diff --git a/Graphics/GraphicsEngineD3DBase/CMakeLists.txt b/Graphics/GraphicsEngineD3DBase/CMakeLists.txt
index cfdffb0c..dbdd9436 100644
--- a/Graphics/GraphicsEngineD3DBase/CMakeLists.txt
+++ b/Graphics/GraphicsEngineD3DBase/CMakeLists.txt
@@ -62,6 +62,7 @@ PUBLIC
target_link_libraries(Diligent-GraphicsEngineD3DBase
PRIVATE
Diligent-BuildSettings
+ Diligent-HLSLTools
PUBLIC
Diligent-GraphicsEngine
Diligent-GraphicsEngineD3DBaseInterface
diff --git a/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp b/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp
index 899546ce..2667b639 100644
--- a/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp
+++ b/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp
@@ -28,8 +28,6 @@
#pragma once
#include <d3dcommon.h>
-#include <dxcapi.h>
-
#include "Shader.h"
/// \file
@@ -42,17 +40,11 @@ namespace Diligent
class ShaderD3DBase
{
public:
- ShaderD3DBase(const ShaderCreateInfo& ShaderCI, ShaderVersion ShaderModel);
+ ShaderD3DBase(const ShaderCreateInfo& ShaderCI, ShaderVersion ShaderModel, bool IsD3D12);
protected:
CComPtr<ID3DBlob> m_pShaderByteCode;
bool m_isDXIL;
};
-// calls DxcCreateInstance
-HRESULT DXILCreateInstance(
- _In_ REFCLSID rclsid,
- _In_ REFIID riid,
- _Out_ LPVOID* ppv);
-
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp b/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp
index f10b4bef..25ea3406 100644
--- a/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp
+++ b/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp
@@ -33,170 +33,28 @@
#include "RefCntAutoPtr.hpp"
#include <atlcomcli.h>
#include "ShaderD3DBase.hpp"
+#include "DXILUtils.hpp"
+#include "dxc/dxcapi.h"
#include <locale>
#include <cwchar>
namespace Diligent
{
-
-static const Char* g_HLSLDefinitions =
- {
-#include "HLSLDefinitions_inc.fxh"
-};
-
-
namespace
{
-struct DXILCompilerLib
-{
- HMODULE Module = nullptr;
- DxcCreateInstanceProc CreateInstance = nullptr;
- ShaderVersion MaxShaderModel{6, 5};
-
- DXILCompilerLib()
- {
- Module = LoadLibraryA("dxcompiler.dll");
- if (Module)
- {
- CreateInstance = reinterpret_cast<DxcCreateInstanceProc>(GetProcAddress(Module, "DxcCreateInstance"));
-
- if (CreateInstance)
- {
- CComPtr<IDxcValidator> validator;
- if (SUCCEEDED(CreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&validator))))
- {
- CComPtr<IDxcVersionInfo> info;
- if (SUCCEEDED(validator->QueryInterface(IID_PPV_ARGS(&info))))
- {
- UINT32 ver = 0, minor = 0;
- info->GetVersion(&ver, &minor);
-
- LOG_INFO_MESSAGE("Loaded D3D12 DXIL compiler, version ", ver, ".", minor);
-
- ver = (ver << 16) | (minor & 0xFFFF);
-
- // map known DXC version to maximum SM
- switch (ver)
- {
- case 0x10005: MaxShaderModel = {6, 5}; break;
- case 0x10004: MaxShaderModel = {6, 4}; break; // SM 6.4 and SM 6.5 preview ???
- case 0x10002: MaxShaderModel = {6, 2}; break; // SM 6.1 and SM 6.2 preview
- default: MaxShaderModel = (ver > 0x10005 ? ShaderVersion{6, 6} : ShaderVersion{6, 0}); break; // unknown version
- }
- }
- }
- }
- }
- }
-
- ~DXILCompilerLib()
- {
- FreeLibrary(Module);
- }
-
- static DXILCompilerLib& Instance()
- {
- static DXILCompilerLib inst;
- return inst;
- }
-};
-} // namespace
-
-HRESULT DXILCreateInstance(
- _In_ REFCLSID rclsid,
- _In_ REFIID riid,
- _Out_ LPVOID* ppv)
-{
- auto proc = DXILCompilerLib::Instance().CreateInstance;
- if (proc)
- return proc(rclsid, riid, ppv);
- else
- return E_NOTIMPL;
-}
-
-
-namespace
-{
-class DxcIncludeHandlerImpl final : public IDxcIncludeHandler
-{
-public:
- explicit DxcIncludeHandlerImpl(IShaderSourceInputStreamFactory* pStreamFactory, CComPtr<IDxcLibrary> pLibrary) :
- m_pLibrary{pLibrary},
- m_pStreamFactory{pStreamFactory},
- m_RefCount{1}
- {
- }
-
- HRESULT STDMETHODCALLTYPE LoadSource(_In_ LPCWSTR pFilename, _COM_Outptr_result_maybenull_ IDxcBlob** ppIncludeSource) override
- {
- String fileName = std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>, wchar_t>{}.to_bytes(pFilename);
- if (fileName.empty())
- {
- LOG_ERROR("Failed to convert shader include file name ", fileName, ". File name must be ANSI string");
- return E_FAIL;
- }
-
- RefCntAutoPtr<IFileStream> pSourceStream;
- m_pStreamFactory->CreateInputStream(fileName.c_str(), &pSourceStream);
- if (pSourceStream == nullptr)
- {
- LOG_ERROR("Failed to open shader include file ", fileName, ". Check that the file exists");
- return E_FAIL;
- }
-
- RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0));
- pSourceStream->ReadBlob(pFileData);
-
- CComPtr<IDxcBlobEncoding> sourceBlob;
- HRESULT hr = m_pLibrary->CreateBlobWithEncodingFromPinned(pFileData->GetDataPtr(), UINT32(pFileData->GetSize()), CP_UTF8, &sourceBlob);
- if (FAILED(hr))
- {
- LOG_ERROR("Failed to allocate space for shader include file ", fileName, ".");
- return E_FAIL;
- }
-
- m_FileDataCache.push_back(pFileData);
-
- sourceBlob->QueryInterface(IID_PPV_ARGS(ppIncludeSource));
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) override
- {
- return E_FAIL;
- }
-
- ULONG STDMETHODCALLTYPE AddRef(void) override
- {
- return m_RefCount++;
- }
- ULONG STDMETHODCALLTYPE Release(void) override
+static const Char* g_HLSLDefinitions =
{
- --m_RefCount;
- VERIFY(m_RefCount > 0, "Inconsistent call to Release()");
- return m_RefCount;
- }
-
-private:
- CComPtr<IDxcLibrary> m_pLibrary;
- IShaderSourceInputStreamFactory* m_pStreamFactory;
- ULONG m_RefCount;
- std::vector<RefCntAutoPtr<IDataBlob>> m_FileDataCache;
+#include "HLSLDefinitions_inc.fxh"
};
static HRESULT CompileDxilShader(const char* Source,
+ size_t SourceLength,
const ShaderCreateInfo& ShaderCI,
LPCSTR profile,
ID3DBlob** ppBlobOut,
ID3DBlob** ppCompilerOutput)
{
- if (DXILCompilerLib::Instance().CreateInstance == nullptr)
- {
- LOG_ERROR("Failed to load dxcompiler.dll");
- return E_FAIL;
- }
-
struct WStringChunk
{
WCHAR* Buffer;
@@ -295,23 +153,6 @@ static HRESULT CompileDxilShader(const char* Source,
}
}
- HRESULT hr;
-
- CComPtr<IDxcLibrary> library;
- hr = DXILCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&library));
- if (FAILED(hr))
- return E_FAIL;
-
- CComPtr<IDxcCompiler> compiler;
- hr = DXILCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler));
- if (FAILED(hr))
- return E_FAIL;
-
- CComPtr<IDxcBlobEncoding> sourceBlob;
- hr = library->CreateBlobWithEncodingFromPinned(Source, UINT32(strlen(Source)), CP_UTF8, &sourceBlob);
- if (FAILED(hr))
- return E_FAIL;
-
const wchar_t* pArgs[] =
{
L"-Zpc", // Matrices in column-major order
@@ -325,79 +166,23 @@ static HRESULT CompileDxilShader(const char* Source,
#endif
};
- DxcIncludeHandlerImpl IncludeHandler{ShaderCI.pShaderSourceStreamFactory, library};
-
- CComPtr<IDxcOperationResult> result;
- hr = compiler->Compile(
- sourceBlob,
- L"",
- ToUnicode(ShaderCI.EntryPoint),
- ToUnicode(profile),
- pArgs, UINT32(std::size(pArgs)),
- D3DMacros.data(), UINT32(D3DMacros.size()),
- &IncludeHandler,
- &result);
-
- if (SUCCEEDED(hr))
- {
- HRESULT status;
- if (SUCCEEDED(result->GetStatus(&status)))
- hr = status;
- }
-
- if (result)
- {
- CComPtr<IDxcBlobEncoding> errorsBlob;
- CComPtr<IDxcBlobEncoding> errorsBlobUtf8;
- if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob)) && SUCCEEDED(library->GetBlobAsUtf8(errorsBlob, &errorsBlobUtf8)))
- {
- errorsBlobUtf8->QueryInterface(IID_PPV_ARGS(ppCompilerOutput));
- }
- }
-
- if (FAILED(hr))
- return hr; // compilation failed
-
- CComPtr<IDxcBlob> compiled;
- hr = result->GetResult(&compiled);
- if (FAILED(hr))
- return E_FAIL;
-
- CComPtr<IDxcValidator> validator;
- hr = DXILCreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&validator));
- if (FAILED(hr))
- return E_FAIL;
-
- CComPtr<IDxcOperationResult> validationResult;
- hr = validator->Validate(compiled, DxcValidatorFlags_InPlaceEdit, &validationResult);
-
- if (FAILED(hr))
- return hr; // validation failed
+ VERIFY_EXPR(__uuidof(ID3DBlob) == __uuidof(IDxcBlob));
- HRESULT status;
- if (SUCCEEDED(validationResult->GetStatus(&status)) && FAILED(status))
+ if (!DXILCompile(DXILCompilerTarget::Direct3D12,
+ Source, SourceLength,
+ ToUnicode(ShaderCI.EntryPoint),
+ ToUnicode(profile),
+ D3DMacros.data(), D3DMacros.size(),
+ pArgs, std::size(pArgs),
+ ShaderCI.pShaderSourceStreamFactory,
+ reinterpret_cast<IDxcBlob**>(ppBlobOut),
+ reinterpret_cast<IDxcBlob**>(ppCompilerOutput)))
{
- CComPtr<IDxcBlobEncoding> validationOutput;
- CComPtr<IDxcBlobEncoding> validationOutputUtf8;
- validationResult->GetErrorBuffer(&validationOutput);
- library->GetBlobAsUtf8(validationOutput, &validationOutputUtf8);
-
- size_t ValidationMsgLen = validationOutputUtf8 ? validationOutputUtf8->GetBufferSize() : 0;
- const char* ValidationMsg = ValidationMsgLen > 0 ? static_cast<const char*>(validationOutputUtf8->GetBufferPointer()) : "";
-
- LOG_ERROR("Shader validation failed: ", ValidationMsg);
return E_FAIL;
}
-
- VERIFY_EXPR(__uuidof(ID3DBlob) == __uuidof(IDxcBlob));
-
- *ppBlobOut = reinterpret_cast<ID3DBlob*>(compiled.Detach());
return S_OK;
}
-} // namespace
-namespace
-{
class D3DIncludeImpl : public ID3DInclude
{
public:
@@ -440,6 +225,7 @@ private:
};
static HRESULT CompileShader(const char* Source,
+ size_t SourceLength,
const ShaderCreateInfo& ShaderCI,
LPCSTR profile,
ID3DBlob** ppBlobOut,
@@ -505,8 +291,7 @@ static HRESULT CompileShader(const char* Source,
// {
D3DIncludeImpl IncludeImpl(ShaderCI.pShaderSourceStreamFactory);
- auto SourceLen = strlen(Source);
- auto hr = D3DCompile(Source, SourceLen, NULL, D3DMacros.data(), &IncludeImpl, ShaderCI.EntryPoint, profile, dwShaderFlags, 0, ppBlobOut, ppCompilerOutput);
+ auto hr = D3DCompile(Source, SourceLength, NULL, D3DMacros.data(), &IncludeImpl, ShaderCI.EntryPoint, profile, dwShaderFlags, 0, ppBlobOut, ppCompilerOutput);
// if( FAILED(hr) || errors )
// {
@@ -525,7 +310,7 @@ static HRESULT CompileShader(const char* Source,
} // namespace
-ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, ShaderVersion ShaderModel) :
+ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, ShaderVersion ShaderModel, bool IsD3D12) :
m_isDXIL{false}
{
if (ShaderCI.Source || ShaderCI.FilePath)
@@ -533,6 +318,38 @@ ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, ShaderVersion Sha
DEV_CHECK_ERR(ShaderCI.ByteCode == nullptr, "'ByteCode' must be null when shader is created from the source code or a file");
DEV_CHECK_ERR(ShaderCI.ByteCodeSize == 0, "'ByteCodeSize' must be 0 when shader is created from the source code or a file");
+ // validate compiler type
+ switch (ShaderCI.ShaderCompiler)
+ {
+ // clang-format off
+ case SHADER_COMPILER_DEFAULT: m_isDXIL = IsD3D12; break;
+ case SHADER_COMPILER_DXC: m_isDXIL = true; break;
+ case SHADER_COMPILER_FXC: m_isDXIL = false; break;
+ // clang-format on
+ default: UNEXPECTED("Unsupported shader compiler"); m_isDXIL = IsD3D12;
+ }
+
+ // validate shader model
+ if (m_isDXIL)
+ {
+ ShaderModel = (ShaderModel.Major >= 6 ? ShaderModel : ShaderVersion{6, 0});
+
+ // clamp to maximum supported version
+ ShaderVersion MaxSM;
+ if (DXILGetMaxShaderModel(DXILCompilerTarget::Direct3D12, MaxSM))
+ {
+ if (ShaderModel.Major > MaxSM.Major)
+ ShaderModel = MaxSM;
+
+ if (ShaderModel.Major == MaxSM.Major && ShaderModel.Minor > MaxSM.Minor)
+ ShaderModel = MaxSM;
+ }
+ }
+ else
+ {
+ ShaderModel = (ShaderModel.Major < 6 ? ShaderModel : (IsD3D12 ? ShaderVersion{5, 1} : ShaderVersion{5, 0}));
+ }
+
std::string strShaderProfile;
switch (ShaderCI.Desc.ShaderType)
{
@@ -550,24 +367,6 @@ ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, ShaderVersion Sha
default: UNEXPECTED("Unknown shader type");
}
- if (ShaderModel.Major >= 6)
- {
- auto& DxilLib = DXILCompilerLib::Instance();
-
- m_isDXIL = DxilLib.CreateInstance != nullptr;
-
- // clamp to maximum supported version
- if (ShaderModel.Major > DxilLib.MaxShaderModel.Major || (ShaderModel.Major == DxilLib.MaxShaderModel.Major && ShaderModel.Minor > DxilLib.MaxShaderModel.Minor))
- ShaderModel = DxilLib.MaxShaderModel;
-
- if (ShaderModel.Major == 0 || ShaderModel.Major < 6)
- ShaderModel = DxilLib.MaxShaderModel;
-
- // if DXIL is not loaded then try to compile as SM 5.1
- if (!m_isDXIL)
- ShaderModel = {5, 1};
- }
-
strShaderProfile += "_";
strShaderProfile += '0' + (ShaderModel.Major % 10);
strShaderProfile += "_";
@@ -600,14 +399,14 @@ ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, ShaderVersion Sha
HRESULT hr;
if (m_isDXIL)
- hr = CompileDxilShader(ShaderSource.c_str(), ShaderCI, strShaderProfile.c_str(), &m_pShaderByteCode, &errors);
+ hr = CompileDxilShader(ShaderSource.c_str(), ShaderSource.length(), ShaderCI, strShaderProfile.c_str(), &m_pShaderByteCode, &errors);
else
- hr = CompileShader(ShaderSource.c_str(), ShaderCI, strShaderProfile.c_str(), &m_pShaderByteCode, &errors);
+ hr = CompileShader(ShaderSource.c_str(), ShaderSource.length(), ShaderCI, strShaderProfile.c_str(), &m_pShaderByteCode, &errors);
const size_t CompilerMsgLen = errors ? errors->GetBufferSize() : 0;
const char* CompilerMsg = CompilerMsgLen > 0 ? static_cast<const char*>(errors->GetBufferPointer()) : nullptr;
- if (CompilerMsg != nullptr && CompilerMsgLen > 0 && ShaderCI.ppCompilerOutput != nullptr)
+ if (CompilerMsg != nullptr && ShaderCI.ppCompilerOutput != nullptr)
{
auto* pOutputDataBlob = MakeNewRCObj<DataBlobImpl>()(CompilerMsgLen + 1 + ShaderSource.length() + 1);
char* DataPtr = static_cast<char*>(pOutputDataBlob->GetDataPtr());
diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp
index bfa28b88..01266f1d 100644
--- a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp
@@ -53,6 +53,10 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters,
m_GLShaderObj{true, GLObjectWrappers::GLShaderObjCreateReleaseHelper{GetGLShaderType(m_Desc.ShaderType)}}
// clang-format on
{
+ DEV_CHECK_ERR(CreationAttribs.ByteCode == nullptr, "'ByteCode' must be null when shader is created from the source code or a file");
+ DEV_CHECK_ERR(CreationAttribs.ByteCodeSize == 0, "'ByteCodeSize' must be 0 when shader is created from the source code or a file");
+ DEV_CHECK_ERR(CreationAttribs.ShaderCompiler == SHADER_COMPILER_DEFAULT, "only default compiler supported on OpenGL");
+
const auto& deviceCaps = pDeviceGL->GetDeviceCaps();
auto GLSLSource = BuildGLSLSourceString(CreationAttribs, deviceCaps, TargetGLSLCompiler::driver);
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
index 647cf48f..4d4e495b 100644
--- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt
+++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
@@ -179,6 +179,7 @@ set(PRIVATE_DEPENDENCIES
Diligent-TargetPlatform
Diligent-GraphicsEngineNextGenBase
Diligent-GLSLTools
+ Diligent-HLSLTools
)
if (${DILIGENT_NO_HLSL})
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
index 65e9f274..554d9b73 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
@@ -64,32 +64,38 @@ ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters,
"# define VULKAN 1\n"
"#endif\n";
- if (CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL &&
- (CreationAttribs.HLSLVersion.Major == 0 || CreationAttribs.HLSLVersion.Major > 5) &&
- HasDXILCompilerForVulkan())
- {
- m_SPIRV = HLSLtoSPIRVusingDXIL(CreationAttribs, VulkanDefine, CreationAttribs.ppCompilerOutput);
- }
- else
+ switch (CreationAttribs.ShaderCompiler)
{
+ case SHADER_COMPILER_DXC:
+ m_SPIRV = DXILtoSPIRV(CreationAttribs, VulkanDefine, CreationAttribs.ppCompilerOutput);
+ break;
+
+ case SHADER_COMPILER_DEFAULT:
+ case SHADER_COMPILER_GLSLANG:
+ {
#if DILIGENT_NO_GLSLANG
- LOG_ERROR_AND_THROW("Diligent engine was not linked with glslang and can only consume compiled SPIRV bytecode.");
+ LOG_ERROR_AND_THROW("Diligent engine was not linked with glslang, use DXIL compiler or precompiled SPIRV bytecode.");
#else
- if (CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL)
- {
- m_SPIRV = HLSLtoSPIRV(CreationAttribs, VulkanDefine, CreationAttribs.ppCompilerOutput);
+ if (CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL)
+ {
+ m_SPIRV = HLSLtoSPIRV(CreationAttribs, VulkanDefine, CreationAttribs.ppCompilerOutput);
+ }
+ else
+ {
+ auto GLSLSource = BuildGLSLSourceString(CreationAttribs, pRenderDeviceVk->GetDeviceCaps(),
+ TargetGLSLCompiler::glslang,
+ VulkanDefine);
+
+ m_SPIRV = GLSLtoSPIRV(m_Desc.ShaderType, GLSLSource.c_str(),
+ static_cast<int>(GLSLSource.length()),
+ CreationAttribs.ppCompilerOutput);
+ }
+#endif
+ break;
}
- else
- {
- auto GLSLSource = BuildGLSLSourceString(CreationAttribs, pRenderDeviceVk->GetDeviceCaps(),
- TargetGLSLCompiler::glslang,
- VulkanDefine);
- m_SPIRV = GLSLtoSPIRV(m_Desc.ShaderType, GLSLSource.c_str(),
- static_cast<int>(GLSLSource.length()),
- CreationAttribs.ppCompilerOutput);
- }
-#endif
+ default:
+ LOG_ERROR_AND_THROW("Unsupported shader compiler");
}
if (m_SPIRV.empty())
diff --git a/Graphics/HLSLTools/CMakeLists.txt b/Graphics/HLSLTools/CMakeLists.txt
new file mode 100644
index 00000000..ce3b0824
--- /dev/null
+++ b/Graphics/HLSLTools/CMakeLists.txt
@@ -0,0 +1,49 @@
+cmake_minimum_required (VERSION 3.6)
+
+project(Diligent-HLSLTools CXX)
+
+set(INCLUDE
+ include/DXILUtils.hpp
+)
+
+set(SOURCE
+ src/DXILUtils.cpp
+)
+
+add_library(Diligent-HLSLTools STATIC ${SOURCE} ${INCLUDE})
+
+target_include_directories(Diligent-HLSLTools
+PUBLIC
+ include
+PRIVATE
+ ../GraphicsEngine/include
+)
+
+target_link_libraries(Diligent-HLSLTools
+PRIVATE
+ Diligent-BuildSettings
+ Diligent-GraphicsAccessories
+ Diligent-Common
+ Diligent-GLSLTools
+PUBLIC
+ Diligent-GraphicsEngineInterface
+)
+
+target_include_directories(Diligent-HLSLTools
+PUBLIC
+ ../../ThirdParty/DirectXShaderCompiler
+)
+
+set_common_target_properties(Diligent-HLSLTools)
+
+source_group("src" FILES ${SOURCE})
+source_group("include" FILES ${INCLUDE})
+source_group("interface" FILES ${INTERFACE})
+
+set_target_properties(Diligent-HLSLTools PROPERTIES
+ FOLDER DiligentCore/Graphics
+)
+
+if(DILIGENT_INSTALL_CORE)
+ install_core_lib(Diligent-HLSLTools)
+endif()
diff --git a/Graphics/HLSLTools/include/DXILUtils.hpp b/Graphics/HLSLTools/include/DXILUtils.hpp
new file mode 100644
index 00000000..20cfdcfc
--- /dev/null
+++ b/Graphics/HLSLTools/include/DXILUtils.hpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+#include <vector>
+#include <string>
+#include "Shader.h"
+#include "DataBlob.h"
+
+// defined in dxcapi.h
+struct DxcDefine;
+struct IDxcBlob;
+
+namespace Diligent
+{
+
+enum class DXILCompilerTarget
+{
+ Direct3D12,
+ Vulkan,
+};
+
+bool DXILGetMaxShaderModel(DXILCompilerTarget Target,
+ ShaderVersion& Version);
+
+bool DXILCompile(DXILCompilerTarget Target,
+ const char* Source,
+ size_t SourceLength,
+ const wchar_t* EntryPoint,
+ const wchar_t* Profile,
+ const DxcDefine* pDefines,
+ size_t DefinesCount,
+ const wchar_t** pArgs,
+ size_t ArgsCount,
+ IShaderSourceInputStreamFactory* pShaderSourceStreamFactory,
+ IDxcBlob** ppBlobOut,
+ IDxcBlob** ppCompilerOutput);
+
+std::vector<uint32_t> DXILtoSPIRV(const ShaderCreateInfo& Attribs,
+ const char* ExtraDefinitions,
+ IDataBlob** ppCompilerOutput);
+
+#ifdef D3D12_SUPPORTED
+// calls DxcCreateInstance
+HRESULT D3D12DxcCreateInstance(
+ _In_ REFCLSID rclsid,
+ _In_ REFIID riid,
+ _Out_ LPVOID* ppv);
+#endif
+
+} // namespace Diligent \ No newline at end of file
diff --git a/Graphics/HLSLTools/src/DXILUtils.cpp b/Graphics/HLSLTools/src/DXILUtils.cpp
new file mode 100644
index 00000000..82f099fd
--- /dev/null
+++ b/Graphics/HLSLTools/src/DXILUtils.cpp
@@ -0,0 +1,552 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include <unordered_set>
+#include <unordered_map>
+#include <memory>
+#include <array>
+#include <locale>
+#include <cwchar>
+
+#ifdef WIN32
+# include <Unknwn.h>
+# include <guiddef.h>
+# include <atlbase.h>
+# include <atlcom.h>
+#endif
+
+#include "dxc/dxcapi.h"
+
+#include "DXILUtils.hpp"
+#include "DataBlobImpl.hpp"
+#include "RefCntAutoPtr.hpp"
+
+// Platforms that has DXIL compiler.
+#if defined(PLATFORM_WIN32) || defined(PLATFORM_UNIVERSAL_WINDOWS) || defined(PLATFORM_LINUX)
+
+namespace Diligent
+{
+namespace
+{
+
+# if defined(PLATFORM_WIN32) || defined(PLATFORM_UNIVERSAL_WINDOWS)
+struct DXILCompilerWin32
+{
+ HMODULE Module = nullptr;
+ DxcCreateInstanceProc CreateInstance = nullptr;
+
+ DXILCompilerWin32(const std::string& name)
+ {
+ Module = LoadLibraryA((name + ".dll").c_str());
+ if (Module)
+ {
+ CreateInstance = reinterpret_cast<DxcCreateInstanceProc>(GetProcAddress(Module, "DxcCreateInstance"));
+ }
+ }
+
+ ~DXILCompilerWin32()
+ {
+ if (Module)
+ FreeLibrary(Module);
+ }
+};
+using DXILCompilerBase = DXILCompilerWin32;
+# endif // PLATFORM_WIN32
+
+# ifdef PLATFORM_LINUX
+struct DXILCompilerLinux
+{
+ void* Module = nullptr;
+ DxcCreateInstanceProc CreateInstance = nullptr;
+
+ DXILCompilerLinux(const std::string& name)
+ {
+ Module = dlopen((name + ".so").c_str(), RTLD_NOW | RTLD_LOCAL);
+ if (Module)
+ {
+ CreateInstance = reinterpret_cast<DxcCreateInstanceProc>(dlsym(Module, "DxcCreateInstance"));
+ }
+ }
+
+ ~DXILCompilerLinux()
+ {
+ if (Module)
+ dlclose(Module);
+ }
+};
+using DXILCompilerBase = DXILCompilerLinux;
+# endif // PLATFORM_LINUX
+
+
+struct DXILCompilerImpl : DXILCompilerBase
+{
+ ShaderVersion MaxShaderModel{6, 0};
+
+ DXILCompilerImpl(const std::string& name) :
+ DXILCompilerBase{name}
+ {
+ if (CreateInstance)
+ {
+ CComPtr<IDxcValidator> validator;
+ if (SUCCEEDED(CreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&validator))))
+ {
+ CComPtr<IDxcVersionInfo> info;
+ if (SUCCEEDED(validator->QueryInterface(IID_PPV_ARGS(&info))))
+ {
+ UINT32 ver = 0, minor = 0;
+ info->GetVersion(&ver, &minor);
+
+ LOG_INFO_MESSAGE("Loaded DXIL compiler, version ", ver, ".", minor);
+
+ ver = (ver << 16) | (minor & 0xFFFF);
+
+ // map known DXC version to maximum SM
+ switch (ver)
+ {
+ case 0x10005: MaxShaderModel = {6, 5}; break;
+ case 0x10004: MaxShaderModel = {6, 4}; break; // SM 6.4 and SM 6.5 preview
+ case 0x10002: MaxShaderModel = {6, 2}; break; // SM 6.1 and SM 6.2 preview
+ default: MaxShaderModel = (ver > 0x10005 ? ShaderVersion{6, 6} : ShaderVersion{6, 0}); break; // unknown version
+ }
+ }
+ }
+ }
+ }
+};
+
+static DXILCompilerImpl* D3D12CompilerLib()
+{
+# ifdef D3D12_SUPPORTED
+ static DXILCompilerImpl inst{"dxcompiler"};
+ return &inst;
+# else
+ return nullptr;
+# endif
+}
+
+static DXILCompilerImpl* SPIRVCompilerLib()
+{
+# ifdef VULKAN_SUPPORTED
+ static DXILCompilerImpl inst{"vk_dxcompiler"};
+ return &inst;
+# else
+ return nullptr;
+# endif
+}
+
+class DxcIncludeHandlerImpl final : public IDxcIncludeHandler
+{
+public:
+ explicit DxcIncludeHandlerImpl(IShaderSourceInputStreamFactory* pStreamFactory, CComPtr<IDxcLibrary> pLibrary) :
+ m_pLibrary{pLibrary},
+ m_pStreamFactory{pStreamFactory},
+ m_RefCount{1}
+ {
+ }
+
+ HRESULT STDMETHODCALLTYPE LoadSource(_In_ LPCWSTR pFilename, _COM_Outptr_result_maybenull_ IDxcBlob** ppIncludeSource) override
+ {
+ String fileName = std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>, wchar_t>{}.to_bytes(pFilename);
+ if (fileName.empty())
+ {
+ LOG_ERROR("Failed to convert shader include file name ", fileName, ". File name must be ANSI string");
+ return E_FAIL;
+ }
+
+ RefCntAutoPtr<IFileStream> pSourceStream;
+ m_pStreamFactory->CreateInputStream(fileName.c_str(), &pSourceStream);
+ if (pSourceStream == nullptr)
+ {
+ LOG_ERROR("Failed to open shader include file ", fileName, ". Check that the file exists");
+ return E_FAIL;
+ }
+
+ RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0));
+ pSourceStream->ReadBlob(pFileData);
+
+ CComPtr<IDxcBlobEncoding> sourceBlob;
+ HRESULT hr = m_pLibrary->CreateBlobWithEncodingFromPinned(pFileData->GetDataPtr(), UINT32(pFileData->GetSize()), CP_UTF8, &sourceBlob);
+ if (FAILED(hr))
+ {
+ LOG_ERROR("Failed to allocate space for shader include file ", fileName, ".");
+ return E_FAIL;
+ }
+
+ m_FileDataCache.push_back(pFileData);
+
+ sourceBlob->QueryInterface(IID_PPV_ARGS(ppIncludeSource));
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) override
+ {
+ return E_FAIL;
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef(void) override
+ {
+ return m_RefCount++;
+ }
+
+ ULONG STDMETHODCALLTYPE Release(void) override
+ {
+ --m_RefCount;
+ VERIFY(m_RefCount > 0, "Inconsistent call to Release()");
+ return m_RefCount;
+ }
+
+private:
+ CComPtr<IDxcLibrary> m_pLibrary;
+ IShaderSourceInputStreamFactory* m_pStreamFactory;
+ ULONG m_RefCount;
+ std::vector<RefCntAutoPtr<IDataBlob>> m_FileDataCache;
+};
+
+} // namespace
+
+# ifdef D3D12_SUPPORTED
+HRESULT D3D12DxcCreateInstance(
+ _In_ REFCLSID rclsid,
+ _In_ REFIID riid,
+ _Out_ LPVOID* ppv)
+{
+ DXILCompilerImpl* DxilCompiler = D3D12CompilerLib();
+ if (DxilCompiler != nullptr || DxilCompiler->CreateInstance != nullptr)
+ return DxilCompiler->CreateInstance(rclsid, riid, ppv);
+ else
+ return E_NOTIMPL;
+}
+# endif
+
+bool DXILGetMaxShaderModel(DXILCompilerTarget Target,
+ ShaderVersion& Version)
+{
+ DXILCompilerImpl* DxilCompiler = nullptr;
+ switch (Target)
+ {
+ case DXILCompilerTarget::Direct3D12: DxilCompiler = D3D12CompilerLib(); break;
+ case DXILCompilerTarget::Vulkan: DxilCompiler = SPIRVCompilerLib(); break;
+ }
+
+ if (DxilCompiler == nullptr)
+ return false;
+
+ Version = DxilCompiler->MaxShaderModel;
+ return true;
+}
+
+bool DXILCompile(DXILCompilerTarget Target,
+ const char* Source,
+ size_t SourceLength,
+ const wchar_t* EntryPoint,
+ const wchar_t* Profile,
+ const DxcDefine* pDefines,
+ size_t DefinesCount,
+ const wchar_t** pArgs,
+ size_t ArgsCount,
+ IShaderSourceInputStreamFactory* pShaderSourceStreamFactory,
+ IDxcBlob** ppBlobOut,
+ IDxcBlob** ppCompilerOutput)
+{
+ DXILCompilerImpl* DxilCompiler = nullptr;
+ switch (Target)
+ {
+ case DXILCompilerTarget::Direct3D12: DxilCompiler = D3D12CompilerLib(); break;
+ case DXILCompilerTarget::Vulkan: DxilCompiler = SPIRVCompilerLib(); break;
+ }
+
+ if (DxilCompiler == nullptr || DxilCompiler->CreateInstance == nullptr)
+ {
+ LOG_ERROR("Failed to load DXIL compiler");
+ return false;
+ }
+
+ DEV_CHECK_ERR(Source != nullptr && SourceLength > 0, "'Source' must not be null and 'SourceLength' must be greater than 0");
+ DEV_CHECK_ERR(EntryPoint != nullptr, "'EntryPoint' must not be null");
+ DEV_CHECK_ERR(Profile != nullptr, "'Profile' must not be null");
+ DEV_CHECK_ERR((pDefines != nullptr) == (DefinesCount > 0), "'DefinesCount' must be 0 if 'pDefines' is null");
+ DEV_CHECK_ERR((pArgs != nullptr) == (ArgsCount > 0), "'ArgsCount' must be 0 if 'pArgs' is null");
+ DEV_CHECK_ERR(ppBlobOut != nullptr, "'ppBlobOut' must not be null");
+ DEV_CHECK_ERR(ppCompilerOutput != nullptr, "'ppCompilerOutput' must not be null");
+
+ HRESULT hr;
+
+ CComPtr<IDxcLibrary> library;
+ hr = DxilCompiler->CreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&library));
+ if (FAILED(hr))
+ return false;
+
+ CComPtr<IDxcCompiler> compiler;
+ hr = DxilCompiler->CreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler));
+ if (FAILED(hr))
+ return false;
+
+ CComPtr<IDxcBlobEncoding> sourceBlob;
+ hr = library->CreateBlobWithEncodingFromPinned(Source, UINT32(SourceLength), CP_UTF8, &sourceBlob);
+ if (FAILED(hr))
+ return false;
+
+ DxcIncludeHandlerImpl IncludeHandler{pShaderSourceStreamFactory, library};
+
+ CComPtr<IDxcOperationResult> result;
+ hr = compiler->Compile(
+ sourceBlob,
+ L"",
+ EntryPoint,
+ Profile,
+ pArgs, UINT32(ArgsCount),
+ pDefines, UINT32(DefinesCount),
+ pShaderSourceStreamFactory ? &IncludeHandler : nullptr,
+ &result);
+
+ if (SUCCEEDED(hr))
+ {
+ HRESULT status;
+ if (SUCCEEDED(result->GetStatus(&status)))
+ hr = status;
+ }
+
+ if (result)
+ {
+ CComPtr<IDxcBlobEncoding> errorsBlob;
+ CComPtr<IDxcBlobEncoding> errorsBlobUtf8;
+ if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob)) && SUCCEEDED(library->GetBlobAsUtf8(errorsBlob, &errorsBlobUtf8)))
+ {
+ errorsBlobUtf8->QueryInterface(IID_PPV_ARGS(ppCompilerOutput));
+ }
+ }
+
+ if (FAILED(hr))
+ return false; // compilation failed
+
+ CComPtr<IDxcBlob> compiled;
+ hr = result->GetResult(&compiled);
+ if (FAILED(hr))
+ return false;
+
+ CComPtr<IDxcValidator> validator;
+ hr = DxilCompiler->CreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&validator));
+ if (FAILED(hr))
+ return false;
+
+ CComPtr<IDxcOperationResult> validationResult;
+ hr = validator->Validate(compiled, DxcValidatorFlags_InPlaceEdit, &validationResult);
+
+ if (FAILED(hr))
+ return false; // validation failed
+
+ // validate and sign in
+ if (Target == DXILCompilerTarget::Direct3D12)
+ {
+ HRESULT status;
+ if (SUCCEEDED(validationResult->GetStatus(&status)) && FAILED(status))
+ {
+ CComPtr<IDxcBlobEncoding> validationOutput;
+ CComPtr<IDxcBlobEncoding> validationOutputUtf8;
+ validationResult->GetErrorBuffer(&validationOutput);
+ library->GetBlobAsUtf8(validationOutput, &validationOutputUtf8);
+
+ size_t ValidationMsgLen = validationOutputUtf8 ? validationOutputUtf8->GetBufferSize() : 0;
+ const char* ValidationMsg = ValidationMsgLen > 0 ? static_cast<const char*>(validationOutputUtf8->GetBufferPointer()) : "";
+
+ LOG_ERROR("Shader validation failed: ", ValidationMsg);
+ return false;
+ }
+ }
+
+ *ppBlobOut = compiled.Detach();
+ return true;
+}
+
+// Implemented in GLSLSourceBuilder.cpp
+const char* GetShaderTypeDefines(SHADER_TYPE Type);
+
+namespace
+{
+
+// clang-format off
+static const char g_HLSLDefinitions[] =
+{
+#include "../../GraphicsEngineD3DBase/include/HLSLDefinitions_inc.fxh"
+};
+// clang-format on
+
+} // namespace
+
+std::vector<uint32_t> DXILtoSPIRV(const ShaderCreateInfo& Attribs,
+ const char* ExtraDefinitions,
+ IDataBlob** ppCompilerOutput)
+{
+ RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0));
+
+ const char* SourceCode = 0;
+ int SourceCodeLen = 0;
+ if (Attribs.Source)
+ {
+ SourceCode = Attribs.Source;
+ SourceCodeLen = static_cast<int>(strlen(Attribs.Source));
+ }
+ else
+ {
+ VERIFY(Attribs.pShaderSourceStreamFactory, "Input stream factory is null");
+ RefCntAutoPtr<IFileStream> pSourceStream;
+ Attribs.pShaderSourceStreamFactory->CreateInputStream(Attribs.FilePath, &pSourceStream);
+ if (pSourceStream == nullptr)
+ LOG_ERROR_AND_THROW("Failed to open shader source file");
+
+ pSourceStream->ReadBlob(pFileData);
+ SourceCode = reinterpret_cast<char*>(pFileData->GetDataPtr());
+ SourceCodeLen = static_cast<int>(pFileData->GetSize());
+ }
+
+ std::string Source;
+ Source.reserve(SourceCodeLen + sizeof(g_HLSLDefinitions));
+
+ Source.append(g_HLSLDefinitions);
+ if (const auto* ShaderTypeDefine = GetShaderTypeDefines(Attribs.Desc.ShaderType))
+ Source += ShaderTypeDefine;
+
+ if (ExtraDefinitions != nullptr)
+ Source += ExtraDefinitions;
+
+ if (Attribs.Macros != nullptr)
+ {
+ Source += '\n';
+ auto* pMacro = Attribs.Macros;
+ while (pMacro->Name != nullptr && pMacro->Definition != nullptr)
+ {
+ Source += "#define ";
+ Source += pMacro->Name;
+ Source += ' ';
+ Source += pMacro->Definition;
+ Source += "\n";
+ ++pMacro;
+ }
+ }
+
+ Source.append(SourceCode, SourceCodeLen);
+
+ // validate shader version
+ ShaderVersion ShaderModel = Attribs.HLSLVersion;
+ ShaderVersion MaxSM;
+
+ if (DXILGetMaxShaderModel(DXILCompilerTarget::Vulkan, MaxSM))
+ {
+ if (ShaderModel.Major < 6 || ShaderModel.Major > MaxSM.Major)
+ ShaderModel = MaxSM;
+
+ if (ShaderModel.Major == MaxSM.Major && ShaderModel.Minor > MaxSM.Minor)
+ ShaderModel = MaxSM;
+ }
+
+ std::wstring Profile;
+ switch (Attribs.Desc.ShaderType)
+ {
+ // clang-format off
+ case SHADER_TYPE_VERTEX: Profile = L"vs_"; break;
+ case SHADER_TYPE_PIXEL: Profile = L"ps_"; break;
+ case SHADER_TYPE_GEOMETRY: Profile = L"gs_"; break;
+ case SHADER_TYPE_HULL: Profile = L"hs_"; break;
+ case SHADER_TYPE_DOMAIN: Profile = L"ds_"; break;
+ case SHADER_TYPE_COMPUTE: Profile = L"cs_"; break;
+ case SHADER_TYPE_AMPLIFICATION: Profile = L"as_"; break;
+ case SHADER_TYPE_MESH: Profile = L"ms_"; break;
+ default: UNEXPECTED("Unexpected shader type");
+ // clang-format on
+ }
+
+ Profile += L'0' + (ShaderModel.Major % 10);
+ Profile += L'_';
+ Profile += L'0' + (ShaderModel.Minor % 10);
+
+ const wchar_t* pArgs[] =
+ {
+ L"-spirv",
+ L"-fspv-reflect",
+ L"-WX", // Warnings as errors
+ L"-O3", // Optimization level 3
+ };
+
+ CComPtr<IDxcBlob> compiled;
+ CComPtr<IDxcBlob> errors;
+
+ bool result = DXILCompile(DXILCompilerTarget::Vulkan,
+ Source.c_str(), Source.length(),
+ std::wstring{Attribs.EntryPoint, Attribs.EntryPoint + strlen(Attribs.EntryPoint)}.c_str(),
+ Profile.c_str(),
+ nullptr, 0,
+ pArgs, std::size(pArgs),
+ Attribs.pShaderSourceStreamFactory,
+ &compiled,
+ &errors);
+
+ const size_t CompilerMsgLen = errors ? errors->GetBufferSize() : 0;
+ const char* CompilerMsg = CompilerMsgLen > 0 ? static_cast<const char*>(errors->GetBufferPointer()) : nullptr;
+
+ if (CompilerMsg != nullptr && ppCompilerOutput != nullptr)
+ {
+ auto* pOutputDataBlob = MakeNewRCObj<DataBlobImpl>()(Source.length() + 1 + CompilerMsgLen + 1);
+ char* DataPtr = static_cast<char*>(pOutputDataBlob->GetDataPtr());
+ memcpy(DataPtr, CompilerMsg, CompilerMsgLen + 1);
+ memcpy(DataPtr + CompilerMsgLen + 1, Source.data(), Source.length() + 1);
+ pOutputDataBlob->QueryInterface(IID_DataBlob, reinterpret_cast<IObject**>(ppCompilerOutput));
+ }
+
+ std::vector<uint32_t> SPIRV;
+
+ if (result && compiled && compiled->GetBufferSize() > 0)
+ {
+ SPIRV.assign(static_cast<uint32_t*>(compiled->GetBufferPointer()),
+ static_cast<uint32_t*>(compiled->GetBufferPointer()) + compiled->GetBufferSize() / sizeof(uint32_t));
+ }
+ return SPIRV;
+}
+
+} // namespace Diligent
+
+#else
+
+namespace Diligent
+{
+
+bool DXILCompile(DXILCompilerTarget Target,
+ const char* Source,
+ const wchar_t* EntryPoint,
+ const wchar_t* Profile,
+ const DxcDefine* pDefines,
+ size_t DefinesCount,
+ const wchar_t** pArgs,
+ size_t ArgsCount,
+ IShaderSourceInputStreamFactory* pShaderSourceStreamFactory,
+ IDxcBlob** ppBlobOut,
+ IDxcBlob** ppCompilerOutput)
+{
+ return false;
+}
+
+} // namespace Diligent
+#endif \ No newline at end of file