| // Copyright 2015 The Shaderc Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "shaderc_private.h" |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cstdint> |
| #include <sstream> |
| #include <vector> |
| |
| #include "SPIRV/spirv.hpp" |
| |
| #include "libshaderc_util/compiler.h" |
| #include "libshaderc_util/counting_includer.h" |
| #include "libshaderc_util/resources.h" |
| #include "libshaderc_util/spirv_tools_wrapper.h" |
| #include "libshaderc_util/version_profile.h" |
| |
| #if (defined(_MSC_VER) && !defined(_CPPUNWIND)) || !defined(__EXCEPTIONS) |
| #define TRY_IF_EXCEPTIONS_ENABLED |
| #define CATCH_IF_EXCEPTIONS_ENABLED(X) if (0) |
| #else |
| #define TRY_IF_EXCEPTIONS_ENABLED try |
| #define CATCH_IF_EXCEPTIONS_ENABLED(X) catch (X) |
| #endif |
| |
| namespace { |
| |
| // Returns shader stage (ie: vertex, fragment, etc.) in response to forced |
| // shader kinds. If the shader kind is not a forced kind, returns EshLangCount |
| // to let #pragma annotation or shader stage deducer determine the stage to |
| // use. |
| EShLanguage GetForcedStage(shaderc_shader_kind kind) { |
| switch (kind) { |
| case shaderc_glsl_vertex_shader: |
| return EShLangVertex; |
| case shaderc_glsl_fragment_shader: |
| return EShLangFragment; |
| case shaderc_glsl_compute_shader: |
| return EShLangCompute; |
| case shaderc_glsl_geometry_shader: |
| return EShLangGeometry; |
| case shaderc_glsl_tess_control_shader: |
| return EShLangTessControl; |
| case shaderc_glsl_tess_evaluation_shader: |
| return EShLangTessEvaluation; |
| |
| #ifdef NV_EXTENSIONS |
| case shaderc_glsl_raygen_shader: |
| return EShLangRayGenNV; |
| case shaderc_glsl_anyhit_shader: |
| return EShLangAnyHitNV; |
| case shaderc_glsl_closesthit_shader: |
| return EShLangClosestHitNV; |
| case shaderc_glsl_miss_shader: |
| return EShLangMissNV; |
| case shaderc_glsl_intersection_shader: |
| return EShLangIntersectNV; |
| case shaderc_glsl_callable_shader: |
| return EShLangCallableNV; |
| case shaderc_glsl_task_shader: |
| return EShLangTaskNV; |
| case shaderc_glsl_mesh_shader: |
| return EShLangMeshNV; |
| #endif |
| |
| case shaderc_glsl_infer_from_source: |
| case shaderc_glsl_default_vertex_shader: |
| case shaderc_glsl_default_fragment_shader: |
| case shaderc_glsl_default_compute_shader: |
| case shaderc_glsl_default_geometry_shader: |
| case shaderc_glsl_default_tess_control_shader: |
| case shaderc_glsl_default_tess_evaluation_shader: |
| #ifdef NV_EXTENSIONS |
| case shaderc_glsl_default_raygen_shader: |
| case shaderc_glsl_default_anyhit_shader: |
| case shaderc_glsl_default_closesthit_shader: |
| case shaderc_glsl_default_miss_shader: |
| case shaderc_glsl_default_intersection_shader: |
| case shaderc_glsl_default_callable_shader: |
| case shaderc_glsl_default_task_shader: |
| case shaderc_glsl_default_mesh_shader: |
| #endif |
| case shaderc_spirv_assembly: |
| return EShLangCount; |
| } |
| assert(0 && "Unhandled shaderc_shader_kind"); |
| return EShLangCount; |
| } |
| |
| // A wrapper functor class to be used as stage deducer for libshaderc_util |
| // Compile() interface. When the given shader kind is one of the default shader |
| // kinds, this functor will be called if #pragma is not found in the source |
| // code. And it returns the corresponding shader stage. When the shader kind is |
| // a forced shader kind, this functor won't be called and it simply returns |
| // EShLangCount to make the syntax correct. When the shader kind is set to |
| // shaderc_glsl_deduce_from_pragma, this functor also returns EShLangCount, but |
| // the compiler should emit error if #pragma annotation is not found in this |
| // case. |
| class StageDeducer { |
| public: |
| explicit StageDeducer( |
| shaderc_shader_kind kind = shaderc_glsl_infer_from_source) |
| : kind_(kind), error_(false){} |
| // The method that underlying glslang will call to determine the shader stage |
| // to be used in current compilation. It is called only when there is neither |
| // forced shader kind (or say stage, in the view of glslang), nor #pragma |
| // annotation in the source code. This method transforms an user defined |
| // 'default' shader kind to the corresponding shader stage. As this is the |
| // last trial to determine the shader stage, failing to find the corresponding |
| // shader stage will record an error. |
| // Note that calling this method more than once during one compilation will |
| // have the error recorded for the previous call been overwriten by the next |
| // call. |
| EShLanguage operator()(std::ostream* /*error_stream*/, |
| const shaderc_util::string_piece& /*error_tag*/) { |
| EShLanguage stage = GetDefaultStage(kind_); |
| if (stage == EShLangCount) { |
| error_ = true; |
| } else { |
| error_ = false; |
| } |
| return stage; |
| } |
| |
| // Returns true if there is error during shader stage deduction. |
| bool error() const { return error_; } |
| |
| private: |
| // Gets the corresponding shader stage for a given 'default' shader kind. All |
| // other kinds are mapped to EShLangCount which should not be used. |
| EShLanguage GetDefaultStage(shaderc_shader_kind kind) const { |
| switch (kind) { |
| case shaderc_glsl_vertex_shader: |
| case shaderc_glsl_fragment_shader: |
| case shaderc_glsl_compute_shader: |
| case shaderc_glsl_geometry_shader: |
| case shaderc_glsl_tess_control_shader: |
| case shaderc_glsl_tess_evaluation_shader: |
| case shaderc_glsl_infer_from_source: |
| #ifdef NV_EXTENSIONS |
| case shaderc_glsl_raygen_shader: |
| case shaderc_glsl_anyhit_shader: |
| case shaderc_glsl_closesthit_shader: |
| case shaderc_glsl_miss_shader: |
| case shaderc_glsl_intersection_shader: |
| case shaderc_glsl_callable_shader: |
| case shaderc_glsl_task_shader: |
| case shaderc_glsl_mesh_shader: |
| #endif |
| return EShLangCount; |
| case shaderc_glsl_default_vertex_shader: |
| return EShLangVertex; |
| case shaderc_glsl_default_fragment_shader: |
| return EShLangFragment; |
| case shaderc_glsl_default_compute_shader: |
| return EShLangCompute; |
| case shaderc_glsl_default_geometry_shader: |
| return EShLangGeometry; |
| case shaderc_glsl_default_tess_control_shader: |
| return EShLangTessControl; |
| case shaderc_glsl_default_tess_evaluation_shader: |
| return EShLangTessEvaluation; |
| #ifdef NV_EXTENSIONS |
| case shaderc_glsl_default_raygen_shader: |
| return EShLangRayGenNV; |
| case shaderc_glsl_default_anyhit_shader: |
| return EShLangAnyHitNV; |
| case shaderc_glsl_default_closesthit_shader: |
| return EShLangClosestHitNV; |
| case shaderc_glsl_default_miss_shader: |
| return EShLangMissNV; |
| case shaderc_glsl_default_intersection_shader: |
| return EShLangIntersectNV; |
| case shaderc_glsl_default_callable_shader: |
| return EShLangCallableNV; |
| case shaderc_glsl_default_task_shader: |
| return EShLangTaskNV; |
| case shaderc_glsl_default_mesh_shader: |
| return EShLangMeshNV; |
| #endif |
| case shaderc_spirv_assembly: |
| return EShLangCount; |
| } |
| assert(0 && "Unhandled shaderc_shader_kind"); |
| return EShLangCount; |
| } |
| |
| shaderc_shader_kind kind_; |
| bool error_; |
| }; |
| |
| // A bridge between the libshaderc includer and libshaderc_util includer. |
| class InternalFileIncluder : public shaderc_util::CountingIncluder { |
| public: |
| InternalFileIncluder(const shaderc_include_resolve_fn resolver, |
| const shaderc_include_result_release_fn result_releaser, |
| void* user_data) |
| : resolver_(resolver), |
| result_releaser_(result_releaser), |
| user_data_(user_data){} |
| InternalFileIncluder() |
| : resolver_(nullptr), result_releaser_(nullptr), user_data_(nullptr){} |
| |
| private: |
| // Check the validity of the callbacks. |
| bool AreValidCallbacks() const { |
| return resolver_ != nullptr && result_releaser_ != nullptr; |
| } |
| |
| // Maps CountingIncluder IncludeType value to a shaderc_include_type |
| // value. |
| shaderc_include_type GetIncludeType(IncludeType type) { |
| switch (type) { |
| case IncludeType::Local: |
| return shaderc_include_type_relative; |
| case IncludeType::System: |
| return shaderc_include_type_standard; |
| default: |
| break; |
| } |
| assert(0 && "Unhandled IncludeType"); |
| return shaderc_include_type_relative; |
| } |
| |
| // Resolves an include request for the requested source of the given |
| // type in the context of the specified requesting source. On success, |
| // returns a newly allocated IncludeResponse containing the fully resolved |
| // name of the requested source and the contents of that source. |
| // On failure, returns a newly allocated IncludeResponse where the |
| // resolved name member is an empty string, and the contents members |
| // contains error details. |
| virtual glslang::TShader::Includer::IncludeResult* include_delegate( |
| const char* requested_source, const char* requesting_source, |
| IncludeType type, size_t include_depth) override { |
| if (!AreValidCallbacks()) { |
| static const char kUnexpectedIncludeError[] = |
| "#error unexpected include directive"; |
| return new glslang::TShader::Includer::IncludeResult{ |
| "", kUnexpectedIncludeError, strlen(kUnexpectedIncludeError), |
| nullptr}; |
| } |
| shaderc_include_result* include_result = |
| resolver_(user_data_, requested_source, GetIncludeType(type), |
| requesting_source, include_depth); |
| // Make a glslang IncludeResult from a shaderc_include_result. The |
| // user_data member of the IncludeResult is a pointer to the |
| // shaderc_include_result object, so we can later release the latter. |
| return new glslang::TShader::Includer::IncludeResult{ |
| std::string(include_result->source_name, |
| include_result->source_name_length), |
| include_result->content, include_result->content_length, |
| include_result}; |
| } |
| |
| // Releases the given IncludeResult. |
| virtual void release_delegate( |
| glslang::TShader::Includer::IncludeResult* result) override { |
| if (result && result_releaser_) { |
| result_releaser_(user_data_, |
| static_cast<shaderc_include_result*>(result->userData)); |
| } |
| delete result; |
| } |
| |
| const shaderc_include_resolve_fn resolver_; |
| const shaderc_include_result_release_fn result_releaser_; |
| void* user_data_; |
| }; |
| |
| // Converts the target env to the corresponding one in shaderc_util::Compiler. |
| shaderc_util::Compiler::TargetEnv GetCompilerTargetEnv(shaderc_target_env env) { |
| switch (env) { |
| case shaderc_target_env_opengl: |
| return shaderc_util::Compiler::TargetEnv::OpenGL; |
| case shaderc_target_env_opengl_compat: |
| return shaderc_util::Compiler::TargetEnv::OpenGLCompat; |
| case shaderc_target_env_vulkan: |
| default: |
| break; |
| } |
| |
| return shaderc_util::Compiler::TargetEnv::Vulkan; |
| } |
| |
| shaderc_util::Compiler::TargetEnvVersion GetCompilerTargetEnvVersion( |
| uint32_t version_number) { |
| using namespace shaderc_util; |
| |
| if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_0) == |
| version_number) { |
| return Compiler::TargetEnvVersion::Vulkan_1_0; |
| } |
| if (static_cast<uint32_t>(Compiler::TargetEnvVersion::Vulkan_1_1) == |
| version_number) { |
| return Compiler::TargetEnvVersion::Vulkan_1_1; |
| } |
| if (static_cast<uint32_t>(Compiler::TargetEnvVersion::OpenGL_4_5) == |
| version_number) { |
| return Compiler::TargetEnvVersion::OpenGL_4_5; |
| } |
| |
| return Compiler::TargetEnvVersion::Default; |
| } |
| |
| // Returns the Compiler::Limit enum for the given shaderc_limit enum. |
| shaderc_util::Compiler::Limit CompilerLimit(shaderc_limit limit) { |
| switch (limit) { |
| #define RESOURCE(NAME, FIELD, CNAME) \ |
| case shaderc_limit_##CNAME: \ |
| return shaderc_util::Compiler::Limit::NAME; |
| #include "libshaderc_util/resources.inc" |
| #undef RESOURCE |
| default: |
| break; |
| } |
| assert(0 && "Should not have reached here"); |
| return static_cast<shaderc_util::Compiler::Limit>(0); |
| } |
| |
| // Returns the Compiler::UniformKind for the given shaderc_uniform_kind. |
| shaderc_util::Compiler::UniformKind GetUniformKind(shaderc_uniform_kind kind) { |
| switch (kind) { |
| case shaderc_uniform_kind_texture: |
| return shaderc_util::Compiler::UniformKind::Texture; |
| case shaderc_uniform_kind_sampler: |
| return shaderc_util::Compiler::UniformKind::Sampler; |
| case shaderc_uniform_kind_image: |
| return shaderc_util::Compiler::UniformKind::Image; |
| case shaderc_uniform_kind_buffer: |
| return shaderc_util::Compiler::UniformKind::Buffer; |
| case shaderc_uniform_kind_storage_buffer: |
| return shaderc_util::Compiler::UniformKind::StorageBuffer; |
| case shaderc_uniform_kind_unordered_access_view: |
| return shaderc_util::Compiler::UniformKind::UnorderedAccessView; |
| } |
| assert(0 && "Should not have reached here"); |
| return static_cast<shaderc_util::Compiler::UniformKind>(0); |
| } |
| |
| // Returns the Compiler::Stage for generic stage values in shaderc_shader_kind. |
| shaderc_util::Compiler::Stage GetStage(shaderc_shader_kind kind) { |
| switch (kind) { |
| case shaderc_vertex_shader: |
| return shaderc_util::Compiler::Stage::Vertex; |
| case shaderc_fragment_shader: |
| return shaderc_util::Compiler::Stage::Fragment; |
| case shaderc_compute_shader: |
| return shaderc_util::Compiler::Stage::Compute; |
| case shaderc_tess_control_shader: |
| return shaderc_util::Compiler::Stage::TessControl; |
| case shaderc_tess_evaluation_shader: |
| return shaderc_util::Compiler::Stage::TessEval; |
| case shaderc_geometry_shader: |
| return shaderc_util::Compiler::Stage::Geometry; |
| default: |
| break; |
| } |
| assert(0 && "Should not have reached here"); |
| return static_cast<shaderc_util::Compiler::Stage>(0); |
| } |
| |
| } // anonymous namespace |
| |
| struct shaderc_compile_options { |
| shaderc_target_env target_env = shaderc_target_env_default; |
| uint32_t target_env_version = 0; |
| shaderc_util::Compiler compiler; |
| shaderc_include_resolve_fn include_resolver = nullptr; |
| shaderc_include_result_release_fn include_result_releaser = nullptr; |
| void* include_user_data = nullptr; |
| }; |
| |
| shaderc_compile_options_t shaderc_compile_options_initialize() { |
| return new (std::nothrow) shaderc_compile_options; |
| } |
| |
| shaderc_compile_options_t shaderc_compile_options_clone( |
| const shaderc_compile_options_t options) { |
| if (!options) { |
| return shaderc_compile_options_initialize(); |
| } |
| return new (std::nothrow) shaderc_compile_options(*options); |
| } |
| |
| void shaderc_compile_options_release(shaderc_compile_options_t options) { |
| delete options; |
| } |
| |
| void 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) { |
| options->compiler.AddMacroDefinition(name, name_length, value, value_length); |
| } |
| |
| void shaderc_compile_options_set_source_language( |
| shaderc_compile_options_t options, shaderc_source_language set_lang) { |
| auto lang = shaderc_util::Compiler::SourceLanguage::GLSL; |
| if (set_lang == shaderc_source_language_hlsl) |
| lang = shaderc_util::Compiler::SourceLanguage::HLSL; |
| options->compiler.SetSourceLanguage(lang); |
| } |
| |
| void shaderc_compile_options_set_generate_debug_info( |
| shaderc_compile_options_t options) { |
| options->compiler.SetGenerateDebugInfo(); |
| } |
| |
| void shaderc_compile_options_set_optimization_level( |
| shaderc_compile_options_t options, shaderc_optimization_level level) { |
| auto opt_level = shaderc_util::Compiler::OptimizationLevel::Zero; |
| switch (level) { |
| case shaderc_optimization_level_size: |
| opt_level = shaderc_util::Compiler::OptimizationLevel::Size; |
| break; |
| case shaderc_optimization_level_performance: |
| opt_level = shaderc_util::Compiler::OptimizationLevel::Performance; |
| break; |
| default: |
| break; |
| } |
| |
| options->compiler.SetOptimizationLevel(opt_level); |
| } |
| |
| void shaderc_compile_options_set_forced_version_profile( |
| shaderc_compile_options_t options, int version, shaderc_profile profile) { |
| // Transfer the profile parameter from public enum type to glslang internal |
| // enum type. No default case here so that compiler will complain if new enum |
| // member is added later but not handled here. |
| switch (profile) { |
| case shaderc_profile_none: |
| options->compiler.SetForcedVersionProfile(version, ENoProfile); |
| break; |
| case shaderc_profile_core: |
| options->compiler.SetForcedVersionProfile(version, ECoreProfile); |
| break; |
| case shaderc_profile_compatibility: |
| options->compiler.SetForcedVersionProfile(version, ECompatibilityProfile); |
| break; |
| case shaderc_profile_es: |
| options->compiler.SetForcedVersionProfile(version, EEsProfile); |
| break; |
| } |
| } |
| |
| void 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) { |
| options->include_resolver = resolver; |
| options->include_result_releaser = result_releaser; |
| options->include_user_data = user_data; |
| } |
| |
| void shaderc_compile_options_set_suppress_warnings( |
| shaderc_compile_options_t options) { |
| options->compiler.SetSuppressWarnings(); |
| } |
| |
| void shaderc_compile_options_set_target_env(shaderc_compile_options_t options, |
| shaderc_target_env target, |
| uint32_t version) { |
| options->target_env = target; |
| options->compiler.SetTargetEnv(GetCompilerTargetEnv(target), |
| GetCompilerTargetEnvVersion(version)); |
| } |
| |
| void shaderc_compile_options_set_target_spirv(shaderc_compile_options_t options, |
| shaderc_spirv_version ver) { |
| // We made the values match, so we can get away with a static cast. |
| options->compiler.SetTargetSpirv( |
| static_cast<shaderc_util::Compiler::SpirvVersion>(ver)); |
| } |
| |
| void shaderc_compile_options_set_warnings_as_errors( |
| shaderc_compile_options_t options) { |
| options->compiler.SetWarningsAsErrors(); |
| } |
| |
| void shaderc_compile_options_set_limit(shaderc_compile_options_t options, |
| shaderc_limit limit, int value) { |
| options->compiler.SetLimit(CompilerLimit(limit), value); |
| } |
| |
| void shaderc_compile_options_set_auto_bind_uniforms( |
| shaderc_compile_options_t options, bool auto_bind) { |
| options->compiler.SetAutoBindUniforms(auto_bind); |
| } |
| |
| void shaderc_compile_options_set_hlsl_io_mapping( |
| shaderc_compile_options_t options, bool hlsl_iomap) { |
| options->compiler.SetHlslIoMapping(hlsl_iomap); |
| } |
| |
| void shaderc_compile_options_set_hlsl_offsets(shaderc_compile_options_t options, |
| bool hlsl_offsets) { |
| options->compiler.SetHlslOffsets(hlsl_offsets); |
| } |
| |
| void shaderc_compile_options_set_binding_base(shaderc_compile_options_t options, |
| shaderc_uniform_kind kind, |
| uint32_t base) { |
| options->compiler.SetAutoBindingBase(GetUniformKind(kind), base); |
| } |
| |
| void 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) { |
| options->compiler.SetAutoBindingBaseForStage(GetStage(shader_kind), |
| GetUniformKind(kind), base); |
| } |
| |
| void shaderc_compile_options_set_auto_map_locations( |
| shaderc_compile_options_t options, bool auto_map) { |
| options->compiler.SetAutoMapLocations(auto_map); |
| } |
| |
| void 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) { |
| options->compiler.SetHlslRegisterSetAndBindingForStage(GetStage(shader_kind), |
| reg, set, binding); |
| } |
| |
| void shaderc_compile_options_set_hlsl_register_set_and_binding( |
| shaderc_compile_options_t options, const char* reg, const char* set, |
| const char* binding) { |
| options->compiler.SetHlslRegisterSetAndBinding(reg, set, binding); |
| } |
| |
| void shaderc_compile_options_set_hlsl_functionality1( |
| shaderc_compile_options_t options, bool enable) { |
| options->compiler.EnableHlslFunctionality1(enable); |
| } |
| |
| void shaderc_compile_options_set_invert_y( |
| shaderc_compile_options_t options, bool enable) { |
| options->compiler.EnableInvertY(enable); |
| } |
| |
| void shaderc_compile_options_set_nan_clamp(shaderc_compile_options_t options, |
| bool enable) { |
| options->compiler.SetNanClamp(enable); |
| } |
| |
| shaderc_compiler_t shaderc_compiler_initialize() { |
| static shaderc_util::GlslangInitializer* initializer = |
| new shaderc_util::GlslangInitializer; |
| shaderc_compiler_t compiler = new (std::nothrow) shaderc_compiler; |
| compiler->initializer = initializer; |
| return compiler; |
| } |
| |
| void shaderc_compiler_release(shaderc_compiler_t compiler) { delete compiler; } |
| |
| namespace { |
| shaderc_compilation_result_t 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) { |
| auto* result = new (std::nothrow) shaderc_compilation_result_vector; |
| if (!result) return nullptr; |
| |
| if (!input_file_name) { |
| result->messages = "Input file name string was null."; |
| result->num_errors = 1; |
| result->compilation_status = shaderc_compilation_status_compilation_error; |
| return result; |
| } |
| result->compilation_status = shaderc_compilation_status_invalid_stage; |
| bool compilation_succeeded = false; // In case we exit early. |
| std::vector<uint32_t> compilation_output_data; |
| size_t compilation_output_data_size_in_bytes = 0u; |
| if (!compiler->initializer) return result; |
| TRY_IF_EXCEPTIONS_ENABLED { |
| std::stringstream errors; |
| size_t total_warnings = 0; |
| size_t total_errors = 0; |
| std::string input_file_name_str(input_file_name); |
| EShLanguage forced_stage = GetForcedStage(shader_kind); |
| shaderc_util::string_piece source_string = |
| shaderc_util::string_piece(source_text, source_text + source_text_size); |
| StageDeducer stage_deducer(shader_kind); |
| if (additional_options) { |
| InternalFileIncluder includer(additional_options->include_resolver, |
| additional_options->include_result_releaser, |
| additional_options->include_user_data); |
| // Depends on return value optimization to avoid extra copy. |
| std::tie(compilation_succeeded, compilation_output_data, |
| compilation_output_data_size_in_bytes) = |
| additional_options->compiler.Compile( |
| source_string, forced_stage, input_file_name_str, entry_point_name, |
| // stage_deducer has a flag: error_, which we need to check later. |
| // We need to make this a reference wrapper, so that std::function |
| // won't make a copy for this callable object. |
| std::ref(stage_deducer), includer, output_type, &errors, |
| &total_warnings, &total_errors, compiler->initializer); |
| } else { |
| // Compile with default options. |
| InternalFileIncluder includer; |
| std::tie(compilation_succeeded, compilation_output_data, |
| compilation_output_data_size_in_bytes) = |
| shaderc_util::Compiler().Compile( |
| source_string, forced_stage, input_file_name_str, entry_point_name, |
| std::ref(stage_deducer), includer, output_type, &errors, |
| &total_warnings, &total_errors, compiler->initializer); |
| } |
| |
| result->messages = errors.str(); |
| result->SetOutputData(std::move(compilation_output_data)); |
| result->output_data_size = compilation_output_data_size_in_bytes; |
| result->num_warnings = total_warnings; |
| result->num_errors = total_errors; |
| if (compilation_succeeded) { |
| result->compilation_status = shaderc_compilation_status_success; |
| } else { |
| // Check whether the error is caused by failing to deduce the shader |
| // stage. If it is the case, set the error type to shader kind error. |
| // Otherwise, set it to compilation error. |
| result->compilation_status = |
| stage_deducer.error() ? shaderc_compilation_status_invalid_stage |
| : shaderc_compilation_status_compilation_error; |
| } |
| } |
| CATCH_IF_EXCEPTIONS_ENABLED(...) { |
| result->compilation_status = shaderc_compilation_status_internal_error; |
| } |
| return result; |
| } |
| } // anonymous namespace |
| |
| shaderc_compilation_result_t 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) { |
| return CompileToSpecifiedOutputType( |
| compiler, source_text, source_text_size, shader_kind, input_file_name, |
| entry_point_name, additional_options, |
| shaderc_util::Compiler::OutputType::SpirvBinary); |
| } |
| |
| shaderc_compilation_result_t 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) { |
| return CompileToSpecifiedOutputType( |
| compiler, source_text, source_text_size, shader_kind, input_file_name, |
| entry_point_name, additional_options, |
| shaderc_util::Compiler::OutputType::SpirvAssemblyText); |
| } |
| |
| shaderc_compilation_result_t 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) { |
| return CompileToSpecifiedOutputType( |
| compiler, source_text, source_text_size, shader_kind, input_file_name, |
| entry_point_name, additional_options, |
| shaderc_util::Compiler::OutputType::PreprocessedText); |
| } |
| |
| shaderc_compilation_result_t 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) { |
| auto* result = new (std::nothrow) shaderc_compilation_result_spv_binary; |
| if (!result) return nullptr; |
| result->compilation_status = shaderc_compilation_status_invalid_assembly; |
| if (!compiler->initializer) return result; |
| if (source_assembly == nullptr) return result; |
| |
| TRY_IF_EXCEPTIONS_ENABLED { |
| spv_binary assembling_output_data = nullptr; |
| std::string errors; |
| const auto target_env = additional_options ? additional_options->target_env |
| : shaderc_target_env_default; |
| const uint32_t target_env_version = |
| additional_options ? additional_options->target_env_version : 0; |
| const bool assembling_succeeded = shaderc_util::SpirvToolsAssemble( |
| GetCompilerTargetEnv(target_env), |
| GetCompilerTargetEnvVersion(target_env_version), |
| {source_assembly, source_assembly + source_assembly_size}, |
| &assembling_output_data, &errors); |
| result->num_errors = !assembling_succeeded; |
| if (assembling_succeeded) { |
| result->SetOutputData(assembling_output_data); |
| result->output_data_size = |
| assembling_output_data->wordCount * sizeof(uint32_t); |
| result->compilation_status = shaderc_compilation_status_success; |
| } else { |
| result->messages = std::move(errors); |
| result->compilation_status = shaderc_compilation_status_invalid_assembly; |
| } |
| } |
| CATCH_IF_EXCEPTIONS_ENABLED(...) { |
| result->compilation_status = shaderc_compilation_status_internal_error; |
| } |
| |
| return result; |
| } |
| |
| size_t shaderc_result_get_length(const shaderc_compilation_result_t result) { |
| return result->output_data_size; |
| } |
| |
| size_t shaderc_result_get_num_warnings( |
| const shaderc_compilation_result_t result) { |
| return result->num_warnings; |
| } |
| |
| size_t shaderc_result_get_num_errors( |
| const shaderc_compilation_result_t result) { |
| return result->num_errors; |
| } |
| |
| const char* shaderc_result_get_bytes( |
| const shaderc_compilation_result_t result) { |
| return result->GetBytes(); |
| } |
| |
| void shaderc_result_release(shaderc_compilation_result_t result) { |
| delete result; |
| } |
| |
| const char* shaderc_result_get_error_message( |
| const shaderc_compilation_result_t result) { |
| return result->messages.c_str(); |
| } |
| |
| shaderc_compilation_status shaderc_result_get_compilation_status( |
| const shaderc_compilation_result_t result) { |
| return result->compilation_status; |
| } |
| |
| void shaderc_get_spv_version(unsigned int* version, unsigned int* revision) { |
| *version = spv::Version; |
| *revision = spv::Revision; |
| } |
| |
| bool shaderc_parse_version_profile(const char* str, int* version, |
| shaderc_profile* profile) { |
| EProfile glslang_profile; |
| bool success = shaderc_util::ParseVersionProfile( |
| std::string(str, strlen(str)), version, &glslang_profile); |
| if (!success) return false; |
| |
| switch (glslang_profile) { |
| case EEsProfile: |
| *profile = shaderc_profile_es; |
| return true; |
| case ECoreProfile: |
| *profile = shaderc_profile_core; |
| return true; |
| case ECompatibilityProfile: |
| *profile = shaderc_profile_compatibility; |
| return true; |
| case ENoProfile: |
| *profile = shaderc_profile_none; |
| return true; |
| case EBadProfile: |
| return false; |
| } |
| |
| // Shouldn't reach here, all profile enum should be handled above. |
| // Be strict to return false. |
| return false; |
| } |