1 // Copyright 2015 The Shaderc Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <cassert>
17 #include <cstdint>
18 #include <memory>
19 #include <sstream>
20 #include <vector>
21 
22 #include "libshaderc_util/compiler.h"
23 #include "libshaderc_util/counting_includer.h"
24 #include "libshaderc_util/resources.h"
25 #include "libshaderc_util/spirv_tools_wrapper.h"
26 #include "libshaderc_util/version_profile.h"
27 #include "shaderc_private.h"
28 #include "spirv/unified1/spirv.hpp"
29 
30 #if (defined(_MSC_VER) && !defined(_CPPUNWIND)) || !defined(__EXCEPTIONS)
31 #define TRY_IF_EXCEPTIONS_ENABLED
32 #define CATCH_IF_EXCEPTIONS_ENABLED(X) if (0)
33 #else
34 #define TRY_IF_EXCEPTIONS_ENABLED try
35 #define CATCH_IF_EXCEPTIONS_ENABLED(X) catch (X)
36 #endif
37 
38 namespace {
39 
40 // Returns shader stage (ie: vertex, fragment, etc.) in response to forced
41 // shader kinds. If the shader kind is not a forced kind, returns EshLangCount
42 // to let #pragma annotation or shader stage deducer determine the stage to
43 // use.
GetForcedStage(shaderc_shader_kind kind)44 EShLanguage GetForcedStage(shaderc_shader_kind kind) {
45   switch (kind) {
46     case shaderc_glsl_vertex_shader:
47       return EShLangVertex;
48     case shaderc_glsl_fragment_shader:
49       return EShLangFragment;
50     case shaderc_glsl_compute_shader:
51       return EShLangCompute;
52     case shaderc_glsl_geometry_shader:
53       return EShLangGeometry;
54     case shaderc_glsl_tess_control_shader:
55       return EShLangTessControl;
56     case shaderc_glsl_tess_evaluation_shader:
57       return EShLangTessEvaluation;
58 
59     case shaderc_glsl_raygen_shader:
60       return EShLangRayGenNV;
61     case shaderc_glsl_anyhit_shader:
62       return EShLangAnyHitNV;
63     case shaderc_glsl_closesthit_shader:
64       return EShLangClosestHitNV;
65     case shaderc_glsl_miss_shader:
66       return EShLangMissNV;
67     case shaderc_glsl_intersection_shader:
68       return EShLangIntersectNV;
69     case shaderc_glsl_callable_shader:
70       return EShLangCallableNV;
71     case shaderc_glsl_task_shader:
72       return EShLangTaskNV;
73     case shaderc_glsl_mesh_shader:
74       return EShLangMeshNV;
75 
76     case shaderc_glsl_infer_from_source:
77     case shaderc_glsl_default_vertex_shader:
78     case shaderc_glsl_default_fragment_shader:
79     case shaderc_glsl_default_compute_shader:
80     case shaderc_glsl_default_geometry_shader:
81     case shaderc_glsl_default_tess_control_shader:
82     case shaderc_glsl_default_tess_evaluation_shader:
83     case shaderc_glsl_default_raygen_shader:
84     case shaderc_glsl_default_anyhit_shader:
85     case shaderc_glsl_default_closesthit_shader:
86     case shaderc_glsl_default_miss_shader:
87     case shaderc_glsl_default_intersection_shader:
88     case shaderc_glsl_default_callable_shader:
89     case shaderc_glsl_default_task_shader:
90     case shaderc_glsl_default_mesh_shader:
91     case shaderc_spirv_assembly:
92       return EShLangCount;
93   }
94   assert(0 && "Unhandled shaderc_shader_kind");
95   return EShLangCount;
96 }
97 
98 // A wrapper functor class to be used as stage deducer for libshaderc_util
99 // Compile() interface. When the given shader kind is one of the default shader
100 // kinds, this functor will be called if #pragma is not found in the source
101 // code. And it returns the corresponding shader stage. When the shader kind is
102 // a forced shader kind, this functor won't be called and it simply returns
103 // EShLangCount to make the syntax correct. When the shader kind is set to
104 // shaderc_glsl_deduce_from_pragma, this functor also returns EShLangCount, but
105 // the compiler should emit error if #pragma annotation is not found in this
106 // case.
107 class StageDeducer {
108  public:
StageDeducer(shaderc_shader_kind kind=shaderc_glsl_infer_from_source)109   explicit StageDeducer(
110       shaderc_shader_kind kind = shaderc_glsl_infer_from_source)
111       : kind_(kind), error_(false){}
112   // The method that underlying glslang will call to determine the shader stage
113   // to be used in current compilation. It is called only when there is neither
114   // forced shader kind (or say stage, in the view of glslang), nor #pragma
115   // annotation in the source code. This method transforms an user defined
116   // 'default' shader kind to the corresponding shader stage. As this is the
117   // last trial to determine the shader stage, failing to find the corresponding
118   // shader stage will record an error.
119   // Note that calling this method more than once during one compilation will
120   // have the error recorded for the previous call been overwriten by the next
121   // call.
operator ()(std::ostream *,const shaderc_util::string_piece &)122   EShLanguage operator()(std::ostream* /*error_stream*/,
123                          const shaderc_util::string_piece& /*error_tag*/) {
124     EShLanguage stage = GetDefaultStage(kind_);
125     if (stage == EShLangCount) {
126       error_ = true;
127     } else {
128       error_ = false;
129     }
130     return stage;
131   }
132 
133   // Returns true if there is error during shader stage deduction.
error() const134   bool error() const { return error_; }
135 
136  private:
137   // Gets the corresponding shader stage for a given 'default' shader kind. All
138   // other kinds are mapped to EShLangCount which should not be used.
GetDefaultStage(shaderc_shader_kind kind) const139   EShLanguage GetDefaultStage(shaderc_shader_kind kind) const {
140     switch (kind) {
141       case shaderc_glsl_vertex_shader:
142       case shaderc_glsl_fragment_shader:
143       case shaderc_glsl_compute_shader:
144       case shaderc_glsl_geometry_shader:
145       case shaderc_glsl_tess_control_shader:
146       case shaderc_glsl_tess_evaluation_shader:
147       case shaderc_glsl_infer_from_source:
148       case shaderc_glsl_raygen_shader:
149       case shaderc_glsl_anyhit_shader:
150       case shaderc_glsl_closesthit_shader:
151       case shaderc_glsl_miss_shader:
152       case shaderc_glsl_intersection_shader:
153       case shaderc_glsl_callable_shader:
154       case shaderc_glsl_task_shader:
155       case shaderc_glsl_mesh_shader:
156         return EShLangCount;
157       case shaderc_glsl_default_vertex_shader:
158         return EShLangVertex;
159       case shaderc_glsl_default_fragment_shader:
160         return EShLangFragment;
161       case shaderc_glsl_default_compute_shader:
162         return EShLangCompute;
163       case shaderc_glsl_default_geometry_shader:
164         return EShLangGeometry;
165       case shaderc_glsl_default_tess_control_shader:
166         return EShLangTessControl;
167       case shaderc_glsl_default_tess_evaluation_shader:
168         return EShLangTessEvaluation;
169       case shaderc_glsl_default_raygen_shader:
170         return EShLangRayGenNV;
171       case shaderc_glsl_default_anyhit_shader:
172         return EShLangAnyHitNV;
173       case shaderc_glsl_default_closesthit_shader:
174         return EShLangClosestHitNV;
175       case shaderc_glsl_default_miss_shader:
176         return EShLangMissNV;
177       case shaderc_glsl_default_intersection_shader:
178         return EShLangIntersectNV;
179       case shaderc_glsl_default_callable_shader:
180         return EShLangCallableNV;
181       case shaderc_glsl_default_task_shader:
182         return EShLangTaskNV;
183       case shaderc_glsl_default_mesh_shader:
184         return EShLangMeshNV;
185       case shaderc_spirv_assembly:
186         return EShLangCount;
187     }
188     assert(0 && "Unhandled shaderc_shader_kind");
189     return EShLangCount;
190   }
191 
192   shaderc_shader_kind kind_;
193   bool error_;
194 };
195 
196 // A bridge between the libshaderc includer and libshaderc_util includer.
197 class InternalFileIncluder : public shaderc_util::CountingIncluder {
198  public:
InternalFileIncluder(const shaderc_include_resolve_fn resolver,const shaderc_include_result_release_fn result_releaser,void * user_data)199   InternalFileIncluder(const shaderc_include_resolve_fn resolver,
200                        const shaderc_include_result_release_fn result_releaser,
201                        void* user_data)
202       : resolver_(resolver),
203         result_releaser_(result_releaser),
204         user_data_(user_data){}
InternalFileIncluder()205   InternalFileIncluder()
206       : resolver_(nullptr), result_releaser_(nullptr), user_data_(nullptr){}
207 
208  private:
209   // Check the validity of the callbacks.
AreValidCallbacks() const210   bool AreValidCallbacks() const {
211     return resolver_ != nullptr && result_releaser_ != nullptr;
212   }
213 
214   // Maps CountingIncluder IncludeType value to a shaderc_include_type
215   // value.
GetIncludeType(IncludeType type)216   shaderc_include_type GetIncludeType(IncludeType type) {
217     switch (type) {
218       case IncludeType::Local:
219         return shaderc_include_type_relative;
220       case IncludeType::System:
221         return shaderc_include_type_standard;
222       default:
223         break;
224     }
225     assert(0 && "Unhandled IncludeType");
226     return shaderc_include_type_relative;
227   }
228 
229   // Resolves an include request for the requested source of the given
230   // type in the context of the specified requesting source.  On success,
231   // returns a newly allocated IncludeResponse containing the fully resolved
232   // name of the requested source and the contents of that source.
233   // On failure, returns a newly allocated IncludeResponse where the
234   // resolved name member is an empty string, and the contents members
235   // contains error details.
include_delegate(const char * requested_source,const char * requesting_source,IncludeType type,size_t include_depth)236   virtual glslang::TShader::Includer::IncludeResult* include_delegate(
237       const char* requested_source, const char* requesting_source,
238       IncludeType type, size_t include_depth) override {
239     if (!AreValidCallbacks()) {
240       static const char kUnexpectedIncludeError[] =
241           "#error unexpected include directive";
242       return new glslang::TShader::Includer::IncludeResult{
243           "", kUnexpectedIncludeError, strlen(kUnexpectedIncludeError),
244           nullptr};
245     }
246     shaderc_include_result* include_result =
247         resolver_(user_data_, requested_source, GetIncludeType(type),
248                   requesting_source, include_depth);
249     // Make a glslang IncludeResult from a shaderc_include_result.  The
250     // user_data member of the IncludeResult is a pointer to the
251     // shaderc_include_result object, so we can later release the latter.
252     return new glslang::TShader::Includer::IncludeResult{
253         std::string(include_result->source_name,
254                     include_result->source_name_length),
255         include_result->content, include_result->content_length,
256         include_result};
257   }
258 
259   // Releases the given IncludeResult.
release_delegate(glslang::TShader::Includer::IncludeResult * result)260   virtual void release_delegate(
261       glslang::TShader::Includer::IncludeResult* result) override {
262     if (result && result_releaser_) {
263       result_releaser_(user_data_,
264                        static_cast<shaderc_include_result*>(result->userData));
265     }
266     delete result;
267   }
268 
269   const shaderc_include_resolve_fn resolver_;
270   const shaderc_include_result_release_fn result_releaser_;
271   void* user_data_;
272 };
273 
274 // Converts the target env to the corresponding one in shaderc_util::Compiler.
GetCompilerTargetEnv(shaderc_target_env env)275 shaderc_util::Compiler::TargetEnv GetCompilerTargetEnv(shaderc_target_env env) {
276   switch (env) {
277     case shaderc_target_env_opengl:
278       return shaderc_util::Compiler::TargetEnv::OpenGL;
279     case shaderc_target_env_opengl_compat:
280       return shaderc_util::Compiler::TargetEnv::OpenGLCompat;
281     case shaderc_target_env_webgpu:
282       assert(false);
283       break;
284     case shaderc_target_env_vulkan:
285     default:
286       break;
287   }
288 
289   return shaderc_util::Compiler::TargetEnv::Vulkan;
290 }
291 
GetCompilerTargetEnvVersion(uint32_t version_number)292 shaderc_util::Compiler::TargetEnvVersion GetCompilerTargetEnvVersion(
293     uint32_t version_number) {
294   using namespace shaderc_util;
295 
296   if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_0) ==
297       version_number) {
298     return Compiler::TargetEnvVersion::Vulkan_1_0;
299   }
300   if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_1) ==
301       version_number) {
302     return Compiler::TargetEnvVersion::Vulkan_1_1;
303   }
304   if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_2) ==
305       version_number) {
306     return Compiler::TargetEnvVersion::Vulkan_1_2;
307   }
308   if (static_cast<uint32_t>(Compiler::TargetEnvVersion::OpenGL_4_5) ==
309       version_number) {
310     return Compiler::TargetEnvVersion::OpenGL_4_5;
311   }
312 
313   return Compiler::TargetEnvVersion::Default;
314 }
315 
316 // Returns the Compiler::Limit enum for the given shaderc_limit enum.
CompilerLimit(shaderc_limit limit)317 shaderc_util::Compiler::Limit CompilerLimit(shaderc_limit limit) {
318   switch (limit) {
319 #define RESOURCE(NAME, FIELD, CNAME) \
320   case shaderc_limit_##CNAME:        \
321     return shaderc_util::Compiler::Limit::NAME;
322 #include "libshaderc_util/resources.inc"
323 #undef RESOURCE
324     default:
325       break;
326   }
327   assert(0 && "Should not have reached here");
328   return static_cast<shaderc_util::Compiler::Limit>(0);
329 }
330 
331 // Returns the Compiler::UniformKind for the given shaderc_uniform_kind.
GetUniformKind(shaderc_uniform_kind kind)332 shaderc_util::Compiler::UniformKind GetUniformKind(shaderc_uniform_kind kind) {
333   switch (kind) {
334     case shaderc_uniform_kind_texture:
335       return shaderc_util::Compiler::UniformKind::Texture;
336     case shaderc_uniform_kind_sampler:
337       return shaderc_util::Compiler::UniformKind::Sampler;
338     case shaderc_uniform_kind_image:
339       return shaderc_util::Compiler::UniformKind::Image;
340     case shaderc_uniform_kind_buffer:
341       return shaderc_util::Compiler::UniformKind::Buffer;
342     case shaderc_uniform_kind_storage_buffer:
343       return shaderc_util::Compiler::UniformKind::StorageBuffer;
344     case shaderc_uniform_kind_unordered_access_view:
345       return shaderc_util::Compiler::UniformKind::UnorderedAccessView;
346   }
347   assert(0 && "Should not have reached here");
348   return static_cast<shaderc_util::Compiler::UniformKind>(0);
349 }
350 
351 // Returns the Compiler::Stage for generic stage values in shaderc_shader_kind.
GetStage(shaderc_shader_kind kind)352 shaderc_util::Compiler::Stage GetStage(shaderc_shader_kind kind) {
353   switch (kind) {
354     case shaderc_vertex_shader:
355       return shaderc_util::Compiler::Stage::Vertex;
356     case shaderc_fragment_shader:
357       return shaderc_util::Compiler::Stage::Fragment;
358     case shaderc_compute_shader:
359       return shaderc_util::Compiler::Stage::Compute;
360     case shaderc_tess_control_shader:
361       return shaderc_util::Compiler::Stage::TessControl;
362     case shaderc_tess_evaluation_shader:
363       return shaderc_util::Compiler::Stage::TessEval;
364     case shaderc_geometry_shader:
365       return shaderc_util::Compiler::Stage::Geometry;
366     default:
367       break;
368   }
369   assert(0 && "Should not have reached here");
370   return static_cast<shaderc_util::Compiler::Stage>(0);
371 }
372 
373 }  // anonymous namespace
374 
375 struct shaderc_compile_options {
376   shaderc_target_env target_env = shaderc_target_env_default;
377   uint32_t target_env_version = 0;
378   shaderc_util::Compiler compiler;
379   shaderc_include_resolve_fn include_resolver = nullptr;
380   shaderc_include_result_release_fn include_result_releaser = nullptr;
381   void* include_user_data = nullptr;
382 };
383 
shaderc_compile_options_initialize()384 shaderc_compile_options_t shaderc_compile_options_initialize() {
385   return new (std::nothrow) shaderc_compile_options;
386 }
387 
shaderc_compile_options_clone(const shaderc_compile_options_t options)388 shaderc_compile_options_t shaderc_compile_options_clone(
389     const shaderc_compile_options_t options) {
390   if (!options) {
391     return shaderc_compile_options_initialize();
392   }
393   return new (std::nothrow) shaderc_compile_options(*options);
394 }
395 
shaderc_compile_options_release(shaderc_compile_options_t options)396 void shaderc_compile_options_release(shaderc_compile_options_t options) {
397   delete options;
398 }
399 
shaderc_compile_options_add_macro_definition(shaderc_compile_options_t options,const char * name,size_t name_length,const char * value,size_t value_length)400 void shaderc_compile_options_add_macro_definition(
401     shaderc_compile_options_t options, const char* name, size_t name_length,
402     const char* value, size_t value_length) {
403   options->compiler.AddMacroDefinition(name, name_length, value, value_length);
404 }
405 
shaderc_compile_options_set_source_language(shaderc_compile_options_t options,shaderc_source_language set_lang)406 void shaderc_compile_options_set_source_language(
407     shaderc_compile_options_t options, shaderc_source_language set_lang) {
408   auto lang = shaderc_util::Compiler::SourceLanguage::GLSL;
409   if (set_lang == shaderc_source_language_hlsl)
410     lang = shaderc_util::Compiler::SourceLanguage::HLSL;
411   options->compiler.SetSourceLanguage(lang);
412 }
413 
shaderc_compile_options_set_generate_debug_info(shaderc_compile_options_t options)414 void shaderc_compile_options_set_generate_debug_info(
415     shaderc_compile_options_t options) {
416   options->compiler.SetGenerateDebugInfo();
417 }
418 
shaderc_compile_options_set_optimization_level(shaderc_compile_options_t options,shaderc_optimization_level level)419 void shaderc_compile_options_set_optimization_level(
420     shaderc_compile_options_t options, shaderc_optimization_level level) {
421   auto opt_level = shaderc_util::Compiler::OptimizationLevel::Zero;
422   switch (level) {
423     case shaderc_optimization_level_size:
424       opt_level = shaderc_util::Compiler::OptimizationLevel::Size;
425       break;
426     case shaderc_optimization_level_performance:
427       opt_level = shaderc_util::Compiler::OptimizationLevel::Performance;
428       break;
429     default:
430       break;
431   }
432 
433   options->compiler.SetOptimizationLevel(opt_level);
434 }
435 
shaderc_compile_options_set_forced_version_profile(shaderc_compile_options_t options,int version,shaderc_profile profile)436 void shaderc_compile_options_set_forced_version_profile(
437     shaderc_compile_options_t options, int version, shaderc_profile profile) {
438   // Transfer the profile parameter from public enum type to glslang internal
439   // enum type. No default case here so that compiler will complain if new enum
440   // member is added later but not handled here.
441   switch (profile) {
442     case shaderc_profile_none:
443       options->compiler.SetForcedVersionProfile(version, ENoProfile);
444       break;
445     case shaderc_profile_core:
446       options->compiler.SetForcedVersionProfile(version, ECoreProfile);
447       break;
448     case shaderc_profile_compatibility:
449       options->compiler.SetForcedVersionProfile(version, ECompatibilityProfile);
450       break;
451     case shaderc_profile_es:
452       options->compiler.SetForcedVersionProfile(version, EEsProfile);
453       break;
454   }
455 }
456 
shaderc_compile_options_set_include_callbacks(shaderc_compile_options_t options,shaderc_include_resolve_fn resolver,shaderc_include_result_release_fn result_releaser,void * user_data)457 void shaderc_compile_options_set_include_callbacks(
458     shaderc_compile_options_t options, shaderc_include_resolve_fn resolver,
459     shaderc_include_result_release_fn result_releaser, void* user_data) {
460   options->include_resolver = resolver;
461   options->include_result_releaser = result_releaser;
462   options->include_user_data = user_data;
463 }
464 
shaderc_compile_options_set_suppress_warnings(shaderc_compile_options_t options)465 void shaderc_compile_options_set_suppress_warnings(
466     shaderc_compile_options_t options) {
467   options->compiler.SetSuppressWarnings();
468 }
469 
shaderc_compile_options_set_target_env(shaderc_compile_options_t options,shaderc_target_env target,uint32_t version)470 void shaderc_compile_options_set_target_env(shaderc_compile_options_t options,
471                                             shaderc_target_env target,
472                                             uint32_t version) {
473   options->target_env = target;
474   options->compiler.SetTargetEnv(GetCompilerTargetEnv(target),
475                                  GetCompilerTargetEnvVersion(version));
476 }
477 
shaderc_compile_options_set_target_spirv(shaderc_compile_options_t options,shaderc_spirv_version ver)478 void shaderc_compile_options_set_target_spirv(shaderc_compile_options_t options,
479                                               shaderc_spirv_version ver) {
480   // We made the values match, so we can get away with a static cast.
481   options->compiler.SetTargetSpirv(
482       static_cast<shaderc_util::Compiler::SpirvVersion>(ver));
483 }
484 
shaderc_compile_options_set_warnings_as_errors(shaderc_compile_options_t options)485 void shaderc_compile_options_set_warnings_as_errors(
486     shaderc_compile_options_t options) {
487   options->compiler.SetWarningsAsErrors();
488 }
489 
shaderc_compile_options_set_limit(shaderc_compile_options_t options,shaderc_limit limit,int value)490 void shaderc_compile_options_set_limit(shaderc_compile_options_t options,
491                                        shaderc_limit limit, int value) {
492   options->compiler.SetLimit(CompilerLimit(limit), value);
493 }
494 
shaderc_compile_options_set_auto_bind_uniforms(shaderc_compile_options_t options,bool auto_bind)495 void shaderc_compile_options_set_auto_bind_uniforms(
496     shaderc_compile_options_t options, bool auto_bind) {
497   options->compiler.SetAutoBindUniforms(auto_bind);
498 }
499 
shaderc_compile_options_set_auto_combined_image_sampler(shaderc_compile_options_t options,bool upgrade)500 void shaderc_compile_options_set_auto_combined_image_sampler(
501     shaderc_compile_options_t options, bool upgrade) {
502   options->compiler.SetAutoCombinedImageSampler(upgrade);
503 }
504 
shaderc_compile_options_set_hlsl_io_mapping(shaderc_compile_options_t options,bool hlsl_iomap)505 void shaderc_compile_options_set_hlsl_io_mapping(
506     shaderc_compile_options_t options, bool hlsl_iomap) {
507   options->compiler.SetHlslIoMapping(hlsl_iomap);
508 }
509 
shaderc_compile_options_set_hlsl_offsets(shaderc_compile_options_t options,bool hlsl_offsets)510 void shaderc_compile_options_set_hlsl_offsets(shaderc_compile_options_t options,
511                                               bool hlsl_offsets) {
512   options->compiler.SetHlslOffsets(hlsl_offsets);
513 }
514 
shaderc_compile_options_set_binding_base(shaderc_compile_options_t options,shaderc_uniform_kind kind,uint32_t base)515 void shaderc_compile_options_set_binding_base(shaderc_compile_options_t options,
516                                               shaderc_uniform_kind kind,
517                                               uint32_t base) {
518   options->compiler.SetAutoBindingBase(GetUniformKind(kind), base);
519 }
520 
shaderc_compile_options_set_binding_base_for_stage(shaderc_compile_options_t options,shaderc_shader_kind shader_kind,shaderc_uniform_kind kind,uint32_t base)521 void shaderc_compile_options_set_binding_base_for_stage(
522     shaderc_compile_options_t options, shaderc_shader_kind shader_kind,
523     shaderc_uniform_kind kind, uint32_t base) {
524   options->compiler.SetAutoBindingBaseForStage(GetStage(shader_kind),
525                                                GetUniformKind(kind), base);
526 }
527 
shaderc_compile_options_set_auto_map_locations(shaderc_compile_options_t options,bool auto_map)528 void shaderc_compile_options_set_auto_map_locations(
529     shaderc_compile_options_t options, bool auto_map) {
530   options->compiler.SetAutoMapLocations(auto_map);
531 }
532 
shaderc_compile_options_set_hlsl_register_set_and_binding_for_stage(shaderc_compile_options_t options,shaderc_shader_kind shader_kind,const char * reg,const char * set,const char * binding)533 void shaderc_compile_options_set_hlsl_register_set_and_binding_for_stage(
534     shaderc_compile_options_t options, shaderc_shader_kind shader_kind,
535     const char* reg, const char* set, const char* binding) {
536   options->compiler.SetHlslRegisterSetAndBindingForStage(GetStage(shader_kind),
537                                                          reg, set, binding);
538 }
539 
shaderc_compile_options_set_hlsl_register_set_and_binding(shaderc_compile_options_t options,const char * reg,const char * set,const char * binding)540 void shaderc_compile_options_set_hlsl_register_set_and_binding(
541     shaderc_compile_options_t options, const char* reg, const char* set,
542     const char* binding) {
543   options->compiler.SetHlslRegisterSetAndBinding(reg, set, binding);
544 }
545 
shaderc_compile_options_set_hlsl_functionality1(shaderc_compile_options_t options,bool enable)546 void shaderc_compile_options_set_hlsl_functionality1(
547     shaderc_compile_options_t options, bool enable) {
548   options->compiler.EnableHlslFunctionality1(enable);
549 }
550 
shaderc_compile_options_set_invert_y(shaderc_compile_options_t options,bool enable)551 void shaderc_compile_options_set_invert_y(
552     shaderc_compile_options_t options, bool enable) {
553   options->compiler.EnableInvertY(enable);
554 }
555 
shaderc_compile_options_set_nan_clamp(shaderc_compile_options_t options,bool enable)556 void shaderc_compile_options_set_nan_clamp(shaderc_compile_options_t options,
557                                            bool enable) {
558   options->compiler.SetNanClamp(enable);
559 }
560 
shaderc_compiler_initialize()561 shaderc_compiler_t shaderc_compiler_initialize() {
562   shaderc_compiler_t compiler = new (std::nothrow) shaderc_compiler;
563   if (compiler) {
564     compiler->initializer.reset(new shaderc_util::GlslangInitializer);
565   }
566   return compiler;
567 }
568 
shaderc_compiler_release(shaderc_compiler_t compiler)569 void shaderc_compiler_release(shaderc_compiler_t compiler) {
570   delete compiler;
571 }
572 
573 namespace {
CompileToSpecifiedOutputType(const shaderc_compiler_t compiler,const char * source_text,size_t source_text_size,shaderc_shader_kind shader_kind,const char * input_file_name,const char * entry_point_name,const shaderc_compile_options_t additional_options,shaderc_util::Compiler::OutputType output_type)574 shaderc_compilation_result_t CompileToSpecifiedOutputType(
575     const shaderc_compiler_t compiler, const char* source_text,
576     size_t source_text_size, shaderc_shader_kind shader_kind,
577     const char* input_file_name, const char* entry_point_name,
578     const shaderc_compile_options_t additional_options,
579     shaderc_util::Compiler::OutputType output_type) {
580   auto* result = new (std::nothrow) shaderc_compilation_result_vector;
581   if (!result) return nullptr;
582 
583   if (!input_file_name) {
584     result->messages = "Input file name string was null.";
585     result->num_errors = 1;
586     result->compilation_status = shaderc_compilation_status_compilation_error;
587     return result;
588   }
589   result->compilation_status = shaderc_compilation_status_invalid_stage;
590   bool compilation_succeeded = false;  // In case we exit early.
591   std::vector<uint32_t> compilation_output_data;
592   size_t compilation_output_data_size_in_bytes = 0u;
593   if (!compiler->initializer) return result;
594   TRY_IF_EXCEPTIONS_ENABLED {
595     std::stringstream errors;
596     size_t total_warnings = 0;
597     size_t total_errors = 0;
598     std::string input_file_name_str(input_file_name);
599     EShLanguage forced_stage = GetForcedStage(shader_kind);
600     shaderc_util::string_piece source_string =
601         shaderc_util::string_piece(source_text, source_text + source_text_size);
602     StageDeducer stage_deducer(shader_kind);
603     if (additional_options) {
604       InternalFileIncluder includer(additional_options->include_resolver,
605                                     additional_options->include_result_releaser,
606                                     additional_options->include_user_data);
607       // Depends on return value optimization to avoid extra copy.
608       std::tie(compilation_succeeded, compilation_output_data,
609                compilation_output_data_size_in_bytes) =
610           additional_options->compiler.Compile(
611               source_string, forced_stage, input_file_name_str, entry_point_name,
612               // stage_deducer has a flag: error_, which we need to check later.
613               // We need to make this a reference wrapper, so that std::function
614               // won't make a copy for this callable object.
615               std::ref(stage_deducer), includer, output_type, &errors,
616               &total_warnings, &total_errors);
617     } else {
618       // Compile with default options.
619       InternalFileIncluder includer;
620       std::tie(compilation_succeeded, compilation_output_data,
621                compilation_output_data_size_in_bytes) =
622           shaderc_util::Compiler().Compile(
623               source_string, forced_stage, input_file_name_str, entry_point_name,
624               std::ref(stage_deducer), includer, output_type, &errors,
625               &total_warnings, &total_errors);
626     }
627 
628     result->messages = errors.str();
629     result->SetOutputData(std::move(compilation_output_data));
630     result->output_data_size = compilation_output_data_size_in_bytes;
631     result->num_warnings = total_warnings;
632     result->num_errors = total_errors;
633     if (compilation_succeeded) {
634       result->compilation_status = shaderc_compilation_status_success;
635     } else {
636       // Check whether the error is caused by failing to deduce the shader
637       // stage. If it is the case, set the error type to shader kind error.
638       // Otherwise, set it to compilation error.
639       result->compilation_status =
640           stage_deducer.error() ? shaderc_compilation_status_invalid_stage
641                                 : shaderc_compilation_status_compilation_error;
642     }
643   }
644   CATCH_IF_EXCEPTIONS_ENABLED(...) {
645     result->compilation_status = shaderc_compilation_status_internal_error;
646   }
647   return result;
648 }
649 }  // anonymous namespace
650 
shaderc_compile_into_spv(const shaderc_compiler_t compiler,const char * source_text,size_t source_text_size,shaderc_shader_kind shader_kind,const char * input_file_name,const char * entry_point_name,const shaderc_compile_options_t additional_options)651 shaderc_compilation_result_t shaderc_compile_into_spv(
652     const shaderc_compiler_t compiler, const char* source_text,
653     size_t source_text_size, shaderc_shader_kind shader_kind,
654     const char* input_file_name, const char* entry_point_name,
655     const shaderc_compile_options_t additional_options) {
656   return CompileToSpecifiedOutputType(
657       compiler, source_text, source_text_size, shader_kind, input_file_name,
658       entry_point_name, additional_options,
659       shaderc_util::Compiler::OutputType::SpirvBinary);
660 }
661 
shaderc_compile_into_spv_assembly(const shaderc_compiler_t compiler,const char * source_text,size_t source_text_size,shaderc_shader_kind shader_kind,const char * input_file_name,const char * entry_point_name,const shaderc_compile_options_t additional_options)662 shaderc_compilation_result_t shaderc_compile_into_spv_assembly(
663     const shaderc_compiler_t compiler, const char* source_text,
664     size_t source_text_size, shaderc_shader_kind shader_kind,
665     const char* input_file_name, const char* entry_point_name,
666     const shaderc_compile_options_t additional_options) {
667   return CompileToSpecifiedOutputType(
668       compiler, source_text, source_text_size, shader_kind, input_file_name,
669       entry_point_name, additional_options,
670       shaderc_util::Compiler::OutputType::SpirvAssemblyText);
671 }
672 
shaderc_compile_into_preprocessed_text(const shaderc_compiler_t compiler,const char * source_text,size_t source_text_size,shaderc_shader_kind shader_kind,const char * input_file_name,const char * entry_point_name,const shaderc_compile_options_t additional_options)673 shaderc_compilation_result_t shaderc_compile_into_preprocessed_text(
674     const shaderc_compiler_t compiler, const char* source_text,
675     size_t source_text_size, shaderc_shader_kind shader_kind,
676     const char* input_file_name, const char* entry_point_name,
677     const shaderc_compile_options_t additional_options) {
678   return CompileToSpecifiedOutputType(
679       compiler, source_text, source_text_size, shader_kind, input_file_name,
680       entry_point_name, additional_options,
681       shaderc_util::Compiler::OutputType::PreprocessedText);
682 }
683 
shaderc_assemble_into_spv(const shaderc_compiler_t compiler,const char * source_assembly,size_t source_assembly_size,const shaderc_compile_options_t additional_options)684 shaderc_compilation_result_t shaderc_assemble_into_spv(
685     const shaderc_compiler_t compiler, const char* source_assembly,
686     size_t source_assembly_size,
687     const shaderc_compile_options_t additional_options) {
688   auto* result = new (std::nothrow) shaderc_compilation_result_spv_binary;
689   if (!result) return nullptr;
690   result->compilation_status = shaderc_compilation_status_invalid_assembly;
691   if (!compiler->initializer) return result;
692   if (source_assembly == nullptr) return result;
693 
694   TRY_IF_EXCEPTIONS_ENABLED {
695     spv_binary assembling_output_data = nullptr;
696     std::string errors;
697     const auto target_env = additional_options ? additional_options->target_env
698                                                : shaderc_target_env_default;
699     const uint32_t target_env_version =
700         additional_options ? additional_options->target_env_version : 0;
701     const bool assembling_succeeded = shaderc_util::SpirvToolsAssemble(
702         GetCompilerTargetEnv(target_env),
703         GetCompilerTargetEnvVersion(target_env_version),
704         {source_assembly, source_assembly + source_assembly_size},
705         &assembling_output_data, &errors);
706     result->num_errors = !assembling_succeeded;
707     if (assembling_succeeded) {
708       result->SetOutputData(assembling_output_data);
709       result->output_data_size =
710           assembling_output_data->wordCount * sizeof(uint32_t);
711       result->compilation_status = shaderc_compilation_status_success;
712     } else {
713       result->messages = std::move(errors);
714       result->compilation_status = shaderc_compilation_status_invalid_assembly;
715     }
716   }
717   CATCH_IF_EXCEPTIONS_ENABLED(...) {
718     result->compilation_status = shaderc_compilation_status_internal_error;
719   }
720 
721   return result;
722 }
723 
shaderc_result_get_length(const shaderc_compilation_result_t result)724 size_t shaderc_result_get_length(const shaderc_compilation_result_t result) {
725   return result->output_data_size;
726 }
727 
shaderc_result_get_num_warnings(const shaderc_compilation_result_t result)728 size_t shaderc_result_get_num_warnings(
729     const shaderc_compilation_result_t result) {
730   return result->num_warnings;
731 }
732 
shaderc_result_get_num_errors(const shaderc_compilation_result_t result)733 size_t shaderc_result_get_num_errors(
734     const shaderc_compilation_result_t result) {
735   return result->num_errors;
736 }
737 
shaderc_result_get_bytes(const shaderc_compilation_result_t result)738 const char* shaderc_result_get_bytes(
739     const shaderc_compilation_result_t result) {
740   return result->GetBytes();
741 }
742 
shaderc_result_release(shaderc_compilation_result_t result)743 void shaderc_result_release(shaderc_compilation_result_t result) {
744   delete result;
745 }
746 
shaderc_result_get_error_message(const shaderc_compilation_result_t result)747 const char* shaderc_result_get_error_message(
748     const shaderc_compilation_result_t result) {
749   return result->messages.c_str();
750 }
751 
shaderc_result_get_compilation_status(const shaderc_compilation_result_t result)752 shaderc_compilation_status shaderc_result_get_compilation_status(
753     const shaderc_compilation_result_t result) {
754   return result->compilation_status;
755 }
756 
shaderc_get_spv_version(unsigned int * version,unsigned int * revision)757 void shaderc_get_spv_version(unsigned int* version, unsigned int* revision) {
758   *version = spv::Version;
759   *revision = spv::Revision;
760 }
761 
shaderc_parse_version_profile(const char * str,int * version,shaderc_profile * profile)762 bool shaderc_parse_version_profile(const char* str, int* version,
763                                    shaderc_profile* profile) {
764   EProfile glslang_profile;
765   bool success = shaderc_util::ParseVersionProfile(
766       std::string(str, strlen(str)), version, &glslang_profile);
767   if (!success) return false;
768 
769   switch (glslang_profile) {
770     case EEsProfile:
771       *profile = shaderc_profile_es;
772       return true;
773     case ECoreProfile:
774       *profile = shaderc_profile_core;
775       return true;
776     case ECompatibilityProfile:
777       *profile = shaderc_profile_compatibility;
778       return true;
779     case ENoProfile:
780       *profile = shaderc_profile_none;
781       return true;
782     case EBadProfile:
783     case EProfileCount:
784       return false;
785   }
786 
787   // Shouldn't reach here, all profile enum should be handled above.
788   // Be strict to return false.
789   return false;
790 }
791