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#ifndef SHADERC_SHADERC_HPP_ 16#define SHADERC_SHADERC_HPP_ 17 18#include <memory> 19#include <string> 20#include <vector> 21 22#include "shaderc.h" 23 24namespace shaderc { 25// A CompilationResult contains the compiler output, compilation status, 26// and messages. 27// 28// The compiler output is stored as an array of elements and accessed 29// via random access iterators provided by cbegin() and cend(). The iterators 30// are contiguous in the sense of "Contiguous Iterators: A Refinement of 31// Random Access Iterators", Nevin Liber, C++ Library Evolution Working 32// Group Working Paper N3884. 33// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf 34// 35// Methods begin() and end() are also provided to enable range-based for. 36// They are synonyms to cbegin() and cend(), respectively. 37template <typename OutputElementType> 38class CompilationResult { 39 public: 40 typedef OutputElementType element_type; 41 // The type used to describe the begin and end iterators on the 42 // compiler output. 43 typedef const OutputElementType* const_iterator; 44 45 // Upon creation, the CompilationResult takes ownership of the 46 // shaderc_compilation_result instance. During destruction of the 47 // CompilationResult, the shaderc_compilation_result will be released. 48 explicit CompilationResult(shaderc_compilation_result_t compilation_result) 49 : compilation_result_(compilation_result) {} 50 ~CompilationResult() { shaderc_result_release(compilation_result_); } 51 52 CompilationResult(CompilationResult&& other) { 53 compilation_result_ = other.compilation_result_; 54 other.compilation_result_ = nullptr; 55 } 56 57 // Returns any error message found during compilation. 58 std::string GetErrorMessage() const { 59 if (!compilation_result_) { 60 return ""; 61 } 62 return shaderc_result_get_error_message(compilation_result_); 63 } 64 65 // Returns the compilation status, indicating whether the compilation 66 // succeeded, or failed due to some reasons, like invalid shader stage or 67 // compilation errors. 68 shaderc_compilation_status GetCompilationStatus() const { 69 if (!compilation_result_) { 70 return shaderc_compilation_status_null_result_object; 71 } 72 return shaderc_result_get_compilation_status(compilation_result_); 73 } 74 75 // Returns a random access (contiguous) iterator pointing to the start 76 // of the compilation output. It is valid for the lifetime of this object. 77 // If there is no compilation result, then returns nullptr. 78 const_iterator cbegin() const { 79 if (!compilation_result_) return nullptr; 80 return reinterpret_cast<const_iterator>( 81 shaderc_result_get_bytes(compilation_result_)); 82 } 83 84 // Returns a random access (contiguous) iterator pointing to the end of 85 // the compilation output. It is valid for the lifetime of this object. 86 // If there is no compilation result, then returns nullptr. 87 const_iterator cend() const { 88 if (!compilation_result_) return nullptr; 89 return cbegin() + 90 shaderc_result_get_length(compilation_result_) / 91 sizeof(OutputElementType); 92 } 93 94 // Returns the same iterator as cbegin(). 95 const_iterator begin() const { return cbegin(); } 96 // Returns the same iterator as cend(). 97 const_iterator end() const { return cend(); } 98 99 // Returns the number of warnings generated during the compilation. 100 size_t GetNumWarnings() const { 101 if (!compilation_result_) { 102 return 0; 103 } 104 return shaderc_result_get_num_warnings(compilation_result_); 105 } 106 107 // Returns the number of errors generated during the compilation. 108 size_t GetNumErrors() const { 109 if (!compilation_result_) { 110 return 0; 111 } 112 return shaderc_result_get_num_errors(compilation_result_); 113 } 114 115 private: 116 CompilationResult(const CompilationResult& other) = delete; 117 CompilationResult& operator=(const CompilationResult& other) = delete; 118 119 shaderc_compilation_result_t compilation_result_; 120}; 121 122// A compilation result for a SPIR-V binary module, which is an array 123// of uint32_t words. 124using SpvCompilationResult = CompilationResult<uint32_t>; 125// A compilation result in SPIR-V assembly syntax. 126using AssemblyCompilationResult = CompilationResult<char>; 127// Preprocessed source text. 128using PreprocessedSourceCompilationResult = CompilationResult<char>; 129 130// Contains any options that can have default values for a compilation. 131class CompileOptions { 132 public: 133 CompileOptions() { options_ = shaderc_compile_options_initialize(); } 134 ~CompileOptions() { shaderc_compile_options_release(options_); } 135 CompileOptions(const CompileOptions& other) { 136 options_ = shaderc_compile_options_clone(other.options_); 137 } 138 CompileOptions(CompileOptions&& other) { 139 options_ = other.options_; 140 other.options_ = nullptr; 141 } 142 143 // Adds a predefined macro to the compilation options. It behaves the same as 144 // shaderc_compile_options_add_macro_definition in shaderc.h. 145 void AddMacroDefinition(const char* name, size_t name_length, 146 const char* value, size_t value_length) { 147 shaderc_compile_options_add_macro_definition(options_, name, name_length, 148 value, value_length); 149 } 150 151 // Adds a valueless predefined macro to the compilation options. 152 void AddMacroDefinition(const std::string& name) { 153 AddMacroDefinition(name.c_str(), name.size(), nullptr, 0u); 154 } 155 156 // Adds a predefined macro to the compilation options. 157 void AddMacroDefinition(const std::string& name, const std::string& value) { 158 AddMacroDefinition(name.c_str(), name.size(), value.c_str(), value.size()); 159 } 160 161 // Sets the compiler mode to generate debug information in the output. 162 void SetGenerateDebugInfo() { 163 shaderc_compile_options_set_generate_debug_info(options_); 164 } 165 166 // Sets the compiler optimization level to the given level. Only the last one 167 // takes effect if multiple calls of this function exist. 168 void SetOptimizationLevel(shaderc_optimization_level level) { 169 shaderc_compile_options_set_optimization_level(options_, level); 170 } 171 172 // A C++ version of the libshaderc includer interface. 173 class IncluderInterface { 174 public: 175 // Handles shaderc_include_resolver_fn callbacks. 176 virtual shaderc_include_result* GetInclude(const char* requested_source, 177 shaderc_include_type type, 178 const char* requesting_source, 179 size_t include_depth) = 0; 180 181 // Handles shaderc_include_result_release_fn callbacks. 182 virtual void ReleaseInclude(shaderc_include_result* data) = 0; 183 }; 184 185 // Sets the includer instance for libshaderc to call during compilation, as 186 // described in shaderc_compile_options_set_include_callbacks(). Callbacks 187 // are routed to this includer's methods. 188 void SetIncluder(std::unique_ptr<IncluderInterface>&& includer) { 189 includer_ = std::move(includer); 190 shaderc_compile_options_set_include_callbacks( 191 options_, 192 [](void* user_data, const char* requested_source, int type, 193 const char* requesting_source, size_t include_depth) { 194 auto* includer = static_cast<IncluderInterface*>(user_data); 195 return includer->GetInclude(requested_source, 196 (shaderc_include_type)type, 197 requesting_source, include_depth); 198 }, 199 [](void* user_data, shaderc_include_result* include_result) { 200 auto* includer = static_cast<IncluderInterface*>(user_data); 201 return includer->ReleaseInclude(include_result); 202 }, 203 includer_.get()); 204 } 205 206 // Forces the GLSL language version and profile to a given pair. The version 207 // number is the same as would appear in the #version annotation in the 208 // source. Version and profile specified here overrides the #version 209 // annotation in the source. Use profile: 'shaderc_profile_none' for GLSL 210 // versions that do not define profiles, e.g. versions below 150. 211 void SetForcedVersionProfile(int version, shaderc_profile profile) { 212 shaderc_compile_options_set_forced_version_profile(options_, version, 213 profile); 214 } 215 216 // Sets the compiler mode to suppress warnings. Note this option overrides 217 // warnings-as-errors mode. When both suppress-warnings and warnings-as-errors 218 // modes are turned on, warning messages will be inhibited, and will not be 219 // emitted as error message. 220 void SetSuppressWarnings() { 221 shaderc_compile_options_set_suppress_warnings(options_); 222 } 223 224 // Sets the source language. The default is GLSL. 225 void SetSourceLanguage(shaderc_source_language lang) { 226 shaderc_compile_options_set_source_language(options_, lang); 227 } 228 229 // Sets the target shader environment, affecting which warnings or errors will 230 // be issued. 231 // The version will be for distinguishing between different versions of the 232 // target environment. 233 // "0" is the only supported version at this point 234 void SetTargetEnvironment(shaderc_target_env target, uint32_t version) { 235 shaderc_compile_options_set_target_env(options_, target, version); 236 } 237 238 // Sets the compiler mode to make all warnings into errors. Note the 239 // suppress-warnings mode overrides this option, i.e. if both 240 // warning-as-errors and suppress-warnings modes are set on, warnings will not 241 // be emitted as error message. 242 void SetWarningsAsErrors() { 243 shaderc_compile_options_set_warnings_as_errors(options_); 244 } 245 246 // Sets a resource limit. 247 void SetLimit(shaderc_limit limit, int value) { 248 shaderc_compile_options_set_limit(options_, limit, value); 249 } 250 251 // Sets whether the compiler should automatically assign bindings to uniforms 252 // that aren't already explicitly bound in the shader source. 253 void SetAutoBindUniforms(bool auto_bind) { 254 shaderc_compile_options_set_auto_bind_uniforms(options_, auto_bind); 255 } 256 257 // Sets whether the compiler should use HLSL IO mapping rules for bindings. 258 // Defaults to false. 259 void SetHlslIoMapping(bool hlsl_iomap) { 260 shaderc_compile_options_set_hlsl_io_mapping(options_, hlsl_iomap); 261 } 262 263 // Sets whether the compiler should determine block member offsets using HLSL 264 // packing rules instead of standard GLSL rules. Defaults to false. Only 265 // affects GLSL compilation. HLSL rules are always used when compiling HLSL. 266 void SetHlslOffsets(bool hlsl_offsets) { 267 shaderc_compile_options_set_hlsl_offsets(options_, hlsl_offsets); 268 } 269 270 // Sets the base binding number used for for a uniform resource type when 271 // automatically assigning bindings. For GLSL compilation, sets the lowest 272 // automatically assigned number. For HLSL compilation, the regsiter number 273 // assigned to the resource is added to this specified base. 274 void SetBindingBase(shaderc_uniform_kind kind, uint32_t base) { 275 shaderc_compile_options_set_binding_base(options_, kind, base); 276 } 277 278 // Like SetBindingBase, but only takes effect when compiling a given shader 279 // stage. The stage is assumed to be one of vertex, fragment, tessellation 280 // evaluation, tesselation control, geometry, or compute. 281 void SetBindingBaseForStage(shaderc_shader_kind shader_kind, 282 shaderc_uniform_kind kind, uint32_t base) { 283 shaderc_compile_options_set_binding_base_for_stage(options_, shader_kind, 284 kind, base); 285 } 286 287 // Sets a descriptor set and binding for an HLSL register in the given stage. 288 // Copies the parameter strings. 289 void SetHlslRegisterSetAndBindingForStage(shaderc_shader_kind shader_kind, 290 const std::string& reg, 291 const std::string& set, 292 const std::string& binding) { 293 shaderc_compile_options_set_hlsl_register_set_and_binding_for_stage( 294 options_, shader_kind, reg.c_str(), set.c_str(), binding.c_str()); 295 } 296 297 // Sets a descriptor set and binding for an HLSL register in any stage. 298 // Copies the parameter strings. 299 void SetHlslRegisterSetAndBinding(const std::string& reg, 300 const std::string& set, 301 const std::string& binding) { 302 shaderc_compile_options_set_hlsl_register_set_and_binding( 303 options_, reg.c_str(), set.c_str(), binding.c_str()); 304 } 305 306 private: 307 CompileOptions& operator=(const CompileOptions& other) = delete; 308 shaderc_compile_options_t options_; 309 std::unique_ptr<IncluderInterface> includer_; 310 311 friend class Compiler; 312}; 313 314// The compilation context for compiling source to SPIR-V. 315class Compiler { 316 public: 317 Compiler() : compiler_(shaderc_compiler_initialize()) {} 318 ~Compiler() { shaderc_compiler_release(compiler_); } 319 320 Compiler(Compiler&& other) { 321 compiler_ = other.compiler_; 322 other.compiler_ = nullptr; 323 } 324 325 bool IsValid() const { return compiler_ != nullptr; } 326 327 // Compiles the given source GLSL and returns a SPIR-V binary module 328 // compilation result. 329 // The source_text parameter must be a valid pointer. 330 // The source_text_size parameter must be the length of the source text. 331 // The shader_kind parameter either forces the compilation to be done with a 332 // specified shader kind, or hint the compiler how to determine the exact 333 // shader kind. If the shader kind is set to shaderc_glslc_infer_from_source, 334 // the compiler will try to deduce the shader kind from the source string and 335 // a failure in this proess will generate an error. Currently only #pragma 336 // annotation is supported. If the shader kind is set to one of the default 337 // shader kinds, the compiler will fall back to the specified default shader 338 // kind in case it failed to deduce the shader kind from the source string. 339 // The input_file_name is a null-termintated string. It is used as a tag to 340 // identify the source string in cases like emitting error messages. It 341 // doesn't have to be a 'file name'. 342 // The entry_point_name parameter is a null-terminated string specifying 343 // the entry point name for HLSL compilation. For GLSL compilation, the 344 // entry point name is assumed to be "main". 345 // The compilation is passed any options specified in the CompileOptions 346 // parameter. 347 // It is valid for the returned CompilationResult object to outlive this 348 // compiler object. 349 // Note when the options_ has disassembly mode or preprocessing only mode set 350 // on, the returned CompilationResult will hold a text string, instead of a 351 // SPIR-V binary generated with default options. 352 SpvCompilationResult CompileGlslToSpv(const char* source_text, 353 size_t source_text_size, 354 shaderc_shader_kind shader_kind, 355 const char* input_file_name, 356 const char* entry_point_name, 357 const CompileOptions& options) const { 358 shaderc_compilation_result_t compilation_result = shaderc_compile_into_spv( 359 compiler_, source_text, source_text_size, shader_kind, input_file_name, 360 entry_point_name, options.options_); 361 return SpvCompilationResult(compilation_result); 362 } 363 364 // Compiles the given source shader and returns a SPIR-V binary module 365 // compilation result. 366 // Like the first CompileGlslToSpv method but assumes the entry point name 367 // is "main". 368 SpvCompilationResult CompileGlslToSpv(const char* source_text, 369 size_t source_text_size, 370 shaderc_shader_kind shader_kind, 371 const char* input_file_name, 372 const CompileOptions& options) const { 373 return CompileGlslToSpv(source_text, source_text_size, shader_kind, 374 input_file_name, "main", options); 375 } 376 377 // Compiles the given source GLSL and returns a SPIR-V binary module 378 // compilation result. 379 // Like the previous CompileGlslToSpv method but uses default options. 380 SpvCompilationResult CompileGlslToSpv(const char* source_text, 381 size_t source_text_size, 382 shaderc_shader_kind shader_kind, 383 const char* input_file_name) const { 384 shaderc_compilation_result_t compilation_result = 385 shaderc_compile_into_spv(compiler_, source_text, source_text_size, 386 shader_kind, input_file_name, "main", nullptr); 387 return SpvCompilationResult(compilation_result); 388 } 389 390 // Compiles the given source shader and returns a SPIR-V binary module 391 // compilation result. 392 // Like the first CompileGlslToSpv method but the source is provided as 393 // a std::string, and we assume the entry point is "main". 394 SpvCompilationResult CompileGlslToSpv(const std::string& source_text, 395 shaderc_shader_kind shader_kind, 396 const char* input_file_name, 397 const CompileOptions& options) const { 398 return CompileGlslToSpv(source_text.data(), source_text.size(), shader_kind, 399 input_file_name, options); 400 } 401 402 // Compiles the given source shader and returns a SPIR-V binary module 403 // compilation result. 404 // Like the first CompileGlslToSpv method but the source is provided as 405 // a std::string. 406 SpvCompilationResult CompileGlslToSpv(const std::string& source_text, 407 shaderc_shader_kind shader_kind, 408 const char* input_file_name, 409 const char* entry_point_name, 410 const CompileOptions& options) const { 411 return CompileGlslToSpv(source_text.data(), source_text.size(), shader_kind, 412 input_file_name, entry_point_name, options); 413 } 414 415 // Compiles the given source GLSL and returns a SPIR-V binary module 416 // compilation result. 417 // Like the previous CompileGlslToSpv method but assumes the entry point 418 // name is "main". 419 SpvCompilationResult CompileGlslToSpv(const std::string& source_text, 420 shaderc_shader_kind shader_kind, 421 const char* input_file_name) const { 422 return CompileGlslToSpv(source_text.data(), source_text.size(), shader_kind, 423 input_file_name); 424 } 425 426 // Assembles the given SPIR-V assembly and returns a SPIR-V binary module 427 // compilation result. 428 // The assembly should follow the syntax defined in the SPIRV-Tools project 429 // (https://github.com/KhronosGroup/SPIRV-Tools/blob/master/syntax.md). 430 // It is valid for the returned CompilationResult object to outlive this 431 // compiler object. 432 // The assembling will pick options suitable for assembling specified in the 433 // CompileOptions parameter. 434 SpvCompilationResult AssembleToSpv(const char* source_assembly, 435 size_t source_assembly_size, 436 const CompileOptions& options) const { 437 return SpvCompilationResult(shaderc_assemble_into_spv( 438 compiler_, source_assembly, source_assembly_size, options.options_)); 439 } 440 441 // Assembles the given SPIR-V assembly and returns a SPIR-V binary module 442 // compilation result. 443 // Like the first AssembleToSpv method but uses the default compiler options. 444 SpvCompilationResult AssembleToSpv(const char* source_assembly, 445 size_t source_assembly_size) const { 446 return SpvCompilationResult(shaderc_assemble_into_spv( 447 compiler_, source_assembly, source_assembly_size, nullptr)); 448 } 449 450 // Assembles the given SPIR-V assembly and returns a SPIR-V binary module 451 // compilation result. 452 // Like the first AssembleToSpv method but the source is provided as a 453 // std::string. 454 SpvCompilationResult AssembleToSpv(const std::string& source_assembly, 455 const CompileOptions& options) const { 456 return SpvCompilationResult( 457 shaderc_assemble_into_spv(compiler_, source_assembly.data(), 458 source_assembly.size(), options.options_)); 459 } 460 461 // Assembles the given SPIR-V assembly and returns a SPIR-V binary module 462 // compilation result. 463 // Like the first AssembleToSpv method but the source is provided as a 464 // std::string and also uses default compiler options. 465 SpvCompilationResult AssembleToSpv(const std::string& source_assembly) const { 466 return SpvCompilationResult(shaderc_assemble_into_spv( 467 compiler_, source_assembly.data(), source_assembly.size(), nullptr)); 468 } 469 470 // Compiles the given source GLSL and returns the SPIR-V assembly text 471 // compilation result. 472 // Options are similar to the first CompileToSpv method. 473 AssemblyCompilationResult CompileGlslToSpvAssembly( 474 const char* source_text, size_t source_text_size, 475 shaderc_shader_kind shader_kind, const char* input_file_name, 476 const char* entry_point_name, const CompileOptions& options) const { 477 shaderc_compilation_result_t compilation_result = 478 shaderc_compile_into_spv_assembly( 479 compiler_, source_text, source_text_size, shader_kind, 480 input_file_name, entry_point_name, options.options_); 481 return AssemblyCompilationResult(compilation_result); 482 } 483 484 // Compiles the given source GLSL and returns the SPIR-V assembly text 485 // compilation result. 486 // Similare to the previous method, but assumes entry point name is "main". 487 AssemblyCompilationResult CompileGlslToSpvAssembly( 488 const char* source_text, size_t source_text_size, 489 shaderc_shader_kind shader_kind, const char* input_file_name, 490 const CompileOptions& options) const { 491 return CompileGlslToSpvAssembly(source_text, source_text_size, shader_kind, 492 input_file_name, "main", options); 493 } 494 495 // Compiles the given source GLSL and returns the SPIR-V assembly text 496 // result. Like the first CompileGlslToSpvAssembly method but the source 497 // is provided as a std::string. Options are otherwise similar to 498 // the first CompileToSpv method. 499 AssemblyCompilationResult CompileGlslToSpvAssembly( 500 const std::string& source_text, shaderc_shader_kind shader_kind, 501 const char* input_file_name, const char* entry_point_name, 502 const CompileOptions& options) const { 503 return CompileGlslToSpvAssembly(source_text.data(), source_text.size(), 504 shader_kind, input_file_name, 505 entry_point_name, options); 506 } 507 508 // Compiles the given source GLSL and returns the SPIR-V assembly text 509 // result. Like the previous CompileGlslToSpvAssembly method but assumes 510 // the entry point name is "main". 511 AssemblyCompilationResult CompileGlslToSpvAssembly( 512 const std::string& source_text, shaderc_shader_kind shader_kind, 513 const char* input_file_name, const CompileOptions& options) const { 514 return CompileGlslToSpvAssembly(source_text, shader_kind, input_file_name, 515 "main", options); 516 } 517 518 // Preprocesses the given source GLSL and returns the preprocessed 519 // source text as a compilation result. 520 // Options are similar to the first CompileToSpv method. 521 PreprocessedSourceCompilationResult PreprocessGlsl( 522 const char* source_text, size_t source_text_size, 523 shaderc_shader_kind shader_kind, const char* input_file_name, 524 const CompileOptions& options) const { 525 shaderc_compilation_result_t compilation_result = 526 shaderc_compile_into_preprocessed_text( 527 compiler_, source_text, source_text_size, shader_kind, 528 input_file_name, "main", options.options_); 529 return PreprocessedSourceCompilationResult(compilation_result); 530 } 531 532 // Preprocesses the given source GLSL and returns text result. Like the first 533 // PreprocessGlsl method but the source is provided as a std::string. 534 // Options are otherwise similar to the first CompileToSpv method. 535 PreprocessedSourceCompilationResult PreprocessGlsl( 536 const std::string& source_text, shaderc_shader_kind shader_kind, 537 const char* input_file_name, const CompileOptions& options) const { 538 return PreprocessGlsl(source_text.data(), source_text.size(), shader_kind, 539 input_file_name, options); 540 } 541 542 private: 543 Compiler(const Compiler&) = delete; 544 Compiler& operator=(const Compiler& other) = delete; 545 546 shaderc_compiler_t compiler_; 547}; 548} // namespace shaderc 549 550#endif // SHADERC_SHADERC_HPP_ 551