14
14
15
15
#include < cstdint>
16
16
#include < exception>
17
+ #include < filesystem>
17
18
#include < ios>
18
19
#include < map>
19
20
#include < mutex>
20
21
#include < optional>
21
22
#include < shared_mutex>
22
23
#include < span>
23
24
#include < string>
25
+ #include < unordered_map>
24
26
#include < vector>
25
27
26
28
#include < include/reshade.hpp>
29
+ #include " ./path.hpp"
27
30
#include " format.hpp"
28
31
29
32
namespace renodx ::utils::shader::compiler {
@@ -35,6 +38,83 @@ static HMODULE dxc_compiler_library = nullptr;
35
38
static std::shared_mutex mutex_fxc_compiler;
36
39
static std::shared_mutex mutex_dxc_compiler;
37
40
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
+
38
118
inline HRESULT CreateLibrary (IDxcLibrary** dxc_library) {
39
119
// HMODULE dxil_loader = LoadLibraryW(L"dxil.dll");
40
120
if (dxc_compiler_library == nullptr ) {
@@ -255,12 +335,15 @@ inline std::vector<uint8_t> CompileShaderFromFileFXC(
255
335
throw std::exception (" Could not to load D3DCompileFromFile from D3DCompiler_47.dll" );
256
336
}
257
337
338
+ // Create a new Custom D3DInclude that supports relative imports
339
+ auto custom_include = FxcD3DInclude (file_path);
340
+
258
341
std::unique_lock lock (mutex_fxc_compiler);
259
342
CComPtr<ID3DBlob> error_blob;
260
343
if (FAILED (d3d_compilefromfile (
261
344
file_path,
262
345
defines,
263
- D3D_COMPILE_STANDARD_FILE_INCLUDE ,
346
+ &custom_include ,
264
347
" main" ,
265
348
shader_target,
266
349
D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY,
0 commit comments