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