Skip to content

Commit 23966fe

Browse files
committed
Merge branch 'hlsl-compiler-impl' into cad_example
2 parents 5837bd6 + d4bb5c0 commit 23966fe

File tree

6 files changed

+144
-134
lines changed

6 files changed

+144
-134
lines changed

include/nbl/asset/utils/CGLSLCompiler.h

Lines changed: 12 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@ namespace nbl::asset
1414
class NBL_API2 CGLSLCompiler final : public IShaderCompiler
1515
{
1616
public:
17-
//string to be replaced with all "#" except those in "#include"
18-
static constexpr const char* PREPROC_DIRECTIVE_DISABLER = "_this_is_a_hash_";
19-
static constexpr const char* PREPROC_DIRECTIVE_ENABLER = PREPROC_DIRECTIVE_DISABLER;
20-
static constexpr const char* PREPROC_GL__DISABLER = "_this_is_a_GL__prefix_";
21-
static constexpr const char* PREPROC_GL__ENABLER = PREPROC_GL__DISABLER;
22-
static constexpr const char* PREPROC_LINE_CONTINUATION_DISABLER = "_this_is_a_line_continuation_\n";
23-
static constexpr const char* PREPROC_LINE_CONTINUATION_ENABLER = "_this_is_a_line_continuation_";
24-
2517

2618
IShader::E_CONTENT_TYPE getCodeContentType() const override { return IShader::E_CONTENT_TYPE::ECT_GLSL; };
2719

@@ -134,69 +126,28 @@ class NBL_API2 CGLSLCompiler final : public IShaderCompiler
134126
}
135127
}
136128

137-
static void disableAllDirectivesExceptIncludes(std::string& _code)
129+
std::string preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const override;
130+
131+
static constexpr const char* PREPROC_GL__DISABLER = "_this_is_a_GL__prefix_";
132+
static constexpr const char* PREPROC_GL__ENABLER = PREPROC_GL__DISABLER;
133+
static constexpr const char* PREPROC_LINE_CONTINUATION_DISABLER = "_this_is_a_line_continuation_\n";
134+
static constexpr const char* PREPROC_LINE_CONTINUATION_ENABLER = "_this_is_a_line_continuation_";
135+
136+
static void disableGlDirectives(std::string& _code)
138137
{
139-
// TODO: replace this with a proper-ish proprocessor and includer one day
140-
std::regex directive("#(?!(include|version|pragma shader_stage|line))");//all # not followed by "include" nor "version" nor "pragma shader_stage"
141-
//`#pragma shader_stage(...)` is needed for determining shader stage when `_stage` param of IShaderCompiler functions is set to ESS_UNKNOWN
142-
auto result = std::regex_replace(_code, directive, PREPROC_DIRECTIVE_DISABLER);
143138
std::regex glMacro("[ \t\r\n\v\f]GL_");
144-
result = std::regex_replace(result, glMacro, PREPROC_GL__DISABLER);
139+
auto result = std::regex_replace(_code, glMacro, PREPROC_GL__DISABLER);
145140
std::regex lineContinuation("\\\\[ \t\r\n\v\f]*\n");
146141
_code = std::regex_replace(result, lineContinuation, PREPROC_LINE_CONTINUATION_DISABLER);
147142
}
148-
static void reenableDirectives(std::string& _code)
143+
144+
static void reenableGlDirectives(std::string& _code)
149145
{
150146
std::regex lineContinuation(PREPROC_LINE_CONTINUATION_ENABLER);
151147
auto result = std::regex_replace(_code, lineContinuation, " \\");
152148
std::regex glMacro(PREPROC_GL__ENABLER);
153-
result = std::regex_replace(result, glMacro, " GL_");
154-
std::regex directive(PREPROC_DIRECTIVE_ENABLER);
155-
_code = std::regex_replace(result, directive, "#");
149+
_code = std::regex_replace(result, glMacro, " GL_");
156150
}
157-
static std::string encloseWithinExtraInclGuards(std::string&& _code, uint32_t _maxInclusions, const char* _identifier)
158-
{
159-
assert(_maxInclusions != 0u);
160-
161-
using namespace std::string_literals;
162-
std::string defBase_ = "_GENERATED_INCLUDE_GUARD_"s + _identifier + "_";
163-
std::replace_if(defBase_.begin(), defBase_.end(), [](char c) ->bool { return !::isalpha(c) && !::isdigit(c); }, '_');
164-
165-
auto genDefs = [&defBase_, _maxInclusions, _identifier] {
166-
auto defBase = [&defBase_](uint32_t n) { return defBase_ + std::to_string(n); };
167-
std::string defs = "#ifndef " + defBase(0) + "\n\t#define " + defBase(0) + "\n";
168-
for (uint32_t i = 1u; i <= _maxInclusions; ++i) {
169-
const std::string defname = defBase(i);
170-
defs += "#elif !defined(" + defname + ")\n\t#define " + defname + "\n";
171-
}
172-
defs += "#endif\n";
173-
return defs;
174-
};
175-
auto genUndefs = [&defBase_, _maxInclusions, _identifier] {
176-
auto defBase = [&defBase_](int32_t n) { return defBase_ + std::to_string(n); };
177-
std::string undefs = "#ifdef " + defBase(_maxInclusions) + "\n\t#undef " + defBase(_maxInclusions) + "\n";
178-
for (int32_t i = _maxInclusions - 1; i >= 0; --i) {
179-
const std::string defname = defBase(i);
180-
undefs += "#elif defined(" + defname + ")\n\t#undef " + defname + "\n";
181-
}
182-
undefs += "#endif\n";
183-
return undefs;
184-
};
185-
186-
return
187-
genDefs() +
188-
"\n"
189-
"#ifndef " + defBase_ + std::to_string(_maxInclusions) +
190-
"\n" +
191-
"#line 1 \"" + _identifier + "\"\n" +
192-
_code +
193-
"\n"
194-
"#endif"
195-
"\n\n" +
196-
genUndefs();
197-
}
198-
199-
std::string preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const override;
200151

201152
protected:
202153

include/nbl/asset/utils/CHLSLCompiler.h

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
#include "nbl/asset/utils/ISPIRVOptimizer.h"
99
#include "nbl/asset/utils/IShaderCompiler.h"
1010

11-
#include <combaseapi.h>
12-
#include <dxc/dxc/include/dxc/dxcapi.h>
11+
#include <wrl.h>
12+
13+
using Microsoft::WRL::ComPtr;
14+
15+
class IDxcUtils;
16+
class IDxcCompiler3;
1317

1418
namespace nbl::asset
1519
{
@@ -20,7 +24,6 @@ class NBL_API2 CHLSLCompiler final : public IShaderCompiler
2024
IShader::E_CONTENT_TYPE getCodeContentType() const override { return IShader::E_CONTENT_TYPE::ECT_HLSL; };
2125

2226
CHLSLCompiler(core::smart_refctd_ptr<system::ISystem>&& system);
23-
~CHLSLCompiler();
2427

2528
struct SOptions : IShaderCompiler::SCompilerOptions
2629
{
@@ -44,13 +47,15 @@ class NBL_API2 CHLSLCompiler final : public IShaderCompiler
4447

4548
std::string preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const override;
4649

47-
protected:
48-
4950
void insertIntoStart(std::string& code, std::ostringstream&& ins) const override;
5051

52+
IDxcUtils* getDxcUtils() const { return m_dxcUtils.Get(); }
53+
IDxcCompiler3* getDxcCompiler() const { return m_dxcCompiler.Get(); }
54+
protected:
55+
5156
// TODO do we want to use ComPtr?
52-
std::unique_ptr<IDxcUtils> m_dxcUtils;
53-
std::unique_ptr<IDxcCompiler3> m_dxcCompiler;
57+
ComPtr<IDxcUtils> m_dxcUtils;
58+
ComPtr<IDxcCompiler3> m_dxcCompiler;
5459

5560
static CHLSLCompiler::SOptions option_cast(const IShaderCompiler::SCompilerOptions& options)
5661
{
@@ -61,29 +66,6 @@ class NBL_API2 CHLSLCompiler final : public IShaderCompiler
6166
ret.setCommonData(options);
6267
return ret;
6368
}
64-
65-
class DxcCompilationResult
66-
{
67-
public:
68-
IDxcBlobEncoding* errorMessages;
69-
IDxcBlob* objectBlob;
70-
IDxcResult* compileResult;
71-
72-
char* GetErrorMessagesString()
73-
{
74-
return reinterpret_cast<char*>(errorMessages->GetBufferPointer());
75-
}
76-
77-
// TODO figure out why this is crashing when done as part of the destructor
78-
void release()
79-
{
80-
errorMessages->Release();
81-
objectBlob->Release();
82-
compileResult->Release();
83-
}
84-
};
85-
86-
CHLSLCompiler::DxcCompilationResult dxcCompile(std::string& source, LPCWSTR* args, uint32_t argCount, const SOptions& options) const;
8769
};
8870

8971
}

include/nbl/asset/utils/IShaderCompiler.h

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted
136136
{
137137
IShader::E_SHADER_STAGE stage = IShader::E_SHADER_STAGE::ESS_UNKNOWN;
138138
E_SPIRV_VERSION targetSpirvVersion = E_SPIRV_VERSION::ESV_1_6;
139-
std::string_view entryPoint = "";
140139
const ISPIRVOptimizer* spirvOptimizer = nullptr;
141140
bool genDebugInfo = true;
142141
SPreprocessorOptions preprocessorOptions = {};
@@ -255,6 +254,69 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted
255254
}
256255
}
257256

257+
//string to be replaced with all "#" except those in "#include"
258+
static constexpr const char* PREPROC_DIRECTIVE_DISABLER = "_this_is_a_hash_";
259+
static constexpr const char* PREPROC_DIRECTIVE_ENABLER = PREPROC_DIRECTIVE_DISABLER;
260+
261+
// TODO make sure there are no GLSL specifics for these functions in the HLSL compiler
262+
//
263+
//all "#", except those in "#include"/"#version"/"#pragma shader_stage(...)", replaced with `PREPROC_DIRECTIVE_DISABLER`
264+
static void disableAllDirectivesExceptIncludes(std::string& _code)
265+
{
266+
// TODO: replace this with a proper-ish proprocessor and includer one day
267+
std::regex directive("#(?!(include|version|pragma shader_stage))");//all # not followed by "include" nor "version" nor "pragma shader_stage"
268+
//`#pragma shader_stage(...)` is needed for determining shader stage when `_stage` param of IShaderCompiler functions is set to ESS_UNKNOWN
269+
_code = std::regex_replace(_code, directive, PREPROC_DIRECTIVE_DISABLER);
270+
}
271+
272+
static void reenableDirectives(std::string& _code)
273+
{
274+
std::regex directive(PREPROC_DIRECTIVE_ENABLER);
275+
_code = std::regex_replace(_code, directive, "#");
276+
}
277+
278+
static std::string encloseWithinExtraInclGuards(std::string&& _code, uint32_t _maxInclusions, const char* _identifier)
279+
{
280+
assert(_maxInclusions != 0u);
281+
282+
using namespace std::string_literals;
283+
std::string defBase_ = "_GENERATED_INCLUDE_GUARD_"s + _identifier + "_";
284+
std::replace_if(defBase_.begin(), defBase_.end(), [](char c) ->bool { return !::isalpha(c) && !::isdigit(c); }, '_');
285+
286+
auto genDefs = [&defBase_, _maxInclusions, _identifier] {
287+
auto defBase = [&defBase_](uint32_t n) { return defBase_ + std::to_string(n); };
288+
std::string defs = "#ifndef " + defBase(0) + "\n\t#define " + defBase(0) + "\n";
289+
for (uint32_t i = 1u; i <= _maxInclusions; ++i) {
290+
const std::string defname = defBase(i);
291+
defs += "#elif !defined(" + defname + ")\n\t#define " + defname + "\n";
292+
}
293+
defs += "#endif\n";
294+
return defs;
295+
};
296+
auto genUndefs = [&defBase_, _maxInclusions, _identifier] {
297+
auto defBase = [&defBase_](int32_t n) { return defBase_ + std::to_string(n); };
298+
std::string undefs = "#ifdef " + defBase(_maxInclusions) + "\n\t#undef " + defBase(_maxInclusions) + "\n";
299+
for (int32_t i = _maxInclusions - 1; i >= 0; --i) {
300+
const std::string defname = defBase(i);
301+
undefs += "#elif defined(" + defname + ")\n\t#undef " + defname + "\n";
302+
}
303+
undefs += "#endif\n";
304+
return undefs;
305+
};
306+
307+
return
308+
genDefs() +
309+
"\n"
310+
"#ifndef " + defBase_ + std::to_string(_maxInclusions) +
311+
"\n" +
312+
"#line 1 \"" + _identifier + "\"\n" +
313+
_code +
314+
"\n"
315+
"#endif"
316+
"\n\n" +
317+
genUndefs();
318+
}
319+
258320
virtual IShader::E_CONTENT_TYPE getCodeContentType() const = 0;
259321

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

src/nbl/asset/utils/CGLSLCompiler.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ namespace nbl::asset::impl
6666
}
6767
else {
6868
//employ encloseWithinExtraInclGuards() in order to prevent infinite loop of (not necesarilly direct) self-inclusions while other # directives (incl guards among them) are disabled
69-
CGLSLCompiler::disableAllDirectivesExceptIncludes(res_str);
70-
res_str = CGLSLCompiler::encloseWithinExtraInclGuards(std::move(res_str), m_maxInclCnt, name.string().c_str());
69+
IShaderCompiler::disableAllDirectivesExceptIncludes(res_str);
70+
CGLSLCompiler::disableGlDirectives(res_str);
71+
res_str = IShaderCompiler::encloseWithinExtraInclGuards(std::move(res_str), m_maxInclCnt, name.string().c_str());
7172

7273
res->content_length = res_str.size();
7374
res->content = new char[res_str.size() + 1u];
@@ -106,7 +107,8 @@ std::string CGLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE
106107
}
107108
if (preprocessOptions.includeFinder != nullptr)
108109
{
109-
CGLSLCompiler::disableAllDirectivesExceptIncludes(code);//all "#", except those in "#include"/"#version"/"#pragma shader_stage(...)", replaced with `PREPROC_DIRECTIVE_DISABLER`
110+
IShaderCompiler::disableAllDirectivesExceptIncludes(code);
111+
CGLSLCompiler::disableGlDirectives(code);
110112
shaderc::Compiler comp;
111113
shaderc::CompileOptions options;
112114
options.SetTargetSpirv(shaderc_spirv_version_1_6);
@@ -121,7 +123,8 @@ std::string CGLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE
121123
}
122124

123125
auto resolvedString = std::string(res.cbegin(), std::distance(res.cbegin(), res.cend()));
124-
CGLSLCompiler::reenableDirectives(resolvedString);
126+
IShaderCompiler::reenableDirectives(resolvedString);
127+
CGLSLCompiler::reenableGlDirectives(resolvedString);
125128
return resolvedString;
126129
}
127130
else
@@ -140,12 +143,6 @@ core::smart_refctd_ptr<ICPUShader> CGLSLCompiler::compileToSPIRV(const char* cod
140143
return nullptr;
141144
}
142145

143-
if (glslOptions.entryPoint.compare("main") != 0)
144-
{
145-
glslOptions.preprocessorOptions.logger.log("shaderc requires entry point to be \"main\" in GLSL", system::ILogger::ELL_ERROR);
146-
return nullptr;
147-
}
148-
149146
auto newCode = preprocessShader(code, glslOptions.stage, glslOptions.preprocessorOptions);
150147

151148
shaderc::Compiler comp;
@@ -155,7 +152,7 @@ core::smart_refctd_ptr<ICPUShader> CGLSLCompiler::compileToSPIRV(const char* cod
155152
if (glslOptions.genDebugInfo)
156153
shadercOptions.SetGenerateDebugInfo();
157154

158-
shaderc::SpvCompilationResult bin_res = comp.CompileGlslToSpv(newCode.c_str(), newCode.size(), stage, glslOptions.preprocessorOptions.sourceIdentifier.data() ? glslOptions.preprocessorOptions.sourceIdentifier.data() : "", glslOptions.entryPoint.data(), shadercOptions);
155+
shaderc::SpvCompilationResult bin_res = comp.CompileGlslToSpv(newCode.c_str(), newCode.size(), stage, glslOptions.preprocessorOptions.sourceIdentifier.data() ? glslOptions.preprocessorOptions.sourceIdentifier.data() : "", "main", shadercOptions);
159156

160157
if (bin_res.GetCompilationStatus() == shaderc_compilation_status_success)
161158
{

0 commit comments

Comments
 (0)