Skip to content

Commit 8c61959

Browse files
committed
Add fix for line indicators
1 parent 511ee08 commit 8c61959

File tree

3 files changed

+61
-10
lines changed

3 files changed

+61
-10
lines changed

include/nbl/asset/utils/IShaderCompiler.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ namespace nbl::asset
2020
class NBL_API2 IShaderCompiler : public core::IReferenceCounted
2121
{
2222
public:
23+
//string to be replaced with all "#" except those in "#include"
24+
static constexpr const char* PREPROC_DIRECTIVE_DISABLER = "_this_is_a_hash_";
25+
static constexpr const char* PREPROC_DIRECTIVE_ENABLER = PREPROC_DIRECTIVE_DISABLER;
2326

2427
class NBL_API2 IIncludeLoader : public core::IReferenceCounted
2528
{
@@ -260,6 +263,8 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted
260263

261264
static std::string encloseWithinExtraInclGuards(std::string&& _code, uint32_t _maxInclusions, const char* _identifier);
262265

266+
static uint32_t encloseWithinExtraInclGuardsLeadingLines(uint32_t _maxInclusions);
267+
263268
virtual IShader::E_CONTENT_TYPE getCodeContentType() const = 0;
264269

265270
CIncludeFinder* getDefaultIncludeFinder() { return m_defaultIncludeFinder.get(); }

src/nbl/asset/utils/CHLSLCompiler.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ using namespace nbl;
2121
using namespace nbl::asset;
2222
using Microsoft::WRL::ComPtr;
2323

24+
static constexpr const wchar_t* SHADER_MODEL_PROFILE = L"XX_6_2";
25+
2426
namespace nbl::asset::hlsl::impl
2527
{
2628
struct DXC {
@@ -57,7 +59,10 @@ static tcpp::IInputStream* getInputStreamInclude(
5759
uint32_t _maxInclCnt,
5860
const char* _requesting_source,
5961
const char* _requested_source,
60-
bool _type // true for #include "string"; false for #include <string>
62+
bool _type, // true for #include "string"; false for #include <string>
63+
uint32_t lexerLineIndex,
64+
uint32_t leadingLinesImports,
65+
std::vector<std::pair<uint32_t, std::string>>& includeStack
6166
)
6267
{
6368
std::string res_str;
@@ -87,8 +92,25 @@ static tcpp::IInputStream* getInputStreamInclude(
8792
return new tcpp::StringInputStream("#error File not found");
8893
}
8994

95+
// Figure out what line in the current file this #include was
96+
// That would be the current lexer line, minus the line where the current file was included
97+
uint32_t lineGoBackTo = lexerLineIndex - includeStack.back().first -
98+
// if this is 2 includes deep (include within include), subtract leading import lines
99+
// from the previous include
100+
(includeStack.size() > 1 ? leadingLinesImports : 0);
101+
90102
IShaderCompiler::disableAllDirectivesExceptIncludes(res_str);
91103
res_str = IShaderCompiler::encloseWithinExtraInclGuards(std::move(res_str), _maxInclCnt, name.string().c_str());
104+
res_str = res_str + "\n" +
105+
IShaderCompiler::PREPROC_DIRECTIVE_DISABLER + "line " + std::to_string(lineGoBackTo) + " \"" + includeStack.back().second + "\"\n";
106+
107+
// HACK: tcpp is having issues parsing the string, so this is a hack/mitigation that could be removed once tcpp is fixed
108+
std::string identifier = name.string().c_str();
109+
std::replace(identifier.begin(), identifier.end(), '\\', '/');
110+
111+
includeStack.push_back(std::pair<uint32_t, std::string>(lineGoBackTo, identifier));
112+
113+
printf("included res_str:\n%s\n", res_str.c_str());
92114

93115
return new tcpp::StringInputStream(std::move(res_str));
94116
}
@@ -169,13 +191,24 @@ DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset::hlsl:
169191

170192
std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const
171193
{
194+
std::ostringstream insertion;
195+
insertion << IShaderCompiler::PREPROC_DIRECTIVE_ENABLER;
196+
insertion << "line 1\n";
197+
insertIntoStart(code, std::move(insertion));
198+
199+
uint32_t defineLeadingLinesMain = 0;
200+
uint32_t leadingLinesImports = IShaderCompiler::encloseWithinExtraInclGuardsLeadingLines(preprocessOptions.maxSelfInclusionCount + 1u);
172201
if (preprocessOptions.extraDefines.size())
173202
{
174203
insertExtraDefines(code, preprocessOptions.extraDefines);
204+
defineLeadingLinesMain += preprocessOptions.extraDefines.size();
175205
}
176206

177207
IShaderCompiler::disableAllDirectivesExceptIncludes(code);
178208

209+
// Keep track of the line in the original file where each #include was on each level of the include stack
210+
std::vector<std::pair<uint32_t, std::string>> lineOffsetStack = { std::pair<uint32_t, std::string>(defineLeadingLinesMain, preprocessOptions.sourceIdentifier) };
211+
179212
tcpp::StringInputStream codeIs = tcpp::StringInputStream(code);
180213
tcpp::Lexer lexer(codeIs);
181214
tcpp::Preprocessor proc(
@@ -188,13 +221,17 @@ std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE
188221
{
189222
return getInputStreamInclude(
190223
preprocessOptions.includeFinder, m_system.get(), preprocessOptions.maxSelfInclusionCount + 1u,
191-
preprocessOptions.sourceIdentifier.data(), path.c_str(), !isSystemPath
224+
preprocessOptions.sourceIdentifier.data(), path.c_str(), !isSystemPath,
225+
lexer.GetCurrLineIndex(), leadingLinesImports, lineOffsetStack
192226
);
193227
}
194228
else
195229
{
196230
return static_cast<tcpp::IInputStream*>(new tcpp::StringInputStream(std::string("#error No include handler")));
197231
}
232+
},
233+
[&]() {
234+
lineOffsetStack.pop_back();
198235
}
199236
);
200237

@@ -239,6 +276,8 @@ std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE
239276

240277
auto resolvedString = proc.Process();
241278
IShaderCompiler::reenableDirectives(resolvedString);
279+
280+
printf("Resolved string:\n\n%s\n", resolvedString.c_str());
242281
return resolvedString;
243282
}
244283

@@ -265,7 +304,7 @@ core::smart_refctd_ptr<ICPUShader> CHLSLCompiler::compileToSPIRV(const char* cod
265304
// Another option is trying to fetch it from the commandline tool, either from parsing the help message
266305
// or from brute forcing every -T option until one isn't accepted
267306
//
268-
std::wstring targetProfile(L"XX_6_2");
307+
std::wstring targetProfile(SHADER_MODEL_PROFILE);
269308

270309
// Set profile two letter prefix based on stage
271310
switch (stage) {

src/nbl/asset/utils/IShaderCompiler.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,18 @@
1212
using namespace nbl;
1313
using namespace nbl::asset;
1414

15-
//string to be replaced with all "#" except those in "#include"
16-
static constexpr const char* PREPROC_DIRECTIVE_DISABLER = "_this_is_a_hash_";
17-
static constexpr const char* PREPROC_DIRECTIVE_ENABLER = PREPROC_DIRECTIVE_DISABLER;
18-
1915
//all "#", except those in "#include"/"#version"/"#pragma shader_stage(...)", replaced with `PREPROC_DIRECTIVE_DISABLER`
2016
void IShaderCompiler::disableAllDirectivesExceptIncludes(std::string& _code)
2117
{
2218
// TODO: replace this with a proper-ish proprocessor and includer one day
2319
std::regex directive("#(?!(include|version|pragma shader_stage))");//all # not followed by "include" nor "version" nor "pragma shader_stage"
2420
//`#pragma shader_stage(...)` is needed for determining shader stage when `_stage` param of IShaderCompiler functions is set to ESS_UNKNOWN
25-
_code = std::regex_replace(_code, directive, PREPROC_DIRECTIVE_DISABLER);
21+
_code = std::regex_replace(_code, directive, IShaderCompiler::PREPROC_DIRECTIVE_DISABLER);
2622
}
2723

2824
void IShaderCompiler::reenableDirectives(std::string& _code)
2925
{
30-
std::regex directive(PREPROC_DIRECTIVE_ENABLER);
26+
std::regex directive(IShaderCompiler::PREPROC_DIRECTIVE_ENABLER);
3127
_code = std::regex_replace(_code, directive, "#");
3228
}
3329

@@ -70,14 +66,25 @@ std::string IShaderCompiler::encloseWithinExtraInclGuards(std::string&& _code, u
7066
"#ifndef " + defBase_ + std::to_string(_maxInclusions) +
7167
"\n" +
7268
// This will get turned back into #line after the directives get re-enabled
73-
PREPROC_DIRECTIVE_DISABLER + "line 1 \"" + identifier.c_str() + "\"\n" +
69+
IShaderCompiler::PREPROC_DIRECTIVE_DISABLER + "line 1 \"" + identifier.c_str() + "\"\n" +
7470
_code +
7571
"\n"
7672
"#endif"
7773
"\n\n" +
7874
genUndefs();
7975
}
8076

77+
// Amount of lines before the #line after having run encloseWithinExtraInclGuards
78+
uint32_t IShaderCompiler::encloseWithinExtraInclGuardsLeadingLines(uint32_t _maxInclusions)
79+
{
80+
auto lineDirectiveString = std::string(IShaderCompiler::PREPROC_DIRECTIVE_DISABLER) + "line";
81+
std::string str = IShaderCompiler::encloseWithinExtraInclGuards(std::string(""), _maxInclusions, "encloseWithinExtraInclGuardsLeadingLines");
82+
size_t lineDirectivePos = str.find(lineDirectiveString);
83+
auto substr = str.substr(0, lineDirectivePos - lineDirectiveString.length());
84+
85+
return std::count(substr.begin(), substr.end(), '\n');
86+
}
87+
8188
IShaderCompiler::IShaderCompiler(core::smart_refctd_ptr<system::ISystem>&& system)
8289
: m_system(std::move(system))
8390
{

0 commit comments

Comments
 (0)