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