mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-04-21 10:58:44 +00:00
chore: dynamically enable shader compilation if available
This commit is contained in:
@@ -1,20 +1,13 @@
|
|||||||
#include "PixelShaderCompilerIW4.h"
|
#include "PixelShaderCompilerIW4.h"
|
||||||
|
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
#include "Shader/ShaderCommon.h"
|
#include "Shader/D3DShaderCompiler.h"
|
||||||
#include "Techset/ShaderIncludeHandler.h"
|
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <d3dcompiler.h>
|
|
||||||
|
|
||||||
#pragma comment(lib, "d3dcompiler.lib")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace IW4;
|
using namespace IW4;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -30,74 +23,28 @@ namespace
|
|||||||
|
|
||||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
auto result = shader::CompileShader(assetName, "PSMain", "ps_3_0", false, m_search_path, m_memory);
|
||||||
const auto fileName = shader::GetSourceFileNameForShaderAssetName(assetName);
|
|
||||||
auto file = m_search_path.Open(fileName);
|
|
||||||
if (!file.IsOpen() || file.m_length <= 0)
|
|
||||||
return AssetCreationResult::NoAction();
|
|
||||||
|
|
||||||
if (std::cmp_greater(file.m_length, techset::ShaderIncludeHandler::MAX_SHADER_SIZE))
|
if (result.has_value())
|
||||||
{
|
{
|
||||||
con::error("Invalid shader source \"{}\": File too big: {}", assetName, file.m_length);
|
const std::optional maybeShader(*std::move(result));
|
||||||
return AssetCreationResult::Failure();
|
if (!maybeShader.has_value())
|
||||||
|
return AssetCreationResult::NoAction();
|
||||||
|
|
||||||
|
con::info("Compiled pixel shader \"{}\"", assetName);
|
||||||
|
|
||||||
|
assert(maybeShader->m_shader_size % sizeof(uint32_t) == 0);
|
||||||
|
|
||||||
|
auto* pixelShader = m_memory.Alloc<MaterialPixelShader>();
|
||||||
|
pixelShader->name = m_memory.Dup(assetName.c_str());
|
||||||
|
pixelShader->prog.loadDef.program = static_cast<unsigned int*>(maybeShader->m_shader_bin);
|
||||||
|
pixelShader->prog.loadDef.programSize = static_cast<uint16_t>(maybeShader->m_shader_size / sizeof(uint32_t));
|
||||||
|
|
||||||
|
return AssetCreationResult::Success(context.AddAsset(AssetRegistration<AssetPixelShader>(assetName, pixelShader)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto shaderSize = static_cast<size_t>(file.m_length);
|
con::error("Failed to compile pixel shader \"{}\": {}", assetName, result.error());
|
||||||
const auto shaderData = std::make_unique<char[]>(shaderSize);
|
return AssetCreationResult::Failure();
|
||||||
file.m_stream->read(shaderData.get(), shaderSize);
|
|
||||||
file.m_stream.reset();
|
|
||||||
|
|
||||||
constexpr unsigned shaderFlags = D3DCOMPILE_OPTIMIZATION_LEVEL1
|
|
||||||
#ifdef _DEBUG
|
|
||||||
| D3DCOMPILE_DEBUG
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
techset::ShaderIncludeHandler shaderIncluder(m_search_path);
|
|
||||||
|
|
||||||
ID3DBlob* shaderBlob = nullptr;
|
|
||||||
ID3DBlob* errorBlob = nullptr;
|
|
||||||
const auto errorCode = D3DCompile(
|
|
||||||
shaderData.get(), shaderSize, assetName.c_str(), nullptr, &shaderIncluder, "PSMain", "ps_3_0", shaderFlags, 0u, &shaderBlob, &errorBlob);
|
|
||||||
|
|
||||||
if (FAILED(errorCode))
|
|
||||||
{
|
|
||||||
con::error("Invalid pixel shader \"{}\": Compilation error", assetName);
|
|
||||||
|
|
||||||
if (errorBlob)
|
|
||||||
{
|
|
||||||
std::cerr << " " << static_cast<char*>(errorBlob->GetBufferPointer()) << "\n";
|
|
||||||
errorBlob->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shaderBlob)
|
|
||||||
shaderBlob->Release();
|
|
||||||
|
|
||||||
return AssetCreationResult::Failure();
|
|
||||||
}
|
|
||||||
|
|
||||||
con::info("Compiled pixel shader \"{}\"", assetName);
|
|
||||||
|
|
||||||
const auto shaderBlobSize = static_cast<size_t>(shaderBlob->GetBufferSize());
|
|
||||||
assert(shaderBlobSize % sizeof(uint32_t) == 0);
|
|
||||||
|
|
||||||
auto* pixelShader = m_memory.Alloc<MaterialPixelShader>();
|
|
||||||
pixelShader->name = m_memory.Dup(assetName.c_str());
|
|
||||||
pixelShader->prog.loadDef.programSize = static_cast<uint16_t>(shaderBlobSize / sizeof(uint32_t));
|
|
||||||
pixelShader->prog.loadDef.loadForRenderer = 0;
|
|
||||||
pixelShader->prog.ps = nullptr;
|
|
||||||
|
|
||||||
auto* assetShaderBuffer = m_memory.Alloc<char>(shaderBlobSize);
|
|
||||||
memcpy(assetShaderBuffer, shaderBlob->GetBufferPointer(), shaderBlobSize);
|
|
||||||
pixelShader->prog.loadDef.program = reinterpret_cast<uint32_t*>(assetShaderBuffer);
|
|
||||||
|
|
||||||
shaderBlob->Release();
|
|
||||||
|
|
||||||
return AssetCreationResult::Success(context.AddAsset(AssetRegistration<AssetPixelShader>(assetName, pixelShader)));
|
|
||||||
#else
|
|
||||||
// Shader compilation is only support with Windows
|
|
||||||
return AssetCreationResult::NoAction();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeZone(AssetCreationContext& context) override {}
|
void FinalizeZone(AssetCreationContext& context) override {}
|
||||||
@@ -112,6 +59,9 @@ namespace techset
|
|||||||
{
|
{
|
||||||
std::unique_ptr<IAssetCreator> CreatePixelShaderCompilerIW4(MemoryManager& memory, ISearchPath& searchPath)
|
std::unique_ptr<IAssetCreator> CreatePixelShaderCompilerIW4(MemoryManager& memory, ISearchPath& searchPath)
|
||||||
{
|
{
|
||||||
|
if (!shader::ShaderCompilationAvailable())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
return std::make_unique<PixelShaderCompilerIW4>(memory, searchPath);
|
return std::make_unique<PixelShaderCompilerIW4>(memory, searchPath);
|
||||||
}
|
}
|
||||||
} // namespace techset
|
} // namespace techset
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
#include "VertexShaderCompilerIW4.h"
|
#include "VertexShaderCompilerIW4.h"
|
||||||
|
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
#include "Shader/ShaderCommon.h"
|
#include "Shader/D3DShaderCompiler.h"
|
||||||
#include "Techset/ShaderIncludeHandler.h"
|
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <d3dcompiler.h>
|
|
||||||
|
|
||||||
#pragma comment(lib, "d3dcompiler.lib")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace IW4;
|
using namespace IW4;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -30,74 +23,28 @@ namespace
|
|||||||
|
|
||||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
auto result = shader::CompileShader(assetName, "VSMain", "vs_3_0", false, m_search_path, m_memory);
|
||||||
const auto fileName = shader::GetSourceFileNameForShaderAssetName(assetName);
|
|
||||||
auto file = m_search_path.Open(fileName);
|
|
||||||
if (!file.IsOpen() || file.m_length <= 0)
|
|
||||||
return AssetCreationResult::NoAction();
|
|
||||||
|
|
||||||
if (std::cmp_greater(file.m_length, techset::ShaderIncludeHandler::MAX_SHADER_SIZE))
|
if (result.has_value())
|
||||||
{
|
{
|
||||||
con::error("Invalid shader source \"{}\": File too big: {}", assetName, file.m_length);
|
const std::optional maybeShader(*std::move(result));
|
||||||
return AssetCreationResult::Failure();
|
if (!maybeShader.has_value())
|
||||||
|
return AssetCreationResult::NoAction();
|
||||||
|
|
||||||
|
con::info("Compiled vertex shader \"{}\"", assetName);
|
||||||
|
|
||||||
|
assert(maybeShader->m_shader_size % sizeof(uint32_t) == 0);
|
||||||
|
|
||||||
|
auto* vertexShader = m_memory.Alloc<MaterialVertexShader>();
|
||||||
|
vertexShader->name = m_memory.Dup(assetName.c_str());
|
||||||
|
vertexShader->prog.loadDef.program = static_cast<unsigned int*>(maybeShader->m_shader_bin);
|
||||||
|
vertexShader->prog.loadDef.programSize = static_cast<uint16_t>(maybeShader->m_shader_size / sizeof(uint32_t));
|
||||||
|
|
||||||
|
return AssetCreationResult::Success(context.AddAsset(AssetRegistration<AssetVertexShader>(assetName, vertexShader)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto shaderSize = static_cast<size_t>(file.m_length);
|
con::error("Failed to compile vertex shader \"{}\": {}", assetName, result.error());
|
||||||
const auto shaderData = std::make_unique<char[]>(shaderSize);
|
return AssetCreationResult::Failure();
|
||||||
file.m_stream->read(shaderData.get(), shaderSize);
|
|
||||||
file.m_stream.reset();
|
|
||||||
|
|
||||||
constexpr unsigned shaderFlags = D3DCOMPILE_OPTIMIZATION_LEVEL1
|
|
||||||
#ifdef _DEBUG
|
|
||||||
| D3DCOMPILE_DEBUG
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
techset::ShaderIncludeHandler shaderIncluder(m_search_path);
|
|
||||||
|
|
||||||
ID3DBlob* shaderBlob = nullptr;
|
|
||||||
ID3DBlob* errorBlob = nullptr;
|
|
||||||
const auto errorCode = D3DCompile(
|
|
||||||
shaderData.get(), shaderSize, assetName.c_str(), nullptr, &shaderIncluder, "VSMain", "vs_3_0", shaderFlags, 0u, &shaderBlob, &errorBlob);
|
|
||||||
|
|
||||||
if (FAILED(errorCode))
|
|
||||||
{
|
|
||||||
con::error("Invalid vertex shader \"{}\": Compilation error", assetName);
|
|
||||||
|
|
||||||
if (errorBlob)
|
|
||||||
{
|
|
||||||
std::cerr << " " << static_cast<char*>(errorBlob->GetBufferPointer()) << "\n";
|
|
||||||
errorBlob->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shaderBlob)
|
|
||||||
shaderBlob->Release();
|
|
||||||
|
|
||||||
return AssetCreationResult::Failure();
|
|
||||||
}
|
|
||||||
|
|
||||||
con::info("Compiled vertex shader \"{}\"", assetName);
|
|
||||||
|
|
||||||
const auto shaderBlobSize = static_cast<size_t>(shaderBlob->GetBufferSize());
|
|
||||||
assert(shaderBlobSize % sizeof(uint32_t) == 0);
|
|
||||||
|
|
||||||
auto* vertexShader = m_memory.Alloc<MaterialVertexShader>();
|
|
||||||
vertexShader->name = m_memory.Dup(assetName.c_str());
|
|
||||||
vertexShader->prog.loadDef.programSize = static_cast<uint16_t>(shaderBlobSize / sizeof(uint32_t));
|
|
||||||
vertexShader->prog.loadDef.loadForRenderer = 0;
|
|
||||||
vertexShader->prog.vs = nullptr;
|
|
||||||
|
|
||||||
auto* assetShaderBuffer = m_memory.Alloc<char>(shaderBlobSize);
|
|
||||||
memcpy(assetShaderBuffer, shaderBlob->GetBufferPointer(), shaderBlobSize);
|
|
||||||
vertexShader->prog.loadDef.program = reinterpret_cast<uint32_t*>(assetShaderBuffer);
|
|
||||||
|
|
||||||
shaderBlob->Release();
|
|
||||||
|
|
||||||
return AssetCreationResult::Success(context.AddAsset(AssetRegistration<AssetVertexShader>(assetName, vertexShader)));
|
|
||||||
#else
|
|
||||||
// Shader compilation is only support with Windows
|
|
||||||
return AssetCreationResult::NoAction();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeZone(AssetCreationContext& context) override {}
|
void FinalizeZone(AssetCreationContext& context) override {}
|
||||||
@@ -112,6 +59,9 @@ namespace techset
|
|||||||
{
|
{
|
||||||
std::unique_ptr<IAssetCreator> CreateVertexShaderCompilerIW4(MemoryManager& memory, ISearchPath& searchPath)
|
std::unique_ptr<IAssetCreator> CreateVertexShaderCompilerIW4(MemoryManager& memory, ISearchPath& searchPath)
|
||||||
{
|
{
|
||||||
|
if (!shader::ShaderCompilationAvailable())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
return std::make_unique<VertexShaderCompilerIW4>(memory, searchPath);
|
return std::make_unique<VertexShaderCompilerIW4>(memory, searchPath);
|
||||||
}
|
}
|
||||||
} // namespace techset
|
} // namespace techset
|
||||||
|
|||||||
302
src/ObjCompiling/Shader/D3DShaderCompiler.cpp
Normal file
302
src/ObjCompiling/Shader/D3DShaderCompiler.cpp
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
#include "D3DShaderCompiler.h"
|
||||||
|
|
||||||
|
#include "Shader/ShaderCommon.h"
|
||||||
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// The types based on vkd3d which is licensed under the
|
||||||
|
// GNU Lesser General Public License as published by the Free Software Foundation
|
||||||
|
// All types are prefixed with OAT_ to not cause conflicts as the original definition may be included
|
||||||
|
// depending on the platform.
|
||||||
|
// Types were duplicated to be available on any platform and to not require the corresponding library
|
||||||
|
// to be installed
|
||||||
|
|
||||||
|
typedef int OAT_HRESULT;
|
||||||
|
#define OAT_SUCCEEDED(hr) ((OAT_HRESULT)(hr) >= 0)
|
||||||
|
#define OAT_FAILED(hr) ((OAT_HRESULT)(hr) < 0)
|
||||||
|
|
||||||
|
typedef unsigned int OAT_ULONG;
|
||||||
|
typedef unsigned long OAT_ULONG_PTR;
|
||||||
|
typedef OAT_ULONG_PTR OAT_SIZE_T;
|
||||||
|
|
||||||
|
#define OAT_HRESULT_TYPEDEF(x) ((OAT_HRESULT)x)
|
||||||
|
|
||||||
|
#define OAT_S_OK OAT_HRESULT_TYPEDEF(0)
|
||||||
|
#define OAT_S_FALSE OAT_HRESULT_TYPEDEF(1)
|
||||||
|
|
||||||
|
#define OAT_E_FAIL OAT_HRESULT_TYPEDEF(0x80004005)
|
||||||
|
|
||||||
|
#define OAT_D3DCOMPILE_DEBUG 0x00000001
|
||||||
|
#define OAT_D3DCOMPILE_SKIP_VALIDATION 0x00000002
|
||||||
|
#define OAT_D3DCOMPILE_SKIP_OPTIMIZATION 0x00000004
|
||||||
|
#define OAT_D3DCOMPILE_PACK_MATRIX_ROW_MAJOR 0x00000008
|
||||||
|
#define OAT_D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR 0x00000010
|
||||||
|
#define OAT_D3DCOMPILE_PARTIAL_PRECISION 0x00000020
|
||||||
|
#define OAT_D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT 0x00000040
|
||||||
|
#define OAT_D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT 0x00000080
|
||||||
|
#define OAT_D3DCOMPILE_NO_PRESHADER 0x00000100
|
||||||
|
#define OAT_D3DCOMPILE_AVOID_FLOW_CONTROL 0x00000200
|
||||||
|
#define OAT_D3DCOMPILE_PREFER_FLOW_CONTROL 0x00000400
|
||||||
|
#define OAT_D3DCOMPILE_ENABLE_STRICTNESS 0x00000800
|
||||||
|
#define OAT_D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY 0x00001000
|
||||||
|
#define OAT_D3DCOMPILE_IEEE_STRICTNESS 0x00002000
|
||||||
|
#define OAT_D3DCOMPILE_OPTIMIZATION_LEVEL0 0x00004000
|
||||||
|
#define OAT_D3DCOMPILE_OPTIMIZATION_LEVEL1 0x00000000
|
||||||
|
#define OAT_D3DCOMPILE_OPTIMIZATION_LEVEL2 0x0000c000
|
||||||
|
#define OAT_D3DCOMPILE_OPTIMIZATION_LEVEL3 0x00008000
|
||||||
|
#define OAT_D3DCOMPILE_RESERVED16 0x00010000
|
||||||
|
#define OAT_D3DCOMPILE_RESERVED17 0x00020000
|
||||||
|
#define OAT_D3DCOMPILE_WARNINGS_ARE_ERRORS 0x00040000
|
||||||
|
#define OAT_D3DCOMPILE_RESOURCES_MAY_ALIAS 0x00080000
|
||||||
|
#define OAT_D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES 0x00100000
|
||||||
|
#define OAT_D3DCOMPILE_ALL_RESOURCES_BOUND 0x00200000
|
||||||
|
#define OAT_D3DCOMPILE_DEBUG_NAME_FOR_SOURCE 0x00400000
|
||||||
|
#define OAT_D3DCOMPILE_DEBUG_NAME_FOR_BINARY 0x00800000
|
||||||
|
|
||||||
|
enum OAT_D3D_INCLUDE_TYPE : uint32_t
|
||||||
|
{
|
||||||
|
OAT_D3D_INCLUDE_LOCAL = 0,
|
||||||
|
OAT_D3D_INCLUDE_SYSTEM = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OAT_ID3DInclude
|
||||||
|
{
|
||||||
|
virtual OAT_HRESULT __stdcall Open(
|
||||||
|
OAT_D3D_INCLUDE_TYPE includeType, const char* fileName, const void* parentData, const void** data, unsigned int* size) = 0;
|
||||||
|
virtual OAT_HRESULT __stdcall Close(const void* data) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OAT_GUID
|
||||||
|
{
|
||||||
|
unsigned int Data1;
|
||||||
|
unsigned short Data2;
|
||||||
|
unsigned short Data3;
|
||||||
|
unsigned char Data4[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef OAT_GUID OAT_IID;
|
||||||
|
|
||||||
|
struct OAT_IUnknown
|
||||||
|
{
|
||||||
|
virtual OAT_HRESULT __stdcall QueryInterface(const OAT_IID& riid, void** object) = 0;
|
||||||
|
|
||||||
|
virtual OAT_ULONG __stdcall AddRef() = 0;
|
||||||
|
|
||||||
|
virtual OAT_ULONG __stdcall Release() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OAT_ID3DBlob : OAT_IUnknown
|
||||||
|
{
|
||||||
|
virtual void* __stdcall GetBufferPointer() = 0;
|
||||||
|
|
||||||
|
virtual OAT_SIZE_T __stdcall GetBufferSize() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OAT_D3D_SHADER_MACRO
|
||||||
|
{
|
||||||
|
const char* Name;
|
||||||
|
const char* Definition;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef OAT_HRESULT(__stdcall* D3DCompile_t)(const void* data,
|
||||||
|
OAT_SIZE_T dataSize,
|
||||||
|
const char* filename,
|
||||||
|
const OAT_D3D_SHADER_MACRO* defines,
|
||||||
|
OAT_ID3DInclude* include,
|
||||||
|
const char* entrypoint,
|
||||||
|
const char* target,
|
||||||
|
unsigned int flags,
|
||||||
|
unsigned int effectFlags,
|
||||||
|
OAT_ID3DBlob** shader,
|
||||||
|
OAT_ID3DBlob** errorMessages);
|
||||||
|
|
||||||
|
constexpr size_t MAX_SHADER_SIZE = 0x1900000u;
|
||||||
|
|
||||||
|
class ShaderIncludeHandler : public OAT_ID3DInclude
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ShaderIncludeHandler(ISearchPath& searchPath)
|
||||||
|
: m_search_path(searchPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OAT_HRESULT
|
||||||
|
__stdcall Open(OAT_D3D_INCLUDE_TYPE includeType, const char* fileName, const void* parentData, const void** data, unsigned int* size) override
|
||||||
|
{
|
||||||
|
const auto fullFileName = shader::GetSourceFileNameForShaderAssetName(fileName);
|
||||||
|
auto file = m_search_path.Open(fullFileName);
|
||||||
|
if (!file.IsOpen() || file.m_length <= 0)
|
||||||
|
return OAT_E_FAIL;
|
||||||
|
|
||||||
|
if (std::cmp_greater(file.m_length, MAX_SHADER_SIZE))
|
||||||
|
{
|
||||||
|
con::error("Invalid shader source \"{}\": File too big: {}\n", fileName, file.m_length);
|
||||||
|
return OAT_E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto shaderSize = static_cast<size_t>(file.m_length);
|
||||||
|
auto shaderData = std::make_unique<char[]>(shaderSize);
|
||||||
|
file.m_stream->read(shaderData.get(), static_cast<std::streamsize>(shaderSize));
|
||||||
|
file.m_stream.reset();
|
||||||
|
|
||||||
|
*data = shaderData.get();
|
||||||
|
*size = static_cast<unsigned int>(shaderSize);
|
||||||
|
|
||||||
|
m_file_buffers_in_use.push_back(std::move(shaderData));
|
||||||
|
|
||||||
|
return OAT_S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
OAT_HRESULT __stdcall Close(const void* data) override
|
||||||
|
{
|
||||||
|
for (auto i = m_file_buffers_in_use.begin(); i != m_file_buffers_in_use.end(); ++i)
|
||||||
|
{
|
||||||
|
if (i->get() == data)
|
||||||
|
{
|
||||||
|
m_file_buffers_in_use.erase(i);
|
||||||
|
return OAT_S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OAT_E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISearchPath& m_search_path;
|
||||||
|
std::vector<std::unique_ptr<char[]>> m_file_buffers_in_use;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool initialized = false;
|
||||||
|
bool compilationAvailable = false;
|
||||||
|
D3DCompile_t d3dCompile = nullptr;
|
||||||
|
|
||||||
|
void PrintInitializationFailedMessage()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
con::warn("Could not initialize shader compilation. Make sure DirectX is installed on your machine if you want to make use of it.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeShaderCompilation()
|
||||||
|
{
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
const auto d3dCompiler = LoadLibraryA("D3DCOMPILER_47.dll");
|
||||||
|
if (!d3dCompiler)
|
||||||
|
{
|
||||||
|
PrintInitializationFailedMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto d3dCompileAddress = GetProcAddress(d3dCompiler, "D3DCompile");
|
||||||
|
if (!d3dCompileAddress)
|
||||||
|
{
|
||||||
|
PrintInitializationFailedMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d3dCompile = reinterpret_cast<D3DCompile_t>(d3dCompileAddress);
|
||||||
|
compilationAvailable = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace shader
|
||||||
|
{
|
||||||
|
bool ShaderCompilationAvailable()
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
InitializeShaderCompilation();
|
||||||
|
|
||||||
|
return compilationAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
result::Expected<std::optional<CompiledShader>, std::string> CompileShader(const std::string& shaderFile,
|
||||||
|
const std::string& entryPoint,
|
||||||
|
const std::string& target,
|
||||||
|
const bool debug,
|
||||||
|
ISearchPath& searchPath,
|
||||||
|
MemoryManager& memory)
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
InitializeShaderCompilation();
|
||||||
|
if (!compilationAvailable)
|
||||||
|
return result::Unexpected<std::string>("Shader compilation unavailable");
|
||||||
|
|
||||||
|
const auto fileName = GetSourceFileNameForShaderAssetName(shaderFile);
|
||||||
|
auto file = searchPath.Open(fileName);
|
||||||
|
if (!file.IsOpen() || file.m_length <= 0)
|
||||||
|
return std::optional<CompiledShader>(std::nullopt);
|
||||||
|
|
||||||
|
if (std::cmp_greater(file.m_length, MAX_SHADER_SIZE))
|
||||||
|
return result::Unexpected(std::format("File too big: {}", file.m_length));
|
||||||
|
|
||||||
|
const auto shaderSize = file.m_length;
|
||||||
|
const auto shaderData = std::make_unique<char[]>(static_cast<size_t>(shaderSize));
|
||||||
|
file.m_stream->read(shaderData.get(), static_cast<std::streamsize>(shaderSize));
|
||||||
|
file.m_stream.reset();
|
||||||
|
|
||||||
|
unsigned shaderFlags = OAT_D3DCOMPILE_OPTIMIZATION_LEVEL1;
|
||||||
|
if (debug)
|
||||||
|
shaderFlags |= OAT_D3DCOMPILE_DEBUG;
|
||||||
|
|
||||||
|
ShaderIncludeHandler shaderIncluder(searchPath);
|
||||||
|
|
||||||
|
OAT_ID3DBlob* shaderBlob = nullptr;
|
||||||
|
OAT_ID3DBlob* errorBlob = nullptr;
|
||||||
|
const auto errorCode = d3dCompile(shaderData.get(),
|
||||||
|
static_cast<OAT_SIZE_T>(shaderSize),
|
||||||
|
fileName.c_str(),
|
||||||
|
nullptr,
|
||||||
|
&shaderIncluder,
|
||||||
|
entryPoint.c_str(),
|
||||||
|
target.c_str(),
|
||||||
|
shaderFlags,
|
||||||
|
0u,
|
||||||
|
&shaderBlob,
|
||||||
|
&errorBlob);
|
||||||
|
|
||||||
|
if (OAT_FAILED(errorCode))
|
||||||
|
{
|
||||||
|
std::string errorMessage;
|
||||||
|
|
||||||
|
if (errorBlob)
|
||||||
|
{
|
||||||
|
errorMessage = std::format("Compilation error: {}", static_cast<const char*>(errorBlob->GetBufferPointer()));
|
||||||
|
errorBlob->Release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorMessage = "Unknown compilation error";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shaderBlob)
|
||||||
|
shaderBlob->Release();
|
||||||
|
|
||||||
|
return result::Unexpected(std::move(errorMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto shaderBlobSize = static_cast<size_t>(shaderBlob->GetBufferSize());
|
||||||
|
auto* assetShaderBuffer = memory.Alloc<char>(shaderBlobSize);
|
||||||
|
memcpy(assetShaderBuffer, shaderBlob->GetBufferPointer(), shaderBlobSize);
|
||||||
|
|
||||||
|
shaderBlob->Release();
|
||||||
|
|
||||||
|
return std::optional(CompiledShader{
|
||||||
|
.m_shader_bin = assetShaderBuffer,
|
||||||
|
.m_shader_size = shaderBlobSize,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} // namespace shader
|
||||||
23
src/ObjCompiling/Shader/D3DShaderCompiler.h
Normal file
23
src/ObjCompiling/Shader/D3DShaderCompiler.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
#include "Utils/MemoryManager.h"
|
||||||
|
#include "Utils/Result.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace shader
|
||||||
|
{
|
||||||
|
class CompiledShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void* m_shader_bin;
|
||||||
|
size_t m_shader_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ShaderCompilationAvailable();
|
||||||
|
|
||||||
|
result::Expected<std::optional<CompiledShader>, std::string> CompileShader(
|
||||||
|
const std::string& shaderFile, const std::string& entryPoint, const std::string& target, bool debug, ISearchPath& searchPath, MemoryManager& memory);
|
||||||
|
} // namespace shader
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#include "ShaderIncludeHandler.h"
|
|
||||||
|
|
||||||
#include "Shader/ShaderCommon.h"
|
|
||||||
#include "Utils/Logging/Log.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
namespace techset
|
|
||||||
{
|
|
||||||
ShaderIncludeHandler::ShaderIncludeHandler(ISearchPath& searchPath)
|
|
||||||
: m_search_path(searchPath)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ShaderIncludeHandler::Open(D3D_INCLUDE_TYPE includeType, const LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes)
|
|
||||||
{
|
|
||||||
const auto fileName = shader::GetSourceFileNameForShaderAssetName(pFileName);
|
|
||||||
auto file = m_search_path.Open(fileName);
|
|
||||||
if (!file.IsOpen() || file.m_length <= 0)
|
|
||||||
return E_FAIL;
|
|
||||||
|
|
||||||
if (std::cmp_greater(file.m_length, MAX_SHADER_SIZE))
|
|
||||||
{
|
|
||||||
con::error("Invalid shader source \"{}\": File too big: {}\n", pFileName, file.m_length);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto shaderSize = static_cast<size_t>(file.m_length);
|
|
||||||
auto shaderData = std::make_unique<char[]>(shaderSize);
|
|
||||||
file.m_stream->read(shaderData.get(), static_cast<std::streamsize>(shaderSize));
|
|
||||||
file.m_stream.reset();
|
|
||||||
|
|
||||||
*ppData = shaderData.get();
|
|
||||||
*pBytes = static_cast<UINT>(shaderSize);
|
|
||||||
|
|
||||||
m_file_buffers_in_use.push_back(std::move(shaderData));
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ShaderIncludeHandler::Close(const LPCVOID pData)
|
|
||||||
{
|
|
||||||
for (auto i = m_file_buffers_in_use.begin(); i != m_file_buffers_in_use.end(); ++i)
|
|
||||||
{
|
|
||||||
if (i->get() == pData)
|
|
||||||
{
|
|
||||||
m_file_buffers_in_use.erase(i);
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
} // namespace techset
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "SearchPath/ISearchPath.h"
|
|
||||||
|
|
||||||
// Shader compilation only available on Windows
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <d3dcompiler.h>
|
|
||||||
|
|
||||||
namespace techset
|
|
||||||
{
|
|
||||||
class ShaderIncludeHandler : public ID3DInclude
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static constexpr size_t MAX_SHADER_SIZE = 0x1900000u;
|
|
||||||
|
|
||||||
explicit ShaderIncludeHandler(ISearchPath& searchPath);
|
|
||||||
virtual ~ShaderIncludeHandler() = default;
|
|
||||||
|
|
||||||
HRESULT __declspec(nothrow) __stdcall Open(D3D_INCLUDE_TYPE includeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) override;
|
|
||||||
HRESULT __declspec(nothrow) __stdcall Close(LPCVOID pData) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ISearchPath& m_search_path;
|
|
||||||
std::vector<std::unique_ptr<char[]>> m_file_buffers_in_use;
|
|
||||||
};
|
|
||||||
} // namespace techset
|
|
||||||
#endif
|
|
||||||
@@ -13,6 +13,9 @@ AssetCreatorCollection::AssetCreatorCollection(const Zone& zone)
|
|||||||
|
|
||||||
void AssetCreatorCollection::AddAssetCreator(std::unique_ptr<IAssetCreator> creator)
|
void AssetCreatorCollection::AddAssetCreator(std::unique_ptr<IAssetCreator> creator)
|
||||||
{
|
{
|
||||||
|
if (!creator)
|
||||||
|
return;
|
||||||
|
|
||||||
const auto maybeHandlingAssetType = creator->GetHandlingAssetType();
|
const auto maybeHandlingAssetType = creator->GetHandlingAssetType();
|
||||||
assert(!maybeHandlingAssetType || static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size());
|
assert(!maybeHandlingAssetType || static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size());
|
||||||
if (maybeHandlingAssetType && static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size())
|
if (maybeHandlingAssetType && static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size())
|
||||||
@@ -23,6 +26,9 @@ void AssetCreatorCollection::AddAssetCreator(std::unique_ptr<IAssetCreator> crea
|
|||||||
|
|
||||||
void AssetCreatorCollection::AddSubAssetCreator(std::unique_ptr<ISubAssetCreator> creator)
|
void AssetCreatorCollection::AddSubAssetCreator(std::unique_ptr<ISubAssetCreator> creator)
|
||||||
{
|
{
|
||||||
|
if (!creator)
|
||||||
|
return;
|
||||||
|
|
||||||
const auto maybeHandlingSubAssetType = creator->GetHandlingSubAssetType();
|
const auto maybeHandlingSubAssetType = creator->GetHandlingSubAssetType();
|
||||||
assert(!maybeHandlingSubAssetType || static_cast<unsigned>(*maybeHandlingSubAssetType) < m_sub_asset_creators_by_type.size());
|
assert(!maybeHandlingSubAssetType || static_cast<unsigned>(*maybeHandlingSubAssetType) < m_sub_asset_creators_by_type.size());
|
||||||
if (maybeHandlingSubAssetType && static_cast<unsigned>(*maybeHandlingSubAssetType) < m_sub_asset_creators_by_type.size())
|
if (maybeHandlingSubAssetType && static_cast<unsigned>(*maybeHandlingSubAssetType) < m_sub_asset_creators_by_type.size())
|
||||||
@@ -33,6 +39,9 @@ void AssetCreatorCollection::AddSubAssetCreator(std::unique_ptr<ISubAssetCreator
|
|||||||
|
|
||||||
void AssetCreatorCollection::AddAssetPostProcessor(std::unique_ptr<IAssetPostProcessor> postProcessor)
|
void AssetCreatorCollection::AddAssetPostProcessor(std::unique_ptr<IAssetPostProcessor> postProcessor)
|
||||||
{
|
{
|
||||||
|
if (!postProcessor)
|
||||||
|
return;
|
||||||
|
|
||||||
const auto handlingAssetType = postProcessor->GetHandlingAssetType();
|
const auto handlingAssetType = postProcessor->GetHandlingAssetType();
|
||||||
assert(static_cast<unsigned>(handlingAssetType) < m_asset_post_processors_by_type.size());
|
assert(static_cast<unsigned>(handlingAssetType) < m_asset_post_processors_by_type.size());
|
||||||
if (static_cast<unsigned>(handlingAssetType) < m_asset_post_processors_by_type.size())
|
if (static_cast<unsigned>(handlingAssetType) < m_asset_post_processors_by_type.size())
|
||||||
@@ -43,6 +52,9 @@ void AssetCreatorCollection::AddAssetPostProcessor(std::unique_ptr<IAssetPostPro
|
|||||||
|
|
||||||
void AssetCreatorCollection::AddDefaultAssetCreator(std::unique_ptr<IDefaultAssetCreator> defaultAssetCreator)
|
void AssetCreatorCollection::AddDefaultAssetCreator(std::unique_ptr<IDefaultAssetCreator> defaultAssetCreator)
|
||||||
{
|
{
|
||||||
|
if (!defaultAssetCreator)
|
||||||
|
return;
|
||||||
|
|
||||||
const auto handlingAssetType = defaultAssetCreator->GetHandlingAssetType();
|
const auto handlingAssetType = defaultAssetCreator->GetHandlingAssetType();
|
||||||
assert(static_cast<unsigned>(handlingAssetType) < m_default_asset_creators_by_type.size());
|
assert(static_cast<unsigned>(handlingAssetType) < m_default_asset_creators_by_type.size());
|
||||||
assert(!m_default_asset_creators_by_type[handlingAssetType]);
|
assert(!m_default_asset_creators_by_type[handlingAssetType]);
|
||||||
|
|||||||
Reference in New Issue
Block a user