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