Improve ResourceLimits interface to be more forward compatible
[platform/upstream/glslang.git] / glslang / CInterface / glslang_c_interface.cpp
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:
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
94         virtual ~CallbackIncludeResult() {}
95
96     protected:
97         friend class CallbackIncluder;
98
99         glsl_include_result_t* includeResult;
100     };
101
102 public:
103     CallbackIncluder(glsl_include_callbacks_t _callbacks, void* _context) : callbacks(_callbacks), context(_context) {}
104
105     virtual ~CallbackIncluder() {}
106
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
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 */
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:
156     CallbackIncluder() {}
157
158     /* C callback pointers */
159     glsl_include_callbacks_t callbacks;
160     /* User-defined context */
161     void* context;
162 };
163
164 GLSLANG_EXPORT int glslang_initialize_process() { return static_cast<int>(glslang::InitializeProcess()); }
165
166 GLSLANG_EXPORT void glslang_finalize_process() { glslang::FinalizeProcess(); }
167
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
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
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
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
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
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
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
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
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
354 GLSLANG_EXPORT void glslang_shader_set_preamble(glslang_shader_t* shader, const char* s) {
355     shader->shader->setPreamble(s);
356 }
357
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
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
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
385 GLSLANG_EXPORT void glslang_shader_set_glsl_version(glslang_shader_t* shader, int version)
386 {
387     shader->shader->setOverrideVersion(version);
388 }
389
390 GLSLANG_EXPORT const char* glslang_shader_get_preprocessed_code(glslang_shader_t* shader)
391 {
392     return shader->preprocessedGLSL.c_str();
393 }
394
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
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
424 GLSLANG_EXPORT const char* glslang_shader_get_info_log(glslang_shader_t* shader) { return shader->shader->getInfoLog(); }
425
426 GLSLANG_EXPORT const char* glslang_shader_get_info_debug_log(glslang_shader_t* shader) { return shader->shader->getInfoDebugLog(); }
427
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
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
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
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
458 GLSLANG_EXPORT int glslang_program_link(glslang_program_t* program, int messages)
459 {
460     return (int)program->program->link((EShMessages)messages);
461 }
462
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
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
473 GLSLANG_EXPORT int glslang_program_map_io(glslang_program_t* program)
474 {
475     return (int)program->program->mapIO();
476 }
477
478 GLSLANG_EXPORT const char* glslang_program_get_info_log(glslang_program_t* program)
479 {
480     return program->program->getInfoLog();
481 }
482
483 GLSLANG_EXPORT const char* glslang_program_get_info_debug_log(glslang_program_t* program)
484 {
485     return program->program->getInfoDebugLog();
486 }