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