Finished first version of shader compiler. HLSL -> DXIL.
Submitting vertex and frag shader needed to display a triangle.
This commit is contained in:
@@ -99,9 +99,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DXCompiler.h"/>
|
||||
<ClCompile Include="ShaderCompiler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CopyFileToFolders Include="DXShaderCompiler\dxcompiler.dll">
|
||||
@@ -111,6 +109,10 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</CopyFileToFolders>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DXShaderCompiler\DXCompiler.h" />
|
||||
<ClInclude Include="ShaderCompiler.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
199
JulietShaderCompiler/ShaderCompiler.cpp
Normal file
199
JulietShaderCompiler/ShaderCompiler.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include <ShaderCompiler.h>
|
||||
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <DXShaderCompiler/DXCompiler.h>
|
||||
|
||||
#pragma comment(lib, "dxcompiler.lib")
|
||||
|
||||
using namespace Juliet;
|
||||
|
||||
namespace
|
||||
{
|
||||
ByteBuffer CompileWithDXC(HLSLShaderInfo& info, bool compileToSpirv)
|
||||
{
|
||||
Assert(!compileToSpirv && "SPIRV is not supported yet");
|
||||
|
||||
IDxcCompiler3* compiler = nullptr;
|
||||
DxcCreateInstance(&CLSID_DxcCompiler, IID_IDxcCompiler3, reinterpret_cast<void**>(&compiler));
|
||||
|
||||
IDxcUtils* utils = nullptr;
|
||||
DxcCreateInstance(&CLSID_DxcUtils, &IID_IDxcUtils, reinterpret_cast<void**>(&utils));
|
||||
|
||||
if (compiler == nullptr)
|
||||
{
|
||||
LogError(LogCategory::Tool, "Cannot create DXCompiler instance");
|
||||
return {};
|
||||
}
|
||||
|
||||
IDxcResult* dxcResult = nullptr;
|
||||
LPCWSTR* args = nullptr;
|
||||
auto deferred = Defer(
|
||||
[&]()
|
||||
{
|
||||
SafeFree(args);
|
||||
if (dxcResult)
|
||||
{
|
||||
dxcResult->lpVtbl->Release(dxcResult);
|
||||
}
|
||||
if (compiler)
|
||||
{
|
||||
compiler->lpVtbl->Release(compiler);
|
||||
}
|
||||
if (utils)
|
||||
{
|
||||
utils->lpVtbl->Release(utils);
|
||||
}
|
||||
});
|
||||
|
||||
if (utils == nullptr)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Cannot create IDxcUtils instance");
|
||||
return {};
|
||||
}
|
||||
|
||||
IDxcIncludeHandler* includeHandler;
|
||||
utils->lpVtbl->CreateDefaultIncludeHandler(utils, &includeHandler);
|
||||
if (includeHandler == nullptr)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Cannot create Default include handler");
|
||||
return {};
|
||||
}
|
||||
|
||||
StringBuffer convertedBuffer = {};
|
||||
char inplaceBuffer[1024];
|
||||
convertedBuffer.Data = inplaceBuffer;
|
||||
convertedBuffer.Capacity = sizeof(inplaceBuffer);
|
||||
if (!ConvertString(StringEncoding::UTF8, StringEncoding::UTF16, info.EntryPoint, convertedBuffer))
|
||||
{
|
||||
LogError(LogCategory::Tool, "Cannot convert entry point string to utf16");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Creating args for the compiler
|
||||
// Allocating enough to fit them all
|
||||
static constexpr size_t kExpectedArgCount = 32;
|
||||
uint32 argCount = 0;
|
||||
args = static_cast<LPCWSTR*>(Calloc(kExpectedArgCount, sizeof(LPCWSTR)));
|
||||
if (!args)
|
||||
{
|
||||
LogError(LogCategory::Tool, "Couldn't allocate Args array");
|
||||
return {};
|
||||
}
|
||||
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"-E");
|
||||
args[argCount++] = reinterpret_cast<LPCWSTR>(inplaceBuffer);
|
||||
|
||||
DxcBuffer source;
|
||||
source.Ptr = info.ByteCodeBuffer.Data;
|
||||
source.Size = info.ByteCodeBuffer.Size;
|
||||
source.Encoding = DXC_CP_ACP;
|
||||
|
||||
switch (info.Stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"-T");
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"vs_6_0");
|
||||
break;
|
||||
}
|
||||
case ShaderStage::Fragment:
|
||||
{
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"-T");
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"ps_6_0");
|
||||
break;
|
||||
}
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"-T");
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"cs_6_0");
|
||||
break;
|
||||
}
|
||||
case ShaderStage::Invalid:
|
||||
{
|
||||
Assert(false && "Invalid shader stage");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (compileToSpirv)
|
||||
{
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"-spirv");
|
||||
args[argCount++] = const_cast<LPCWSTR>(L"-fspv-flatten-resource-arrays");
|
||||
}
|
||||
|
||||
char nameInplaceBuffer[1024];
|
||||
if (IsValid(info.Name))
|
||||
{
|
||||
StringBuffer nameUtf16 = {};
|
||||
nameUtf16.Data = nameInplaceBuffer;
|
||||
nameUtf16.Capacity = sizeof(nameInplaceBuffer);
|
||||
if (ConvertString(StringEncoding::UTF8, StringEncoding::UTF16, info.Name, nameUtf16))
|
||||
{
|
||||
args[argCount++] = reinterpret_cast<LPCWSTR>(nameInplaceBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT result = compiler->lpVtbl->Compile(compiler, &source, args, argCount, includeHandler, IID_IDxcResult,
|
||||
reinterpret_cast<void**>(&dxcResult));
|
||||
if (result < 0)
|
||||
{
|
||||
LogError(LogCategory::Tool, "IDxcShaderCompiler3::Compile failed: %X", result);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (dxcResult == nullptr)
|
||||
{
|
||||
LogError(LogCategory::Tool, "%s", "HLSL compilation failed with no IDxcResult");
|
||||
return {};
|
||||
}
|
||||
|
||||
IDxcBlob* blob = nullptr;
|
||||
IDxcBlobUtf8* errors = nullptr;
|
||||
result = dxcResult->lpVtbl->GetOutput(dxcResult, DXC_OUT_OBJECT, IID_IDxcBlob, reinterpret_cast<void**>(&blob), nullptr);
|
||||
if (result < 0)
|
||||
{
|
||||
// Compilation failed, display errors
|
||||
dxcResult->lpVtbl->GetOutput(dxcResult, DXC_OUT_ERRORS, IID_IDxcBlobUtf8, reinterpret_cast<void**>(&errors), nullptr);
|
||||
if (errors != nullptr && errors->lpVtbl->GetBufferSize(errors) != 0)
|
||||
{
|
||||
LogError(LogCategory::Tool, "HLSL compilation failed: %s",
|
||||
static_cast<char*>(errors->lpVtbl->GetBufferPointer(errors)));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError(LogCategory::Tool, "Compilation failed with unknown error");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// If compilation succeeded, but there are errors, those are warnings
|
||||
dxcResult->lpVtbl->GetOutput(dxcResult, DXC_OUT_ERRORS, IID_IDxcBlobUtf8, reinterpret_cast<void**>(&errors), nullptr);
|
||||
if (errors != nullptr && errors->lpVtbl->GetBufferSize(errors) != 0)
|
||||
{
|
||||
LogWarning(LogCategory::Tool, "HLSL compiled with warnings: %s",
|
||||
static_cast<char*>(errors->lpVtbl->GetBufferPointer(errors)));
|
||||
}
|
||||
|
||||
// TODO: Scratch allocator. No malloc
|
||||
ByteBuffer buffer = {};
|
||||
buffer.Size = blob->lpVtbl->GetBufferSize(blob);
|
||||
buffer.Data = static_cast<Byte*>(Malloc(buffer.Size));
|
||||
MemCopy(buffer.Data, blob->lpVtbl->GetBufferPointer(blob), buffer.Size);
|
||||
|
||||
blob->lpVtbl->Release(blob);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ByteBuffer CompileDXIL(HLSLShaderInfo& info)
|
||||
{
|
||||
// TODO: Use SPIRV an do hlsl -> spirv -> hlsl -> dxil.
|
||||
// This is from Shadercross SDL_ShaderCross_CompileDXILFromHLSL.
|
||||
// Not sure why yet.
|
||||
|
||||
return CompileWithDXC(info, false);
|
||||
}
|
||||
42
JulietShaderCompiler/ShaderCompiler.h
Normal file
42
JulietShaderCompiler/ShaderCompiler.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/CoreTypes.h>
|
||||
#include <Core/Common/String.h>
|
||||
|
||||
enum class SourceLanguage : uint8
|
||||
{
|
||||
HLSL = 0,
|
||||
Count = 1,
|
||||
Invalid = Count
|
||||
};
|
||||
|
||||
enum class ShaderFormat : uint8
|
||||
{
|
||||
DXIL = 0,
|
||||
Count = 1,
|
||||
Invalid = Count
|
||||
};
|
||||
|
||||
enum class ShaderStage : uint8
|
||||
{
|
||||
Vertex = 0,
|
||||
Fragment = 1,
|
||||
Compute = 2,
|
||||
Count = 3,
|
||||
Invalid = Count
|
||||
};
|
||||
|
||||
struct ShaderInfo
|
||||
{
|
||||
ByteBuffer ByteCodeBuffer;
|
||||
Juliet::String EntryPoint;
|
||||
Juliet::String Name;
|
||||
ShaderStage Stage;
|
||||
};
|
||||
|
||||
struct HLSLShaderInfo : ShaderInfo
|
||||
{
|
||||
// TODO Defines and includes
|
||||
};
|
||||
|
||||
ByteBuffer CompileDXIL(HLSLShaderInfo& info);
|
||||
@@ -1,56 +1,229 @@
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Core/Common/String.h>
|
||||
#include <Core/HAL/IO/IOStream.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
|
||||
// Must be before everything else.
|
||||
// Cannot include DX12Includes because we redefine everything.
|
||||
// TODO : Separate lib
|
||||
// TODO : Only when not shipping
|
||||
// Check if we just load the dll and not link against?
|
||||
#include <DXCompiler.h>
|
||||
|
||||
#pragma comment(lib, "dxcompiler.lib")
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <ShaderCompiler.h>
|
||||
|
||||
using namespace Juliet;
|
||||
|
||||
void Compile()
|
||||
void PrintHelp()
|
||||
{
|
||||
IDxcCompiler3* compiler = nullptr;
|
||||
DxcCreateInstance(&CLSID_DxcCompiler, IID_IDxcCompiler3, reinterpret_cast<void**>(&compiler));
|
||||
|
||||
IDxcUtils* utils = nullptr;
|
||||
DxcCreateInstance(&CLSID_DxcUtils, &IID_IDxcUtils, reinterpret_cast<void**>(&utils));
|
||||
|
||||
if (compiler == nullptr)
|
||||
{
|
||||
Juliet::Log(LogLevel::Error, LogCategory::Graphics, "Cannot create DXCompiler instance");
|
||||
}
|
||||
|
||||
if (utils == nullptr)
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "Cannot create IDxcUtils instance");
|
||||
compiler->lpVtbl->Release(compiler);
|
||||
}
|
||||
|
||||
IDxcIncludeHandler* includeHandler;
|
||||
utils->lpVtbl->CreateDefaultIncludeHandler(utils, &includeHandler);
|
||||
if (includeHandler == nullptr)
|
||||
{
|
||||
compiler->lpVtbl->Release(compiler);
|
||||
utils->lpVtbl->Release(utils);
|
||||
}
|
||||
LogMessage(LogCategory::Tool, "Usage: JulietShaderCompiler.exe <input> [options]");
|
||||
LogMessage(LogCategory::Tool, "Required Parameters:");
|
||||
static constexpr int kColumnWdith = 32;
|
||||
LogMessage(LogCategory::Tool, " %-*s %s", kColumnWdith, "-o | --output <value>", "Output file.");
|
||||
// LogMessage(LogCategory::Tool, "\n");
|
||||
// LogMessage(LogCategory::Tool, "Required Parameters that can be inferred from filename:");
|
||||
// LogMessage(LogCategory::Tool, " %-*s %s", kColumnWdith, "-s | --src <value>", "Source Language. Values: [HLSL*] | * Default");
|
||||
// LogMessage(LogCategory::Tool, " %-*s %s", kColumnWdith, "-d | --dest <value>", "Destination Format. Values: [DXIL*] | * Default");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// auto* stream = IOFromFile(ConstString("XF"), ConstString("w"));
|
||||
String filename = {};
|
||||
ByteBuffer fileData = {};
|
||||
|
||||
String outputFilename = {};
|
||||
|
||||
String entryPoint = WrapString("main");
|
||||
|
||||
bool sourceLangDetected = false;
|
||||
auto srcLanguage = SourceLanguage::Invalid;
|
||||
|
||||
bool dstShaderFormatDetected = false;
|
||||
auto dstShaderFormat = ShaderFormat::Invalid;
|
||||
|
||||
bool shaderStageDetected = false;
|
||||
auto shaderStage = ShaderStage::Invalid;
|
||||
|
||||
IOStream* outStream = nullptr;
|
||||
|
||||
auto deferred = Defer(
|
||||
[&]()
|
||||
{
|
||||
if (IsValid(fileData))
|
||||
{
|
||||
Free(fileData);
|
||||
}
|
||||
if (outStream)
|
||||
{
|
||||
IOClose(outStream);
|
||||
}
|
||||
// Pause here to not close the console window immediately on stop
|
||||
system("PAUSE");
|
||||
});
|
||||
|
||||
for (int idx = 1; idx < argc; ++idx)
|
||||
{
|
||||
String arg = WrapString(argv[idx]);
|
||||
if (CStr(arg)[0] == '-')
|
||||
{
|
||||
if (StringCompareCaseInsensitive(arg, ConstString("-h")) == 0 ||
|
||||
StringCompareCaseInsensitive(arg, ConstString("--help")) == 0)
|
||||
{
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (StringCompareCaseInsensitive(arg, ConstString("-o")) == 0 ||
|
||||
StringCompareCaseInsensitive(arg, ConstString("--output")) == 0)
|
||||
{
|
||||
if (idx + 1 >= argc)
|
||||
{
|
||||
LogError(LogCategory::Tool, "%s requires an argument", argv);
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
idx += 1;
|
||||
outputFilename = WrapString(argv[idx]);
|
||||
}
|
||||
}
|
||||
else if (IsValid(filename) == false)
|
||||
{
|
||||
filename = arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError(LogCategory::Tool, "%s: Unknown parameter: %s", argv[0], CStr(arg));
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsValid(filename))
|
||||
{
|
||||
LogError(LogCategory::Tool, "%s: missing input filename path", argv[0]);
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
if (!IsValid(outputFilename))
|
||||
{
|
||||
LogError(LogCategory::Tool, "%s: missing output path", argv[0]);
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
fileData = LoadFile(filename);
|
||||
if (!IsValid(fileData))
|
||||
{
|
||||
LogError(LogCategory::Tool, "Invalid file: %s", CStr(filename));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Find the source language from filename
|
||||
{
|
||||
if (!sourceLangDetected)
|
||||
{
|
||||
if (IsValid(FindString(filename, WrapString("hlsl"))))
|
||||
{
|
||||
srcLanguage = SourceLanguage::HLSL;
|
||||
}
|
||||
static_assert(ToUnderlying(SourceLanguage::Count) == 1, "SourceLanguage must be one of: HLSL");
|
||||
}
|
||||
|
||||
if (srcLanguage == SourceLanguage::Invalid)
|
||||
{
|
||||
LogError(LogCategory::Tool,
|
||||
"%s: Invalid source language. Please either have a valid file extension or use -s/--src", argv[0]);
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the destination format from output file name
|
||||
{
|
||||
if (!dstShaderFormatDetected)
|
||||
{
|
||||
if (IsValid(FindString(outputFilename, WrapString("dxil"))))
|
||||
{
|
||||
dstShaderFormat = ShaderFormat::DXIL;
|
||||
}
|
||||
static_assert(ToUnderlying(ShaderFormat::Count) == 1, "ShaderFormat must be one of: DXIL");
|
||||
|
||||
if (dstShaderFormat == ShaderFormat::Invalid)
|
||||
{
|
||||
LogError(LogCategory::Tool,
|
||||
"%s: Invalid shader format. Please either have a valid file extension or use -d/--dest", argv[0]);
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find shader stage from filename
|
||||
{
|
||||
if (!shaderStageDetected)
|
||||
{
|
||||
// TODO Need a case insensitive FindString
|
||||
if (IsValid(FindString(filename, WrapString("vert"))))
|
||||
{
|
||||
shaderStage = ShaderStage::Vertex;
|
||||
}
|
||||
else if (IsValid(FindString(filename, WrapString("frag"))))
|
||||
{
|
||||
shaderStage = ShaderStage::Fragment;
|
||||
}
|
||||
else if (IsValid(FindString(filename, WrapString("comp"))))
|
||||
{
|
||||
shaderStage = ShaderStage::Compute;
|
||||
}
|
||||
static_assert(ToUnderlying(ShaderFormat::Count) == 1, "ShaderStage must be one of: vert, frag, comp");
|
||||
|
||||
if (shaderStage == ShaderStage::Invalid)
|
||||
{
|
||||
LogError(LogCategory::Tool, "%s: Invalid shader stage. Please include it in the filename", argv[0]);
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outStream = IOFromFile(outputFilename, WrapString("w"));
|
||||
if (!outStream)
|
||||
{
|
||||
LogError(LogCategory::Tool, "%s: Failed to open %s for writing", argv[0], CStr(outputFilename));
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (srcLanguage)
|
||||
{
|
||||
case SourceLanguage::HLSL:
|
||||
{
|
||||
HLSLShaderInfo hlslInfo = {};
|
||||
hlslInfo.ByteCodeBuffer = fileData;
|
||||
hlslInfo.EntryPoint = entryPoint;
|
||||
hlslInfo.Name = filename;
|
||||
hlslInfo.Stage = shaderStage;
|
||||
|
||||
switch (dstShaderFormat)
|
||||
{
|
||||
case ShaderFormat::DXIL:
|
||||
{
|
||||
ByteBuffer compiledBuffer = CompileDXIL(hlslInfo);
|
||||
if (!IsValid(compiledBuffer))
|
||||
{
|
||||
LogError(LogCategory::Tool, "Failed to compile DXBC from HLSL. Error: %s", "Unknown");
|
||||
}
|
||||
else
|
||||
{
|
||||
IOWrite(outStream, compiledBuffer);
|
||||
Free(compiledBuffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ShaderFormat::Invalid: Assert(false && "Shader format is invalid"); return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SourceLanguage::Invalid: Assert(false && "Source Language is invalid"); return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// IOPrintf(stream, ":)");
|
||||
// IOPrintf(stream, "%d%s", 1234, "Hello World!");
|
||||
|
||||
size_t bytesRead = 0;
|
||||
auto* data = LoadFile(ConstString("XF"),bytesRead );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user