1 /**
2 This code is based on the glslang_c_interface implementation by Viktor Latypov
3 **/
4
5 /**
6 BSD 2-Clause License
7
8 Copyright (c) 2019, Viktor Latypov
9 All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
13
14 1. Redistributions of source code must retain the above copyright notice, this
15 list of conditions and the following disclaimer.
16
17 2. Redistributions in binary form must reproduce the above copyright notice,
18 this list of conditions and the following disclaimer in the documentation
19 and/or other materials provided with the distribution.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **/
32
33 #include "glslang/Include/glslang_c_interface.h"
34
35 #include "StandAlone/DirStackFileIncluder.h"
36 #include "StandAlone/ResourceLimits.h"
37 #include "glslang/Include/ShHandle.h"
38
39 #include "glslang/Include/ResourceLimits.h"
40 #include "glslang/MachineIndependent/Versions.h"
41
42 static_assert(int(GLSLANG_STAGE_COUNT) == EShLangCount, "");
43 static_assert(int(GLSLANG_STAGE_MASK_COUNT) == EShLanguageMaskCount, "");
44 static_assert(int(GLSLANG_SOURCE_COUNT) == glslang::EShSourceCount, "");
45 static_assert(int(GLSLANG_CLIENT_COUNT) == glslang::EShClientCount, "");
46 static_assert(int(GLSLANG_TARGET_COUNT) == glslang::EShTargetCount, "");
47 static_assert(int(GLSLANG_TARGET_CLIENT_VERSION_COUNT) == glslang::EShTargetClientVersionCount, "");
48 static_assert(int(GLSLANG_TARGET_LANGUAGE_VERSION_COUNT) == glslang::EShTargetLanguageVersionCount, "");
49 static_assert(int(GLSLANG_OPT_LEVEL_COUNT) == EshOptLevelCount, "");
50 static_assert(int(GLSLANG_TEX_SAMP_TRANS_COUNT) == EShTexSampTransCount, "");
51 static_assert(int(GLSLANG_MSG_COUNT) == EShMsgCount, "");
52 static_assert(int(GLSLANG_REFLECTION_COUNT) == EShReflectionCount, "");
53 static_assert(int(GLSLANG_PROFILE_COUNT) == EProfileCount, "");
54 static_assert(sizeof(glslang_limits_t) == sizeof(TLimits), "");
55 static_assert(sizeof(glslang_resource_t) == sizeof(TBuiltInResource), "");
56
57 typedef struct glslang_shader_s {
58 glslang::TShader* shader;
59 std::string preprocessedGLSL;
60 } glslang_shader_t;
61
62 typedef struct glslang_program_s {
63 glslang::TProgram* program;
64 std::vector<unsigned int> spirv;
65 std::string loggerMessages;
66 } glslang_program_t;
67
68 /* Wrapper/Adapter for C glsl_include_callbacks_t functions
69
70 This class contains a 'glsl_include_callbacks_t' structure
71 with C include_local/include_system callback pointers.
72
73 This class implement TShader::Includer interface
74 by redirecting C++ virtual methods to C callbacks.
75
76 The 'IncludeResult' instances produced by this Includer
77 contain a reference to glsl_include_result_t C structure
78 to allow its lifetime management by another C callback
79 (CallbackIncluder::callbacks::free_include_result)
80 */
81 class CallbackIncluder : public glslang::TShader::Includer {
82 public:
83 /* Wrapper of IncludeResult which stores a glsl_include_result object internally */
84 class CallbackIncludeResult : public glslang::TShader::Includer::IncludeResult {
85 public:
CallbackIncludeResult(const std::string & headerName,const char * const headerData,const size_t headerLength,void * userData,glsl_include_result_t * includeResult)86 CallbackIncludeResult(const std::string& headerName, const char* const headerData, const size_t headerLength,
87 void* userData, glsl_include_result_t* includeResult)
88 : glslang::TShader::Includer::IncludeResult(headerName, headerData, headerLength, userData),
89 includeResult(includeResult)
90 {
91 }
92
~CallbackIncludeResult()93 virtual ~CallbackIncludeResult() {}
94
95 protected:
96 friend class CallbackIncluder;
97
98 glsl_include_result_t* includeResult;
99 };
100
101 public:
CallbackIncluder(glsl_include_callbacks_t _callbacks,void * _context)102 CallbackIncluder(glsl_include_callbacks_t _callbacks, void* _context) : callbacks(_callbacks), context(_context) {}
103
~CallbackIncluder()104 virtual ~CallbackIncluder() {}
105
includeSystem(const char * headerName,const char * includerName,size_t inclusionDepth)106 virtual IncludeResult* includeSystem(const char* headerName, const char* includerName,
107 size_t inclusionDepth) override
108 {
109 if (this->callbacks.include_system) {
110 glsl_include_result_t* result =
111 this->callbacks.include_system(this->context, headerName, includerName, inclusionDepth);
112
113 return new CallbackIncludeResult(std::string(headerName), result->header_data, result->header_length,
114 nullptr, result);
115 }
116
117 return glslang::TShader::Includer::includeSystem(headerName, includerName, inclusionDepth);
118 }
119
includeLocal(const char * headerName,const char * includerName,size_t inclusionDepth)120 virtual IncludeResult* includeLocal(const char* headerName, const char* includerName,
121 size_t inclusionDepth) override
122 {
123 if (this->callbacks.include_local) {
124 glsl_include_result_t* result =
125 this->callbacks.include_local(this->context, headerName, includerName, inclusionDepth);
126
127 return new CallbackIncludeResult(std::string(headerName), result->header_data, result->header_length,
128 nullptr, result);
129 }
130
131 return glslang::TShader::Includer::includeLocal(headerName, includerName, inclusionDepth);
132 }
133
134 /* This function only calls free_include_result callback
135 when the IncludeResult instance is allocated by a C function */
releaseInclude(IncludeResult * result)136 virtual void releaseInclude(IncludeResult* result) override
137 {
138 if (result == nullptr)
139 return;
140
141 if (this->callbacks.free_include_result && (result->userData == nullptr)) {
142 CallbackIncludeResult* innerResult = static_cast<CallbackIncludeResult*>(result);
143 /* use internal free() function */
144 this->callbacks.free_include_result(this->context, innerResult->includeResult);
145 /* ignore internal fields of TShader::Includer::IncludeResult */
146 delete result;
147 return;
148 }
149
150 delete[] static_cast<char*>(result->userData);
151 delete result;
152 }
153
154 private:
CallbackIncluder()155 CallbackIncluder() {}
156
157 /* C callback pointers */
158 glsl_include_callbacks_t callbacks;
159 /* User-defined context */
160 void* context;
161 };
162
glslang_initialize_process()163 GLSLANG_EXPORT int glslang_initialize_process() { return static_cast<int>(glslang::InitializeProcess()); }
164
glslang_finalize_process()165 GLSLANG_EXPORT void glslang_finalize_process() { glslang::FinalizeProcess(); }
166
c_shader_stage(glslang_stage_t stage)167 static EShLanguage c_shader_stage(glslang_stage_t stage)
168 {
169 switch (stage) {
170 case GLSLANG_STAGE_VERTEX:
171 return EShLangVertex;
172 case GLSLANG_STAGE_TESSCONTROL:
173 return EShLangTessControl;
174 case GLSLANG_STAGE_TESSEVALUATION:
175 return EShLangTessEvaluation;
176 case GLSLANG_STAGE_GEOMETRY:
177 return EShLangGeometry;
178 case GLSLANG_STAGE_FRAGMENT:
179 return EShLangFragment;
180 case GLSLANG_STAGE_COMPUTE:
181 return EShLangCompute;
182 case GLSLANG_STAGE_RAYGEN_NV:
183 return EShLangRayGen;
184 case GLSLANG_STAGE_INTERSECT_NV:
185 return EShLangIntersect;
186 case GLSLANG_STAGE_ANYHIT_NV:
187 return EShLangAnyHit;
188 case GLSLANG_STAGE_CLOSESTHIT_NV:
189 return EShLangClosestHit;
190 case GLSLANG_STAGE_MISS_NV:
191 return EShLangMiss;
192 case GLSLANG_STAGE_CALLABLE_NV:
193 return EShLangCallable;
194 case GLSLANG_STAGE_TASK_NV:
195 return EShLangTaskNV;
196 case GLSLANG_STAGE_MESH_NV:
197 return EShLangMeshNV;
198 default:
199 break;
200 }
201 return EShLangCount;
202 }
203
c_shader_messages(glslang_messages_t messages)204 static int c_shader_messages(glslang_messages_t messages)
205 {
206 #define CONVERT_MSG(in, out) \
207 if ((messages & in) == in) \
208 res |= out;
209
210 int res = 0;
211
212 CONVERT_MSG(GLSLANG_MSG_RELAXED_ERRORS_BIT, EShMsgRelaxedErrors);
213 CONVERT_MSG(GLSLANG_MSG_SUPPRESS_WARNINGS_BIT, EShMsgSuppressWarnings);
214 CONVERT_MSG(GLSLANG_MSG_AST_BIT, EShMsgAST);
215 CONVERT_MSG(GLSLANG_MSG_SPV_RULES_BIT, EShMsgSpvRules);
216 CONVERT_MSG(GLSLANG_MSG_VULKAN_RULES_BIT, EShMsgVulkanRules);
217 CONVERT_MSG(GLSLANG_MSG_ONLY_PREPROCESSOR_BIT, EShMsgOnlyPreprocessor);
218 CONVERT_MSG(GLSLANG_MSG_READ_HLSL_BIT, EShMsgReadHlsl);
219 CONVERT_MSG(GLSLANG_MSG_CASCADING_ERRORS_BIT, EShMsgCascadingErrors);
220 CONVERT_MSG(GLSLANG_MSG_KEEP_UNCALLED_BIT, EShMsgKeepUncalled);
221 CONVERT_MSG(GLSLANG_MSG_HLSL_OFFSETS_BIT, EShMsgHlslOffsets);
222 CONVERT_MSG(GLSLANG_MSG_DEBUG_INFO_BIT, EShMsgDebugInfo);
223 CONVERT_MSG(GLSLANG_MSG_HLSL_ENABLE_16BIT_TYPES_BIT, EShMsgHlslEnable16BitTypes);
224 CONVERT_MSG(GLSLANG_MSG_HLSL_LEGALIZATION_BIT, EShMsgHlslLegalization);
225 CONVERT_MSG(GLSLANG_MSG_HLSL_DX9_COMPATIBLE_BIT, EShMsgHlslDX9Compatible);
226 CONVERT_MSG(GLSLANG_MSG_BUILTIN_SYMBOL_TABLE_BIT, EShMsgBuiltinSymbolTable);
227 return res;
228 #undef CONVERT_MSG
229 }
230
231 static glslang::EShTargetLanguageVersion
c_shader_target_language_version(glslang_target_language_version_t target_language_version)232 c_shader_target_language_version(glslang_target_language_version_t target_language_version)
233 {
234 switch (target_language_version) {
235 case GLSLANG_TARGET_SPV_1_0:
236 return glslang::EShTargetSpv_1_0;
237 case GLSLANG_TARGET_SPV_1_1:
238 return glslang::EShTargetSpv_1_1;
239 case GLSLANG_TARGET_SPV_1_2:
240 return glslang::EShTargetSpv_1_2;
241 case GLSLANG_TARGET_SPV_1_3:
242 return glslang::EShTargetSpv_1_3;
243 case GLSLANG_TARGET_SPV_1_4:
244 return glslang::EShTargetSpv_1_4;
245 case GLSLANG_TARGET_SPV_1_5:
246 return glslang::EShTargetSpv_1_5;
247 default:
248 break;
249 }
250 return glslang::EShTargetSpv_1_0;
251 }
252
c_shader_client(glslang_client_t client)253 static glslang::EShClient c_shader_client(glslang_client_t client)
254 {
255 switch (client) {
256 case GLSLANG_CLIENT_VULKAN:
257 return glslang::EShClientVulkan;
258 case GLSLANG_CLIENT_OPENGL:
259 return glslang::EShClientOpenGL;
260 default:
261 break;
262 }
263
264 return glslang::EShClientNone;
265 }
266
c_shader_client_version(glslang_target_client_version_t client_version)267 static glslang::EShTargetClientVersion c_shader_client_version(glslang_target_client_version_t client_version)
268 {
269 switch (client_version) {
270 case GLSLANG_TARGET_VULKAN_1_1:
271 return glslang::EShTargetVulkan_1_1;
272 case GLSLANG_TARGET_OPENGL_450:
273 return glslang::EShTargetOpenGL_450;
274 default:
275 break;
276 }
277
278 return glslang::EShTargetVulkan_1_0;
279 }
280
c_shader_target_language(glslang_target_language_t target_language)281 static glslang::EShTargetLanguage c_shader_target_language(glslang_target_language_t target_language)
282 {
283 if (target_language == GLSLANG_TARGET_NONE)
284 return glslang::EShTargetNone;
285
286 return glslang::EShTargetSpv;
287 }
288
c_shader_source(glslang_source_t source)289 static glslang::EShSource c_shader_source(glslang_source_t source)
290 {
291 switch (source) {
292 case GLSLANG_SOURCE_GLSL:
293 return glslang::EShSourceGlsl;
294 case GLSLANG_SOURCE_HLSL:
295 return glslang::EShSourceHlsl;
296 default:
297 break;
298 }
299
300 return glslang::EShSourceNone;
301 }
302
c_shader_profile(glslang_profile_t profile)303 static EProfile c_shader_profile(glslang_profile_t profile)
304 {
305 switch (profile) {
306 case GLSLANG_BAD_PROFILE:
307 return EBadProfile;
308 case GLSLANG_NO_PROFILE:
309 return ENoProfile;
310 case GLSLANG_CORE_PROFILE:
311 return ECoreProfile;
312 case GLSLANG_COMPATIBILITY_PROFILE:
313 return ECompatibilityProfile;
314 case GLSLANG_ES_PROFILE:
315 return EEsProfile;
316 case GLSLANG_PROFILE_COUNT: // Should not use this
317 break;
318 }
319
320 return EProfile();
321 }
322
glslang_shader_create(const glslang_input_t * input)323 GLSLANG_EXPORT glslang_shader_t* glslang_shader_create(const glslang_input_t* input)
324 {
325 if (!input || !input->code) {
326 printf("Error creating shader: null input(%p)/input->code\n", input);
327
328 if (input)
329 printf("input->code = %p\n", input->code);
330
331 return nullptr;
332 }
333
334 glslang_shader_t* shader = new glslang_shader_t();
335
336 shader->shader = new glslang::TShader(c_shader_stage(input->stage));
337 shader->shader->setStrings(&input->code, 1);
338 shader->shader->setEnvInput(c_shader_source(input->language), c_shader_stage(input->stage),
339 c_shader_client(input->client), input->default_version);
340 shader->shader->setEnvClient(c_shader_client(input->client), c_shader_client_version(input->client_version));
341 shader->shader->setEnvTarget(c_shader_target_language(input->target_language),
342 c_shader_target_language_version(input->target_language_version));
343
344 return shader;
345 }
346
glslang_shader_get_preprocessed_code(glslang_shader_t * shader)347 GLSLANG_EXPORT const char* glslang_shader_get_preprocessed_code(glslang_shader_t* shader)
348 {
349 return shader->preprocessedGLSL.c_str();
350 }
351
glslang_shader_preprocess(glslang_shader_t * shader,const glslang_input_t * input)352 GLSLANG_EXPORT int glslang_shader_preprocess(glslang_shader_t* shader, const glslang_input_t* input)
353 {
354 DirStackFileIncluder Includer;
355 /* TODO: use custom callbacks if they are available in 'i->callbacks' */
356 return shader->shader->preprocess(
357 reinterpret_cast<const TBuiltInResource*>(input->resource),
358 input->default_version,
359 c_shader_profile(input->default_profile),
360 input->force_default_version_and_profile != 0,
361 input->forward_compatible != 0,
362 (EShMessages)c_shader_messages(input->messages),
363 &shader->preprocessedGLSL,
364 Includer
365 );
366 }
367
glslang_shader_parse(glslang_shader_t * shader,const glslang_input_t * input)368 GLSLANG_EXPORT int glslang_shader_parse(glslang_shader_t* shader, const glslang_input_t* input)
369 {
370 const char* preprocessedCStr = shader->preprocessedGLSL.c_str();
371 shader->shader->setStrings(&preprocessedCStr, 1);
372
373 return shader->shader->parse(
374 reinterpret_cast<const TBuiltInResource*>(input->resource),
375 input->default_version,
376 input->forward_compatible != 0,
377 (EShMessages)c_shader_messages(input->messages)
378 );
379 }
380
glslang_shader_get_info_log(glslang_shader_t * shader)381 GLSLANG_EXPORT const char* glslang_shader_get_info_log(glslang_shader_t* shader) { return shader->shader->getInfoLog(); }
382
glslang_shader_get_info_debug_log(glslang_shader_t * shader)383 GLSLANG_EXPORT const char* glslang_shader_get_info_debug_log(glslang_shader_t* shader) { return shader->shader->getInfoDebugLog(); }
384
glslang_shader_delete(glslang_shader_t * shader)385 GLSLANG_EXPORT void glslang_shader_delete(glslang_shader_t* shader)
386 {
387 if (!shader)
388 return;
389
390 delete (shader->shader);
391 delete (shader);
392 }
393
glslang_program_create()394 GLSLANG_EXPORT glslang_program_t* glslang_program_create()
395 {
396 glslang_program_t* p = new glslang_program_t();
397 p->program = new glslang::TProgram();
398 return p;
399 }
400
glslang_program_delete(glslang_program_t * program)401 GLSLANG_EXPORT void glslang_program_delete(glslang_program_t* program)
402 {
403 if (!program)
404 return;
405
406 delete (program->program);
407 delete (program);
408 }
409
glslang_program_add_shader(glslang_program_t * program,glslang_shader_t * shader)410 GLSLANG_EXPORT void glslang_program_add_shader(glslang_program_t* program, glslang_shader_t* shader)
411 {
412 program->program->addShader(shader->shader);
413 }
414
glslang_program_link(glslang_program_t * program,int messages)415 GLSLANG_EXPORT int glslang_program_link(glslang_program_t* program, int messages)
416 {
417 return (int)program->program->link((EShMessages)messages);
418 }
419
glslang_program_get_info_log(glslang_program_t * program)420 GLSLANG_EXPORT const char* glslang_program_get_info_log(glslang_program_t* program)
421 {
422 return program->program->getInfoLog();
423 }
424
glslang_program_get_info_debug_log(glslang_program_t * program)425 GLSLANG_EXPORT const char* glslang_program_get_info_debug_log(glslang_program_t* program)
426 {
427 return program->program->getInfoDebugLog();
428 }
429