• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "glslang/Public/ResourceLimits.h"
37 #include "glslang/Include/ShHandle.h"
38 
39 #include "glslang/Include/ResourceLimits.h"
40 #include "glslang/MachineIndependent/Versions.h"
41 #include "glslang/MachineIndependent/localintermediate.h"
42 
43 static_assert(int(GLSLANG_STAGE_COUNT) == EShLangCount, "");
44 static_assert(int(GLSLANG_STAGE_MASK_COUNT) == EShLanguageMaskCount, "");
45 static_assert(int(GLSLANG_SOURCE_COUNT) == glslang::EShSourceCount, "");
46 static_assert(int(GLSLANG_CLIENT_COUNT) == glslang::EShClientCount, "");
47 static_assert(int(GLSLANG_TARGET_COUNT) == glslang::EShTargetCount, "");
48 static_assert(int(GLSLANG_TARGET_CLIENT_VERSION_COUNT) == glslang::EShTargetClientVersionCount, "");
49 static_assert(int(GLSLANG_TARGET_LANGUAGE_VERSION_COUNT) == glslang::EShTargetLanguageVersionCount, "");
50 static_assert(int(GLSLANG_OPT_LEVEL_COUNT) == EshOptLevelCount, "");
51 static_assert(int(GLSLANG_TEX_SAMP_TRANS_COUNT) == EShTexSampTransCount, "");
52 static_assert(int(GLSLANG_MSG_COUNT) == EShMsgCount, "");
53 static_assert(int(GLSLANG_REFLECTION_COUNT) == EShReflectionCount, "");
54 static_assert(int(GLSLANG_PROFILE_COUNT) == EProfileCount, "");
55 static_assert(sizeof(glslang_limits_t) == sizeof(TLimits), "");
56 static_assert(sizeof(glslang_resource_t) == sizeof(TBuiltInResource), "");
57 
58 typedef struct glslang_shader_s {
59     glslang::TShader* shader;
60     std::string preprocessedGLSL;
61 } glslang_shader_t;
62 
63 typedef struct glslang_program_s {
64     glslang::TProgram* program;
65     std::vector<unsigned int> spirv;
66     std::string loggerMessages;
67 } glslang_program_t;
68 
69 /* Wrapper/Adapter for C glsl_include_callbacks_t functions
70 
71    This class contains a 'glsl_include_callbacks_t' structure
72    with C include_local/include_system callback pointers.
73 
74    This class implement TShader::Includer interface
75    by redirecting C++ virtual methods to C callbacks.
76 
77    The 'IncludeResult' instances produced by this Includer
78    contain a reference to glsl_include_result_t C structure
79    to allow its lifetime management by another C callback
80    (CallbackIncluder::callbacks::free_include_result)
81 */
82 class CallbackIncluder : public glslang::TShader::Includer {
83 public:
84     /* Wrapper of IncludeResult which stores a glsl_include_result object internally */
85     class CallbackIncludeResult : public glslang::TShader::Includer::IncludeResult {
86     public:
CallbackIncludeResult(const std::string & headerName,const char * const headerData,const size_t headerLength,void * userData,glsl_include_result_t * includeResult)87         CallbackIncludeResult(const std::string& headerName, const char* const headerData, const size_t headerLength,
88                               void* userData, glsl_include_result_t* includeResult)
89             : glslang::TShader::Includer::IncludeResult(headerName, headerData, headerLength, userData),
90               includeResult(includeResult)
91         {
92         }
93 
~CallbackIncludeResult()94         virtual ~CallbackIncludeResult() {}
95 
96     protected:
97         friend class CallbackIncluder;
98 
99         glsl_include_result_t* includeResult;
100     };
101 
102 public:
CallbackIncluder(glsl_include_callbacks_t _callbacks,void * _context)103     CallbackIncluder(glsl_include_callbacks_t _callbacks, void* _context) : callbacks(_callbacks), context(_context) {}
104 
~CallbackIncluder()105     virtual ~CallbackIncluder() {}
106 
includeSystem(const char * headerName,const char * includerName,size_t inclusionDepth)107     virtual IncludeResult* includeSystem(const char* headerName, const char* includerName,
108                                          size_t inclusionDepth) override
109     {
110         if (this->callbacks.include_system) {
111             glsl_include_result_t* result =
112                 this->callbacks.include_system(this->context, headerName, includerName, inclusionDepth);
113 
114             return new CallbackIncludeResult(std::string(headerName), result->header_data, result->header_length,
115                                              nullptr, result);
116         }
117 
118         return glslang::TShader::Includer::includeSystem(headerName, includerName, inclusionDepth);
119     }
120 
includeLocal(const char * headerName,const char * includerName,size_t inclusionDepth)121     virtual IncludeResult* includeLocal(const char* headerName, const char* includerName,
122                                         size_t inclusionDepth) override
123     {
124         if (this->callbacks.include_local) {
125             glsl_include_result_t* result =
126                 this->callbacks.include_local(this->context, headerName, includerName, inclusionDepth);
127 
128             return new CallbackIncludeResult(std::string(headerName), result->header_data, result->header_length,
129                                              nullptr, result);
130         }
131 
132         return glslang::TShader::Includer::includeLocal(headerName, includerName, inclusionDepth);
133     }
134 
135     /* This function only calls free_include_result callback
136        when the IncludeResult instance is allocated by a C function */
releaseInclude(IncludeResult * result)137     virtual void releaseInclude(IncludeResult* result) override
138     {
139         if (result == nullptr)
140             return;
141 
142         if (this->callbacks.free_include_result && (result->userData == nullptr)) {
143             CallbackIncludeResult* innerResult = static_cast<CallbackIncludeResult*>(result);
144             /* use internal free() function */
145             this->callbacks.free_include_result(this->context, innerResult->includeResult);
146             /* ignore internal fields of TShader::Includer::IncludeResult */
147             delete result;
148             return;
149         }
150 
151         delete[] static_cast<char*>(result->userData);
152         delete result;
153     }
154 
155 private:
CallbackIncluder()156     CallbackIncluder() {}
157 
158     /* C callback pointers */
159     glsl_include_callbacks_t callbacks;
160     /* User-defined context */
161     void* context;
162 };
163 
glslang_initialize_process()164 GLSLANG_EXPORT int glslang_initialize_process() { return static_cast<int>(glslang::InitializeProcess()); }
165 
glslang_finalize_process()166 GLSLANG_EXPORT void glslang_finalize_process() { glslang::FinalizeProcess(); }
167 
c_shader_stage(glslang_stage_t stage)168 static EShLanguage c_shader_stage(glslang_stage_t stage)
169 {
170     switch (stage) {
171     case GLSLANG_STAGE_VERTEX:
172         return EShLangVertex;
173     case GLSLANG_STAGE_TESSCONTROL:
174         return EShLangTessControl;
175     case GLSLANG_STAGE_TESSEVALUATION:
176         return EShLangTessEvaluation;
177     case GLSLANG_STAGE_GEOMETRY:
178         return EShLangGeometry;
179     case GLSLANG_STAGE_FRAGMENT:
180         return EShLangFragment;
181     case GLSLANG_STAGE_COMPUTE:
182         return EShLangCompute;
183     case GLSLANG_STAGE_RAYGEN_NV:
184         return EShLangRayGen;
185     case GLSLANG_STAGE_INTERSECT_NV:
186         return EShLangIntersect;
187     case GLSLANG_STAGE_ANYHIT_NV:
188         return EShLangAnyHit;
189     case GLSLANG_STAGE_CLOSESTHIT_NV:
190         return EShLangClosestHit;
191     case GLSLANG_STAGE_MISS_NV:
192         return EShLangMiss;
193     case GLSLANG_STAGE_CALLABLE_NV:
194         return EShLangCallable;
195     case GLSLANG_STAGE_TASK:
196         return EShLangTask;
197     case GLSLANG_STAGE_MESH:
198         return EShLangMesh;
199     default:
200         break;
201     }
202     return EShLangCount;
203 }
204 
c_shader_messages(glslang_messages_t messages)205 static int c_shader_messages(glslang_messages_t messages)
206 {
207 #define CONVERT_MSG(in, out)                                                                                           \
208     if ((messages & in) == in)                                                                                         \
209         res |= out;
210 
211     int res = 0;
212 
213     CONVERT_MSG(GLSLANG_MSG_RELAXED_ERRORS_BIT, EShMsgRelaxedErrors);
214     CONVERT_MSG(GLSLANG_MSG_SUPPRESS_WARNINGS_BIT, EShMsgSuppressWarnings);
215     CONVERT_MSG(GLSLANG_MSG_AST_BIT, EShMsgAST);
216     CONVERT_MSG(GLSLANG_MSG_SPV_RULES_BIT, EShMsgSpvRules);
217     CONVERT_MSG(GLSLANG_MSG_VULKAN_RULES_BIT, EShMsgVulkanRules);
218     CONVERT_MSG(GLSLANG_MSG_ONLY_PREPROCESSOR_BIT, EShMsgOnlyPreprocessor);
219     CONVERT_MSG(GLSLANG_MSG_READ_HLSL_BIT, EShMsgReadHlsl);
220     CONVERT_MSG(GLSLANG_MSG_CASCADING_ERRORS_BIT, EShMsgCascadingErrors);
221     CONVERT_MSG(GLSLANG_MSG_KEEP_UNCALLED_BIT, EShMsgKeepUncalled);
222     CONVERT_MSG(GLSLANG_MSG_HLSL_OFFSETS_BIT, EShMsgHlslOffsets);
223     CONVERT_MSG(GLSLANG_MSG_DEBUG_INFO_BIT, EShMsgDebugInfo);
224     CONVERT_MSG(GLSLANG_MSG_HLSL_ENABLE_16BIT_TYPES_BIT, EShMsgHlslEnable16BitTypes);
225     CONVERT_MSG(GLSLANG_MSG_HLSL_LEGALIZATION_BIT, EShMsgHlslLegalization);
226     CONVERT_MSG(GLSLANG_MSG_HLSL_DX9_COMPATIBLE_BIT, EShMsgHlslDX9Compatible);
227     CONVERT_MSG(GLSLANG_MSG_BUILTIN_SYMBOL_TABLE_BIT, EShMsgBuiltinSymbolTable);
228     return res;
229 #undef CONVERT_MSG
230 }
231 
232 static glslang::EShTargetLanguageVersion
c_shader_target_language_version(glslang_target_language_version_t target_language_version)233 c_shader_target_language_version(glslang_target_language_version_t target_language_version)
234 {
235     switch (target_language_version) {
236     case GLSLANG_TARGET_SPV_1_0:
237         return glslang::EShTargetSpv_1_0;
238     case GLSLANG_TARGET_SPV_1_1:
239         return glslang::EShTargetSpv_1_1;
240     case GLSLANG_TARGET_SPV_1_2:
241         return glslang::EShTargetSpv_1_2;
242     case GLSLANG_TARGET_SPV_1_3:
243         return glslang::EShTargetSpv_1_3;
244     case GLSLANG_TARGET_SPV_1_4:
245         return glslang::EShTargetSpv_1_4;
246     case GLSLANG_TARGET_SPV_1_5:
247         return glslang::EShTargetSpv_1_5;
248     case GLSLANG_TARGET_SPV_1_6:
249         return glslang::EShTargetSpv_1_6;
250     default:
251         break;
252     }
253     return glslang::EShTargetSpv_1_0;
254 }
255 
c_shader_client(glslang_client_t client)256 static glslang::EShClient c_shader_client(glslang_client_t client)
257 {
258     switch (client) {
259     case GLSLANG_CLIENT_VULKAN:
260         return glslang::EShClientVulkan;
261     case GLSLANG_CLIENT_OPENGL:
262         return glslang::EShClientOpenGL;
263     default:
264         break;
265     }
266 
267     return glslang::EShClientNone;
268 }
269 
c_shader_client_version(glslang_target_client_version_t client_version)270 static glslang::EShTargetClientVersion c_shader_client_version(glslang_target_client_version_t client_version)
271 {
272     switch (client_version) {
273     case GLSLANG_TARGET_VULKAN_1_1:
274         return glslang::EShTargetVulkan_1_1;
275     case GLSLANG_TARGET_VULKAN_1_2:
276         return glslang::EShTargetVulkan_1_2;
277     case GLSLANG_TARGET_VULKAN_1_3:
278         return glslang::EShTargetVulkan_1_3;
279     case GLSLANG_TARGET_OPENGL_450:
280         return glslang::EShTargetOpenGL_450;
281     default:
282         break;
283     }
284 
285     return glslang::EShTargetVulkan_1_0;
286 }
287 
c_shader_target_language(glslang_target_language_t target_language)288 static glslang::EShTargetLanguage c_shader_target_language(glslang_target_language_t target_language)
289 {
290     if (target_language == GLSLANG_TARGET_NONE)
291         return glslang::EShTargetNone;
292 
293     return glslang::EShTargetSpv;
294 }
295 
c_shader_source(glslang_source_t source)296 static glslang::EShSource c_shader_source(glslang_source_t source)
297 {
298     switch (source) {
299     case GLSLANG_SOURCE_GLSL:
300         return glslang::EShSourceGlsl;
301     case GLSLANG_SOURCE_HLSL:
302         return glslang::EShSourceHlsl;
303     default:
304         break;
305     }
306 
307     return glslang::EShSourceNone;
308 }
309 
c_shader_profile(glslang_profile_t profile)310 static EProfile c_shader_profile(glslang_profile_t profile)
311 {
312     switch (profile) {
313     case GLSLANG_BAD_PROFILE:
314         return EBadProfile;
315     case GLSLANG_NO_PROFILE:
316         return ENoProfile;
317     case GLSLANG_CORE_PROFILE:
318         return ECoreProfile;
319     case GLSLANG_COMPATIBILITY_PROFILE:
320         return ECompatibilityProfile;
321     case GLSLANG_ES_PROFILE:
322         return EEsProfile;
323     case GLSLANG_PROFILE_COUNT: // Should not use this
324         break;
325     }
326 
327     return EProfile();
328 }
329 
glslang_shader_create(const glslang_input_t * input)330 GLSLANG_EXPORT glslang_shader_t* glslang_shader_create(const glslang_input_t* input)
331 {
332     if (!input || !input->code) {
333         printf("Error creating shader: null input(%p)/input->code\n", input);
334 
335         if (input)
336             printf("input->code = %p\n", input->code);
337 
338         return nullptr;
339     }
340 
341     glslang_shader_t* shader = new glslang_shader_t();
342 
343     shader->shader = new glslang::TShader(c_shader_stage(input->stage));
344     shader->shader->setStrings(&input->code, 1);
345     shader->shader->setEnvInput(c_shader_source(input->language), c_shader_stage(input->stage),
346                                 c_shader_client(input->client), input->default_version);
347     shader->shader->setEnvClient(c_shader_client(input->client), c_shader_client_version(input->client_version));
348     shader->shader->setEnvTarget(c_shader_target_language(input->target_language),
349                                  c_shader_target_language_version(input->target_language_version));
350 
351     return shader;
352 }
353 
glslang_shader_set_preamble(glslang_shader_t * shader,const char * s)354 GLSLANG_EXPORT void glslang_shader_set_preamble(glslang_shader_t* shader, const char* s) {
355     shader->shader->setPreamble(s);
356 }
357 
glslang_shader_shift_binding(glslang_shader_t * shader,glslang_resource_type_t res,unsigned int base)358 GLSLANG_EXPORT void glslang_shader_shift_binding(glslang_shader_t* shader, glslang_resource_type_t res, unsigned int base)
359 {
360     const glslang::TResourceType res_type = glslang::TResourceType(res);
361     shader->shader->setShiftBinding(res_type, base);
362 }
363 
glslang_shader_shift_binding_for_set(glslang_shader_t * shader,glslang_resource_type_t res,unsigned int base,unsigned int set)364 GLSLANG_EXPORT void glslang_shader_shift_binding_for_set(glslang_shader_t* shader, glslang_resource_type_t res, unsigned int base, unsigned int set)
365 {
366     const glslang::TResourceType res_type = glslang::TResourceType(res);
367     shader->shader->setShiftBindingForSet(res_type, base, set);
368 }
369 
glslang_shader_set_options(glslang_shader_t * shader,int options)370 GLSLANG_EXPORT void glslang_shader_set_options(glslang_shader_t* shader, int options)
371 {
372     if (options & GLSLANG_SHADER_AUTO_MAP_BINDINGS) {
373         shader->shader->setAutoMapBindings(true);
374     }
375 
376     if (options & GLSLANG_SHADER_AUTO_MAP_LOCATIONS) {
377         shader->shader->setAutoMapLocations(true);
378     }
379 
380     if (options & GLSLANG_SHADER_VULKAN_RULES_RELAXED) {
381         shader->shader->setEnvInputVulkanRulesRelaxed();
382     }
383 }
384 
glslang_shader_set_glsl_version(glslang_shader_t * shader,int version)385 GLSLANG_EXPORT void glslang_shader_set_glsl_version(glslang_shader_t* shader, int version)
386 {
387     shader->shader->setOverrideVersion(version);
388 }
389 
glslang_shader_get_preprocessed_code(glslang_shader_t * shader)390 GLSLANG_EXPORT const char* glslang_shader_get_preprocessed_code(glslang_shader_t* shader)
391 {
392     return shader->preprocessedGLSL.c_str();
393 }
394 
glslang_shader_preprocess(glslang_shader_t * shader,const glslang_input_t * input)395 GLSLANG_EXPORT int glslang_shader_preprocess(glslang_shader_t* shader, const glslang_input_t* input)
396 {
397     DirStackFileIncluder Includer;
398     /* TODO: use custom callbacks if they are available in 'i->callbacks' */
399     return shader->shader->preprocess(
400         reinterpret_cast<const TBuiltInResource*>(input->resource),
401         input->default_version,
402         c_shader_profile(input->default_profile),
403         input->force_default_version_and_profile != 0,
404         input->forward_compatible != 0,
405         (EShMessages)c_shader_messages(input->messages),
406         &shader->preprocessedGLSL,
407         Includer
408     );
409 }
410 
glslang_shader_parse(glslang_shader_t * shader,const glslang_input_t * input)411 GLSLANG_EXPORT int glslang_shader_parse(glslang_shader_t* shader, const glslang_input_t* input)
412 {
413     const char* preprocessedCStr = shader->preprocessedGLSL.c_str();
414     shader->shader->setStrings(&preprocessedCStr, 1);
415 
416     return shader->shader->parse(
417         reinterpret_cast<const TBuiltInResource*>(input->resource),
418         input->default_version,
419         input->forward_compatible != 0,
420         (EShMessages)c_shader_messages(input->messages)
421     );
422 }
423 
glslang_shader_get_info_log(glslang_shader_t * shader)424 GLSLANG_EXPORT const char* glslang_shader_get_info_log(glslang_shader_t* shader) { return shader->shader->getInfoLog(); }
425 
glslang_shader_get_info_debug_log(glslang_shader_t * shader)426 GLSLANG_EXPORT const char* glslang_shader_get_info_debug_log(glslang_shader_t* shader) { return shader->shader->getInfoDebugLog(); }
427 
glslang_shader_delete(glslang_shader_t * shader)428 GLSLANG_EXPORT void glslang_shader_delete(glslang_shader_t* shader)
429 {
430     if (!shader)
431         return;
432 
433     delete (shader->shader);
434     delete (shader);
435 }
436 
glslang_program_create()437 GLSLANG_EXPORT glslang_program_t* glslang_program_create()
438 {
439     glslang_program_t* p = new glslang_program_t();
440     p->program = new glslang::TProgram();
441     return p;
442 }
443 
glslang_program_delete(glslang_program_t * program)444 GLSLANG_EXPORT void glslang_program_delete(glslang_program_t* program)
445 {
446     if (!program)
447         return;
448 
449     delete (program->program);
450     delete (program);
451 }
452 
glslang_program_add_shader(glslang_program_t * program,glslang_shader_t * shader)453 GLSLANG_EXPORT void glslang_program_add_shader(glslang_program_t* program, glslang_shader_t* shader)
454 {
455     program->program->addShader(shader->shader);
456 }
457 
glslang_program_link(glslang_program_t * program,int messages)458 GLSLANG_EXPORT int glslang_program_link(glslang_program_t* program, int messages)
459 {
460     return (int)program->program->link((EShMessages)messages);
461 }
462 
glslang_program_add_source_text(glslang_program_t * program,glslang_stage_t stage,const char * text,size_t len)463 GLSLANG_EXPORT void glslang_program_add_source_text(glslang_program_t* program, glslang_stage_t stage, const char* text, size_t len) {
464     glslang::TIntermediate* intermediate = program->program->getIntermediate(c_shader_stage(stage));
465     intermediate->addSourceText(text, len);
466 }
467 
glslang_program_set_source_file(glslang_program_t * program,glslang_stage_t stage,const char * file)468 GLSLANG_EXPORT void glslang_program_set_source_file(glslang_program_t* program, glslang_stage_t stage, const char* file) {
469     glslang::TIntermediate* intermediate = program->program->getIntermediate(c_shader_stage(stage));
470     intermediate->setSourceFile(file);
471 }
472 
glslang_program_map_io(glslang_program_t * program)473 GLSLANG_EXPORT int glslang_program_map_io(glslang_program_t* program)
474 {
475     return (int)program->program->mapIO();
476 }
477 
glslang_program_get_info_log(glslang_program_t * program)478 GLSLANG_EXPORT const char* glslang_program_get_info_log(glslang_program_t* program)
479 {
480     return program->program->getInfoLog();
481 }
482 
glslang_program_get_info_debug_log(glslang_program_t * program)483 GLSLANG_EXPORT const char* glslang_program_get_info_debug_log(glslang_program_t* program)
484 {
485     return program->program->getInfoDebugLog();
486 }
487