Skip to content

Commit b71b4a4

Browse files
committed
feat(shader_compiler): support relative paths via custom D3DInclude
1 parent 8c9a251 commit b71b4a4

File tree

1 file changed

+84
-1
lines changed

1 file changed

+84
-1
lines changed

src/utils/shader_compiler.hpp

+84-1
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@
1414

1515
#include <cstdint>
1616
#include <exception>
17+
#include <filesystem>
1718
#include <ios>
1819
#include <map>
1920
#include <mutex>
2021
#include <optional>
2122
#include <shared_mutex>
2223
#include <span>
2324
#include <string>
25+
#include <unordered_map>
2426
#include <vector>
2527

2628
#include <include/reshade.hpp>
29+
#include "./path.hpp"
2730
#include "format.hpp"
2831

2932
namespace renodx::utils::shader::compiler {
@@ -35,6 +38,83 @@ static HMODULE dxc_compiler_library = nullptr;
3538
static std::shared_mutex mutex_fxc_compiler;
3639
static std::shared_mutex mutex_dxc_compiler;
3740

41+
class FxcD3DInclude : public ID3DInclude {
42+
public:
43+
LPCWSTR initial_file;
44+
explicit FxcD3DInclude(LPCWSTR initial_file) {
45+
this->initial_file = initial_file;
46+
};
47+
48+
// Don't use map in case file contents are identical
49+
std::vector<std::pair<std::string, std::filesystem::path>> file_paths;
50+
std::map<std::filesystem::path, std::string> file_contents;
51+
52+
HRESULT __stdcall Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) override {
53+
std::filesystem::path new_path;
54+
if (pParentData != nullptr) {
55+
std::string parent_data = static_cast<const char*>(pParentData);
56+
for (auto pair = file_paths.rbegin(); pair != file_paths.rend(); ++pair) {
57+
if (pair->first == parent_data) {
58+
new_path = pair->second.parent_path();
59+
break;
60+
}
61+
}
62+
}
63+
if (new_path.empty()) {
64+
new_path = initial_file;
65+
new_path = new_path.parent_path();
66+
}
67+
68+
new_path /= pFileName;
69+
new_path = new_path.lexically_normal();
70+
71+
*ppData = nullptr;
72+
*pBytes = 0;
73+
74+
try {
75+
std::string output;
76+
if (auto pair = file_contents.find(new_path); pair != file_contents.end()) {
77+
output = pair->second;
78+
} else {
79+
output = renodx::utils::path::ReadTextFile(new_path);
80+
}
81+
file_paths.emplace_back(output, new_path);
82+
83+
*ppData = _strdup(output.c_str());
84+
*pBytes = static_cast<UINT>(output.size());
85+
86+
} catch (...) {
87+
{
88+
std::stringstream s;
89+
s << "FxcD3DInclude::Open(Failed to open";
90+
s << pFileName;
91+
s << ", type: " << IncludeType;
92+
s << ", parent: " << pParentData;
93+
s << ")";
94+
reshade::log_message(reshade::log_level::error, s.str().c_str());
95+
}
96+
return -1;
97+
}
98+
99+
return S_OK;
100+
}
101+
102+
HRESULT __stdcall Close(LPCVOID pData) override {
103+
if (pData != nullptr) {
104+
std::string data = static_cast<const char*>(pData);
105+
for (auto pair = file_paths.rbegin(); pair != file_paths.rend(); ++pair) {
106+
if (pair->first == data) {
107+
file_paths.erase(std::next(pair).base());
108+
break;
109+
}
110+
}
111+
}
112+
113+
free(const_cast<void*>(pData));
114+
return S_OK;
115+
}
116+
};
117+
38118
inline HRESULT CreateLibrary(IDxcLibrary** dxc_library) {
39119
// HMODULE dxil_loader = LoadLibraryW(L"dxil.dll");
40120
if (dxc_compiler_library == nullptr) {
@@ -255,12 +335,15 @@ inline std::vector<uint8_t> CompileShaderFromFileFXC(
255335
throw std::exception("Could not to load D3DCompileFromFile from D3DCompiler_47.dll");
256336
}
257337

338+
// Create a new Custom D3DInclude that supports relative imports
339+
auto custom_include = FxcD3DInclude(file_path);
340+
258341
std::unique_lock lock(mutex_fxc_compiler);
259342
CComPtr<ID3DBlob> error_blob;
260343
if (FAILED(d3d_compilefromfile(
261344
file_path,
262345
defines,
263-
D3D_COMPILE_STANDARD_FILE_INCLUDE,
346+
&custom_include,
264347
"main",
265348
shader_target,
266349
D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY,

0 commit comments

Comments
 (0)