3
3
// For conditions of distribution and use, see copyright notice in nabla.h
4
4
#include " nbl/asset/utils/CHLSLCompiler.h"
5
5
#include " nbl/asset/utils/shadercUtils.h"
6
- // TODO: review
7
6
#ifdef NBL_EMBED_BUILTIN_RESOURCES
8
7
#include " nbl/builtin/CArchive.h"
9
8
#include " spirv/builtin/CArchive.h"
10
9
#endif // NBL_EMBED_BUILTIN_RESOURCES
11
10
12
11
#ifdef _NBL_PLATFORM_WINDOWS_
13
12
14
- #include < wrl.h>
15
- #include < combaseapi.h>
16
-
17
- #include < dxc/dxcapi.h>
18
-
19
- #include < sstream>
20
13
#include < regex>
21
14
#include < iterator>
22
15
#include < codecvt>
16
+ #include < wrl.h>
17
+ #include < combaseapi.h>
18
+ #include < sstream>
19
+ #include < dxc/dxcapi.h>
23
20
24
21
25
22
using namespace nbl ;
@@ -38,6 +35,19 @@ struct DXC
38
35
};
39
36
}
40
37
38
+ struct DxcCompilationResult
39
+ {
40
+ Microsoft::WRL::ComPtr<IDxcBlobEncoding> errorMessages;
41
+ Microsoft::WRL::ComPtr<IDxcBlob> objectBlob;
42
+ Microsoft::WRL::ComPtr<IDxcResult> compileResult;
43
+
44
+ std::string GetErrorMessagesString ()
45
+ {
46
+ return std::string (reinterpret_cast <char *>(errorMessages->GetBufferPointer ()), errorMessages->GetBufferSize ());
47
+ }
48
+ };
49
+
50
+
41
51
CHLSLCompiler::CHLSLCompiler (core::smart_refctd_ptr<system::ISystem>&& system)
42
52
: IShaderCompiler(std::move(system))
43
53
{
@@ -60,20 +70,7 @@ CHLSLCompiler::~CHLSLCompiler()
60
70
delete m_dxcCompilerTypes;
61
71
}
62
72
63
-
64
- struct DxcCompilationResult
65
- {
66
- ComPtr<IDxcBlobEncoding> errorMessages;
67
- ComPtr<IDxcBlob> objectBlob;
68
- ComPtr<IDxcResult> compileResult;
69
-
70
- std::string GetErrorMessagesString ()
71
- {
72
- return std::string (reinterpret_cast <char *>(errorMessages->GetBufferPointer ()), errorMessages->GetBufferSize ());
73
- }
74
- };
75
-
76
- DxcCompilationResult dxcCompile (const CHLSLCompiler* compiler, nbl::asset::impl::DXC* dxc, std::string& source, LPCWSTR* args, uint32_t argCount, const CHLSLCompiler::SOptions& options)
73
+ CHLSLCompiler::SdxcCompileResult CHLSLCompiler::dxcCompile (std::string& source, LPCWSTR* args, uint32_t argCount, const CHLSLCompiler::SOptions& options) const
77
74
{
78
75
// Append Commandline options into source only if debugInfoFlags will emit source
79
76
auto sourceEmittingFlags =
@@ -83,7 +80,7 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
83
80
if ((options.debugInfoFlags .value & sourceEmittingFlags) != CHLSLCompiler::E_DEBUG_INFO_FLAGS::EDIF_NONE)
84
81
{
85
82
std::ostringstream insertion;
86
- insertion << " // #pragma compile_flags " ;
83
+ insertion << " #pragma wave dxc_compile_flags( " ;
87
84
88
85
std::wstring_convert<std::codecvt_utf8<wchar_t >, wchar_t > conv;
89
86
for (uint32_t arg = 0 ; arg < argCount; arg ++)
@@ -92,10 +89,10 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
92
89
insertion << str.c_str () << " " ;
93
90
}
94
91
95
- insertion << " \n " ;
96
- compiler-> insertIntoStart (source, std::move (insertion));
92
+ insertion << " ) \n " ;
93
+ insertIntoStart (source, std::move (insertion));
97
94
}
98
-
95
+ nbl::asset::impl::DXC* dxc = m_dxcCompilerTypes;
99
96
ComPtr<IDxcBlobEncoding> src;
100
97
auto res = dxc->m_dxcUtils ->CreateBlob (reinterpret_cast <const void *>(source.data ()), source.size (), CP_UTF8, &src);
101
98
assert (SUCCEEDED (res));
@@ -134,7 +131,7 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
134
131
else
135
132
{
136
133
options.preprocessorOptions .logger .log (" DXC Compilation Failed:\n %s" , system::ILogger::ELL_ERROR, errorMessagesString.c_str ());
137
- return result ;
134
+ return { nullptr , 0 } ;
138
135
}
139
136
140
137
ComPtr<IDxcBlob> resultingBlob;
@@ -143,18 +140,19 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
143
140
144
141
result.objectBlob = resultingBlob;
145
142
146
- return result;
143
+ return { ( uint8_t *) result. objectBlob -> GetBufferPointer (), result. objectBlob -> GetBufferSize () } ;
147
144
}
148
145
149
146
150
147
#include " nbl/asset/utils/waveContext.h"
151
148
152
- std::string CHLSLCompiler::preprocessShader (std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const
149
+
150
+ std::string CHLSLCompiler::preprocessShader (std::string&& code, IShader::E_SHADER_STAGE& stage, std::vector<std::string>& dxc_compile_flags_override, const SPreprocessorOptions& preprocessOptions) const
153
151
{
154
152
nbl::wave::context context (code.begin (),code.end (),preprocessOptions.sourceIdentifier .data (),{preprocessOptions});
155
153
context.add_macro_definition (" __HLSL_VERSION" );
156
154
157
- // instead of defining extraDefines as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D 32768",
155
+ // instead of defining extraDefines as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D 32768",
158
156
// now define them as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D=32768"
159
157
// to match boost wave syntax
160
158
// https://www.boost.org/doc/libs/1_82_0/libs/wave/doc/class_reference_context.html#:~:text=Maintain%20defined%20macros-,add_macro_definition,-bool%20add_macro_definition
@@ -192,12 +190,22 @@ std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE
192
190
}
193
191
}
194
192
193
+ if (context.get_hooks ().m_dxc_compile_flags_override .size () != 0 )
194
+ dxc_compile_flags_override = context.get_hooks ().m_dxc_compile_flags_override ;
195
+
195
196
if (context.get_hooks ().m_pragmaStage != IShader::ESS_UNKNOWN)
196
197
stage = context.get_hooks ().m_pragmaStage ;
197
198
199
+
200
+
198
201
return resolvedString;
199
202
}
200
203
204
+ std::string CHLSLCompiler::preprocessShader (std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const
205
+ {
206
+ std::vector<std::string> extra_dxc_compile_flags = {};
207
+ return preprocessShader (std::move (code), stage, extra_dxc_compile_flags, preprocessOptions);
208
+ }
201
209
202
210
core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV (const char * code, const IShaderCompiler::SCompilerOptions& options) const
203
211
{
@@ -208,9 +216,9 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
208
216
hlslOptions.preprocessorOptions .logger .log (" code is nullptr" , system::ILogger::ELL_ERROR);
209
217
return nullptr ;
210
218
}
211
-
219
+ std::vector<std::string> dxc_compile_flags = {};
212
220
auto stage = hlslOptions.stage ;
213
- auto newCode = preprocessShader (code, stage, hlslOptions.preprocessorOptions );
221
+ auto newCode = preprocessShader (code, stage, dxc_compile_flags, hlslOptions.preprocessorOptions );
214
222
215
223
// Suffix is the shader model version
216
224
// TODO: Figure out a way to get the shader model version automatically
@@ -256,7 +264,21 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
256
264
return nullptr ;
257
265
};
258
266
259
- std::vector<LPCWSTR> arguments = {
267
+ std::wstring* arg_storage = NULL ;
268
+ std::vector<LPCWSTR> arguments;
269
+
270
+ if (dxc_compile_flags.size ()) { // #pragma wave overrides compile flags
271
+ size_t arg_size = dxc_compile_flags.size ();
272
+ arguments = {};
273
+ arguments.reserve (arg_size);
274
+ arg_storage = new std::wstring[arg_size]; // prevent deallocation before shader compilation
275
+ for (size_t i = 0 ; i < dxc_compile_flags.size (); i++) {
276
+ arg_storage[i] = std::wstring (dxc_compile_flags[i].begin (), dxc_compile_flags[i].end ());
277
+ arguments.push_back (arg_storage[i].c_str ());
278
+ }
279
+ }
280
+ else {
281
+ arguments = {
260
282
L" -spirv" ,
261
283
L" -HV" , L" 202x" ,
262
284
L" -T" , targetProfile.c_str (),
@@ -267,47 +289,48 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
267
289
L" -Wno-c++1z-extensions" ,
268
290
L" -Wno-gnu-static-float-init" ,
269
291
L" -fspv-target-env=vulkan1.3"
270
- };
292
+ };
293
+ // If a custom SPIR-V optimizer is specified, use that instead of DXC's spirv-opt.
294
+ // This is how we can get more optimizer options.
295
+ //
296
+ // Optimization is also delegated to SPIRV-Tools. Right now there are no difference between
297
+ // optimization levels greater than zero; they will all invoke the same optimization recipe.
298
+ // https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#optimization
299
+ if (hlslOptions.spirvOptimizer )
300
+ {
301
+ arguments.push_back (L" -O0" );
302
+ }
271
303
272
- // If a custom SPIR-V optimizer is specified, use that instead of DXC's spirv-opt.
273
- // This is how we can get more optimizer options.
274
- //
275
- // Optimization is also delegated to SPIRV-Tools. Right now there are no difference between
276
- // optimization levels greater than zero; they will all invoke the same optimization recipe.
277
- // https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#optimization
278
- if (hlslOptions.spirvOptimizer )
279
- {
280
- arguments.push_back (L" -O0" );
304
+ // Debug only values
305
+ if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_FILE_BIT))
306
+ arguments.push_back (L" -fspv-debug=file" );
307
+ if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_SOURCE_BIT))
308
+ arguments.push_back (L" -fspv-debug=source" );
309
+ if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_LINE_BIT))
310
+ arguments.push_back (L" -fspv-debug=line" );
311
+ if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_TOOL_BIT))
312
+ arguments.push_back (L" -fspv-debug=tool" );
313
+ if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_NON_SEMANTIC_BIT))
314
+ arguments.push_back (L" -fspv-debug=vulkan-with-source" );
281
315
}
282
316
283
- // Debug only values
284
- if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_FILE_BIT))
285
- arguments.push_back (L" -fspv-debug=file" );
286
- if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_SOURCE_BIT))
287
- arguments.push_back (L" -fspv-debug=source" );
288
- if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_LINE_BIT))
289
- arguments.push_back (L" -fspv-debug=line" );
290
- if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_TOOL_BIT))
291
- arguments.push_back (L" -fspv-debug=tool" );
292
- if (hlslOptions.debugInfoFlags .hasFlags (E_DEBUG_INFO_FLAGS::EDIF_NON_SEMANTIC_BIT))
293
- arguments.push_back (L" -fspv-debug=vulkan-with-source" );
294
-
295
- auto compileResult = dxcCompile (
296
- this ,
297
- m_dxcCompilerTypes,
317
+ auto compileResult = dxcCompile (
298
318
newCode,
299
- & arguments[ 0 ] ,
319
+ arguments. data () ,
300
320
arguments.size (),
301
321
hlslOptions
302
322
);
303
323
304
- if (!compileResult.objectBlob )
324
+ if (arg_storage)
325
+ delete[] arg_storage;
326
+
327
+ if (!compileResult.begin )
305
328
{
306
329
return nullptr ;
307
330
}
308
331
309
- auto outSpirv = core::make_smart_refctd_ptr<ICPUBuffer>(compileResult.objectBlob -> GetBufferSize () );
310
- memcpy (outSpirv->getPointer (), compileResult.objectBlob -> GetBufferPointer () , compileResult.objectBlob -> GetBufferSize () );
332
+ auto outSpirv = core::make_smart_refctd_ptr<ICPUBuffer>(compileResult.size );
333
+ memcpy (outSpirv->getPointer (), compileResult.begin , compileResult.size );
311
334
312
335
// Optimizer step
313
336
if (hlslOptions.spirvOptimizer )
@@ -322,4 +345,6 @@ void CHLSLCompiler::insertIntoStart(std::string& code, std::ostringstream&& ins)
322
345
{
323
346
code.insert (0u , ins.str ());
324
347
}
348
+
349
+
325
350
#endif
0 commit comments