Skip to content

Commit cc8c793

Browse files
committed
TODO: Guessing extension, shader stage upgrade function
1 parent caa599e commit cc8c793

File tree

4 files changed

+104
-86
lines changed

4 files changed

+104
-86
lines changed

include/nbl/asset/utils/CHLSLCompiler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class NBL_API2 CHLSLCompiler final : public IShaderCompiler
5151
//}
5252

5353
std::string preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const override;
54-
std::string preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, std::vector<std::string>& dxc_compile_flags_override, const SPreprocessorOptions& preprocessOptions) const;
54+
std::string preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions, std::vector<std::string>& dxc_compile_flags_override) const;
5555

5656
void insertIntoStart(std::string& code, std::ostringstream&& ins) const override;
5757
constexpr static inline const wchar_t* RequiredArguments[] = {
@@ -64,7 +64,7 @@ class NBL_API2 CHLSLCompiler final : public IShaderCompiler
6464
L"-Wno-gnu-static-float-init",
6565
L"-fspv-target-env=vulkan1.3"
6666
};
67-
constexpr static inline uint32_t RequiredArgumentCount = 8;
67+
constexpr static inline uint32_t RequiredArgumentCount = sizeof(RequiredArguments) / sizeof(RequiredArguments[0]);
6868

6969
protected:
7070
// This can't be a unique_ptr due to it being an undefined type

src/nbl/asset/utils/CHLSLCompiler.cpp

Lines changed: 83 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,34 @@
1818
#include <sstream>
1919
#include <dxc/dxcapi.h>
2020

21-
2221
using namespace nbl;
2322
using namespace nbl::asset;
2423
using Microsoft::WRL::ComPtr;
2524

2625
static constexpr const wchar_t* SHADER_MODEL_PROFILE = L"XX_6_7";
27-
26+
static const wchar_t* ShaderStageToString(asset::IShader::E_SHADER_STAGE stage) {
27+
switch (stage)
28+
{
29+
case asset::IShader::ESS_VERTEX:
30+
return L"vs";
31+
case asset::IShader::ESS_TESSELLATION_CONTROL:
32+
return L"ds";
33+
case asset::IShader::ESS_TESSELLATION_EVALUATION:
34+
return L"hs";
35+
case asset::IShader::ESS_GEOMETRY:
36+
return L"gs";
37+
case asset::IShader::ESS_FRAGMENT:
38+
return L"ps";
39+
case asset::IShader::ESS_COMPUTE:
40+
return L"cs";
41+
case asset::IShader::ESS_TASK:
42+
return L"as";
43+
case asset::IShader::ESS_MESH:
44+
return L"ms";
45+
default:
46+
return nullptr;
47+
};
48+
}
2849

2950
namespace nbl::asset::impl
3051
{
@@ -71,58 +92,66 @@ CHLSLCompiler::~CHLSLCompiler()
7192
}
7293

7394

74-
static void try_upgrade_hlsl_version(std::vector<std::wstring>& arguments)
95+
static void try_upgrade_hlsl_version(std::vector<std::wstring>& arguments, system::logger_opt_ptr& logger)
7596
{
76-
auto foundShaderStageArgument = std::find(arguments.begin(), arguments.end(), L"-HV");
77-
if (foundShaderStageArgument != arguments.end()) {
78-
auto foundShaderStageArgumentValueIdx = foundShaderStageArgument - arguments.begin() + 1;
79-
std::wstring version = arguments[foundShaderStageArgumentValueIdx];
80-
if (version.length() >= 4 && (version[2] < '2' || (version[2] == '2' && version[3] <= '0')))
81-
arguments[foundShaderStageArgumentValueIdx] = L"2021";
97+
auto stageArgumentPos = std::find(arguments.begin(), arguments.end(), L"-HV");
98+
if (stageArgumentPos != arguments.end()) {
99+
auto index = stageArgumentPos - arguments.begin() + 1; // -HV XXXXX, get index of second
100+
std::wstring version = arguments[index];
101+
if (!isalpha(version.back()) && version.length() >= 4 && std::stoi(version) < 2021)
102+
arguments[index] = L"2021";
103+
}
104+
else {
105+
logger.log("Compile flag error: Required compile flag not found -HV. Force enabling -HV 202x, as it is required by Nabla.", system::ILogger::ELL_WARNING);
106+
arguments.push_back(L"-HV");
107+
arguments.push_back(L"202x");
82108
}
83109
}
84110

85111

86-
static void try_upgrade_shader_stage(std::vector<std::wstring> &arguments) {
112+
static void try_upgrade_shader_stage(std::vector<std::wstring> &arguments, asset::IShader::E_SHADER_STAGE shaderStageOverrideFromPragma, system::logger_opt_ptr& logger) {
87113
auto foundShaderStageArgument = std::find(arguments.begin(), arguments.end(), L"-T");
88114
if (foundShaderStageArgument != arguments.end()) {
89115
auto foundShaderStageArgumentValueIdx = foundShaderStageArgument - arguments.begin() + 1;
90-
std::wstring targetProfile = arguments[foundShaderStageArgumentValueIdx];
91-
if (targetProfile.length() >= 6) {
92-
int argument_version = (targetProfile[3] - '0') * 10 + (targetProfile[5] - '0');
116+
std::wstring s = arguments[foundShaderStageArgumentValueIdx];
117+
if (s.length() >= 6) {
118+
//TODO replace first 2 if shaderStageOverrideFromPragma != Unknown
119+
120+
//TODO fix this parsing in case 6_10 gets released
121+
//Even though they could name it 7_0 at that point
122+
123+
auto it = std::find(s.begin(), s.end(), '_');
124+
while (it != s.end())
125+
{
126+
127+
}
128+
/* int argument_version = (targetProfile[3] - '0') * 10 + (targetProfile[5] - '0');
93129
if (argument_version < 67)
94130
{
95131
targetProfile.replace(3, 3, L"6_7");
96132
arguments[foundShaderStageArgumentValueIdx] = targetProfile;
97-
}
133+
}*/
98134
}
99135
}
100136
}
101137

102138

103139
static void add_required_arguments_if_not_present(std::vector<std::wstring>& arguments, system::logger_opt_ptr &logger) {
104-
bool found_arg_flags[CHLSLCompiler::RequiredArgumentCount]{};
105-
int argc = arguments.size();
106-
for (int i = 0; i < argc; i++)
107-
{
108-
for (int j = 0; j < CHLSLCompiler::RequiredArgumentCount; j++)
109-
{
110-
if (arguments[i] == CHLSLCompiler::RequiredArguments[j]) {
111-
found_arg_flags[j] = true;
112-
break;
113-
}
114-
}
115-
}
140+
auto set = std::unordered_set<std::wstring>();
141+
for (int i = 0; i < arguments.size(); i++)
142+
set.insert(arguments[i]);
116143
for (int j = 0; j < CHLSLCompiler::RequiredArgumentCount; j++)
117144
{
118-
if (!found_arg_flags[j]) {
119-
logger.log("Required compile flag not found %ls. This flag will be force enabled as it is required by Nabla.", system::ILogger::ELL_WARNING, CHLSLCompiler::RequiredArguments[j]);
145+
bool missing = set.find(CHLSLCompiler::RequiredArguments[j]) == set.end();
146+
if (missing) {
147+
logger.log("Compile flag error: Required compile flag not found %ls. This flag will be force enabled, as it is required by Nabla.", system::ILogger::ELL_WARNING, CHLSLCompiler::RequiredArguments[j]);
120148
arguments.push_back(CHLSLCompiler::RequiredArguments[j]);
121149
}
122150
}
123151
}
124152

125-
153+
// adds missing required arguments
154+
// converts arguments from std::string to std::wstring
126155
template <typename T>
127156
static void populate_arguments_with_type_conversion(std::vector<std::wstring> &arguments, T &iterable_collection, system::logger_opt_ptr &logger) {
128157
size_t arg_size = iterable_collection.size();
@@ -211,7 +240,7 @@ static DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset
211240
#include "nbl/asset/utils/waveContext.h"
212241

213242

214-
std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, std::vector<std::string>& dxc_compile_flags_override, const SPreprocessorOptions& preprocessOptions) const
243+
std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions, std::vector<std::string>& dxc_compile_flags_override) const
215244
{
216245
nbl::wave::context context(code.begin(),code.end(),preprocessOptions.sourceIdentifier.data(),{preprocessOptions});
217246
context.add_macro_definition("__HLSL_VERSION");
@@ -268,7 +297,7 @@ std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE
268297
std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const
269298
{
270299
std::vector<std::string> extra_dxc_compile_flags = {};
271-
return preprocessShader(std::move(code), stage, extra_dxc_compile_flags, preprocessOptions);
300+
return preprocessShader(std::move(code), stage, preprocessOptions, extra_dxc_compile_flags);
272301
}
273302

274303
core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* code, const IShaderCompiler::SCompilerOptions& options) const
@@ -281,8 +310,8 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
281310
return nullptr;
282311
}
283312
std::vector<std::string> dxc_compile_flags = {};
284-
auto stage = hlslOptions.stage;
285-
auto newCode = preprocessShader(code, stage, dxc_compile_flags, hlslOptions.preprocessorOptions);
313+
IShader::E_SHADER_STAGE stageOverrideFromPragma = IShader::ESS_UNKNOWN;
314+
auto newCode = preprocessShader(code, stageOverrideFromPragma, hlslOptions.preprocessorOptions, dxc_compile_flags);
286315

287316
// Suffix is the shader model version
288317
// TODO: Figure out a way to get the shader model version automatically
@@ -295,47 +324,33 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
295324
// or from brute forcing every -T option until one isn't accepted
296325
//
297326
std::wstring targetProfile(SHADER_MODEL_PROFILE);
298-
299-
// Set profile two letter prefix based on stage
300-
switch (stage)
327+
IShader::E_SHADER_STAGE stage = options.stage;
328+
if (stageOverrideFromPragma != IShader::ESS_UNKNOWN)
301329
{
302-
case asset::IShader::ESS_VERTEX:
303-
targetProfile.replace(0, 2, L"vs");
304-
break;
305-
case asset::IShader::ESS_TESSELLATION_CONTROL:
306-
targetProfile.replace(0, 2, L"ds");
307-
break;
308-
case asset::IShader::ESS_TESSELLATION_EVALUATION:
309-
targetProfile.replace(0, 2, L"hs");
310-
break;
311-
case asset::IShader::ESS_GEOMETRY:
312-
targetProfile.replace(0, 2, L"gs");
313-
break;
314-
case asset::IShader::ESS_FRAGMENT:
315-
targetProfile.replace(0, 2, L"ps");
316-
break;
317-
case asset::IShader::ESS_COMPUTE:
318-
targetProfile.replace(0, 2, L"cs");
319-
break;
320-
case asset::IShader::ESS_TASK:
321-
targetProfile.replace(0, 2, L"as");
322-
break;
323-
case asset::IShader::ESS_MESH:
324-
targetProfile.replace(0, 2, L"ms");
325-
break;
326-
default:
327-
hlslOptions.preprocessorOptions.logger.log("invalid shader stage %i", system::ILogger::ELL_ERROR, stage);
328-
return nullptr;
329-
};
330-
330+
// Shader Stage was overriden using #pragma
331+
// #pragma wave shaderStage overrides all other definitions of shader stage, such as
332+
// -T argument (passed here as options.stage)
333+
// shader stage inferred from file extension in asset namespace
334+
stage = stageOverrideFromPragma;
335+
}
336+
331337
std::vector<std::wstring> arguments = {};
332-
if (dxc_compile_flags.size()) { // #pragma dxc_compile_flags takes priority
338+
if (dxc_compile_flags.size() || hlslOptions.dxcOptions.size()) { // #pragma dxc_compile_flags takes priority
333339
populate_arguments_with_type_conversion(arguments, dxc_compile_flags, hlslOptions.preprocessorOptions.logger);
334340
}
335341
else if (hlslOptions.dxcOptions.size()) { // second in order of priority is command line arguments
336342
populate_arguments_with_type_conversion(arguments, hlslOptions.dxcOptions, hlslOptions.preprocessorOptions.logger);
337343
}
338-
else { //lastly default arguments
344+
else { // lastly default arguments
345+
346+
// Set profile two letter prefix based on stage
347+
auto stageStr = ShaderStageToString(stage);
348+
if (!stageStr) {
349+
hlslOptions.preprocessorOptions.logger.log("invalid shader stage %i", system::ILogger::ELL_ERROR, stage);
350+
return nullptr;
351+
}
352+
targetProfile.replace(0, 2, stageStr);
353+
339354
arguments = {
340355
L"-HV", L"202x",
341356
L"-T", targetProfile.c_str(),
@@ -366,7 +381,7 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
366381
arguments.push_back(L"-fspv-debug=vulkan-with-source");
367382
}
368383

369-
try_upgrade_shader_stage(arguments);
384+
try_upgrade_shader_stage(arguments, stageOverrideFromPragma);
370385
try_upgrade_hlsl_version(arguments);
371386

372387
uint32_t argc = arguments.size();

src/nbl/asset/utils/waveContext.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ struct preprocessing_hooks final : public boost::wave::context_policies::default
5252
hash_token_occurences = 0;
5353
}
5454

55+
template <typename ContextT, typename TokenT>
56+
bool found_directive(ContextT const& ctx, TokenT const& directive)
57+
{
58+
hash_token_occurences++;
59+
return false;
60+
}
61+
5562
template <typename ContextT>
5663
bool locate_include_file(ContextT& ctx, std::string& file_path, bool is_system, char const* current_name, std::string& dir_path, std::string& native_name)
5764
{
@@ -68,7 +75,6 @@ struct preprocessing_hooks final : public boost::wave::context_policies::default
6875
typename ContextT::token_type const& act_token
6976
)
7077
{
71-
hash_token_occurences++;
7278
auto optionStr = option.get_value().c_str();
7379
if (strcmp(optionStr,"shader_stage")==0)
7480
{
@@ -103,24 +109,27 @@ struct preprocessing_hooks final : public boost::wave::context_policies::default
103109
return true;
104110
}
105111

106-
if (strcmp(optionStr, "dxc_compile_flags") == 0 && hash_token_occurences == 1) {
112+
if (strcmp(optionStr, "dxc_compile_flags") ) {
113+
if (0 && hash_token_occurences != 1) {
114+
m_logger.log("Pre-processor error: Encountered a \"#pragma wave dxc_compile_flags\" but it is not the first preprocessor directive.", system::ILogger::ELL_ERROR);
115+
return false;
116+
}
107117
m_dxc_compile_flags_override.clear();
108118
std::string arg = "";
109119
for (auto valueIter = values.begin(); valueIter != values.end(); valueIter++) {
110120
std::string compiler_option_s = std::string(valueIter->get_value().c_str());
111-
//the compiler_option_s is a token thus can be only part of the actual argument, i.e. "-spirv" will be split into tokens [ "-", "spirv" ]
112-
//for dxc_compile_flags just join the strings until it finds a whitespace or end of args
121+
// the compiler_option_s is a token thus can be only part of the actual argument, i.e. "-spirv" will be split into tokens [ "-", "spirv" ]
122+
// for dxc_compile_flags just join the strings until it finds a whitespace or end of args
113123

114-
// if the compiler flag is a separator that is a whitespace, do not add to list of flag overrides
115124
if (compiler_option_s == " ")
116125
{
117-
//reset
126+
// push argument and reset
118127
m_dxc_compile_flags_override.push_back(arg);
119128
arg.clear();
120129
}
121130
else
122131
{
123-
//append
132+
// append string
124133
arg += compiler_option_s;
125134
}
126135
}
@@ -491,7 +500,8 @@ template<> inline bool boost::wave::impl::pp_iterator_functor<nbl::wave::context
491500
result = includeFinder->getIncludeRelative(ctx.get_current_directory(),file_path);
492501
}
493502
else {
494-
ctx.get_hooks().m_logger.log("Include finder not assigned, preprocessor will not include file " + file_path, nbl::system::ILogger::ELL_ERROR);
503+
ctx.get_hooks().m_logger.log("Pre-processor error: Include finder not assigned, preprocessor will not include file " + file_path, nbl::system::ILogger::ELL_ERROR);
504+
return false;
495505
}
496506

497507
if (!result)

tools/nsc/main.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,21 +114,14 @@ class ShaderCompiler final : public system::IApplicationFramework
114114
constexpr uint32_t WorkgroupSize = 256;
115115
constexpr uint32_t WorkgroupCount = 2048;
116116
const string WorkgroupSizeAsStr = std::to_string(WorkgroupSize);
117-
const IShaderCompiler::SPreprocessorOptions::SMacroDefinition WorkgroupSizeDefine = { "WORKGROUP_SIZE",WorkgroupSizeAsStr };
118117

119118
smart_refctd_ptr<CHLSLCompiler> hlslcompiler = make_smart_refctd_ptr<CHLSLCompiler>(smart_refctd_ptr(m_system));
120119

121120
CHLSLCompiler::SOptions options = {};
122-
// want as much debug as possible
123121
options.stage = asset::IShader::E_SHADER_STAGE::ESS_UNKNOWN;
124-
options.debugInfoFlags = IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_LINE_BIT;
125-
// this lets you source-level debug/step shaders in renderdoc
126-
//if (physDev->getLimits().shaderNonSemanticInfo)
127-
//options.debugInfoFlags |= IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_NON_SEMANTIC_BIT;
128-
// if you don't set the logger and source identifier you'll have no meaningful errors
122+
//options.debugInfoFlags = IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_LINE_BIT;
129123
options.preprocessorOptions.sourceIdentifier = sourceIdentifier;
130124
options.preprocessorOptions.logger = m_logger.get();
131-
options.preprocessorOptions.extraDefines = { &WorkgroupSizeDefine,&WorkgroupSizeDefine + 1 };
132125
options.dxcOptions = std::span<std::string>(m_arguments);
133126
auto includeFinder = make_smart_refctd_ptr<IShaderCompiler::CIncludeFinder>(smart_refctd_ptr(m_system));
134127
options.preprocessorOptions.includeFinder = includeFinder.get();

0 commit comments

Comments
 (0)