diff options
| author | azhirnov <zh1dron@gmail.com> | 2020-08-25 01:56:42 +0000 |
|---|---|---|
| committer | azhirnov <zh1dron@gmail.com> | 2020-08-25 01:56:42 +0000 |
| commit | 1313de1ab167fe67d14fa2a848946f442491ca11 (patch) | |
| tree | a87dad429e9a639b5403d0c923ca2d35b610479c /Graphics | |
| parent | added AdapterId to Vulkan backend (diff) | |
| download | DiligentCore-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.txt | 4 | ||||
| -rw-r--r-- | Graphics/GLSLTools/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsEngine/interface/Shader.h | 25 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3D11/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3D12/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp | 4 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3DBase/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp | 10 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp | 307 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp | 4 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineVulkan/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp | 48 | ||||
| -rw-r--r-- | Graphics/HLSLTools/CMakeLists.txt | 49 | ||||
| -rw-r--r-- | Graphics/HLSLTools/include/DXILUtils.hpp | 76 | ||||
| -rw-r--r-- | Graphics/HLSLTools/src/DXILUtils.cpp | 552 |
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 |
