190 lines
7.5 KiB
C
190 lines
7.5 KiB
C
#include <ShaderCompiler.h>
|
|
|
|
#include <Core/Common/CoreUtils.h>
|
|
#include <Core/Logging/LogManager.h>
|
|
#include <Core/Logging/LogTypes.h>
|
|
#include <Core/Memory/Allocator.h>
|
|
#include <DXShaderCompiler/DXCompiler.h>
|
|
|
|
internal ByteBuffer CompileWithDXC(const HLSLShaderInfo* info, bool8 compileToSpirv)
|
|
{
|
|
Assert(info != NULL);
|
|
Assert(!compileToSpirv && "SPIRV is not supported yet");
|
|
|
|
ByteBuffer outBuffer = { 0 };
|
|
IDxcCompiler3* compiler = NULL;
|
|
DxcCreateInstance(&CLSID_DxcCompiler, IID_IDxcCompiler3, (void**)&compiler);
|
|
|
|
IDxcUtils* utils = NULL;
|
|
DxcCreateInstance(&CLSID_DxcUtils, IID_IDxcUtils, (void**)&utils);
|
|
|
|
IDxcResult* dxcResult = NULL;
|
|
LPCWSTR* args = NULL;
|
|
|
|
if (compiler == NULL)
|
|
{
|
|
LogError(LogCategory_Tool, "Cannot create DXCompiler instance");
|
|
}
|
|
else if (utils == NULL)
|
|
{
|
|
LogError(LogCategory_Graphics, "Cannot create IDxcUtils instance");
|
|
}
|
|
else
|
|
{
|
|
IDxcIncludeHandler* includeHandler = NULL;
|
|
utils->lpVtbl->CreateDefaultIncludeHandler(utils, &includeHandler);
|
|
if (includeHandler == NULL)
|
|
{
|
|
LogError(LogCategory_Graphics, "Cannot create Default include handler");
|
|
}
|
|
else
|
|
{
|
|
StringBuffer convertedBuffer = { 0 };
|
|
char inplaceBuffer[1024];
|
|
convertedBuffer.Str = inplaceBuffer;
|
|
convertedBuffer.Capacity = sizeof(inplaceBuffer);
|
|
const bool8 kAddNullTerminator = true;
|
|
if (!ConvertString(StringEncoding_UTF8, StringEncoding_UTF16, info->EntryPoint, &convertedBuffer, kAddNullTerminator))
|
|
{
|
|
LogError(LogCategory_Tool, "Cannot convert entry point string to utf16");
|
|
}
|
|
else
|
|
{
|
|
const size_t kExpectedArgCount = 32;
|
|
uint32 argCount = 0;
|
|
args = (LPCWSTR*)Calloc(kExpectedArgCount, sizeof(LPCWSTR));
|
|
if (args == NULL)
|
|
{
|
|
LogError(LogCategory_Tool, "Couldn't allocate Args array");
|
|
}
|
|
else
|
|
{
|
|
args[argCount++] = L"-E";
|
|
args[argCount++] = (LPCWSTR)inplaceBuffer;
|
|
|
|
DxcBuffer source;
|
|
source.Ptr = info->ByteCodeBuffer.Data;
|
|
source.Size = info->ByteCodeBuffer.Size;
|
|
source.Encoding = DXC_CP_ACP;
|
|
|
|
bool8 stageValid = true;
|
|
switch (info->Stage)
|
|
{
|
|
case ShaderStage_Vertex:
|
|
{
|
|
args[argCount++] = L"-T";
|
|
args[argCount++] = L"vs_6_6";
|
|
break;
|
|
}
|
|
case ShaderStage_Fragment:
|
|
{
|
|
args[argCount++] = L"-T";
|
|
args[argCount++] = L"ps_6_6";
|
|
break;
|
|
}
|
|
case ShaderStage_Compute:
|
|
{
|
|
args[argCount++] = L"-T";
|
|
args[argCount++] = L"cs_6_6";
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Assert(false && "Invalid shader stage");
|
|
stageValid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (stageValid)
|
|
{
|
|
if (compileToSpirv)
|
|
{
|
|
args[argCount++] = L"-spirv";
|
|
args[argCount++] = L"-fspv-flatten-resource-arrays";
|
|
}
|
|
|
|
char nameInplaceBuffer[1024];
|
|
if (IsValidString(info->Name))
|
|
{
|
|
StringBuffer nameUtf16 = { 0 };
|
|
nameUtf16.Str = nameInplaceBuffer;
|
|
nameUtf16.Capacity = sizeof(nameInplaceBuffer);
|
|
if (ConvertString(StringEncoding_UTF8, StringEncoding_UTF16, info->Name, &nameUtf16, kAddNullTerminator))
|
|
{
|
|
args[argCount++] = (LPCWSTR)nameInplaceBuffer;
|
|
}
|
|
}
|
|
|
|
HRESULT result = compiler->lpVtbl->Compile(compiler, &source, args, argCount, includeHandler,
|
|
IID_IDxcResult, (void**)&dxcResult);
|
|
if (result < 0)
|
|
{
|
|
LogError(LogCategory_Tool, "IDxcShaderCompiler3::Compile failed: %X", result);
|
|
}
|
|
else if (dxcResult == NULL)
|
|
{
|
|
LogError(LogCategory_Tool, "%s", "HLSL compilation failed with no IDxcResult");
|
|
}
|
|
else
|
|
{
|
|
IDxcBlob* blob = NULL;
|
|
IDxcBlobUtf8* errors = NULL;
|
|
result = dxcResult->lpVtbl->GetOutput(dxcResult, DXC_OUT_OBJECT, IID_IDxcBlob, (void**)&blob, NULL);
|
|
if (result < 0)
|
|
{
|
|
dxcResult->lpVtbl->GetOutput(dxcResult, DXC_OUT_ERRORS, IID_IDxcBlobUtf8, (void**)&errors, NULL);
|
|
if (errors != NULL && errors->lpVtbl->GetBufferSize(errors) != 0)
|
|
{
|
|
LogError(LogCategory_Tool, "HLSL compilation failed: %s",
|
|
(char*)errors->lpVtbl->GetBufferPointer(errors));
|
|
}
|
|
else
|
|
{
|
|
LogError(LogCategory_Tool, "Compilation failed with unknown error");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dxcResult->lpVtbl->GetOutput(dxcResult, DXC_OUT_ERRORS, IID_IDxcBlobUtf8, (void**)&errors, NULL);
|
|
if (errors != NULL && errors->lpVtbl->GetBufferSize(errors) != 0)
|
|
{
|
|
LogWarning(LogCategory_Tool, "HLSL compiled with warnings: %s",
|
|
(char*)errors->lpVtbl->GetBufferPointer(errors));
|
|
}
|
|
|
|
outBuffer.Size = blob->lpVtbl->GetBufferSize(blob);
|
|
outBuffer.Data = (Byte*)Malloc(outBuffer.Size);
|
|
MemCopy(outBuffer.Data, blob->lpVtbl->GetBufferPointer(blob), outBuffer.Size);
|
|
|
|
blob->lpVtbl->Release(blob);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SafeFree(args);
|
|
if (dxcResult != NULL)
|
|
{
|
|
dxcResult->lpVtbl->Release(dxcResult);
|
|
}
|
|
if (compiler != NULL)
|
|
{
|
|
compiler->lpVtbl->Release(compiler);
|
|
}
|
|
if (utils != NULL)
|
|
{
|
|
utils->lpVtbl->Release(utils);
|
|
}
|
|
|
|
return outBuffer;
|
|
}
|
|
|
|
ByteBuffer CompileDXIL(const HLSLShaderInfo* info)
|
|
{
|
|
return CompileWithDXC(info, false);
|
|
}
|