From 3abff09adc2b349be3a90584ddec8cf4cbcb6406 Mon Sep 17 00:00:00 2001 From: Minmin Gong Date: Tue, 21 Apr 2020 22:27:20 -0700 Subject: [PATCH] [Link] Enable to compile HLSLs to Dxil modules, and link them Related work item: Github #10 --- External/googletest.cmake | 2 +- Include/ShaderConductor/ShaderConductor.hpp | 22 +- Source/Core/ShaderConductor.cpp | 270 +++++++++++++----- Source/Tests/CMakeLists.txt | 3 + .../Expected/CalcLight+Diffuse.Debug.dxilasm | Bin 0 -> 7407 bytes .../CalcLight+Diffuse.Release.dxilasm | Bin 0 -> 7383 bytes .../CalcLight+DiffuseSpecular.Debug.dxilasm | 218 ++++++++++++++ .../CalcLight+DiffuseSpecular.Release.dxilasm | 217 ++++++++++++++ Source/Tests/Data/Input/CalcLight.hlsl | 29 ++ Source/Tests/Data/Input/CalcLightDiffuse.hlsl | 8 + .../Data/Input/CalcLightDiffuseSpecular.hlsl | 29 ++ Source/Tests/ShaderConductorTest.cpp | 74 ++++- Source/Wrapper/Native.cpp | 2 +- Source/Wrapper/Program.cs | 1 + Source/Wrapper/Wrapper.cs | 1 + 15 files changed, 802 insertions(+), 74 deletions(-) create mode 100644 Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm create mode 100644 Source/Tests/Data/Expected/CalcLight+Diffuse.Release.dxilasm create mode 100644 Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Debug.dxilasm create mode 100644 Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm create mode 100644 Source/Tests/Data/Input/CalcLight.hlsl create mode 100644 Source/Tests/Data/Input/CalcLightDiffuse.hlsl create mode 100644 Source/Tests/Data/Input/CalcLightDiffuseSpecular.hlsl diff --git a/External/googletest.cmake b/External/googletest.cmake index 40b944fe..1bd1a4eb 100644 --- a/External/googletest.cmake +++ b/External/googletest.cmake @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -set(googletest_REV "440527a61e1c91188195f7de212c63c77e8f0a45") +set(googletest_REV "dcc92d0ab6c4ce022162a23566d44f673251eee4") UpdateExternalLib("googletest" "https://github.com/google/googletest.git" ${googletest_REV}) diff --git a/Include/ShaderConductor/ShaderConductor.hpp b/Include/ShaderConductor/ShaderConductor.hpp index c9f619c7..c91b962e 100644 --- a/Include/ShaderConductor/ShaderConductor.hpp +++ b/Include/ShaderConductor/ShaderConductor.hpp @@ -164,6 +164,7 @@ namespace ShaderConductor { ShadingLanguage language; const char* version; + bool asModule; }; struct ResultDesc @@ -178,15 +179,34 @@ namespace ShaderConductor struct DisassembleDesc { ShadingLanguage language; - uint8_t* binary; + const uint8_t* binary; uint32_t binarySize; }; + struct ModuleDesc + { + const char* name; + Blob* target; + }; + + struct LinkDesc + { + const char* entryPoint; + ShaderStage stage; + + const ModuleDesc** modules; + uint32_t numModules; + }; + public: static ResultDesc Compile(const SourceDesc& source, const Options& options, const TargetDesc& target); static void Compile(const SourceDesc& source, const Options& options, const TargetDesc* targets, uint32_t numTargets, ResultDesc* results); static ResultDesc Disassemble(const DisassembleDesc& source); + + // Currently only Dxil on Windows supports linking + static bool LinkSupport(); + static ResultDesc Link(const LinkDesc& modules, const Options& options, const TargetDesc& target); }; } // namespace ShaderConductor diff --git a/Source/Core/ShaderConductor.cpp b/Source/Core/ShaderConductor.cpp index 71aa484a..130787e8 100644 --- a/Source/Core/ShaderConductor.cpp +++ b/Source/Core/ShaderConductor.cpp @@ -78,6 +78,18 @@ namespace return m_compiler; } + CComPtr CreateLinker() const + { + CComPtr linker; + IFT(m_createInstanceFunc(CLSID_DxcLinker, __uuidof(IDxcLinker), reinterpret_cast(&linker))); + return linker; + } + + bool LinkerSupport() const + { + return m_linkerSupport; + } + void Destroy() { if (m_dxcompilerDll) @@ -157,6 +169,8 @@ namespace { throw std::runtime_error("COULDN'T load dxcompiler."); } + + m_linkerSupport = (CreateLinker() != nullptr); } private: @@ -165,6 +179,8 @@ namespace CComPtr m_library; CComPtr m_compiler; + + bool m_linkerSupport; }; class ScIncludeHandler : public IDxcIncludeHandler @@ -305,13 +321,10 @@ namespace result.hasError = true; } - Compiler::ResultDesc CompileToBinary(const Compiler::SourceDesc& source, const Compiler::Options& options, - ShadingLanguage targetLanguage) + std::wstring ShaderProfileName(ShaderStage stage, Compiler::ShaderModel shaderModel) { - assert((targetLanguage == ShadingLanguage::Dxil) || (targetLanguage == ShadingLanguage::SpirV)); - std::wstring shaderProfile; - switch (source.stage) + switch (stage) { case ShaderStage::VertexShader: shaderProfile = L"vs"; @@ -340,10 +353,69 @@ namespace default: llvm_unreachable("Invalid shader stage."); } + shaderProfile.push_back(L'_'); - shaderProfile.push_back(L'0' + options.shaderModel.major_ver); + shaderProfile.push_back(L'0' + shaderModel.major_ver); shaderProfile.push_back(L'_'); - shaderProfile.push_back(L'0' + options.shaderModel.minor_ver); + shaderProfile.push_back(L'0' + shaderModel.minor_ver); + + return shaderProfile; + } + + void ConvertDxcResult(Compiler::ResultDesc& result, IDxcOperationResult* dxcResult) + { + HRESULT status; + IFT(dxcResult->GetStatus(&status)); + + result.target = nullptr; + result.errorWarningMsg = nullptr; + + CComPtr errors; + IFT(dxcResult->GetErrorBuffer(&errors)); + if (errors != nullptr) + { + if (errors->GetBufferSize() > 0) + { + result.errorWarningMsg = CreateBlob(errors->GetBufferPointer(), static_cast(errors->GetBufferSize())); + } + errors = nullptr; + } + + result.hasError = true; + if (SUCCEEDED(status)) + { + CComPtr program; + IFT(dxcResult->GetResult(&program)); + dxcResult = nullptr; + if (program != nullptr) + { + result.target = CreateBlob(program->GetBufferPointer(), static_cast(program->GetBufferSize())); + result.hasError = false; + } + } + } + + Compiler::ResultDesc CompileToBinary(const Compiler::SourceDesc& source, const Compiler::Options& options, + ShadingLanguage targetLanguage, bool asModule) + { + assert((targetLanguage == ShadingLanguage::Dxil) || (targetLanguage == ShadingLanguage::SpirV)); + + std::wstring shaderProfile; + if (asModule) + { + if (targetLanguage == ShadingLanguage::Dxil) + { + shaderProfile = L"lib_6_x"; + } + else + { + llvm_unreachable("Spir-V module is not supported."); + } + } + else + { + shaderProfile = ShaderProfileName(source.stage, options.shaderModel); + } std::vector dxcDefines; std::vector dxcDefineStrings; @@ -491,44 +563,14 @@ namespace dxcArgs.data(), static_cast(dxcArgs.size()), dxcDefines.data(), static_cast(dxcDefines.size()), includeHandler, &compileResult)); - HRESULT status; - IFT(compileResult->GetStatus(&status)); - - Compiler::ResultDesc ret; - - ret.target = nullptr; - ret.isText = false; - ret.errorWarningMsg = nullptr; - - CComPtr errors; - IFT(compileResult->GetErrorBuffer(&errors)); - if (errors != nullptr) - { - if (errors->GetBufferSize() > 0) - { - ret.errorWarningMsg = CreateBlob(errors->GetBufferPointer(), static_cast(errors->GetBufferSize())); - } - errors = nullptr; - } - - ret.hasError = true; - if (SUCCEEDED(status)) - { - CComPtr program; - IFT(compileResult->GetResult(&program)); - compileResult = nullptr; - if (program != nullptr) - { - ret.target = CreateBlob(program->GetBufferPointer(), static_cast(program->GetBufferSize())); - ret.hasError = false; - } - } + Compiler::ResultDesc ret{}; + ConvertDxcResult(ret, compileResult); return ret; } - Compiler::ResultDesc ConvertBinary(const Compiler::ResultDesc& binaryResult, const Compiler::SourceDesc& source, - const Compiler::TargetDesc& target) + Compiler::ResultDesc CrossCompile(const Compiler::ResultDesc& binaryResult, const Compiler::SourceDesc& source, + const Compiler::TargetDesc& target) { assert((target.language != ShadingLanguage::Dxil) && (target.language != ShadingLanguage::SpirV)); assert((binaryResult.target->Size() & (sizeof(uint32_t) - 1)) == 0); @@ -781,6 +823,42 @@ namespace return ret; } + + Compiler::ResultDesc ConvertBinary(const Compiler::ResultDesc& binaryResult, const Compiler::SourceDesc& source, + const Compiler::TargetDesc& target) + { + if (!binaryResult.hasError) + { + if (target.asModule) + { + return binaryResult; + } + else + { + switch (target.language) + { + case ShadingLanguage::Dxil: + case ShadingLanguage::SpirV: + return binaryResult; + + case ShadingLanguage::Hlsl: + case ShadingLanguage::Glsl: + case ShadingLanguage::Essl: + case ShadingLanguage::Msl_macOS: + case ShadingLanguage::Msl_iOS: + return CrossCompile(binaryResult, source, target); + + default: + llvm_unreachable("Invalid shading language."); + break; + } + } + } + else + { + return binaryResult; + } + } } // namespace namespace ShaderConductor @@ -818,12 +896,17 @@ namespace ShaderConductor } bool hasDxil = false; + bool hasDxilModule = false; bool hasSpirV = false; for (uint32_t i = 0; i < numTargets; ++i) { if (targets[i].language == ShadingLanguage::Dxil) { hasDxil = true; + if (targets[i].asModule) + { + hasDxilModule = true; + } } else { @@ -834,52 +917,49 @@ namespace ShaderConductor ResultDesc dxilBinaryResult{}; if (hasDxil) { - dxilBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::Dxil); + dxilBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::Dxil, false); + } + + ResultDesc dxilModuleBinaryResult{}; + if (hasDxilModule) + { + dxilModuleBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::Dxil, true); } ResultDesc spirvBinaryResult{}; if (hasSpirV) { - spirvBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::SpirV); + spirvBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::SpirV, false); } for (uint32_t i = 0; i < numTargets; ++i) { - ResultDesc binaryResult = targets[i].language == ShadingLanguage::Dxil ? dxilBinaryResult : spirvBinaryResult; - if (binaryResult.target) + ResultDesc binaryResult; + if (targets[i].language == ShadingLanguage::Dxil) { - binaryResult.target = CreateBlob(binaryResult.target->Data(), binaryResult.target->Size()); + if (targets[i].asModule) + { + binaryResult = dxilModuleBinaryResult; + } + else + { + binaryResult = dxilBinaryResult; + } } - if (binaryResult.errorWarningMsg) + else { - binaryResult.errorWarningMsg = CreateBlob(binaryResult.errorWarningMsg->Data(), binaryResult.errorWarningMsg->Size()); + binaryResult = spirvBinaryResult; } - if (!binaryResult.hasError) - { - switch (targets[i].language) - { - case ShadingLanguage::Dxil: - case ShadingLanguage::SpirV: - results[i] = binaryResult; - break; - case ShadingLanguage::Hlsl: - case ShadingLanguage::Glsl: - case ShadingLanguage::Essl: - case ShadingLanguage::Msl_macOS: - case ShadingLanguage::Msl_iOS: - results[i] = ConvertBinary(binaryResult, sourceOverride, targets[i]); - break; - - default: - llvm_unreachable("Invalid shading language."); - break; - } + if (binaryResult.target) + { + binaryResult.target = CreateBlob(binaryResult.target->Data(), binaryResult.target->Size()); } - else + if (binaryResult.errorWarningMsg) { - results[i] = binaryResult; + binaryResult.errorWarningMsg = CreateBlob(binaryResult.errorWarningMsg->Data(), binaryResult.errorWarningMsg->Size()); } + results[i] = ConvertBinary(binaryResult, sourceOverride, targets[i]); } if (hasDxil) @@ -887,6 +967,11 @@ namespace ShaderConductor DestroyBlob(dxilBinaryResult.target); DestroyBlob(dxilBinaryResult.errorWarningMsg); } + if (hasDxilModule) + { + DestroyBlob(dxilModuleBinaryResult.target); + DestroyBlob(dxilModuleBinaryResult.errorWarningMsg); + } if (hasSpirV) { DestroyBlob(spirvBinaryResult.target); @@ -952,6 +1037,51 @@ namespace ShaderConductor return ret; } + + bool Compiler::LinkSupport() + { + return Dxcompiler::Instance().LinkerSupport(); + } + + Compiler::ResultDesc Compiler::Link(const LinkDesc& modules, const Compiler::Options& options, const TargetDesc& target) + { + auto linker = Dxcompiler::Instance().CreateLinker(); + IFTPTR(linker); + + auto* library = Dxcompiler::Instance().Library(); + + std::vector moduleNames(modules.numModules); + std::vector moduleNamesUtf16(modules.numModules); + std::vector> moduleBlobs(modules.numModules); + for (uint32_t i = 0; i < modules.numModules; ++i) + { + IFTARG(modules.modules[i] != nullptr); + + IFT(library->CreateBlobWithEncodingOnHeapCopy(modules.modules[i]->target->Data(), modules.modules[i]->target->Size(), CP_UTF8, + &moduleBlobs[i])); + IFTARG(moduleBlobs[i]->GetBufferSize() >= 4); + + Unicode::UTF8ToUTF16String(modules.modules[i]->name, &moduleNames[i]); + moduleNamesUtf16[i] = moduleNames[i].c_str(); + IFT(linker->RegisterLibrary(moduleNamesUtf16[i], moduleBlobs[i])); + } + + std::wstring entryPointUtf16; + Unicode::UTF8ToUTF16String(modules.entryPoint, &entryPointUtf16); + + const std::wstring shaderProfile = ShaderProfileName(modules.stage, options.shaderModel); + CComPtr linkResult; + IFT(linker->Link(entryPointUtf16.c_str(), shaderProfile.c_str(), moduleNamesUtf16.data(), + static_cast(moduleNamesUtf16.size()), nullptr, 0, &linkResult)); + + Compiler::ResultDesc binaryResult{}; + ConvertDxcResult(binaryResult, linkResult); + + Compiler::SourceDesc source{}; + source.entryPoint = modules.entryPoint; + source.stage = modules.stage; + return ConvertBinary(binaryResult, source, target); + } } // namespace ShaderConductor #ifdef _WIN32 diff --git a/Source/Tests/CMakeLists.txt b/Source/Tests/CMakeLists.txt index 7aa2b363..2d987e11 100644 --- a/Source/Tests/CMakeLists.txt +++ b/Source/Tests/CMakeLists.txt @@ -14,6 +14,9 @@ set(DATA_INC_FILES ) set(DATA_FILES + Data/Input/CalcLight.hlsl + Data/Input/CalcLightDiffuse.hlsl + Data/Input/CalcLightDiffuseSpecular.hlsl Data/Input/Common.hlsli Data/Input/Constant_PS.hlsl Data/Input/Constant_VS.hlsl diff --git a/Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm b/Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm new file mode 100644 index 0000000000000000000000000000000000000000..000eb7841c7d393d50393be47f390f6c5d6ad8ba GIT binary patch literal 7407 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, <3 x float>, float } +%dx.types.CBufRet.f32 = type { float, float, float, float } +%dx.types.Handle = type { i8* } + +@cbPS = external constant %cbPS + +; Function Attrs: nounwind readnone +declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0 + +; Function Attrs: nounwind readonly +declare %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32, %dx.types.Handle, i32) #1 + +; Function Attrs: nounwind readnone +declare float @dx.op.binary.f32(i32, float, float) #0 + +; Function Attrs: nounwind readnone +declare float @dx.op.dot3.f32(i32, float, float, float, float, float, float) #0 + +; Function Attrs: nounwind +declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #2 + +; Function Attrs: nounwind readnone +declare float @dx.op.unary.f32(i32, float) #0 + +define void @main() { +entry: + %cbPS_cbuffer = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %0 = call float @dx.op.loadInput.f32(i32 4, i32 3, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %1 = call float @dx.op.loadInput.f32(i32 4, i32 3, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %2 = call float @dx.op.loadInput.f32(i32 4, i32 3, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %3 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %4 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %5 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %6 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %7 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %8 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %9 = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %cbPS_cbuffer, i32 1) ; CBufferLoadLegacy(handle,regIndex) + %10 = extractvalue %dx.types.CBufRet.f32 %9, 3 + %11 = extractvalue %dx.types.CBufRet.f32 %9, 0 + %12 = extractvalue %dx.types.CBufRet.f32 %9, 1 + %13 = extractvalue %dx.types.CBufRet.f32 %9, 2 + %14 = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %cbPS_cbuffer, i32 0) ; CBufferLoadLegacy(handle,regIndex) + %15 = extractvalue %dx.types.CBufRet.f32 %14, 0 + %16 = extractvalue %dx.types.CBufRet.f32 %14, 1 + %17 = extractvalue %dx.types.CBufRet.f32 %14, 2 + %add.i.i.i = fadd fast float %10, 2.000000e+00 + %div.i.i.i = fmul fast float %add.i.i.i, 1.250000e-01 + %18 = call float @dx.op.dot3.f32(i32 55, float %0, float %1, float %2, float %6, float %7, float %8) #2 ; Dot3(ax,ay,az,bx,by,bz) + %FMax.i = call float @dx.op.binary.f32(i32 35, float %18, float 0.000000e+00) #2 ; FMax(a,b) + %Log3.i = call float @dx.op.unary.f32(i32 23, float %FMax.i) #2 ; Log(value) + %19 = fmul fast float %Log3.i, %10 + %Exp4.i = call float @dx.op.unary.f32(i32 21, float %19) #2 ; Exp(value) + %mul.i.i0.i = fmul fast float %Exp4.i, %div.i.i.i + %20 = call float @dx.op.dot3.f32(i32 55, float %3, float %4, float %5, float %0, float %1, float %2) #2 ; Dot3(ax,ay,az,bx,by,bz) + %Saturate.i = call float @dx.op.unary.f32(i32 7, float %20) #2 ; Saturate(value) + %cmp.i.i.i0.i = fcmp fast ogt float %11, 0.000000e+00 + %cmp.i.i.i1.i = fcmp fast ogt float %12, 0.000000e+00 + %cmp.i.i.i2.i = fcmp fast ogt float %13, 0.000000e+00 + %sub.i.i.i0.i = fsub fast float 1.000000e+00, %11 + %sub.i.i.i1.i = fsub fast float 1.000000e+00, %12 + %sub.i.i.i2.i = fsub fast float 1.000000e+00, %13 + %sub2.i.i.i = fsub fast float 1.000000e+00, %Saturate.i + %Log.i = call float @dx.op.unary.f32(i32 23, float %sub2.i.i.i) #2 ; Log(value) + %21 = fmul fast float %Log.i, 5.000000e+00 + %Exp.i = call float @dx.op.unary.f32(i32 21, float %21) #2 ; Exp(value) + %mul.i.i.i0.i = fmul fast float %Exp.i, %sub.i.i.i0.i + %mul.i.i.i1.i = fmul fast float %Exp.i, %sub.i.i.i1.i + %mul.i.i.i2.i = fmul fast float %Exp.i, %sub.i.i.i2.i + %add.i.4.i.i0.i = fadd fast float %mul.i.i.i0.i, %11 + %add.i.4.i.i1.i = fadd fast float %mul.i.i.i1.i, %12 + %add.i.4.i.i2.i = fadd fast float %mul.i.i.i2.i, %13 + %22 = select i1 %cmp.i.i.i0.i, float %add.i.4.i.i0.i, float 0.000000e+00 + %23 = select i1 %cmp.i.i.i1.i, float %add.i.4.i.i1.i, float 0.000000e+00 + %24 = select i1 %cmp.i.i.i2.i, float %add.i.4.i.i2.i, float 0.000000e+00 + %mul3.i.i0.i = fmul fast float %mul.i.i0.i, %22 + %mul3.i.i1.i = fmul fast float %mul.i.i0.i, %23 + %mul3.i.i2.i = fmul fast float %mul.i.i0.i, %24 + %add.i0.i = fadd fast float %mul3.i.i0.i, %15 + %add.i1.i = fadd fast float %mul3.i.i1.i, %16 + %add.i2.i = fadd fast float %mul3.i.i2.i, %17 + %25 = call float @dx.op.dot3.f32(i32 55, float %6, float %7, float %8, float %3, float %4, float %5) #2 ; Dot3(ax,ay,az,bx,by,bz) + %mul.i0.i = fmul fast float %add.i0.i, %25 + %mul.i1.i = fmul fast float %add.i1.i, %25 + %mul.i2.i = fmul fast float %add.i2.i, %25 + %FMax5.i = call float @dx.op.binary.f32(i32 35, float %mul.i0.i, float 0.000000e+00) #2 ; FMax(a,b) + %FMax6.i = call float @dx.op.binary.f32(i32 35, float %mul.i1.i, float 0.000000e+00) #2 ; FMax(a,b) + %FMax7.i = call float @dx.op.binary.f32(i32 35, float %mul.i2.i, float 0.000000e+00) #2 ; FMax(a,b) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %FMax5.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %FMax6.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %FMax7.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 1.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + ret void +} + +; Function Attrs: nounwind readonly +declare %dx.types.Handle @dx.op.createHandle(i32, i8, i32, i32, i1) #1 + +attributes #0 = { nounwind readnone } +attributes #1 = { nounwind readonly } +attributes #2 = { nounwind } + +!llvm.ident = !{!0, !0} +!dx.version = !{!1} +!dx.valver = !{!2} +!dx.shaderModel = !{!3} +!dx.resources = !{!4} +!dx.typeAnnotations = !{!7, !12} +!dx.viewIdState = !{!16} +!dx.entryPoints = !{!17} + +!0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"} +!1 = !{i32 1, i32 0} +!2 = !{i32 1, i32 6} +!3 = !{!"ps", i32 6, i32 0} +!4 = !{null, null, !5, null} +!5 = !{!6} +!6 = !{i32 0, %cbPS* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} +!7 = !{i32 0, %cbPS undef, !8} +!8 = !{i32 32, !9, !10, !11} +!9 = !{i32 6, !"diffColor", i32 3, i32 0, i32 7, i32 9} +!10 = !{i32 6, !"specColor", i32 3, i32 16, i32 7, i32 9} +!11 = !{i32 6, !"shininess", i32 3, i32 28, i32 7, i32 9} +!12 = !{i32 1, void ()* @main, !13} +!13 = !{!14} +!14 = !{i32 0, !15, !15} +!15 = !{} +!16 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7]} +!17 = !{void ()* @main, !"main", !18, !4, null} +!18 = !{!19, !27, null} +!19 = !{!20, !22, !24, !25} +!20 = !{i32 0, !"SV_Position", i8 9, i8 3, !21, i8 4, i32 1, i8 4, i32 0, i8 0, null} +!21 = !{i32 0} +!22 = !{i32 1, !"NORMAL", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 1, i8 0, !23} +!23 = !{i32 3, i32 7} +!24 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 2, i8 0, !23} +!25 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !26, i8 2, i32 1, i8 3, i32 3, i8 0, !23} +!26 = !{i32 1} +!27 = !{!28} +!28 = !{i32 0, !"SV_Target", i8 9, i8 16, !21, i8 0, i32 1, i8 4, i32 0, i8 0, !29} +!29 = !{i32 3, i32 15} + \ No newline at end of file diff --git a/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm b/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm new file mode 100644 index 00000000..689db471 --- /dev/null +++ b/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm @@ -0,0 +1,217 @@ +; +; Input signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; SV_Position 0 xyzw 0 POS float +; NORMAL 0 xyz 1 NONE float xyz +; TEXCOORD 0 xyz 2 NONE float xyz +; TEXCOORD 1 xyz 3 NONE float xyz +; +; +; Output signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; SV_Target 0 xyzw 0 TARGET float xyzw +; +; shader debug name: f20646310e1953c8e33a9279b16f83a9.pdb +; shader hash: f20646310e1953c8e33a9279b16f83a9 +; +; Pipeline Runtime Information: +; +; Pixel Shader +; DepthOutput=0 +; SampleFrequency=0 +; +; +; Input signature: +; +; Name Index InterpMode DynIdx +; -------------------- ----- ---------------------- ------ +; SV_Position 0 noperspective +; NORMAL 0 linear +; TEXCOORD 0 linear +; TEXCOORD 1 linear +; +; Output signature: +; +; Name Index InterpMode DynIdx +; -------------------- ----- ---------------------- ------ +; SV_Target 0 +; +; Buffer Definitions: +; +; cbuffer cbPS +; { +; +; struct cbPS +; { +; +; float3 diffColor; ; Offset: 0 +; float3 specColor; ; Offset: 16 +; float shininess; ; Offset: 28 +; +; } cbPS; ; Offset: 0 Size: 32 +; +; } +; +; +; Resource Bindings: +; +; Name Type Format Dim ID HLSL Bind Count +; ------------------------------ ---------- ------- ----------- ------- -------------- ------ +; cbPS cbuffer NA NA CB0 cb0 1 +; +; +; ViewId state: +; +; Number of inputs: 15, outputs: 4 +; Outputs dependent on ViewId: { } +; Inputs contributing to computation of Outputs: +; output 0 depends on inputs: { 4, 5, 6, 8, 9, 10, 12, 13, 14 } +; output 1 depends on inputs: { 4, 5, 6, 8, 9, 10, 12, 13, 14 } +; output 2 depends on inputs: { 4, 5, 6, 8, 9, 10, 12, 13, 14 } +; +target triple = "dxil-ms-dx" + +%cbPS = type { <3 x float>, <3 x float>, float } +%dx.types.CBufRet.f32 = type { float, float, float, float } +%dx.types.Handle = type { i8* } + +@cbPS = external constant %cbPS + +; Function Attrs: nounwind readnone +declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0 + +; Function Attrs: nounwind readonly +declare %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32, %dx.types.Handle, i32) #1 + +; Function Attrs: nounwind readnone +declare float @dx.op.binary.f32(i32, float, float) #0 + +; Function Attrs: nounwind readnone +declare float @dx.op.dot3.f32(i32, float, float, float, float, float, float) #0 + +; Function Attrs: nounwind +declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #2 + +; Function Attrs: nounwind readnone +declare float @dx.op.unary.f32(i32, float) #0 + +define void @main() { + %cbPS_cbuffer = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %1 = call float @dx.op.loadInput.f32(i32 4, i32 3, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %2 = call float @dx.op.loadInput.f32(i32 4, i32 3, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %3 = call float @dx.op.loadInput.f32(i32 4, i32 3, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %4 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %5 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %6 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %7 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %8 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %9 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %10 = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %cbPS_cbuffer, i32 1) ; CBufferLoadLegacy(handle,regIndex) + %11 = extractvalue %dx.types.CBufRet.f32 %10, 3 + %12 = extractvalue %dx.types.CBufRet.f32 %10, 0 + %13 = extractvalue %dx.types.CBufRet.f32 %10, 1 + %14 = extractvalue %dx.types.CBufRet.f32 %10, 2 + %15 = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %cbPS_cbuffer, i32 0) ; CBufferLoadLegacy(handle,regIndex) + %16 = extractvalue %dx.types.CBufRet.f32 %15, 0 + %17 = extractvalue %dx.types.CBufRet.f32 %15, 1 + %18 = extractvalue %dx.types.CBufRet.f32 %15, 2 + %19 = fadd fast float %11, 2.000000e+00 + %20 = fmul fast float %19, 1.250000e-01 + %21 = call float @dx.op.dot3.f32(i32 55, float %1, float %2, float %3, float %7, float %8, float %9) #2 ; Dot3(ax,ay,az,bx,by,bz) + %FMax.i = call float @dx.op.binary.f32(i32 35, float %21, float 0.000000e+00) #2 ; FMax(a,b) + %Log1.i = call float @dx.op.unary.f32(i32 23, float %FMax.i) #2 ; Log(value) + %22 = fmul fast float %Log1.i, %11 + %Exp2.i = call float @dx.op.unary.f32(i32 21, float %22) #2 ; Exp(value) + %.i0.i = fmul fast float %Exp2.i, %20 + %23 = call float @dx.op.dot3.f32(i32 55, float %4, float %5, float %6, float %1, float %2, float %3) #2 ; Dot3(ax,ay,az,bx,by,bz) + %Saturate.i = call float @dx.op.unary.f32(i32 7, float %23) #2 ; Saturate(value) + %.i06.i = fcmp fast ogt float %12, 0.000000e+00 + %.i17.i = fcmp fast ogt float %13, 0.000000e+00 + %.i28.i = fcmp fast ogt float %14, 0.000000e+00 + %.i010.i = fsub fast float 1.000000e+00, %12 + %.i112.i = fsub fast float 1.000000e+00, %13 + %.i214.i = fsub fast float 1.000000e+00, %14 + %24 = fsub fast float 1.000000e+00, %Saturate.i + %Log.i = call float @dx.op.unary.f32(i32 23, float %24) #2 ; Log(value) + %25 = fmul fast float %Log.i, 5.000000e+00 + %Exp.i = call float @dx.op.unary.f32(i32 21, float %25) #2 ; Exp(value) + %.i015.i = fmul fast float %Exp.i, %.i010.i + %.i116.i = fmul fast float %Exp.i, %.i112.i + %.i217.i = fmul fast float %Exp.i, %.i214.i + %.i019.i = fadd fast float %.i015.i, %12 + %.i121.i = fadd fast float %.i116.i, %13 + %.i223.i = fadd fast float %.i217.i, %14 + %26 = select i1 %.i06.i, float %.i019.i, float 0.000000e+00 + %27 = select i1 %.i17.i, float %.i121.i, float 0.000000e+00 + %28 = select i1 %.i28.i, float %.i223.i, float 0.000000e+00 + %.i024.i = fmul fast float %.i0.i, %26 + %.i125.i = fmul fast float %.i0.i, %27 + %.i226.i = fmul fast float %.i0.i, %28 + %.i027.i = fadd fast float %.i024.i, %16 + %.i128.i = fadd fast float %.i125.i, %17 + %.i229.i = fadd fast float %.i226.i, %18 + %29 = call float @dx.op.dot3.f32(i32 55, float %7, float %8, float %9, float %4, float %5, float %6) #2 ; Dot3(ax,ay,az,bx,by,bz) + %.i030.i = fmul fast float %.i027.i, %29 + %.i131.i = fmul fast float %.i128.i, %29 + %.i232.i = fmul fast float %.i229.i, %29 + %FMax3.i = call float @dx.op.binary.f32(i32 35, float %.i030.i, float 0.000000e+00) #2 ; FMax(a,b) + %FMax4.i = call float @dx.op.binary.f32(i32 35, float %.i131.i, float 0.000000e+00) #2 ; FMax(a,b) + %FMax5.i = call float @dx.op.binary.f32(i32 35, float %.i232.i, float 0.000000e+00) #2 ; FMax(a,b) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %FMax3.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %FMax4.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %FMax5.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 1.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value) + ret void +} + +; Function Attrs: nounwind readonly +declare %dx.types.Handle @dx.op.createHandle(i32, i8, i32, i32, i1) #1 + +attributes #0 = { nounwind readnone } +attributes #1 = { nounwind readonly } +attributes #2 = { nounwind } + +!llvm.ident = !{!0, !0} +!dx.version = !{!1} +!dx.valver = !{!2} +!dx.shaderModel = !{!3} +!dx.resources = !{!4} +!dx.typeAnnotations = !{!7, !12} +!dx.viewIdState = !{!16} +!dx.entryPoints = !{!17} + +!0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"} +!1 = !{i32 1, i32 0} +!2 = !{i32 1, i32 6} +!3 = !{!"ps", i32 6, i32 0} +!4 = !{null, null, !5, null} +!5 = !{!6} +!6 = !{i32 0, %cbPS* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} +!7 = !{i32 0, %cbPS undef, !8} +!8 = !{i32 32, !9, !10, !11} +!9 = !{i32 6, !"diffColor", i32 3, i32 0, i32 7, i32 9} +!10 = !{i32 6, !"specColor", i32 3, i32 16, i32 7, i32 9} +!11 = !{i32 6, !"shininess", i32 3, i32 28, i32 7, i32 9} +!12 = !{i32 1, void ()* @main, !13} +!13 = !{!14} +!14 = !{i32 0, !15, !15} +!15 = !{} +!16 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7]} +!17 = !{void ()* @main, !"main", !18, !4, null} +!18 = !{!19, !27, null} +!19 = !{!20, !22, !24, !25} +!20 = !{i32 0, !"SV_Position", i8 9, i8 3, !21, i8 4, i32 1, i8 4, i32 0, i8 0, null} +!21 = !{i32 0} +!22 = !{i32 1, !"NORMAL", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 1, i8 0, !23} +!23 = !{i32 3, i32 7} +!24 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 2, i8 0, !23} +!25 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !26, i8 2, i32 1, i8 3, i32 3, i8 0, !23} +!26 = !{i32 1} +!27 = !{!28} +!28 = !{i32 0, !"SV_Target", i8 9, i8 16, !21, i8 0, i32 1, i8 4, i32 0, i8 0, !29} +!29 = !{i32 3, i32 15} + \ No newline at end of file diff --git a/Source/Tests/Data/Input/CalcLight.hlsl b/Source/Tests/Data/Input/CalcLight.hlsl new file mode 100644 index 00000000..27626d2b --- /dev/null +++ b/Source/Tests/Data/Input/CalcLight.hlsl @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +struct PSInput +{ + float4 pos : SV_Position; + float3 normal : NORMAL; + float3 lightVec : TEXCOORD0; + float3 halfway : TEXCOORD1; +}; + +cbuffer cbPS : register(b0) +{ + float3 diffColor; + float3 specColor; + float shininess; +}; + +float3 CalcBrdf(float3 diffColor, float3 specColor, float shininess, float3 lightVec, float3 halfway, float3 normal); + +[shader("pixel")] +float4 main(PSInput input) : SV_Target +{ + float4 color; + color.rgb = CalcBrdf(diffColor, specColor, shininess, input.lightVec, input.halfway, input.normal); + color.a = 1.0f; + + return color; +} diff --git a/Source/Tests/Data/Input/CalcLightDiffuse.hlsl b/Source/Tests/Data/Input/CalcLightDiffuse.hlsl new file mode 100644 index 00000000..63537413 --- /dev/null +++ b/Source/Tests/Data/Input/CalcLightDiffuse.hlsl @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Diffuse only +float3 CalcBrdf(float3 diffColor, float3 specColor, float shininess, float3 lightVec, float3 halfway, float3 normal) +{ + return max(diffColor * dot(normal, lightVec), 0); +} diff --git a/Source/Tests/Data/Input/CalcLightDiffuseSpecular.hlsl b/Source/Tests/Data/Input/CalcLightDiffuseSpecular.hlsl new file mode 100644 index 00000000..40ec848f --- /dev/null +++ b/Source/Tests/Data/Input/CalcLightDiffuseSpecular.hlsl @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +float SpecularNormalizeFactor(float shininess) +{ + return (shininess + 2) / 8; +} + +float3 DistributionTerm(float3 halfway, float3 normal, float shininess) +{ + return pow(max(dot(halfway, normal), 0.0f), shininess); +} + +float3 FresnelTerm(float3 lightVec, float3 halfway, float3 specColor) +{ + float eN = saturate(dot(lightVec, halfway)); + return specColor > 0 ? specColor + (1 - specColor) * pow(1 - eN, 5) : 0; +} + +float3 SpecularTerm(float3 specColor, float3 lightVec, float3 halfway, float3 normal, float shininess) +{ + return SpecularNormalizeFactor(shininess) * DistributionTerm(halfway, normal, shininess) * FresnelTerm(lightVec, halfway, specColor); +} + +// Diffuse and specular +float3 CalcBrdf(float3 diffColor, float3 specColor, float shininess, float3 lightVec, float3 halfway, float3 normal) +{ + return max((diffColor + SpecularTerm(specColor, lightVec, halfway, normal, shininess)) * dot(normal, lightVec), 0); +} diff --git a/Source/Tests/ShaderConductorTest.cpp b/Source/Tests/ShaderConductorTest.cpp index 01a9400b..7da42d53 100644 --- a/Source/Tests/ShaderConductorTest.cpp +++ b/Source/Tests/ShaderConductorTest.cpp @@ -116,6 +116,21 @@ namespace } } + Compiler::ModuleDesc CompileToModule(const char* moduleName, const std::string& inputFileName, const Compiler::TargetDesc& target) + { + std::vector input = LoadFile(inputFileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + const auto result = Compiler::Compile({ source.c_str(), inputFileName.c_str(), "", ShaderStage::PixelShader }, {}, target); + + EXPECT_FALSE(result.hasError); + EXPECT_FALSE(result.isText); + + DestroyBlob(result.errorWarningMsg); + + return { moduleName, result.target }; + } + class TestBase : public testing::Test { public: @@ -589,7 +604,7 @@ namespace option.enable16bitTypes = true; const auto result = Compiler::Compile({ source.c_str(), fileName.c_str(), "HalfOutParamPS", ShaderStage::PixelShader }, option, - { ShadingLanguage::Glsl, "30" }); + { ShadingLanguage::Glsl, "30" }); EXPECT_FALSE(result.hasError); EXPECT_TRUE(result.isText); @@ -600,6 +615,63 @@ namespace DestroyBlob(result.errorWarningMsg); DestroyBlob(result.target); } + + TEST(LinkTest, LinkDxil) + { + if (!Compiler::LinkSupport()) + { + GTEST_SKIP_("Link is not supported on this platform"); + } + + const Compiler::TargetDesc target = { ShadingLanguage::Dxil, "", true }; + const Compiler::ModuleDesc dxilModules[] = { + CompileToModule("CalcLight", TEST_DATA_DIR "Input/CalcLight.hlsl", target), + CompileToModule("CalcLightDiffuse", TEST_DATA_DIR "Input/CalcLightDiffuse.hlsl", target), + CompileToModule("CalcLightDiffuseSpecular", TEST_DATA_DIR "Input/CalcLightDiffuseSpecular.hlsl", target), + }; + + const Compiler::ModuleDesc* testModules[][2] = { + { &dxilModules[0], &dxilModules[1] }, + { &dxilModules[0], &dxilModules[2] }, + }; + +#ifdef NDEBUG + const std::string expectedNames[] = { "CalcLight+Diffuse.Release.dxilasm", "CalcLight+DiffuseSpecular.Release.dxilasm" }; +#else + const std::string expectedNames[] = { "CalcLight+Diffuse.Debug.dxilasm", "CalcLight+DiffuseSpecular.Debug.dxilasm" }; +#endif + + for (size_t i = 0; i < 2; ++i) + { + const auto linkedResult = + Compiler::Link({ "main", ShaderStage::PixelShader, testModules[i], sizeof(testModules[i]) / sizeof(testModules[i][0]) }, {}, + { ShadingLanguage::Dxil, "" }); + + EXPECT_FALSE(linkedResult.hasError); + EXPECT_FALSE(linkedResult.isText); + + Compiler::DisassembleDesc disasmDesc; + disasmDesc.binary = reinterpret_cast(linkedResult.target->Data()); + disasmDesc.binarySize = linkedResult.target->Size(); + disasmDesc.language = ShadingLanguage::Dxil; + const auto disasmResult = Compiler::Disassemble(disasmDesc); + + const uint8_t* target_ptr = reinterpret_cast(disasmResult.target->Data()); + CompareWithExpected(std::vector(target_ptr, target_ptr + disasmResult.target->Size()), disasmResult.isText, + expectedNames[i]); + + DestroyBlob(linkedResult.errorWarningMsg); + DestroyBlob(linkedResult.target); + + DestroyBlob(disasmResult.errorWarningMsg); + DestroyBlob(disasmResult.target); + } + + for (auto& mod : dxilModules) + { + DestroyBlob(mod.target); + } + } } // namespace int main(int argc, char** argv) diff --git a/Source/Wrapper/Native.cpp b/Source/Wrapper/Native.cpp index c1bc26fb..5eb5484f 100644 --- a/Source/Wrapper/Native.cpp +++ b/Source/Wrapper/Native.cpp @@ -51,7 +51,7 @@ void Compile(SourceDescription* source, OptionsDescription* optionsDesc, TargetD options.shiftAllCBuffersBindings = optionsDesc->shiftAllCBuffersBindings; options.shiftAllUABuffersBindings = optionsDesc->shiftAllUABuffersBindings; - Compiler::TargetDesc targetDesc; + Compiler::TargetDesc targetDesc{}; targetDesc.language = target->shadingLanguage; targetDesc.version = target->version; diff --git a/Source/Wrapper/Program.cs b/Source/Wrapper/Program.cs index a298e66c..60d28b0d 100644 --- a/Source/Wrapper/Program.cs +++ b/Source/Wrapper/Program.cs @@ -59,6 +59,7 @@ static void Main(string[] args) { language = Wrapper.ShadingLanguage.Glsl, version = "460", + asModule = false, }; Wrapper.Compile(ref sourceDesc, ref optionsDesc, ref targetDesc, out Wrapper.ResultDesc result); diff --git a/Source/Wrapper/Wrapper.cs b/Source/Wrapper/Wrapper.cs index f1640e0d..68efab75 100644 --- a/Source/Wrapper/Wrapper.cs +++ b/Source/Wrapper/Wrapper.cs @@ -149,6 +149,7 @@ public struct TargetDesc { public ShadingLanguage language; public string version; + public bool asModule; } [StructLayout(LayoutKind.Sequential)]