33// For conditions of distribution and use, see copyright notice in nabla.h
44#include " nbl/asset/utils/CHLSLCompiler.h"
55#include " nbl/asset/utils/shadercUtils.h"
6- // TODO: review
76#ifdef NBL_EMBED_BUILTIN_RESOURCES
87#include " nbl/builtin/CArchive.h"
98#include " spirv/builtin/CArchive.h"
109#endif // NBL_EMBED_BUILTIN_RESOURCES
1110
1211#ifdef _NBL_PLATFORM_WINDOWS_
1312
14- #include < wrl.h>
15- #include < combaseapi.h>
16-
17- #include < dxc/dxcapi.h>
18-
19- #include < sstream>
2013#include < regex>
2114#include < iterator>
2215#include < codecvt>
16+ #include < wrl.h>
17+ #include < combaseapi.h>
18+ #include < sstream>
19+ #include < dxc/dxcapi.h>
2320
2421
2522using namespace nbl ;
@@ -38,6 +35,19 @@ struct DXC
3835};
3936}
4037
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+
4151CHLSLCompiler::CHLSLCompiler (core::smart_refctd_ptr<system::ISystem>&& system)
4252 : IShaderCompiler(std::move(system))
4353{
@@ -60,20 +70,7 @@ CHLSLCompiler::~CHLSLCompiler()
6070 delete m_dxcCompilerTypes;
6171}
6272
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
7774{
7875 // Append Commandline options into source only if debugInfoFlags will emit source
7976 auto sourceEmittingFlags =
@@ -83,7 +80,7 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
8380 if ((options.debugInfoFlags .value & sourceEmittingFlags) != CHLSLCompiler::E_DEBUG_INFO_FLAGS::EDIF_NONE)
8481 {
8582 std::ostringstream insertion;
86- insertion << " // #pragma compile_flags " ;
83+ insertion << " #pragma wave dxc_compile_flags( " ;
8784
8885 std::wstring_convert<std::codecvt_utf8<wchar_t >, wchar_t > conv;
8986 for (uint32_t arg = 0 ; arg < argCount; arg ++)
@@ -92,10 +89,10 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
9289 insertion << str.c_str () << " " ;
9390 }
9491
95- insertion << " \n " ;
96- compiler-> insertIntoStart (source, std::move (insertion));
92+ insertion << " ) \n " ;
93+ insertIntoStart (source, std::move (insertion));
9794 }
98-
95+ nbl::asset::impl::DXC* dxc = m_dxcCompilerTypes;
9996 ComPtr<IDxcBlobEncoding> src;
10097 auto res = dxc->m_dxcUtils ->CreateBlob (reinterpret_cast <const void *>(source.data ()), source.size (), CP_UTF8, &src);
10198 assert (SUCCEEDED (res));
@@ -134,7 +131,7 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
134131 else
135132 {
136133 options.preprocessorOptions .logger .log (" DXC Compilation Failed:\n %s" , system::ILogger::ELL_ERROR, errorMessagesString.c_str ());
137- return result ;
134+ return { nullptr , 0 } ;
138135 }
139136
140137 ComPtr<IDxcBlob> resultingBlob;
@@ -143,18 +140,19 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::impl:
143140
144141 result.objectBlob = resultingBlob;
145142
146- return result;
143+ return { ( uint8_t *) result. objectBlob -> GetBufferPointer (), result. objectBlob -> GetBufferSize () } ;
147144}
148145
149146
150147#include " nbl/asset/utils/waveContext.h"
151148
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
153151{
154152 nbl::wave::context context (code.begin (),code.end (),preprocessOptions.sourceIdentifier .data (),{preprocessOptions});
155153 context.add_macro_definition (" __HLSL_VERSION" );
156154
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",
158156 // now define them as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D=32768"
159157 // to match boost wave syntax
160158 // 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
192190 }
193191 }
194192
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+
195196 if (context.get_hooks ().m_pragmaStage != IShader::ESS_UNKNOWN)
196197 stage = context.get_hooks ().m_pragmaStage ;
197198
199+
200+
198201 return resolvedString;
199202}
200203
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+ }
201209
202210core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV (const char * code, const IShaderCompiler::SCompilerOptions& options) const
203211{
@@ -208,9 +216,9 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
208216 hlslOptions.preprocessorOptions .logger .log (" code is nullptr" , system::ILogger::ELL_ERROR);
209217 return nullptr ;
210218 }
211-
219+ std::vector<std::string> dxc_compile_flags = {};
212220 auto stage = hlslOptions.stage ;
213- auto newCode = preprocessShader (code, stage, hlslOptions.preprocessorOptions );
221+ auto newCode = preprocessShader (code, stage, dxc_compile_flags, hlslOptions.preprocessorOptions );
214222
215223 // Suffix is the shader model version
216224 // 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
256264 return nullptr ;
257265 };
258266
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 = {
260282 L" -spirv" ,
261283 L" -HV" , L" 202x" ,
262284 L" -T" , targetProfile.c_str (),
@@ -267,47 +289,48 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
267289 L" -Wno-c++1z-extensions" ,
268290 L" -Wno-gnu-static-float-init" ,
269291 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+ }
271303
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" );
281315 }
282316
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 (
298318 newCode,
299- & arguments[ 0 ] ,
319+ arguments. data () ,
300320 arguments.size (),
301321 hlslOptions
302322 );
303323
304- if (!compileResult.objectBlob )
324+ if (arg_storage)
325+ delete[] arg_storage;
326+
327+ if (!compileResult.begin )
305328 {
306329 return nullptr ;
307330 }
308331
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 );
311334
312335 // Optimizer step
313336 if (hlslOptions.spirvOptimizer )
@@ -322,4 +345,6 @@ void CHLSLCompiler::insertIntoStart(std::string& code, std::ostringstream&& ins)
322345{
323346 code.insert (0u , ins.str ());
324347}
348+
349+
325350#endif
0 commit comments