@@ -13,11 +13,123 @@ using namespace nbl;
13
13
using namespace nbl ::asset;
14
14
15
15
16
+ namespace nbl ::asset::impl
17
+ {
18
+ class Includer : public shaderc ::CompileOptions::IncluderInterface
19
+ {
20
+ const IShaderCompiler::CIncludeFinder* m_defaultIncludeFinder;
21
+ const system::ISystem* m_system;
22
+ const uint32_t m_maxInclCnt;
23
+
24
+ public:
25
+ Includer (const IShaderCompiler::CIncludeFinder* _inclFinder, const system::ISystem* _fs, uint32_t _maxInclCnt) : m_defaultIncludeFinder(_inclFinder), m_system(_fs), m_maxInclCnt{ _maxInclCnt } {}
26
+
27
+ // _requesting_source in top level #include's is what shaderc::Compiler's compiling functions get as `input_file_name` parameter
28
+ // so in order for properly working relative #include's (""-type) `input_file_name` has to be path to file from which the GLSL source really come from
29
+ // or at least path to not necessarily existing file whose directory will be base for ""-type #include's resolution
30
+ shaderc_include_result* GetInclude (const char * _requested_source,
31
+ shaderc_include_type _type,
32
+ const char * _requesting_source,
33
+ size_t _include_depth) override
34
+ {
35
+ shaderc_include_result* res = new shaderc_include_result;
36
+ std::string res_str;
37
+
38
+ std::filesystem::path relDir;
39
+ const bool reqFromBuiltin = builtin::hasPathPrefix (_requesting_source);
40
+ const bool reqBuiltin = builtin::hasPathPrefix (_requested_source);
41
+ if (!reqFromBuiltin && !reqBuiltin)
42
+ {
43
+ // While #includ'ing a builtin, one must specify its full path (starting with "nbl/builtin" or "/nbl/builtin").
44
+ // This rule applies also while a builtin is #includ`ing another builtin.
45
+ // While including a filesystem file it must be either absolute path (or relative to any search dir added to asset::iIncludeHandler; <>-type),
46
+ // or path relative to executable's working directory (""-type).
47
+ relDir = std::filesystem::path (_requesting_source).parent_path ();
48
+ }
49
+ std::filesystem::path name = (_type == shaderc_include_type_relative) ? (relDir / _requested_source) : (_requested_source);
50
+
51
+ if (std::filesystem::exists (name) && !reqBuiltin)
52
+ name = std::filesystem::absolute (name);
53
+
54
+ if (_type == shaderc_include_type_relative)
55
+ res_str = m_defaultIncludeFinder->getIncludeRelative (relDir, _requested_source);
56
+ else // shaderc_include_type_standard
57
+ res_str = m_defaultIncludeFinder->getIncludeStandard (relDir, _requested_source);
58
+
59
+ if (!res_str.size ()) {
60
+ const char * error_str = " Could not open file" ;
61
+ res->content_length = strlen (error_str);
62
+ res->content = new char [res->content_length + 1u ];
63
+ strcpy (const_cast <char *>(res->content ), error_str);
64
+ res->source_name_length = 0u ;
65
+ res->source_name = " " ;
66
+ }
67
+ else {
68
+ // 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 ());
71
+
72
+ res->content_length = res_str.size ();
73
+ res->content = new char [res_str.size () + 1u ];
74
+ strcpy (const_cast <char *>(res->content ), res_str.c_str ());
75
+ res->source_name_length = name.native ().size ();
76
+ res->source_name = new char [name.native ().size () + 1u ];
77
+ strcpy (const_cast <char *>(res->source_name ), name.string ().c_str ());
78
+ }
79
+
80
+ return res;
81
+ }
82
+
83
+ void ReleaseInclude (shaderc_include_result* data) override
84
+ {
85
+ if (data->content_length > 0u )
86
+ delete[] data->content ;
87
+ if (data->source_name_length > 0u )
88
+ delete[] data->source_name ;
89
+ delete data;
90
+ }
91
+ };
92
+ }
93
+
16
94
CGLSLCompiler::CGLSLCompiler (core::smart_refctd_ptr<system::ISystem>&& system)
17
95
: IShaderCompiler(std::move(system))
18
96
{
19
97
}
20
98
99
+
100
+
101
+ std::string CGLSLCompiler::preprocessShader (std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions) const
102
+ {
103
+ if (preprocessOptions.extraDefines .size ())
104
+ {
105
+ insertExtraDefines (code, preprocessOptions.extraDefines );
106
+ }
107
+ if (preprocessOptions.includeFinder != nullptr )
108
+ {
109
+ CGLSLCompiler::disableAllDirectivesExceptIncludes (code);// all "#", except those in "#include"/"#version"/"#pragma shader_stage(...)", replaced with `PREPROC_DIRECTIVE_DISABLER`
110
+ shaderc::Compiler comp;
111
+ shaderc::CompileOptions options;
112
+ options.SetTargetSpirv (shaderc_spirv_version_1_6);
113
+
114
+ options.SetIncluder (std::make_unique<impl::Includer>(preprocessOptions.includeFinder , m_system.get (), preprocessOptions.maxSelfInclusionCount + 1u ));// custom #include handler
115
+ const shaderc_shader_kind scstage = stage == IShader::ESS_UNKNOWN ? shaderc_glsl_infer_from_source : ESStoShadercEnum (stage);
116
+ auto res = comp.PreprocessGlsl (code, scstage, preprocessOptions.sourceIdentifier .data (), options);
117
+
118
+ if (res.GetCompilationStatus () != shaderc_compilation_status_success) {
119
+ preprocessOptions.logger .log (res.GetErrorMessage (), system::ILogger::ELL_ERROR);
120
+ return nullptr ;
121
+ }
122
+
123
+ auto resolvedString = std::string (res.cbegin (), std::distance (res.cbegin (), res.cend ()));
124
+ CGLSLCompiler::reenableDirectives (resolvedString);
125
+ return resolvedString;
126
+ }
127
+ else
128
+ {
129
+ return code;
130
+ }
131
+ }
132
+
21
133
core::smart_refctd_ptr<ICPUShader> CGLSLCompiler::compileToSPIRV (const char * code, const IShaderCompiler::SCompilerOptions& options) const
22
134
{
23
135
auto glslOptions = option_cast (options);
0 commit comments