[Link] Enable to compile HLSLs to Dxil modules, and link them

Related work item: Github #10
This commit is contained in:
Minmin Gong 2020-04-21 22:27:20 -07:00
Родитель f75d8c75d5
Коммит 3abff09adc
15 изменённых файлов: 802 добавлений и 74 удалений

2
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})

Просмотреть файл

@ -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

Просмотреть файл

@ -78,6 +78,18 @@ namespace
return m_compiler;
}
CComPtr<IDxcLinker> CreateLinker() const
{
CComPtr<IDxcLinker> linker;
IFT(m_createInstanceFunc(CLSID_DxcLinker, __uuidof(IDxcLinker), reinterpret_cast<void**>(&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<IDxcLibrary> m_library;
CComPtr<IDxcCompiler> 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<IDxcBlobEncoding> errors;
IFT(dxcResult->GetErrorBuffer(&errors));
if (errors != nullptr)
{
if (errors->GetBufferSize() > 0)
{
result.errorWarningMsg = CreateBlob(errors->GetBufferPointer(), static_cast<uint32_t>(errors->GetBufferSize()));
}
errors = nullptr;
}
result.hasError = true;
if (SUCCEEDED(status))
{
CComPtr<IDxcBlob> program;
IFT(dxcResult->GetResult(&program));
dxcResult = nullptr;
if (program != nullptr)
{
result.target = CreateBlob(program->GetBufferPointer(), static_cast<uint32_t>(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<DxcDefine> dxcDefines;
std::vector<std::wstring> dxcDefineStrings;
@ -491,44 +563,14 @@ namespace
dxcArgs.data(), static_cast<UINT32>(dxcArgs.size()), dxcDefines.data(),
static_cast<UINT32>(dxcDefines.size()), includeHandler, &compileResult));
HRESULT status;
IFT(compileResult->GetStatus(&status));
Compiler::ResultDesc ret;
ret.target = nullptr;
ret.isText = false;
ret.errorWarningMsg = nullptr;
CComPtr<IDxcBlobEncoding> errors;
IFT(compileResult->GetErrorBuffer(&errors));
if (errors != nullptr)
{
if (errors->GetBufferSize() > 0)
{
ret.errorWarningMsg = CreateBlob(errors->GetBufferPointer(), static_cast<uint32_t>(errors->GetBufferSize()));
}
errors = nullptr;
}
ret.hasError = true;
if (SUCCEEDED(status))
{
CComPtr<IDxcBlob> program;
IFT(compileResult->GetResult(&program));
compileResult = nullptr;
if (program != nullptr)
{
ret.target = CreateBlob(program->GetBufferPointer(), static_cast<uint32_t>(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,18 +917,40 @@ 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;
ResultDesc binaryResult;
if (targets[i].language == ShadingLanguage::Dxil)
{
if (targets[i].asModule)
{
binaryResult = dxilModuleBinaryResult;
}
else
{
binaryResult = dxilBinaryResult;
}
}
else
{
binaryResult = spirvBinaryResult;
}
if (binaryResult.target)
{
binaryResult.target = CreateBlob(binaryResult.target->Data(), binaryResult.target->Size());
@ -854,32 +959,7 @@ namespace ShaderConductor
{
binaryResult.errorWarningMsg = CreateBlob(binaryResult.errorWarningMsg->Data(), binaryResult.errorWarningMsg->Size());
}
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;
}
}
else
{
results[i] = binaryResult;
}
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<std::wstring> moduleNames(modules.numModules);
std::vector<const wchar_t*> moduleNamesUtf16(modules.numModules);
std::vector<CComPtr<IDxcBlobEncoding>> 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<IDxcOperationResult> linkResult;
IFT(linker->Link(entryPointUtf16.c_str(), shaderProfile.c_str(), moduleNamesUtf16.data(),
static_cast<UINT32>(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

Просмотреть файл

@ -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

Двоичные данные
Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm Normal file

Двоичный файл не отображается.

Двоичные данные
Source/Tests/Data/Expected/CalcLight+Diffuse.Release.dxilasm Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,218 @@
;
; 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: 3173c150c164bd12fbb10535a796e08b.pdb
; shader hash: 3173c150c164bd12fbb10535a796e08b
;
; 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() {
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}

Просмотреть файл

@ -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}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -116,6 +116,21 @@ namespace
}
}
Compiler::ModuleDesc CompileToModule(const char* moduleName, const std::string& inputFileName, const Compiler::TargetDesc& target)
{
std::vector<uint8_t> input = LoadFile(inputFileName, true);
const std::string source = std::string(reinterpret_cast<char*>(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<const uint8_t*>(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<const uint8_t*>(disasmResult.target->Data());
CompareWithExpected(std::vector<uint8_t>(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)

Просмотреть файл

@ -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;

Просмотреть файл

@ -59,6 +59,7 @@ namespace CSharpConsole
{
language = Wrapper.ShadingLanguage.Glsl,
version = "460",
asModule = false,
};
Wrapper.Compile(ref sourceDesc, ref optionsDesc, ref targetDesc, out Wrapper.ResultDesc result);

Просмотреть файл

@ -149,6 +149,7 @@ namespace CSharpConsole
{
public ShadingLanguage language;
public string version;
public bool asModule;
}
[StructLayout(LayoutKind.Sequential)]