From a39e3cfe4ed8e2b4c41ae9d2e2b6c9590fe86c46 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 20 Oct 2016 14:30:41 -0400 Subject: Ignore .DS_Store files These are automatically generated on OSX. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 27cd089..61cc44f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ cscope.* third_party/glslang/ third_party/googletest/ third_party/spirv-tools/ +.DS_Store -- cgit v1.2.3 From e6b4795750f3ceb028fbfd860bd96b6aec859da1 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 20 Oct 2016 14:29:42 -0400 Subject: Rename GlslInitialzer -> GlslangInitializer --- libshaderc/src/shaderc.cc | 4 ++-- libshaderc/src/shaderc_private.h | 4 ++-- libshaderc_util/include/libshaderc_util/compiler.h | 16 ++++++++-------- libshaderc_util/src/compiler.cc | 2 +- libshaderc_util/src/compiler_test.cc | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc index 4702608..8a2f46a 100644 --- a/libshaderc/src/shaderc.cc +++ b/libshaderc/src/shaderc.cc @@ -338,8 +338,8 @@ void shaderc_compile_options_set_warnings_as_errors( } shaderc_compiler_t shaderc_compiler_initialize() { - static shaderc_util::GlslInitializer* initializer = - new shaderc_util::GlslInitializer; + static shaderc_util::GlslangInitializer* initializer = + new shaderc_util::GlslangInitializer; shaderc_compiler_t compiler = new (std::nothrow) shaderc_compiler; compiler->initializer = initializer; return compiler; diff --git a/libshaderc/src/shaderc_private.h b/libshaderc/src/shaderc_private.h index a11d449..de8fd07 100644 --- a/libshaderc/src/shaderc_private.h +++ b/libshaderc/src/shaderc_private.h @@ -84,11 +84,11 @@ class shaderc_compilation_result_spv_binary }; namespace shaderc_util { -class GlslInitializer; +class GlslangInitializer; } struct shaderc_compiler { - shaderc_util::GlslInitializer* initializer; + shaderc_util::GlslangInitializer* initializer; }; #endif // LIBSHADERC_SRC_SHADERC_PRIVATE_H_ diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h index bbddca5..f774007 100644 --- a/libshaderc_util/include/libshaderc_util/compiler.h +++ b/libshaderc_util/include/libshaderc_util/compiler.h @@ -39,11 +39,11 @@ enum class PassId; // glslang state can be correctly handled. // TODO(awoloszyn): Once glslang no longer has static global mutable state // remove this class. -class GlslInitializer { +class GlslangInitializer { public: - GlslInitializer() { glslang::InitializeProcess(); } + GlslangInitializer() { glslang::InitializeProcess(); } - ~GlslInitializer() { glslang::FinalizeProcess(); } + ~GlslangInitializer() { glslang::FinalizeProcess(); } // Calls release on GlslangInitializer used to intialize this object // when it is destroyed. @@ -63,11 +63,11 @@ class GlslInitializer { InitializationToken(const InitializationToken&) = delete; private: - InitializationToken(GlslInitializer* initializer) + InitializationToken(GlslangInitializer* initializer) : initializer_(initializer) {} - friend class GlslInitializer; - GlslInitializer* initializer_; + friend class GlslangInitializer; + GlslangInitializer* initializer_; }; // Obtains exclusive access to the glslang state. The state remains @@ -163,7 +163,7 @@ class Compiler { // from the shader text. Any #include directives are parsed with the given // includer. // - // The initializer parameter must be a valid GlslInitializer object. + // The initializer parameter must be a valid GlslangInitializer object. // Acquire will be called on the initializer and the result will be // destoryed before the function ends. // @@ -190,7 +190,7 @@ class Compiler { stage_callback, CountingIncluder& includer, OutputType output_type, std::ostream* error_stream, size_t* total_warnings, size_t* total_errors, - GlslInitializer* initializer) const; + GlslangInitializer* initializer) const; static EShMessages GetDefaultRules() { return static_cast(EShMsgSpvRules | EShMsgVulkanRules | diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc index 686f78f..b3c0a4f 100644 --- a/libshaderc_util/src/compiler.cc +++ b/libshaderc_util/src/compiler.cc @@ -91,7 +91,7 @@ std::tuple, size_t> Compiler::Compile( stage_callback, CountingIncluder& includer, OutputType output_type, std::ostream* error_stream, size_t* total_warnings, size_t* total_errors, - GlslInitializer* initializer) const { + GlslangInitializer* initializer) const { // Compilation results to be returned: // Initialize the result tuple as a failed compilation. In error cases, we // should return result_tuple directly without setting its members. diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc index b11e04b..957f8f3 100644 --- a/libshaderc_util/src/compiler_test.cc +++ b/libshaderc_util/src/compiler_test.cc @@ -107,7 +107,7 @@ class CompilerTest : public testing::Test { std::stringstream errors; size_t total_warnings = 0; size_t total_errors = 0; - shaderc_util::GlslInitializer initializer; + shaderc_util::GlslangInitializer initializer; bool result = false; DummyCountingIncluder dummy_includer; std::tie(result, std::ignore, std::ignore) = compiler_.Compile( -- cgit v1.2.3 From fa933206ff7943ff8f58bfb1748d3a401231377c Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 20 Oct 2016 15:08:31 -0400 Subject: Add API support for compiling HLSL Exposes the HLSL functionality in Glslang. Done in three layers: - libshaderc_util::Compiler: Add libshaderc_util::Compiler::SourceLanguage enum. Add libshaderc_util::Compiler::SetSourceLanguage method. The default language remains GLSL. libshaderc_util::Compiler passes the source language option into Glslang. - C API Add function to set source language on compiler options. - C++ API Add shaderc::CompileOptions::SetSourceLanguage --- libshaderc/include/shaderc/shaderc.h | 10 ++++++ libshaderc/include/shaderc/shaderc.hpp | 5 +++ libshaderc/src/common_shaders_for_test.h | 3 ++ libshaderc/src/shaderc.cc | 9 +++++ libshaderc/src/shaderc_cpp_test.cc | 28 +++++++++++++++ libshaderc/src/shaderc_test.cc | 40 ++++++++++++++++++++++ libshaderc_util/include/libshaderc_util/compiler.h | 17 +++++++-- libshaderc_util/src/compiler.cc | 26 +++++++++----- libshaderc_util/src/compiler_test.cc | 27 +++++++++++++++ 9 files changed, 155 insertions(+), 10 deletions(-) diff --git a/libshaderc/include/shaderc/shaderc.h b/libshaderc/include/shaderc/shaderc.h index 46d98b4..64d94ea 100644 --- a/libshaderc/include/shaderc/shaderc.h +++ b/libshaderc/include/shaderc/shaderc.h @@ -23,6 +23,12 @@ extern "C" { #include #include +// Source language kind. +typedef enum { + shaderc_source_language_glsl, + shaderc_source_language_hlsl, +} shaderc_source_language; + typedef enum { // Forced shader kinds. These shader kinds force the compiler to compile the // source code as the specified kind of shader. @@ -158,6 +164,10 @@ 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); +// Sets the source language. The default is GLSL. +void shaderc_compile_options_set_source_language( + shaderc_compile_options_t options, shaderc_source_language lang); + // Sets the compiler mode to generate debug information in the output. void shaderc_compile_options_set_generate_debug_info( shaderc_compile_options_t options); diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp index 4e5dfd7..1dc2631 100644 --- a/libshaderc/include/shaderc/shaderc.hpp +++ b/libshaderc/include/shaderc/shaderc.hpp @@ -221,6 +221,11 @@ class CompileOptions { shaderc_compile_options_set_suppress_warnings(options_); } + // Sets the source language. The default is GLSL. + void SetSourceLanguage(shaderc_source_language lang) { + shaderc_compile_options_set_source_language(options_, lang); + } + // Sets the target shader environment, affecting which warnings or errors will // be issued. // The version will be for distinguishing between different versions of the diff --git a/libshaderc/src/common_shaders_for_test.h b/libshaderc/src/common_shaders_for_test.h index d25c6bf..a0120a2 100644 --- a/libshaderc/src/common_shaders_for_test.h +++ b/libshaderc/src/common_shaders_for_test.h @@ -25,6 +25,9 @@ const char kMinimalShaderWithoutVersion[] = "void main(){}"; const char kMinimalShader[] = "#version 140\n" "void main(){}"; +const char kMinimalHlslShader[] = + "float4 EntryPoint(uint index : SV_VERTEXID) : SV_POSITION\n" + "{ return float4(1.0, 2.0, 3.0, 4.0); }"; const char kMinimalShaderWithMacro[] = "#version 140\n" "#define E main\n" diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc index 8a2f46a..845320b 100644 --- a/libshaderc/src/shaderc.cc +++ b/libshaderc/src/shaderc.cc @@ -270,6 +270,15 @@ void shaderc_compile_options_add_macro_definition( 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(); diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc index 521f109..2762197 100644 --- a/libshaderc/src/shaderc_cpp_test.cc +++ b/libshaderc/src/shaderc_cpp_test.cc @@ -1015,4 +1015,32 @@ TEST_F(CppInterface, BeginAndEndOnPreprocessedResult) { EXPECT_THAT(string_via_begin_end, Eq(forced_to_be_a_string)); } +TEST_F(CppInterface, SourceLangGlslMinimalGlslVertexShaderSucceeds) { + options_.SetSourceLanguage(shaderc_source_language_glsl); + EXPECT_TRUE(CompilationSuccess(kVertexOnlyShader, + shaderc_glsl_vertex_shader, + options_)); +} + +TEST_F(CppInterface, SourceLangGlslMinimalHlslVertexShaderFails) { + options_.SetSourceLanguage(shaderc_source_language_glsl); + EXPECT_FALSE(CompilationSuccess(kMinimalHlslShader, + shaderc_glsl_vertex_shader, + options_)); +} + +TEST_F(CppInterface, SourceLangHlslMinimalGlslVertexShaderFails) { + options_.SetSourceLanguage(shaderc_source_language_hlsl); + EXPECT_FALSE(CompilationSuccess(kVertexOnlyShader, + shaderc_glsl_vertex_shader, + options_)); +} + +TEST_F(CppInterface, SourceLangHlslMinimalHlslVertexShaderSucceeds) { + options_.SetSourceLanguage(shaderc_source_language_hlsl); + EXPECT_TRUE(CompilationSuccess(kMinimalHlslShader, + shaderc_glsl_vertex_shader, + options_)); +} + } // anonymous namespace diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc index c14b9c3..df8a5cb 100644 --- a/libshaderc/src/shaderc_test.cc +++ b/libshaderc/src/shaderc_test.cc @@ -1292,4 +1292,44 @@ TEST_F(CompileStringTest, NullSourceNameFailsCompilingToPreprocessedText) { HasSubstr("Input file name string was null.")); } +const char kGlslVertexShader[] = + "#version 140\nvoid main(){ gl_Position = vec4(0);}"; + +const char kHlslVertexShader[] = + "float4 EntryPoint(uint index : SV_VERTEXID) : SV_POSITION\n" + "{ return float4(1.0, 2.0, 3.0, 4.0); }"; + +TEST_F(CompileStringTest, LangGlslOnGlslVertexSucceeds) { + shaderc_compile_options_set_source_language(options_.get(), + shaderc_source_language_glsl); + EXPECT_TRUE(CompilationSuccess(kGlslVertexShader, + shaderc_glsl_vertex_shader, + options_.get())); +} + +TEST_F(CompileStringTest, LangGlslOnHlslVertexFails) { + shaderc_compile_options_set_source_language(options_.get(), + shaderc_source_language_glsl); + EXPECT_FALSE(CompilationSuccess(kHlslVertexShader, + shaderc_glsl_vertex_shader, + options_.get())); +} + +TEST_F(CompileStringTest, LangHlslOnGlslVertexFails) { + shaderc_compile_options_set_source_language(options_.get(), + shaderc_source_language_hlsl); + EXPECT_FALSE(CompilationSuccess(kGlslVertexShader, + shaderc_glsl_vertex_shader, + options_.get())); +} + +TEST_F(CompileStringTest, LangHlslOnHlslVertexSucceeds) { + shaderc_compile_options_set_source_language(options_.get(), + shaderc_source_language_hlsl); + EXPECT_TRUE(CompilationSuccess(kHlslVertexShader, + shaderc_glsl_vertex_shader, + options_.get())); +} + + } // anonymous namespace diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h index f774007..d396ca1 100644 --- a/libshaderc_util/include/libshaderc_util/compiler.h +++ b/libshaderc_util/include/libshaderc_util/compiler.h @@ -92,6 +92,12 @@ using MacroDictionary = std::unordered_map; // Holds all of the state required to compile source GLSL into SPIR-V. class Compiler { public: + // Source language + enum class SourceLanguage { + GLSL, // The default + HLSL, + }; + // Target environment. enum class TargetEnv { Vulkan, @@ -123,7 +129,8 @@ class Compiler { suppress_warnings_(false), generate_debug_info_(false), enabled_opt_passes_(), - target_env_(TargetEnv::Vulkan) {} + target_env_(TargetEnv::Vulkan), + source_language_(SourceLanguage::GLSL) {} // Requests that the compiler place debug information into the object code, // such as identifier names and line numbers. @@ -149,6 +156,9 @@ class Compiler { // Sets the target environment. void SetTargetEnv(TargetEnv env); + // Sets the souce language. + void SetSourceLanguage(SourceLanguage lang); + // Forces (without any verification) the default version and profile for // subsequent CompileShader() calls. void SetForcedVersionProfile(int version, EProfile profile); @@ -165,7 +175,7 @@ class Compiler { // // The initializer parameter must be a valid GlslangInitializer object. // Acquire will be called on the initializer and the result will be - // destoryed before the function ends. + // destroyed before the function ends. // // The output_type parameter determines what kind of output should be // produced. @@ -292,6 +302,9 @@ class Compiler { // messages as well as the set of available builtins, as per the // implementation of glslang. TargetEnv target_env_; + + // The source language. Defaults to GLSL. + SourceLanguage source_language_; }; // Converts a string to a vector of uint32_t by copying the content of a given diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc index b3c0a4f..52eb81f 100644 --- a/libshaderc_util/src/compiler.cc +++ b/libshaderc_util/src/compiler.cc @@ -65,19 +65,26 @@ std::pair DecodeLineDirective(string_piece directive) { return std::make_pair(line, directive); } -// Gets the corresponding message rules for the given target environment. -EShMessages GetMessageRules(shaderc_util::Compiler::TargetEnv env) { +// Returns the Glslang message rules for the given target environment +// and source language. We assume only valid combinations are used. +EShMessages GetMessageRules(shaderc_util::Compiler::TargetEnv env, + shaderc_util::Compiler::SourceLanguage lang) { using shaderc_util::Compiler; + EShMessages result = EShMsgCascadingErrors; + if (lang == Compiler::SourceLanguage::HLSL) { + result = static_cast(result | EShMsgReadHlsl); + } switch (env) { case Compiler::TargetEnv::OpenGLCompat: break; case Compiler::TargetEnv::OpenGL: - return static_cast(EShMsgSpvRules | EShMsgCascadingErrors); + result = static_cast(result | EShMsgSpvRules); + break; case Compiler::TargetEnv::Vulkan: - return static_cast(EShMsgSpvRules | EShMsgVulkanRules | - EShMsgCascadingErrors); + result = static_cast(result | EShMsgSpvRules | EShMsgVulkanRules); + break; } - return EShMsgCascadingErrors; + return result; } } // anonymous namespace @@ -177,7 +184,8 @@ std::tuple, size_t> Compiler::Compile( bool success = shader.parse(&shaderc_util::kDefaultTBuiltInResource, default_version_, default_profile_, force_version_profile_, kNotForwardCompatible, - GetMessageRules(target_env_), includer); + GetMessageRules(target_env_, source_language_), + includer); success &= PrintFilteredErrors(error_tag, error_stream, warnings_as_errors_, suppress_warnings_, shader.getInfoLog(), @@ -238,6 +246,8 @@ void Compiler::AddMacroDefinition(const char* macro, size_t macro_length, void Compiler::SetTargetEnv(Compiler::TargetEnv env) { target_env_ = env; } +void Compiler::SetSourceLanguage(Compiler::SourceLanguage lang) { source_language_ = lang; } + void Compiler::SetForcedVersionProfile(int version, EProfile profile) { default_version_ = version; default_profile_ = profile; @@ -289,7 +299,7 @@ std::tuple Compiler::PreprocessShader( // So combine the existing rules with the just-give-me-preprocessor-output // flag. const auto rules = static_cast(EShMsgOnlyPreprocessor | - GetMessageRules(target_env_)); + GetMessageRules(target_env_, source_language_)); std::string preprocessed_shader; const bool success = shader.preprocess( diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc index 957f8f3..36931ff 100644 --- a/libshaderc_util/src/compiler_test.cc +++ b/libshaderc_util/src/compiler_test.cc @@ -77,6 +77,11 @@ const std::string kValuelessPredefinitionShader = "#error\n" "#endif"; +// An HLSL vertex shader. +const char kHlslVertexShader[] = + R"(float4 EntryPoint(uint index : SV_VERTEXID) : SV_POSITION + { return float4(1.0, 2.0, 3.0, 4.0); })"; + // A CountingIncluder that never returns valid content for a requested // file inclusion. class DummyCountingIncluder : public shaderc_util::CountingIncluder { @@ -311,4 +316,26 @@ INSTANTIATE_TEST_CASE_P( {"123456789", {0x34333231, 0x38373635, 0x00000039}}, })); +TEST_F(CompilerTest, SetSourceLanguageToGLSLSucceeds) { + compiler_.SetSourceLanguage(Compiler::SourceLanguage::GLSL); + EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex)); +} + +TEST_F(CompilerTest, SetSourceLanguageToGLSLFailsOnHLSL) { + compiler_.SetSourceLanguage(Compiler::SourceLanguage::GLSL); + EXPECT_FALSE(SimpleCompilationSucceeds(kHlslVertexShader, EShLangVertex)); +} + +TEST_F(CompilerTest, SetSourceLanguageToHLSLSucceeds) { + compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL); + EXPECT_TRUE(SimpleCompilationSucceeds(kHlslVertexShader, EShLangVertex)) + << errors_; +} + +TEST_F(CompilerTest, SetSourceLanguageToHLSLFailsOnGLSL) { + compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL); + EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex)); +} + + } // anonymous namespace -- cgit v1.2.3 From cdefe18ac0a172812fda8e44d9249995b2f8451a Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 21 Oct 2016 01:12:53 -0400 Subject: glslc: expose HLSL compilation support from Glslang Support "-x hlsl", i.e. hlsl is a valid language specifier. HLSL compilation ignores -std=... option Files with .hlsl extension default to HLSL. --- CHANGES | 3 +++ glslc/README.asciidoc | 10 +++++--- glslc/src/file.h | 10 +++++--- glslc/src/file_compiler.cc | 15 ++++++++--- glslc/src/file_compiler.h | 3 ++- glslc/src/file_test.cc | 39 +++++++++++++++++----------- glslc/src/main.cc | 49 ++++++++++++++++++++++++++---------- glslc/test/option_dash_x.py | 53 +++++++++++++++++++++++++++++++++++---- glslc/test/option_shader_stage.py | 24 ++++++++++++++++++ glslc/test/option_std.py | 13 ++++++++++ glslc/test/parameter_tests.py | 8 +++--- libshaderc/src/shaderc_test.cc | 15 ++++------- 12 files changed, 184 insertions(+), 58 deletions(-) diff --git a/CHANGES b/CHANGES index 1f9df68..db599b1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Revision history for Shaderc v2016.2-dev 2016-10-12 + - Support HLSL compilation, exposing functionality in Glslang. + - Supported in C, C++ API + - glslc accepts "-x hlsl", and assumes .hlsl files are HLSL. v2016.1 2016-10-12 - C API for assembling now takes an options object diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc index ba6375a..5a546f2 100644 --- a/glslc/README.asciidoc +++ b/glslc/README.asciidoc @@ -11,7 +11,7 @@ ---- glslc [-c|-S|-E] - [-x glsl] [-std=standard] + [-x ...] [-std=standard] [-fshader-stage=...] [--target-env=...] [-g] @@ -158,7 +158,8 @@ GLSL, e.g., `450`. `-std=` behaves as follows: -* `-std=` affects the version of all inputs passed to `glslc`. +* `-std=` affects the version of all GLSL inputs passed to `glslc`. +* `-std=` is ignored for HLSL inputs. * `-std=` overwrites `#version` directives in all input shaders, including those preceding the argument. * If a `-std=` argument specifies a different version from a `#version` @@ -189,8 +190,9 @@ under Vulkan semantics. ==== `-x` -`-x` lets you specify the language of the input shader files. Right now, the -only accepted argument is `glsl`. +`-x` lets you specify the language of the input shader files. Valid languages +are `glsl` and `hlsl`. If the file extension is `hlsl` then the default language +is HLSL. Otherwise the default is 'glsl'. [[compilation-stage-selection-options]] === Compilation Stage Selection Options diff --git a/glslc/src/file.h b/glslc/src/file.h index 93d98ef..902b4cf 100644 --- a/glslc/src/file.h +++ b/glslc/src/file.h @@ -32,9 +32,13 @@ inline bool IsStageFile(const shaderc_util::string_piece& filename) { extension == "tese" || extension == "geom" || extension == "comp"; } -// Returns true if the given file name has extension "glsl". -inline bool IsGlslFile(const shaderc_util::string_piece& filename) { - return glslc::GetFileExtension(filename) == "glsl"; +// Returns the file extension if is either "glsl" or "hlsl", or an empty +// string otherwise. +inline std::string GetGlslOrHlslExtension( + const shaderc_util::string_piece& filename) { + auto extension = glslc::GetFileExtension(filename); + if ((extension == "glsl") || (extension == "hlsl")) return extension.str(); + return ""; } } // namespace glslc diff --git a/glslc/src/file_compiler.cc b/glslc/src/file_compiler.cc index 311fddf..1aed39d 100644 --- a/glslc/src/file_compiler.cc +++ b/glslc/src/file_compiler.cc @@ -63,7 +63,8 @@ bool EmitSpirvBinaryAsCommaSeparatedNumbers(const CompilationResultType& result, namespace glslc { bool FileCompiler::CompileShaderFile(const std::string& input_file, - shaderc_shader_kind shader_stage) { + shaderc_shader_kind shader_stage, + shaderc_source_language lang) { std::vector input_data; std::string path = input_file; if (!shaderc_util::ReadFile(path, &input_data)) { @@ -111,6 +112,11 @@ bool FileCompiler::CompileShaderFile(const std::string& input_file, } } + // Set the language. Since we only use the options object in this + // method, then it's ok to always set it without resetting it after + // compilation. A subsequent compilation will set it again anyway. + options_.SetSourceLanguage(lang); + switch (output_type_) { case OutputType::SpirvBinary: { const auto result = compiler_.CompileGlslToSpv( @@ -152,11 +158,12 @@ bool FileCompiler::EmitCompiledResult( // Handle the error message for failing to deduce the shader kind. if (result.GetCompilationStatus() == shaderc_compilation_status_invalid_stage) { - if (IsGlslFile(error_file_name)) { + auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name); + if (glsl_or_hlsl_extension != "") { std::cerr << "glslc: error: " << "'" << error_file_name << "': " - << ".glsl file encountered but no -fshader-stage " - "specified ahead"; + << "." << glsl_or_hlsl_extension + << " file encountered but no -fshader-stage specified ahead"; } else if (error_file_name == "") { std::cerr << "glslc: error: '-': -fshader-stage required when input is from " diff --git a/glslc/src/file_compiler.h b/glslc/src/file_compiler.h index 6b077a1..4d8cb35 100644 --- a/glslc/src/file_compiler.h +++ b/glslc/src/file_compiler.h @@ -60,7 +60,8 @@ class FileCompiler { // Any errors/warnings found in the shader source will be output to std::cerr // and increment the counts reported by OutputMessages(). bool CompileShaderFile(const std::string& input_file, - shaderc_shader_kind shader_stage); + shaderc_shader_kind shader_stage, + shaderc_source_language lang); // Adds a directory to be searched when processing #include directives. // diff --git a/glslc/src/file_test.cc b/glslc/src/file_test.cc index f242621..d9e075b 100644 --- a/glslc/src/file_test.cc +++ b/glslc/src/file_test.cc @@ -14,14 +14,15 @@ #include "file.h" -#include +#include namespace { using glslc::GetFileExtension; using glslc::IsStageFile; -using glslc::IsGlslFile; +using glslc::GetGlslOrHlslExtension; using shaderc_util::string_piece; +using testing::Eq; class FileExtensionTest : public testing::Test { protected: @@ -36,7 +37,10 @@ class FileExtensionTest : public testing::Test { string_piece geom_ext = "shader.geom"; string_piece comp_ext = "shader.comp"; string_piece glsl_ext = "shader.glsl"; + string_piece hlsl_ext = "shader.hlsl"; string_piece multi_dot = "shader.some..ext"; + string_piece both_hg_ext = "shader.hlsl.glsl"; + string_piece both_gh_ext = "shader.glsl.hlsl"; }; TEST_F(FileExtensionTest, GetFileExtension) { @@ -52,21 +56,26 @@ TEST_F(FileExtensionTest, GetFileExtension) { EXPECT_EQ("comp", GetFileExtension(comp_ext)); EXPECT_EQ("glsl", GetFileExtension(glsl_ext)); EXPECT_EQ("ext", GetFileExtension(multi_dot)); + EXPECT_EQ("glsl", GetFileExtension(both_hg_ext)); + EXPECT_EQ("hlsl", GetFileExtension(both_gh_ext)); } -TEST_F(FileExtensionTest, IsGlslFile) { - EXPECT_FALSE(IsGlslFile(empty)); - EXPECT_FALSE(IsGlslFile(dot)); - EXPECT_FALSE(IsGlslFile(no_ext)); - EXPECT_FALSE(IsGlslFile(trailing_dot)); - EXPECT_FALSE(IsGlslFile(vert_ext)); - EXPECT_FALSE(IsGlslFile(frag_ext)); - EXPECT_FALSE(IsGlslFile(tesc_ext)); - EXPECT_FALSE(IsGlslFile(tese_ext)); - EXPECT_FALSE(IsGlslFile(geom_ext)); - EXPECT_FALSE(IsGlslFile(comp_ext)); - EXPECT_TRUE(IsGlslFile(glsl_ext)); - EXPECT_FALSE(IsGlslFile(multi_dot)); +TEST_F(FileExtensionTest, GetGlslOrHlslExtension) { + EXPECT_THAT(GetGlslOrHlslExtension(empty), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(dot), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(no_ext), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(trailing_dot), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(vert_ext), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(frag_ext), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(tesc_ext), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(tese_ext), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(geom_ext), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(comp_ext), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(glsl_ext), Eq("glsl")); + EXPECT_THAT(GetGlslOrHlslExtension(hlsl_ext), Eq("hlsl")); + EXPECT_THAT(GetGlslOrHlslExtension(multi_dot), Eq("")); + EXPECT_THAT(GetGlslOrHlslExtension(both_hg_ext), Eq("glsl")); + EXPECT_THAT(GetGlslOrHlslExtension(both_gh_ext), Eq("hlsl")); } TEST_F(FileExtensionTest, IsStageFile) { diff --git a/glslc/src/main.cc b/glslc/src/main.cc index 782e3ce..193bc7f 100644 --- a/glslc/src/main.cc +++ b/glslc/src/main.cc @@ -22,6 +22,7 @@ #include #include "libshaderc_util/string_piece.h" +#include "shaderc/shaderc.h" #include "spirv-tools/libspirv.h" #include "file.h" @@ -32,6 +33,13 @@ using shaderc_util::string_piece; namespace { +// Describes an input file to be compiled. +struct InputFileSpec { + std::string name; + shaderc_shader_kind stage; + shaderc_source_language language; +}; + // Prints the help message. void PrintHelp(std::ostream* out) { *out << R"(glslc - Compile shaders into SPIR-V @@ -56,9 +64,9 @@ Options: -I Add directory to include search path. -o Write output to . A file name of '-' represents standard output. - -std= Version and profile for input files. Possible values + -std= Version and profile for GLSL input files. Possible values are concatenations of version and profile, e.g. 310es, - 450core, etc. + 450core, etc. Ignored for HLSL files. -mfmt= Output SPIR-V binary code using the selected format. This option may be specified only when the compilation output is in SPIR-V binary code form. Available options include bin, c @@ -77,7 +85,9 @@ Options: -w Suppresses all warning messages. -Werror Treat all warnings as errors. -x Treat subsequent input files as having type . - The only supported language is glsl. + Valid languages are: glsl, hlsl. + For files ending in .hlsl the default is hlsl. + Otherwise the default is glsl. )"; } @@ -110,8 +120,11 @@ const char kBuildVersion[] = } // anonymous namespace int main(int argc, char** argv) { - std::vector> input_files; + std::vector input_files; shaderc_shader_kind current_fshader_stage = shaderc_glsl_infer_from_source; + bool source_language_forced = false; + shaderc_source_language current_source_language = + shaderc_source_language_glsl; glslc::FileCompiler compiler; bool success = true; bool has_stdin_input = false; @@ -196,11 +209,16 @@ int main(int argc, char** argv) { << std::endl; success = false; } else { - if (option_arg != "glsl") { + if (option_arg == "glsl") { + current_source_language = shaderc_source_language_glsl; + } else if (option_arg == "hlsl") { + current_source_language = shaderc_source_language_hlsl; + } else { std::cerr << "glslc: error: language not recognized: '" << option_arg << "'" << std::endl; return 1; } + source_language_forced = true; } } else if (arg == "-c") { compiler.SetIndividualCompilationFlag(); @@ -329,15 +347,22 @@ int main(int argc, char** argv) { has_stdin_input = true; } + const auto language = source_language_forced + ? current_source_language + : ((glslc::GetFileExtension(arg) == "hlsl") + ? shaderc_source_language_hlsl + : shaderc_source_language_glsl); + // If current_fshader_stage is shaderc_glsl_infer_from_source, that means // we didn't set forced shader kinds (otherwise an error should have // already been emitted before). So we should deduce the shader kind // from the file name. If current_fshader_stage is specifed to one of // the forced shader kinds, use that for the following compilation. - input_files.emplace_back( - arg.str(), current_fshader_stage == shaderc_glsl_infer_from_source - ? glslc::DeduceDefaultShaderKindFromFileName(arg) - : current_fshader_stage); + input_files.emplace_back(InputFileSpec{ + arg.str(), (current_fshader_stage == shaderc_glsl_infer_from_source + ? glslc::DeduceDefaultShaderKindFromFileName(arg) + : current_fshader_stage), + language}); } } @@ -346,10 +371,8 @@ int main(int argc, char** argv) { if (!success) return 1; for (const auto& input_file : input_files) { - const std::string& name = input_file.first; - const shaderc_shader_kind stage = input_file.second; - - success &= compiler.CompileShaderFile(name, stage); + success &= compiler.CompileShaderFile(input_file.name, input_file.stage, + input_file.language); } compiler.OutputMessages(); diff --git a/glslc/test/option_dash_x.py b/glslc/test/option_dash_x.py index 5e2c5ee..43b8b96 100644 --- a/glslc/test/option_dash_x.py +++ b/glslc/test/option_dash_x.py @@ -17,6 +17,10 @@ from glslc_test_framework import inside_glslc_testsuite from placeholder import FileShader MINIMAL_SHADER = "#version 140\nvoid main(){}" +# This one is valid GLSL but not valid HLSL. +GLSL_VERTEX_SHADER = "#version 140\nvoid main(){ gl_Position = vec4(1.0);}" +# This one is valid HLSL but not valid GLSL. +HLSL_VERTEX_SHADER = "float4 EntryPoint() : SV_POSITION { return float4(1.0); }" @inside_glslc_testsuite('OptionDashX') class TestDashXNoArg(expect.ErrorMessage): @@ -29,13 +33,40 @@ class TestDashXNoArg(expect.ErrorMessage): @inside_glslc_testsuite('OptionDashX') -class TestDashXGlsl(expect.ValidObjectFile): - """Tests -x glsl.""" +class TestDashXGlslOnGlslShader(expect.ValidObjectFile): + """Tests -x glsl on a GLSL shader.""" - shader = FileShader(MINIMAL_SHADER, '.vert') + shader = FileShader(GLSL_VERTEX_SHADER, '.vert') glslc_args = ['-x', 'glsl', '-c', shader] +@inside_glslc_testsuite('OptionDashX') +class TestDashXGlslOnHlslShader(expect.ErrorMessageSubstr): + """Tests -x glsl on an HLSL shader.""" + + shader = FileShader(HLSL_VERTEX_SHADER, '.vert') + glslc_args = ['-x', 'glsl', '-c', shader] + expected_error_substr = ["error: #version: Desktop shaders for Vulkan SPIR-V" + " require version 140 or higher\n"] + + +@inside_glslc_testsuite('OptionDashX') +class TestDashXHlslOnHlslShader(expect.ValidObjectFile): + """Tests -x hlsl on an HLSL shader.""" + + shader = FileShader(HLSL_VERTEX_SHADER, '.vert') + glslc_args = ['-x', 'hlsl', '-c', shader] + + +@inside_glslc_testsuite('OptionDashX') +class TestDashXHlslOnGlslShader(expect.ErrorMessageSubstr): + """Tests -x hlsl on a GLSL shader.""" + + shader = FileShader(GLSL_VERTEX_SHADER, '.vert') + glslc_args = ['-x', 'hlsl', '-c', shader] + expected_error_substr = ["error: 'vec4' : no matching overloaded function found\n"] + + @inside_glslc_testsuite('OptionDashX') class TestDashXWrongParam(expect.ErrorMessage): """Tests -x with wrong parameter.""" @@ -47,12 +78,24 @@ class TestDashXWrongParam(expect.ErrorMessage): @inside_glslc_testsuite('OptionDashX') class TestMultipleDashX(expect.ValidObjectFile): - """Tests that multiple -x glsl works.""" + """Tests that multiple -x works with a single language.""" - shader = FileShader(MINIMAL_SHADER, '.vert') + shader = FileShader(GLSL_VERTEX_SHADER, '.vert') glslc_args = ['-c', '-x', 'glsl', '-x', 'glsl', shader, '-x', 'glsl'] +@inside_glslc_testsuite('OptionDashX') +class TestMultipleDashXMixedLanguages(expect.ValidObjectFile): + """Tests that multiple -x works with different languages.""" + + glsl_shader = FileShader(GLSL_VERTEX_SHADER, '.vert') + hlsl_shader = FileShader(HLSL_VERTEX_SHADER, '.vert') + glslc_args = ['-c', '-x', 'hlsl', hlsl_shader, + '-x', 'glsl', glsl_shader, + '-x', 'hlsl', hlsl_shader, + '-x', 'glsl', glsl_shader] + + @inside_glslc_testsuite('OptionDashX') class TestMultipleDashXCorrectWrong(expect.ErrorMessage): """Tests -x glsl -x [wrong-language].""" diff --git a/glslc/test/option_shader_stage.py b/glslc/test/option_shader_stage.py index 8e0bcbb..5114173 100644 --- a/glslc/test/option_shader_stage.py +++ b/glslc/test/option_shader_stage.py @@ -24,6 +24,10 @@ def simple_vertex_shader(): }""" +def simple_hlsl_vertex_shader(): + return """float4 EntryPoint() : SV_POSITION { return float4(1.0); } """ + + def simple_fragment_shader(): return """#version 310 es void main() { @@ -65,6 +69,14 @@ class TestShaderStageWithGlslExtension(expect.ValidObjectFile): glslc_args = ['-c', '-fshader-stage=vertex', shader] +@inside_glslc_testsuite('OptionShaderStage') +class TestShaderStageWithHlslExtension(expect.ValidObjectFile): + """Tests -fshader-stage with .hlsl extension.""" + + shader = FileShader(simple_hlsl_vertex_shader(), '.hlsl') + glslc_args = ['-c', '-fshader-stage=vertex', shader] + + @inside_glslc_testsuite('OptionShaderStage') class TestShaderStageWithKnownExtension(expect.ValidObjectFile): """Tests -fshader-stage with known extension.""" @@ -187,6 +199,18 @@ class TestShaderStageGlslExtensionMissingShaderStage(expect.ErrorMessage): "': .glsl file encountered but no -fshader-stage specified ahead\n"] +@inside_glslc_testsuite('OptionShaderStage') +class TestShaderStageHlslExtensionMissingShaderStage(expect.ErrorMessage): + """Tests that missing -fshader-stage for .hlsl extension results in + an error.""" + + shader = FileShader(simple_hlsl_vertex_shader(), '.hlsl') + glslc_args = ['-c', '-x', 'hlsl', shader] + expected_error = [ + "glslc: error: '", shader, + "': .hlsl file encountered but no -fshader-stage specified ahead\n"] + + @inside_glslc_testsuite('OptionShaderStage') class TestShaderStageUnknownExtensionMissingShaderStage(expect.ErrorMessage): """Tests that missing -fshader-stage for unknown extension results in diff --git a/glslc/test/option_std.py b/glslc/test/option_std.py index 9ad762b..865a4d2 100644 --- a/glslc/test/option_std.py +++ b/glslc/test/option_std.py @@ -28,6 +28,10 @@ def core_frag_shader_without_version(): return 'void main() { int temp = gl_SampleID; }' +def hlsl_compute_shader_with_barriers(): + return 'void Entry() { AllMemoryBarrierWithGroupSync(); }' + + @inside_glslc_testsuite('OptionStd') class TestStdNoArg(expect.ErrorMessage): """Tests -std alone.""" @@ -71,6 +75,15 @@ class TestMissingVersionButHavingStd(expect.ValidObjectFile): glslc_args = ['-c', '-std=450core', shader] +@inside_glslc_testsuite('OptionStd') +class TestStdIgnoredInHlsl(expect.ValidObjectFile): + """Tests HLSL compilation ignores -std.""" + + # Compute shaders are not available in OpenGL 150 + shader = FileShader(hlsl_compute_shader_with_barriers(), '.comp') + glslc_args = ['-c', '-x', 'hlsl', '-std=150', shader] + + @inside_glslc_testsuite('OptionStd') class TestMissingVersionAndWrongStd(expect.ErrorMessage): """Tests missing #version and wrong -std results in errors.""" diff --git a/glslc/test/parameter_tests.py b/glslc/test/parameter_tests.py index 235b609..ff450b1 100644 --- a/glslc/test/parameter_tests.py +++ b/glslc/test/parameter_tests.py @@ -68,9 +68,9 @@ Options: -I Add directory to include search path. -o Write output to . A file name of '-' represents standard output. - -std= Version and profile for input files. Possible values + -std= Version and profile for GLSL input files. Possible values are concatenations of version and profile, e.g. 310es, - 450core, etc. + 450core, etc. Ignored for HLSL files. -mfmt= Output SPIR-V binary code using the selected format. This option may be specified only when the compilation output is in SPIR-V binary code form. Available options include bin, c @@ -89,7 +89,9 @@ Options: -w Suppresses all warning messages. -Werror Treat all warnings as errors. -x Treat subsequent input files as having type . - The only supported language is glsl. + Valid languages are: glsl, hlsl. + For files ending in .hlsl the default is hlsl. + Otherwise the default is glsl. ''' expected_stderr = '' diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc index df8a5cb..280a5d1 100644 --- a/libshaderc/src/shaderc_test.cc +++ b/libshaderc/src/shaderc_test.cc @@ -1293,7 +1293,7 @@ TEST_F(CompileStringTest, NullSourceNameFailsCompilingToPreprocessedText) { } const char kGlslVertexShader[] = - "#version 140\nvoid main(){ gl_Position = vec4(0);}"; + "#version 140\nvoid main(){ gl_Position = vec4(0);}"; const char kHlslVertexShader[] = "float4 EntryPoint(uint index : SV_VERTEXID) : SV_POSITION\n" @@ -1302,34 +1302,29 @@ const char kHlslVertexShader[] = TEST_F(CompileStringTest, LangGlslOnGlslVertexSucceeds) { shaderc_compile_options_set_source_language(options_.get(), shaderc_source_language_glsl); - EXPECT_TRUE(CompilationSuccess(kGlslVertexShader, - shaderc_glsl_vertex_shader, + EXPECT_TRUE(CompilationSuccess(kGlslVertexShader, shaderc_glsl_vertex_shader, options_.get())); } TEST_F(CompileStringTest, LangGlslOnHlslVertexFails) { shaderc_compile_options_set_source_language(options_.get(), shaderc_source_language_glsl); - EXPECT_FALSE(CompilationSuccess(kHlslVertexShader, - shaderc_glsl_vertex_shader, + EXPECT_FALSE(CompilationSuccess(kHlslVertexShader, shaderc_glsl_vertex_shader, options_.get())); } TEST_F(CompileStringTest, LangHlslOnGlslVertexFails) { shaderc_compile_options_set_source_language(options_.get(), shaderc_source_language_hlsl); - EXPECT_FALSE(CompilationSuccess(kGlslVertexShader, - shaderc_glsl_vertex_shader, + EXPECT_FALSE(CompilationSuccess(kGlslVertexShader, shaderc_glsl_vertex_shader, options_.get())); } TEST_F(CompileStringTest, LangHlslOnHlslVertexSucceeds) { shaderc_compile_options_set_source_language(options_.get(), shaderc_source_language_hlsl); - EXPECT_TRUE(CompilationSuccess(kHlslVertexShader, - shaderc_glsl_vertex_shader, + EXPECT_TRUE(CompilationSuccess(kHlslVertexShader, shaderc_glsl_vertex_shader, options_.get())); } - } // anonymous namespace -- cgit v1.2.3 From 525a48c6cca550540be69565152832aac499709f Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 1 Nov 2016 14:56:33 -0400 Subject: Add glslang source file hlsl/hlslAttributes.cpp --- third_party/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/Android.mk b/third_party/Android.mk index 7f6e04c..3ae8fdf 100644 --- a/third_party/Android.mk +++ b/third_party/Android.mk @@ -48,6 +48,7 @@ include $(CLEAR_VARS) LOCAL_MODULE:=HLSL LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti LOCAL_SRC_FILES:= \ + hlsl/hlslAttributes.cpp \ hlsl/hlslGrammar.cpp \ hlsl/hlslOpMap.cpp \ hlsl/hlslParseables.cpp \ -- cgit v1.2.3 From aaa8b0cf8696174e411fc280b46f3bfeb4f7ec9c Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 3 Nov 2016 11:44:13 -0400 Subject: Removed SPIRV-Tools source/instruction.cpp Goes with https://github.com/KhronosGroup/SPIRV-Tools/pull/453 --- third_party/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/third_party/Android.mk b/third_party/Android.mk index 3ae8fdf..78b28db 100644 --- a/third_party/Android.mk +++ b/third_party/Android.mk @@ -177,7 +177,6 @@ LOCAL_SRC_FILES:= \ source/diagnostic.cpp \ source/disassemble.cpp \ source/ext_inst.cpp \ - source/instruction.cpp \ source/libspirv.cpp \ source/name_mapper.cpp \ source/opcode.cpp \ -- cgit v1.2.3 From f0363818a74d60e768ef6ed01d303062b2bf7037 Mon Sep 17 00:00:00 2001 From: David Neto Date: Sat, 29 Oct 2016 09:21:51 -0400 Subject: C, C++ APIs are sensitive to entry_point_name Before, the C API ignored the entry point name. Before, the C++ API didn't have entry points that accepted an entry point name. --- libshaderc/CMakeLists.txt | 4 +- libshaderc/include/shaderc/shaderc.hpp | 73 +++++++++++-- libshaderc/src/shaderc.cc | 4 +- libshaderc/src/shaderc_cpp_test.cc | 73 +++++++++++-- libshaderc/src/shaderc_test.cc | 114 +++++++++++++++------ libshaderc_util/include/libshaderc_util/compiler.h | 9 +- libshaderc_util/src/compiler.cc | 23 +++-- libshaderc_util/src/compiler_test.cc | 34 ++++-- 8 files changed, 260 insertions(+), 74 deletions(-) diff --git a/libshaderc/CMakeLists.txt b/libshaderc/CMakeLists.txt index 59ff932..888c858 100644 --- a/libshaderc/CMakeLists.txt +++ b/libshaderc/CMakeLists.txt @@ -23,7 +23,7 @@ target_link_libraries(shaderc PRIVATE SPIRV-Tools) shaderc_add_tests( TEST_PREFIX shaderc LINK_LIBS shaderc - INCLUDE_DIRS include ${glslang_SOURCE_DIR} + INCLUDE_DIRS include ${glslang_SOURCE_DIR} ${spirv-tools_SOURCE_DIR}/include TEST_NAMES shaderc shaderc_cpp) @@ -34,7 +34,7 @@ shaderc_combine_static_lib(shaderc_combined shaderc) shaderc_add_tests( TEST_PREFIX shaderc_combined LINK_LIBS shaderc_combined ${CMAKE_THREAD_LIBS_INIT} - INCLUDE_DIRS include ${glslang_SOURCE_DIR} + INCLUDE_DIRS include ${glslang_SOURCE_DIR} ${spirv-tools_SOURCE_DIR}/include TEST_NAMES shaderc shaderc_cpp) diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp index 1dc2631..a3facfc 100644 --- a/libshaderc/include/shaderc/shaderc.hpp +++ b/libshaderc/include/shaderc/shaderc.hpp @@ -279,6 +279,9 @@ class Compiler { // The input_file_name is a null-termintated string. It is used as a tag to // identify the source string in cases like emitting error messages. It // doesn't have to be a 'file name'. + // The entry_point_name parameter is a null-terminated string specifying + // the entry point name for HLSL compilation. For GLSL compilation, the + // entry point name is assumed to be "main". // The compilation is passed any options specified in the CompileOptions // parameter. // It is valid for the returned CompilationResult object to outlive this @@ -290,16 +293,30 @@ class Compiler { size_t source_text_size, shaderc_shader_kind shader_kind, const char* input_file_name, + const char* entry_point_name, const CompileOptions& options) const { shaderc_compilation_result_t compilation_result = shaderc_compile_into_spv( compiler_, source_text, source_text_size, shader_kind, input_file_name, - "main", options.options_); + entry_point_name, options.options_); return SpvCompilationResult(compilation_result); } + // Compiles the given source shader and returns a SPIR-V binary module + // compilation result. + // Like the first CompileGlslToSpv method but assumes the entry point name + // is "main". + SpvCompilationResult CompileGlslToSpv(const char* source_text, + size_t source_text_size, + shaderc_shader_kind shader_kind, + const char* input_file_name, + const CompileOptions& options) const { + return CompileGlslToSpv(source_text, source_text_size, shader_kind, + input_file_name, "main", options); + } + // Compiles the given source GLSL and returns a SPIR-V binary module // compilation result. - // Like the first CompileGlslToSpv method but uses default options. + // Like the previous CompileGlslToSpv method but uses default options. SpvCompilationResult CompileGlslToSpv(const char* source_text, size_t source_text_size, shaderc_shader_kind shader_kind, @@ -310,10 +327,10 @@ class Compiler { return SpvCompilationResult(compilation_result); } - // Compiles the given source GLSL and returns a SPIR-V binary module + // Compiles the given source shader and returns a SPIR-V binary module // compilation result. // Like the first CompileGlslToSpv method but the source is provided as - // a std::string. + // a std::string, and we assume the entry point is "main". SpvCompilationResult CompileGlslToSpv(const std::string& source_text, shaderc_shader_kind shader_kind, const char* input_file_name, @@ -322,10 +339,23 @@ class Compiler { input_file_name, options); } - // Compiles the given source GLSL and returns a SPIR-V binary module + // Compiles the given source shader and returns a SPIR-V binary module // compilation result. // Like the first CompileGlslToSpv method but the source is provided as - // a std::string and also uses default compiler options. + // a std::string. + SpvCompilationResult CompileGlslToSpv(const std::string& source_text, + shaderc_shader_kind shader_kind, + const char* input_file_name, + const char* entry_point_name, + const CompileOptions& options) const { + return CompileGlslToSpv(source_text.data(), source_text.size(), shader_kind, + input_file_name, entry_point_name, options); + } + + // Compiles the given source GLSL and returns a SPIR-V binary module + // compilation result. + // Like the previous CompileGlslToSpv method but assumes the entry point + // name is "main". SpvCompilationResult CompileGlslToSpv(const std::string& source_text, shaderc_shader_kind shader_kind, const char* input_file_name) const { @@ -383,23 +413,46 @@ class Compiler { AssemblyCompilationResult CompileGlslToSpvAssembly( const char* source_text, size_t source_text_size, shaderc_shader_kind shader_kind, const char* input_file_name, - const CompileOptions& options) const { + const char* entry_point_name, const CompileOptions& options) const { shaderc_compilation_result_t compilation_result = shaderc_compile_into_spv_assembly( compiler_, source_text, source_text_size, shader_kind, - input_file_name, "main", options.options_); + input_file_name, entry_point_name, options.options_); return AssemblyCompilationResult(compilation_result); } + // Compiles the given source GLSL and returns the SPIR-V assembly text + // compilation result. + // Similare to the previous method, but assumes entry point name is "main". + AssemblyCompilationResult CompileGlslToSpvAssembly( + const char* source_text, size_t source_text_size, + shaderc_shader_kind shader_kind, const char* input_file_name, + const CompileOptions& options) const { + return CompileGlslToSpvAssembly(source_text, source_text_size, shader_kind, + input_file_name, "main", options); + } + // Compiles the given source GLSL and returns the SPIR-V assembly text // result. Like the first CompileGlslToSpvAssembly method but the source // is provided as a std::string. Options are otherwise similar to // the first CompileToSpv method. AssemblyCompilationResult CompileGlslToSpvAssembly( const std::string& source_text, shaderc_shader_kind shader_kind, - const char* input_file_name, const CompileOptions& options) const { + const char* input_file_name, const char* entry_point_name, + const CompileOptions& options) const { return CompileGlslToSpvAssembly(source_text.data(), source_text.size(), - shader_kind, input_file_name, options); + shader_kind, input_file_name, + entry_point_name, options); + } + + // Compiles the given source GLSL and returns the SPIR-V assembly text + // result. Like the previous CompileGlslToSpvAssembly method but assumes + // the entry point name is "main". + AssemblyCompilationResult CompileGlslToSpvAssembly( + const std::string& source_text, shaderc_shader_kind shader_kind, + const char* input_file_name, const CompileOptions& options) const { + return CompileGlslToSpvAssembly(source_text, shader_kind, input_file_name, + "main", options); } // Preprocesses the given source GLSL and returns the preprocessed diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc index 845320b..15d16d2 100644 --- a/libshaderc/src/shaderc.cc +++ b/libshaderc/src/shaderc.cc @@ -394,7 +394,7 @@ shaderc_compilation_result_t CompileToSpecifiedOutputType( 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, + 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. @@ -406,7 +406,7 @@ shaderc_compilation_result_t CompileToSpecifiedOutputType( 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, + 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); } diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc index 2762197..6917e59 100644 --- a/libshaderc/src/shaderc_cpp_test.cc +++ b/libshaderc/src/shaderc_cpp_test.cc @@ -19,6 +19,7 @@ #include #include "SPIRV/spirv.hpp" +#include "spirv-tools/libspirv.hpp" #include "common_shaders_for_test.h" #include "shaderc/shaderc.hpp" @@ -1017,30 +1018,86 @@ TEST_F(CppInterface, BeginAndEndOnPreprocessedResult) { TEST_F(CppInterface, SourceLangGlslMinimalGlslVertexShaderSucceeds) { options_.SetSourceLanguage(shaderc_source_language_glsl); - EXPECT_TRUE(CompilationSuccess(kVertexOnlyShader, - shaderc_glsl_vertex_shader, + EXPECT_TRUE(CompilationSuccess(kVertexOnlyShader, shaderc_glsl_vertex_shader, options_)); } TEST_F(CppInterface, SourceLangGlslMinimalHlslVertexShaderFails) { options_.SetSourceLanguage(shaderc_source_language_glsl); EXPECT_FALSE(CompilationSuccess(kMinimalHlslShader, - shaderc_glsl_vertex_shader, - options_)); + shaderc_glsl_vertex_shader, options_)); } TEST_F(CppInterface, SourceLangHlslMinimalGlslVertexShaderFails) { options_.SetSourceLanguage(shaderc_source_language_hlsl); - EXPECT_FALSE(CompilationSuccess(kVertexOnlyShader, - shaderc_glsl_vertex_shader, + EXPECT_FALSE(CompilationSuccess(kVertexOnlyShader, shaderc_glsl_vertex_shader, options_)); } TEST_F(CppInterface, SourceLangHlslMinimalHlslVertexShaderSucceeds) { options_.SetSourceLanguage(shaderc_source_language_hlsl); - EXPECT_TRUE(CompilationSuccess(kMinimalHlslShader, - shaderc_glsl_vertex_shader, + EXPECT_TRUE(CompilationSuccess(kMinimalHlslShader, shaderc_glsl_vertex_shader, options_)); } +TEST( + EntryPointTest, + SourceLangHlslMinimalHlslVertexShaderAsConstCharPtrSucceedsWithEntryPointName) { + shaderc::Compiler compiler; + CompileOptions options; + options.SetSourceLanguage(shaderc_source_language_hlsl); + auto result = compiler.CompileGlslToSpv( + kMinimalHlslShader, strlen(kMinimalHlslShader), + shaderc_glsl_vertex_shader, "shader", "EntryPoint", options); + std::vector binary(result.begin(), result.end()); + std::string assembly; + spvtools::SpirvTools(SPV_ENV_UNIVERSAL_1_0).Disassemble(binary, &assembly); + EXPECT_THAT(assembly, + HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\"")) + << assembly; +} + +TEST( + EntryPointTest, + SourceLangHlslMinimalHlslVertexShaderAsStdStringSucceedsWithEntryPointName) { + shaderc::Compiler compiler; + CompileOptions options; + options.SetSourceLanguage(shaderc_source_language_hlsl); + std::string shader(kMinimalHlslShader); + auto result = compiler.CompileGlslToSpv(shader, shaderc_glsl_vertex_shader, + "shader", "EntryPoint", options); + std::vector binary(result.begin(), result.end()); + std::string assembly; + spvtools::SpirvTools(SPV_ENV_UNIVERSAL_1_0).Disassemble(binary, &assembly); + EXPECT_THAT(assembly, + HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\"")) + << assembly; +} + +TEST( + EntryPointTest, + SourceLangHlslMinimalHlslVertexShaderAsConstCharPtrSucceedsToAssemblyWithEntryPointName) { + shaderc::Compiler compiler; + CompileOptions options; + options.SetSourceLanguage(shaderc_source_language_hlsl); + auto assembly = compiler.CompileGlslToSpvAssembly( + kMinimalHlslShader, strlen(kMinimalHlslShader), + shaderc_glsl_vertex_shader, "shader", "EntryPoint", options); + EXPECT_THAT(std::string(assembly.begin(), assembly.end()), + HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\"")); +} + +TEST( + EntryPointTest, + SourceLangHlslMinimalHlslVertexShaderAsStdStringSucceedsToAssemblyWithEntryPointName) { + shaderc::Compiler compiler; + CompileOptions options; + options.SetSourceLanguage(shaderc_source_language_hlsl); + std::string shader(kMinimalHlslShader); + auto assembly = compiler.CompileGlslToSpvAssembly( + shader, shaderc_glsl_vertex_shader, "shader", "EntryPoint", options); + EXPECT_THAT(std::string(assembly.begin(), assembly.end()), + HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\"")); +} + } // anonymous namespace diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc index 280a5d1..bde5cf0 100644 --- a/libshaderc/src/shaderc_test.cc +++ b/libshaderc/src/shaderc_test.cc @@ -72,43 +72,49 @@ enum class OutputType { }; // Generate a compilation result object with the given compile, -// shader source, shader kind, input file name, options, and for the -// specified output type. +// shader source, shader kind, input file name, entry point name, options, +// and for the specified output type. The entry point name is only significant +// for HLSL compilation. shaderc_compilation_result_t MakeCompilationResult( const shaderc_compiler_t compiler, const std::string& shader, shaderc_shader_kind kind, const char* input_file_name, - const shaderc_compile_options_t options, OutputType output_type) { + const char* entry_point_name, const shaderc_compile_options_t options, + OutputType output_type) { switch (output_type) { case OutputType::SpirvBinary: return shaderc_compile_into_spv(compiler, shader.c_str(), shader.size(), - kind, input_file_name, "", options); + kind, input_file_name, entry_point_name, + options); break; case OutputType::SpirvAssemblyText: - return shaderc_compile_into_spv_assembly(compiler, shader.c_str(), - shader.size(), kind, - input_file_name, "", options); + return shaderc_compile_into_spv_assembly( + compiler, shader.c_str(), shader.size(), kind, input_file_name, + entry_point_name, options); break; case OutputType::PreprocessedText: return shaderc_compile_into_preprocessed_text( - compiler, shader.c_str(), shader.size(), kind, input_file_name, "", - options); + compiler, shader.c_str(), shader.size(), kind, input_file_name, + entry_point_name, options); break; } // We shouldn't reach here. But some compilers might not know that. // Be a little defensive and produce something. return shaderc_compile_into_spv(compiler, shader.c_str(), shader.size(), kind, - input_file_name, "", options); + input_file_name, entry_point_name, options); } + // RAII class for shaderc_compilation_result. Used for shader compilation. class Compilation { public: // Compiles shader and keeps the result. Compilation(const shaderc_compiler_t compiler, const std::string& shader, shaderc_shader_kind kind, const char* input_file_name, + const char* entry_point_name, const shaderc_compile_options_t options = nullptr, OutputType output_type = OutputType::SpirvBinary) - : compiled_result_(MakeCompilationResult( - compiler, shader, kind, input_file_name, options, output_type)) {} + : compiled_result_( + MakeCompilationResult(compiler, shader, kind, input_file_name, + entry_point_name, options, output_type)) {} ~Compilation() { shaderc_result_release(compiled_result_); } @@ -155,6 +161,17 @@ class Compiler { shaderc_compiler_t compiler; }; +// RAII class for shader_compiler_options_t +class Options { + public: + Options() : options_(shaderc_compile_options_initialize()) {} + ~Options() { shaderc_compile_options_release(options_); } + shaderc_compile_options_t get() { return options_; } + + private: + shaderc_compile_options_t options_; +}; + // Helper function to check if the compilation result indicates a successful // compilation. bool CompilationResultIsSuccess(const shaderc_compilation_result_t result) { @@ -178,7 +195,7 @@ bool CompilesToValidSpv(Compiler& compiler, const std::string& shader, shaderc_shader_kind kind, const shaderc_compile_options_t options = nullptr) { const Compilation comp(compiler.get_compiler_handle(), shader, kind, "shader", - options, OutputType::SpirvBinary); + "main", options, OutputType::SpirvBinary); return ResultContainsValidSpv(comp.result()); } @@ -195,7 +212,7 @@ class CompileStringTest : public testing::Test { OutputType output_type = OutputType::SpirvBinary) { return CompilationResultIsSuccess( Compilation(compiler_.get_compiler_handle(), shader, kind, "shader", - options, output_type) + "main", options, output_type) .result()); } @@ -206,7 +223,7 @@ class CompileStringTest : public testing::Test { const shaderc_compile_options_t options = nullptr, OutputType output_type = OutputType::SpirvBinary) { const Compilation comp(compiler_.get_compiler_handle(), shader, kind, - "shader", options, output_type); + "shader", "main", options, output_type); EXPECT_TRUE(CompilationResultIsSuccess(comp.result())) << kind << '\n' << shader; return shaderc_result_get_error_message(comp.result()); @@ -219,7 +236,7 @@ class CompileStringTest : public testing::Test { OutputType output_type = OutputType::SpirvBinary, const char* source_name = "shader") { const Compilation comp(compiler_.get_compiler_handle(), shader, kind, - source_name, options, output_type); + source_name, "main", options, output_type); EXPECT_FALSE(CompilationResultIsSuccess(comp.result())) << kind << '\n' << shader; EXPECT_EQ(0u, shaderc_result_get_length(comp.result())); @@ -232,7 +249,7 @@ class CompileStringTest : public testing::Test { const shaderc_compile_options_t options = nullptr, OutputType output_type = OutputType::SpirvBinary) { const Compilation comp(compiler_.get_compiler_handle(), shader, kind, - "shader", options, output_type); + "shader", "main", options, output_type); return shaderc_result_get_error_message(comp.result()); }; @@ -243,7 +260,7 @@ class CompileStringTest : public testing::Test { const shaderc_compile_options_t options = nullptr, OutputType output_type = OutputType::SpirvBinary) { const Compilation comp(compiler_.get_compiler_handle(), shader, kind, - "shader", options, output_type); + "shader", "main", options, output_type); EXPECT_TRUE(CompilationResultIsSuccess(comp.result())) << kind << '\n' << shader; // Use string(const char* s, size_t n) constructor instead of @@ -362,7 +379,7 @@ TEST_F(CompileStringTest, WorksWithCompileOptions) { TEST_F(CompileStringTest, GetNumErrors) { Compilation comp(compiler_.get_compiler_handle(), kTwoErrorsShader, - shaderc_glsl_vertex_shader, "shader"); + shaderc_glsl_vertex_shader, "shader", "main"); // Expects compilation failure and two errors. EXPECT_FALSE(CompilationResultIsSuccess(comp.result())); EXPECT_EQ(2u, shaderc_result_get_num_errors(comp.result())); @@ -372,7 +389,7 @@ TEST_F(CompileStringTest, GetNumErrors) { TEST_F(CompileStringTest, GetNumWarnings) { Compilation comp(compiler_.get_compiler_handle(), kTwoWarningsShader, - shaderc_glsl_vertex_shader, "shader"); + shaderc_glsl_vertex_shader, "shader", "main"); // Expects compilation success with two warnings. EXPECT_TRUE(CompilationResultIsSuccess(comp.result())); EXPECT_EQ(2u, shaderc_result_get_num_warnings(comp.result())); @@ -382,7 +399,7 @@ TEST_F(CompileStringTest, GetNumWarnings) { TEST_F(CompileStringTest, ZeroErrorsZeroWarnings) { Compilation comp(compiler_.get_compiler_handle(), kMinimalShader, - shaderc_glsl_vertex_shader, "shader"); + shaderc_glsl_vertex_shader, "shader", "main"); // Expects compilation success with zero warnings. EXPECT_TRUE(CompilationResultIsSuccess(comp.result())); EXPECT_EQ(0u, shaderc_result_get_num_warnings(comp.result())); @@ -394,7 +411,7 @@ TEST_F(CompileStringTest, ErrorTypeUnknownShaderStage) { // The shader kind/stage can not be determined, the error type field should // indicate the error type is shaderc_shader_kind_error. Compilation comp(compiler_.get_compiler_handle(), kMinimalShader, - shaderc_glsl_infer_from_source, "shader"); + shaderc_glsl_infer_from_source, "shader", "main"); EXPECT_EQ(shaderc_compilation_status_invalid_stage, shaderc_result_get_compilation_status(comp.result())); } @@ -402,7 +419,7 @@ TEST_F(CompileStringTest, ErrorTypeCompilationError) { // The shader kind is valid, the result object's error type field should // indicate this compilaion fails due to compilation errors. Compilation comp(compiler_.get_compiler_handle(), kTwoErrorsShader, - shaderc_glsl_vertex_shader, "shader"); + shaderc_glsl_vertex_shader, "shader", "main"); EXPECT_EQ(shaderc_compilation_status_compilation_error, shaderc_result_get_compilation_status(comp.result())); } @@ -869,8 +886,8 @@ TEST_P(IncluderTests, SetIncluderCallbacks) { TestIncluder::ReleaseIncluderResponseWrapper, &includer); const Compilation comp(compiler.get_compiler_handle(), shader, - shaderc_glsl_vertex_shader, "shader", options.get(), - OutputType::PreprocessedText); + shaderc_glsl_vertex_shader, "shader", "main", + options.get(), OutputType::PreprocessedText); // Checks the existence of the expected string. EXPECT_THAT(shaderc_result_get_bytes(comp.result()), HasSubstr(test_case.expected_substring())); @@ -892,7 +909,7 @@ TEST_P(IncluderTests, SetIncluderCallbacksClonedOptions) { shaderc_compile_options_clone(options.get())); const Compilation comp(compiler.get_compiler_handle(), shader, - shaderc_glsl_vertex_shader, "shader", + shaderc_glsl_vertex_shader, "shader", "main", cloned_options.get(), OutputType::PreprocessedText); // Checks the existence of the expected string. EXPECT_THAT(shaderc_result_get_bytes(comp.result()), @@ -998,13 +1015,13 @@ TEST_F(CompileStringWithOptionsTest, // Warnings on particular lines should be inhibited. Compilation comp_line(compiler_.get_compiler_handle(), kDeprecatedAttributeShader, shaderc_glsl_vertex_shader, - "shader", options_.get()); + "shader", "main", options_.get()); EXPECT_EQ(0u, shaderc_result_get_num_warnings(comp_line.result())); // Global warnings should be inhibited. - Compilation comp_global(compiler_.get_compiler_handle(), - kMinimalUnknownVersionShader, - shaderc_glsl_vertex_shader, "shader", options_.get()); + Compilation comp_global( + compiler_.get_compiler_handle(), kMinimalUnknownVersionShader, + shaderc_glsl_vertex_shader, "shader", "main", options_.get()); EXPECT_EQ(0u, shaderc_result_get_num_warnings(comp_global.result())); } @@ -1019,13 +1036,13 @@ TEST_F(CompileStringWithOptionsTest, // Warnings on particular lines should be inhibited. Compilation comp_line(compiler_.get_compiler_handle(), kDeprecatedAttributeShader, shaderc_glsl_vertex_shader, - "shader", options_.get()); + "shader", "main", options_.get()); EXPECT_EQ(0u, shaderc_result_get_num_warnings(comp_line.result())); // Global warnings should be inhibited. - Compilation comp_global(compiler_.get_compiler_handle(), - kMinimalUnknownVersionShader, - shaderc_glsl_vertex_shader, "shader", options_.get()); + Compilation comp_global( + compiler_.get_compiler_handle(), kMinimalUnknownVersionShader, + shaderc_glsl_vertex_shader, "shader", "main", options_.get()); EXPECT_EQ(0u, shaderc_result_get_num_warnings(comp_global.result())); } @@ -1327,4 +1344,33 @@ TEST_F(CompileStringTest, LangHlslOnHlslVertexSucceeds) { options_.get())); } +TEST(EntryPointTest, + LangGlslOnHlslVertexSucceedsButAssumesEntryPointNameIsMain) { + Compiler compiler; + Options options; + auto compilation = + Compilation(compiler.get_compiler_handle(), kGlslVertexShader, + shaderc_glsl_vertex_shader, "shader", "blah blah blah", + options.get(), OutputType::SpirvAssemblyText); + + EXPECT_THAT(shaderc_result_get_bytes(compilation.result()), + HasSubstr("OpEntryPoint Vertex %main \"main\"")) + << std::string(shaderc_result_get_bytes(compilation.result())); +} + +TEST(EntryPointTest, LangHlslOnHlslVertexSucceedsWithGivenEntryPointName) { + Compiler compiler; + Options options; + shaderc_compile_options_set_source_language(options.get(), + shaderc_source_language_hlsl); + auto compilation = + Compilation(compiler.get_compiler_handle(), kHlslVertexShader, + shaderc_glsl_vertex_shader, "shader", "EntryPoint", + options.get(), OutputType::SpirvAssemblyText); + + EXPECT_THAT(shaderc_result_get_bytes(compilation.result()), + HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\"")) + << std::string(shaderc_result_get_bytes(compilation.result())); +} + } // anonymous namespace diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h index d396ca1..fc47766 100644 --- a/libshaderc_util/include/libshaderc_util/compiler.h +++ b/libshaderc_util/include/libshaderc_util/compiler.h @@ -94,7 +94,7 @@ class Compiler { public: // Source language enum class SourceLanguage { - GLSL, // The default + GLSL, // The default HLSL, }; @@ -168,6 +168,11 @@ class Compiler { // If the forced_shader stage parameter is not EShLangCount then // the shader is assumed to be of the given stage. // + // For HLSL compilation, entry_point_name is the null-terminated string for + // the + // entry point. For GLSL compilation, entry_point_name is ignored, and + // compilation assumes the entry point is named "main". + // // The stage_callback function will be called if a shader_stage has // not been forced and the stage can not be determined // from the shader text. Any #include directives are parsed with the given @@ -194,7 +199,7 @@ class Compiler { // If the output is a text string, the size equals the length of that string. std::tuple, size_t> Compile( const string_piece& input_source_string, EShLanguage forced_shader_stage, - const std::string& error_tag, + const std::string& error_tag, const char* entry_point_name, const std::function& stage_callback, diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc index 52eb81f..a170a4c 100644 --- a/libshaderc_util/src/compiler.cc +++ b/libshaderc_util/src/compiler.cc @@ -81,7 +81,8 @@ EShMessages GetMessageRules(shaderc_util::Compiler::TargetEnv env, result = static_cast(result | EShMsgSpvRules); break; case Compiler::TargetEnv::Vulkan: - result = static_cast(result | EShMsgSpvRules | EShMsgVulkanRules); + result = + static_cast(result | EShMsgSpvRules | EShMsgVulkanRules); break; } return result; @@ -92,7 +93,7 @@ EShMessages GetMessageRules(shaderc_util::Compiler::TargetEnv env, namespace shaderc_util { std::tuple, size_t> Compiler::Compile( const string_piece& input_source_string, EShLanguage forced_shader_stage, - const std::string& error_tag, + const std::string& error_tag, const char* entry_point_name, const std::function& stage_callback, @@ -179,13 +180,13 @@ std::tuple, size_t> Compiler::Compile( shader.setStringsWithLengthsAndNames(&shader_strings, &shader_lengths, &string_names, 1); shader.setPreamble(preamble.c_str()); + shader.setEntryPoint(entry_point_name); // TODO(dneto): Generate source-level debug info if requested. - bool success = shader.parse(&shaderc_util::kDefaultTBuiltInResource, - default_version_, default_profile_, - force_version_profile_, kNotForwardCompatible, - GetMessageRules(target_env_, source_language_), - includer); + bool success = shader.parse( + &shaderc_util::kDefaultTBuiltInResource, default_version_, + default_profile_, force_version_profile_, kNotForwardCompatible, + GetMessageRules(target_env_, source_language_), includer); success &= PrintFilteredErrors(error_tag, error_stream, warnings_as_errors_, suppress_warnings_, shader.getInfoLog(), @@ -246,7 +247,9 @@ void Compiler::AddMacroDefinition(const char* macro, size_t macro_length, void Compiler::SetTargetEnv(Compiler::TargetEnv env) { target_env_ = env; } -void Compiler::SetSourceLanguage(Compiler::SourceLanguage lang) { source_language_ = lang; } +void Compiler::SetSourceLanguage(Compiler::SourceLanguage lang) { + source_language_ = lang; +} void Compiler::SetForcedVersionProfile(int version, EProfile profile) { default_version_ = version; @@ -298,8 +301,8 @@ std::tuple Compiler::PreprocessShader( // The preprocessor might be sensitive to the target environment. // So combine the existing rules with the just-give-me-preprocessor-output // flag. - const auto rules = static_cast(EShMsgOnlyPreprocessor | - GetMessageRules(target_env_, source_language_)); + const auto rules = static_cast( + EShMsgOnlyPreprocessor | GetMessageRules(target_env_, source_language_)); std::string preprocessed_shader; const bool success = shader.preprocess( diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc index 36931ff..3af7c22 100644 --- a/libshaderc_util/src/compiler_test.cc +++ b/libshaderc_util/src/compiler_test.cc @@ -16,7 +16,7 @@ #include -#include +#include #include "death_test.h" #include "libshaderc_util/counting_includer.h" @@ -24,6 +24,7 @@ namespace { using shaderc_util::Compiler; +using ::testing::HasSubstr; // A trivial vertex shader const char kVertexShader[] = @@ -105,10 +106,6 @@ class CompilerTest : public testing::Test { // shader stage. bool SimpleCompilationSucceedsForOutputType( std::string source, EShLanguage stage, Compiler::OutputType output_type) { - std::function - stage_callback = [](std::ostream*, const shaderc_util::string_piece&) { - return EShLangCount; - }; std::stringstream errors; size_t total_warnings = 0; size_t total_errors = 0; @@ -116,7 +113,7 @@ class CompilerTest : public testing::Test { bool result = false; DummyCountingIncluder dummy_includer; std::tie(result, std::ignore, std::ignore) = compiler_.Compile( - source, stage, "shader", stage_callback, dummy_includer, + source, stage, "shader", "main", dummy_stage_callback_, dummy_includer, Compiler::OutputType::SpirvBinary, &errors, &total_warnings, &total_errors, &initializer); errors_ = errors.str(); @@ -134,6 +131,11 @@ class CompilerTest : public testing::Test { Compiler compiler_; // The error string from the most recent compilation. std::string errors_; + std::function + dummy_stage_callback_ = + [](std::ostream*, const shaderc_util::string_piece&) { + return EShLangCount; + }; }; TEST_F(CompilerTest, SimpleVertexShaderCompilesSuccessfullyToBinary) { @@ -337,5 +339,25 @@ TEST_F(CompilerTest, SetSourceLanguageToHLSLFailsOnGLSL) { EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex)); } +TEST_F(CompilerTest, EntryPointParameterTakesEffectForHLSL) { + compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL); + std::stringstream errors; + size_t total_warnings = 0; + size_t total_errors = 0; + shaderc_util::GlslangInitializer initializer; + bool result = false; + DummyCountingIncluder dummy_includer; + std::vector words; + std::tie(result, words, std::ignore) = + compiler_.Compile(kHlslVertexShader, EShLangVertex, "shader", + "EntryPoint", dummy_stage_callback_, dummy_includer, + Compiler::OutputType::SpirvAssemblyText, &errors, + &total_warnings, &total_errors, &initializer); + EXPECT_TRUE(result); + std::string assembly(reinterpret_cast(words.data())); + EXPECT_THAT(assembly, + HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\"")) + << assembly; +} } // anonymous namespace -- cgit v1.2.3 From fc71c2f8febc689fd12508e5c28b0f0235ee1354 Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 8 Nov 2016 19:54:15 -0500 Subject: Added SPIRV-Tools source file validate_datarules.cpp --- third_party/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/Android.mk b/third_party/Android.mk index 78b28db..5638f88 100644 --- a/third_party/Android.mk +++ b/third_party/Android.mk @@ -196,6 +196,7 @@ LOCAL_SRC_FILES:= \ source/val/ValidationState.cpp \ source/validate.cpp \ source/validate_cfg.cpp \ + source/validate_datarules.cpp \ source/validate_id.cpp \ source/validate_instruction.cpp \ source/validate_layout.cpp -- cgit v1.2.3 From 38bd2b0bb28f1de6adbdd5d0af9a804139914528 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Tue, 8 Nov 2016 10:40:18 -0800 Subject: Some source files are renamed in SPIRV-Tools. --- third_party/Android.mk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/third_party/Android.mk b/third_party/Android.mk index 5638f88..e8ac4db 100644 --- a/third_party/Android.mk +++ b/third_party/Android.mk @@ -189,11 +189,11 @@ LOCAL_SRC_FILES:= \ source/text.cpp \ source/text_handler.cpp \ source/util/parse_number.cpp \ - source/val/BasicBlock.cpp \ - source/val/Construct.cpp \ - source/val/Function.cpp \ - source/val/Instruction.cpp \ - source/val/ValidationState.cpp \ + source/val/basic_block.cpp \ + source/val/construct.cpp \ + source/val/function.cpp \ + source/val/instruction.cpp \ + source/val/validation_state.cpp \ source/validate.cpp \ source/validate_cfg.cpp \ source/validate_datarules.cpp \ -- cgit v1.2.3 From 4b8ad0e3ada55b77ed870024c5be59aaa30f81e8 Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 15 Nov 2016 14:08:37 -0500 Subject: Add source/parsed_operand.cpp to SPIRV-Tools --- third_party/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/Android.mk b/third_party/Android.mk index e8ac4db..40395ad 100644 --- a/third_party/Android.mk +++ b/third_party/Android.mk @@ -181,6 +181,7 @@ LOCAL_SRC_FILES:= \ source/name_mapper.cpp \ source/opcode.cpp \ source/operand.cpp \ + source/parsed_operand.cpp \ source/print.cpp \ source/software_version.cpp \ source/spirv_endian.cpp \ -- cgit v1.2.3 From 725a8fd2e7b98f45905f8ac791c62e6239ce2898 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Tue, 15 Nov 2016 10:03:43 -0500 Subject: Update READMEs. --- README.md | 26 ++++++++++++++------------ glslc/README.asciidoc | 5 +++-- libshaderc/README.md | 25 ++++++++++++++----------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index f322636..ab68e49 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,11 @@ A collection of tools, libraries and tests for shader compilation. At the moment it includes: -- [`glslc`](glslc), a command line compiler for GLSL to SPIR-V, and -- `libshaderc` a library API for doing the same. +- [`glslc`](glslc), a command line compiler for GLSL/HLSL to SPIR-V, and +- [`libshaderc`](libshaderc), a library API for doing the same. -Shaderc wraps around core functionality in -[Glslang](https://github.com/KhronosGroup/glslang) -and [SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools). Shaderc aims to +Shaderc wraps around core functionality in [glslang][khr-glslang] +and [SPIRV-Tools][spirv-tools]. Shaderc aims to to provide: * a command line compiler with GCC- and Clang-like usage, for better integration with build systems @@ -31,7 +30,7 @@ Shaderc has been shipping in the Those repos are downstream from GitHub.) For licensing terms, please see the [`LICENSE`](LICENSE) file. If interested in -contributing to this project, please see [`CONTRIBUTING.md`](CONTRIBUTING.md) +contributing to this project, please see [`CONTRIBUTING.md`](CONTRIBUTING.md). This is not an official Google product (experimental or otherwise), it is just code that happens to be owned by Google. That may change if Shaderc gains @@ -50,18 +49,17 @@ for more information. See also the [`AUTHORS`](AUTHORS) and - `third_party/`: third party open source packages; see below - `utils/`: utility scripts for Shaderc -Shaderc depends on `glslang`, the Khronos reference compiler for GLSL. +Shaderc depends on glslang, the Khronos reference compiler for GLSL. Sometimes a change updates both Shaderc and glslang. In that case the -glslang change will appear in [google/glslang](https://github.com/google/glslang) -before it appears upstream in -[KhronosGroup/glslang](https://github.com/KhronosGroup/glslang). +glslang change will appear in [google/glslang][google-glslang] +before it appears upstream in [KhronosGroup/glslang][khr-glslang] We intend to upstream all changes to glslang. We maintain the separate copy only to stage those changes for review, and to provide something for Shaderc to build against in the meantime. Please see [DEVELOPMENT.howto.md](DEVELOPMENT.howto.md) for more details. -Shaderc depends on [SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools) -for assembling and disassembling SPIR-V binaries. +Shaderc depends on [SPIRV-Tools][spirv-tools] for assembling, disassembling, +and transforming SPIR-V binaries. Shaderc depends on the [Google Test](https://github.com/google/googletest) testing framework. @@ -212,3 +210,7 @@ ninja report-coverage Then the coverage report can be found under the `$BUILD_DIR/coverage-report` directory. + +[khr-glslang]: https://github.com/KhronosGroup/glslang +[google-glslang]: https://github.com/google/glslang +[spirv-tools]: https://github.com/KhronosGroup/SPIRV-Tools diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc index 5a546f2..a7cdad4 100644 --- a/glslc/README.asciidoc +++ b/glslc/README.asciidoc @@ -5,7 +5,8 @@ == Name -`glslc` - A command-line GLSL to SPIR-V compiler with Clang-compatible arguments. +`glslc` - A command-line GLSL/HLSL to SPIR-V compiler with +Clang-compatible arguments. == Synopsis @@ -27,7 +28,7 @@ glslc [-c|-S|-E] === Input file languages -glslc accepts both GLSL source and SPIR-V assembly files as inputs. +glslc accepts both GLSL/HLSL source and SPIR-V assembly files as inputs. ==== Shader stage specification diff --git a/libshaderc/README.md b/libshaderc/README.md index d5e9ec3..bf9d317 100644 --- a/libshaderc/README.md +++ b/libshaderc/README.md @@ -5,10 +5,10 @@ A library for compiling shader strings into SPIR-V. ## Build Artifacts There are two main shaderc libraries that are created during a CMake -compilation. The first is `libshaderc`, which is a static library -containing just the functionality exposed by libshaderc. It depends +compilation. The first is `libshaderc`, which is a static library +containing just the functionality exposed by libshaderc. It depends on other compilation targets `glslang`, `OSDependent`, `OGLCompiler`, -`shaderc_util` and `SPIRV`. +`shaderc_util`, `SPIRV`, `HLSL`, `SPIRV-Tools`, and `SPIRV-Tools-opt`. The other is `libshaderc_combined`, which is a static library containing libshaderc and all of its dependencies. @@ -34,15 +34,18 @@ should be added to the include path, and platforms `-lpthread` should also be specified. 4. If the external project does not use CMake and cannot use -libshaderc_combined, the following libraries or their platform-dependent +`libshaderc_combined`, the following libraries or their platform-dependent counterparts should be linked in the order specified. - `build/libshaderc/libshaderc.a` - `build/third_party/glslang/glslang/glslang.a` - `build/third_party/glslang/glslang/OSDependent/{Platform}/libOSDependent.a` - `build/third_party/glslang/OGLCompilersDLL/libOGLCompiler.a` - `build/third_party/glslang/libglslang.a` - `build/shaderc_util/libshaderc_util.a` - `build/third_party/glslang/SPIRV/libSPIRV.a` + * `build/libshaderc/libshaderc.a` + * `build/third_party/glslang/glslang/glslang.a` + * `build/third_party/glslang/glslang/OSDependent/{Platform}/libOSDependent.a` + * `build/third_party/glslang/OGLCompilersDLL/libOGLCompiler.a` + * `build/third_party/glslang/libglslang.a` + * `build/shaderc_util/libshaderc_util.a` + * `build/third_party/glslang/SPIRV/libSPIRV.a` + * `build/third_party/glslang/hlsl/libHLSL.a` + * `build/third_party/spirv-tools/libSPIRV-Tools-opt.a` + * `build/third_party/spirv-tools/libSPIRV-Tools.a` 5. If building for Android using the Android NDK, `shaderc/Android.mk` can be included in the application's `Android.mk` and `LOCAL_STATIC_LIBRARIES:=shaderc` -- cgit v1.2.3 From 89eefb94d69e07576682e44cb3d55fa332ce2e91 Mon Sep 17 00:00:00 2001 From: David Neto Date: Sat, 29 Oct 2016 11:30:00 -0400 Subject: Add -fentry-point to glslc Updates to test infrastructure: - TestStatus carries raw PlaceHolder objects - FileShader placeholder now takes an optional assembly_substr. If present, that's a substring expected to be in the dissasembled output of an module generated from that placeholder's input. - Add test mixin classes to check for substring in assembly output per shader input file. - Pass the path to the spirv-dis to the tests, and store it in the test manager class. --- CHANGES | 2 + glslc/README.asciidoc | 7 +++ glslc/src/file_compiler.cc | 34 ++++++------ glslc/src/file_compiler.h | 21 ++++--- glslc/src/main.cc | 23 ++++---- glslc/test/CMakeLists.txt | 3 +- glslc/test/expect.py | 54 ++++++++++++++++++ glslc/test/expect_nosetest.py | 12 ++-- glslc/test/glslc_test_framework.py | 24 +++++--- glslc/test/option_dash_x.py | 8 --- glslc/test/option_fentry_point.py | 109 +++++++++++++++++++++++++++++++++++++ glslc/test/parameter_tests.py | 3 + glslc/test/placeholder.py | 5 +- 13 files changed, 245 insertions(+), 60 deletions(-) create mode 100644 glslc/test/option_fentry_point.py diff --git a/CHANGES b/CHANGES index db599b1..4cf6bd4 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,8 @@ v2016.2-dev 2016-10-12 - Support HLSL compilation, exposing functionality in Glslang. - Supported in C, C++ API - glslc accepts "-x hlsl", and assumes .hlsl files are HLSL. + - glslc accepts "-fentry-point=" to set entry point name, + overriding default value "main". v2016.1 2016-10-12 - C API for assembling now takes an options object diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc index a7cdad4..a8f22c9 100644 --- a/glslc/README.asciidoc +++ b/glslc/README.asciidoc @@ -14,6 +14,7 @@ Clang-compatible arguments. glslc [-c|-S|-E] [-x ...] [-std=standard] [-fshader-stage=...] + [-fentry-point=...] [--target-env=...] [-g] [-O0|-Os] @@ -150,6 +151,12 @@ command line, please put SPIR-V assembly files ahead of the first `-fshader-stage=`, since `-fshader-stage=` only affects the treatment of subsequent files. +[[option-f-entry-point]] +==== `-fentry-point=` + +`-fentry-point=` lets you specify the entry point name. This is only +significant for HLSL compilation. The default is "main". + ==== `-std=` `-std=` lets you specify a shader version and profile on the command diff --git a/glslc/src/file_compiler.cc b/glslc/src/file_compiler.cc index 1aed39d..5469736 100644 --- a/glslc/src/file_compiler.cc +++ b/glslc/src/file_compiler.cc @@ -62,16 +62,14 @@ bool EmitSpirvBinaryAsCommaSeparatedNumbers(const CompilationResultType& result, } // anonymous namespace namespace glslc { -bool FileCompiler::CompileShaderFile(const std::string& input_file, - shaderc_shader_kind shader_stage, - shaderc_source_language lang) { +bool FileCompiler::CompileShaderFile(const InputFileSpec& input_file) { std::vector input_data; - std::string path = input_file; + std::string path = input_file.name; if (!shaderc_util::ReadFile(path, &input_data)) { return false; } - std::string output_name = GetOutputFileName(input_file); + std::string output_name = GetOutputFileName(input_file.name); std::ofstream potential_file_stream; std::ostream* output_stream = @@ -80,7 +78,7 @@ bool FileCompiler::CompileShaderFile(const std::string& input_file, // An error message has already been emitted to the stderr stream. return false; } - string_piece error_file_name = input_file; + string_piece error_file_name = input_file.name; if (error_file_name == "-") { // If the input file was stdin, we want to output errors as . @@ -100,12 +98,12 @@ bool FileCompiler::CompileShaderFile(const std::string& input_file, const auto& used_source_files = includer->file_path_trace(); options_.SetIncluder(std::move(includer)); - if (shader_stage == shaderc_spirv_assembly) { + if (input_file.stage == shaderc_spirv_assembly) { // Only act if the requested target is SPIR-V binary. if (output_type_ == OutputType::SpirvBinary) { const auto result = compiler_.AssembleToSpv(source_string.data(), source_string.size()); - return EmitCompiledResult(result, input_file, error_file_name, + return EmitCompiledResult(result, input_file.name, error_file_name, used_source_files, output_stream); } else { return true; @@ -115,28 +113,30 @@ bool FileCompiler::CompileShaderFile(const std::string& input_file, // Set the language. Since we only use the options object in this // method, then it's ok to always set it without resetting it after // compilation. A subsequent compilation will set it again anyway. - options_.SetSourceLanguage(lang); + options_.SetSourceLanguage(input_file.language); switch (output_type_) { case OutputType::SpirvBinary: { const auto result = compiler_.CompileGlslToSpv( - source_string.data(), source_string.size(), shader_stage, - error_file_name.data(), options_); - return EmitCompiledResult(result, input_file, error_file_name, + source_string.data(), source_string.size(), input_file.stage, + error_file_name.data(), input_file.entry_point_name.c_str(), + options_); + return EmitCompiledResult(result, input_file.name, error_file_name, used_source_files, output_stream); } case OutputType::SpirvAssemblyText: { const auto result = compiler_.CompileGlslToSpvAssembly( - source_string.data(), source_string.size(), shader_stage, - error_file_name.data(), options_); - return EmitCompiledResult(result, input_file, error_file_name, + source_string.data(), source_string.size(), input_file.stage, + error_file_name.data(), input_file.entry_point_name.c_str(), + options_); + return EmitCompiledResult(result, input_file.name, error_file_name, used_source_files, output_stream); } case OutputType::PreprocessedText: { const auto result = compiler_.PreprocessGlsl( - source_string.data(), source_string.size(), shader_stage, + source_string.data(), source_string.size(), input_file.stage, error_file_name.data(), options_); - return EmitCompiledResult(result, input_file, error_file_name, + return EmitCompiledResult(result, input_file.name, error_file_name, used_source_files, output_stream); } } diff --git a/glslc/src/file_compiler.h b/glslc/src/file_compiler.h index 4d8cb35..2f45e92 100644 --- a/glslc/src/file_compiler.h +++ b/glslc/src/file_compiler.h @@ -25,6 +25,14 @@ namespace glslc { +// Describes an input file to be compiled. +struct InputFileSpec { + std::string name; + shaderc_shader_kind stage; + shaderc_source_language language; + std::string entry_point_name; +}; + // Context for managing compilation of source GLSL files into destination // SPIR-V files or preprocessed output. class FileCompiler { @@ -46,10 +54,11 @@ class FileCompiler { total_warnings_(0), total_errors_(0) {} - // Compiles a shader received in input_file, returning true on success and - // false otherwise. If force_shader_stage is not shaderc_glsl_infer_source or - // any default shader stage then the given shader_stage will be used, - // otherwise it will be determined from the source or the file type. + // Compiles a shader received as specified by input_file, returning true + // on success and false otherwise. If force_shader_stage is not + // shaderc_glsl_infer_source or any default shader stage then the given + // shader_stage will be used, otherwise it will be determined from the source + // or the file type. // // Places the compilation output into a new file whose name is derived from // input_file according to the rules from glslc/README.asciidoc. @@ -59,9 +68,7 @@ class FileCompiler { // // Any errors/warnings found in the shader source will be output to std::cerr // and increment the counts reported by OutputMessages(). - bool CompileShaderFile(const std::string& input_file, - shaderc_shader_kind shader_stage, - shaderc_source_language lang); + bool CompileShaderFile(const InputFileSpec& input_file); // Adds a directory to be searched when processing #include directives. // diff --git a/glslc/src/main.cc b/glslc/src/main.cc index 193bc7f..571e65f 100644 --- a/glslc/src/main.cc +++ b/glslc/src/main.cc @@ -33,13 +33,6 @@ using shaderc_util::string_piece; namespace { -// Describes an input file to be compiled. -struct InputFileSpec { - std::string name; - shaderc_shader_kind stage; - shaderc_source_language language; -}; - // Prints the help message. void PrintHelp(std::ostream* out) { *out << R"(glslc - Compile shaders into SPIR-V @@ -57,6 +50,9 @@ Options: Treat subsequent input files as having stage . Valid stages are vertex, fragment, tesscontrol, tesseval, geometry, and compute. + -fentry-point= + Specify the entry point name for HLSL compilation, for + all subsequent source files. Default is "main". -g Generate source-level debug information. Currently this option has no effect. --help Display available options. @@ -120,11 +116,12 @@ const char kBuildVersion[] = } // anonymous namespace int main(int argc, char** argv) { - std::vector input_files; + std::vector input_files; shaderc_shader_kind current_fshader_stage = shaderc_glsl_infer_from_source; bool source_language_forced = false; shaderc_source_language current_source_language = shaderc_source_language_glsl; + std::string current_entry_point_name("main"); glslc::FileCompiler compiler; bool success = true; bool has_stdin_input = false; @@ -156,6 +153,9 @@ int main(int argc, char** argv) { << std::endl; return 1; } + } else if (arg.starts_with("-fentry-point=")) { + current_entry_point_name = + arg.substr(std::strlen("-fentry-point=")).str(); } else if (arg.starts_with("-std=")) { const string_piece standard = arg.substr(std::strlen("-std=")); int version; @@ -358,11 +358,11 @@ int main(int argc, char** argv) { // already been emitted before). So we should deduce the shader kind // from the file name. If current_fshader_stage is specifed to one of // the forced shader kinds, use that for the following compilation. - input_files.emplace_back(InputFileSpec{ + input_files.emplace_back(glslc::InputFileSpec{ arg.str(), (current_fshader_stage == shaderc_glsl_infer_from_source ? glslc::DeduceDefaultShaderKindFromFileName(arg) : current_fshader_stage), - language}); + language, current_entry_point_name}); } } @@ -371,8 +371,7 @@ int main(int argc, char** argv) { if (!success) return 1; for (const auto& input_file : input_files) { - success &= compiler.CompileShaderFile(input_file.name, input_file.stage, - input_file.language); + success &= compiler.CompileShaderFile(input_file); } compiler.OutputMessages(); diff --git a/glslc/test/CMakeLists.txt b/glslc/test/CMakeLists.txt index bb82a70..cca9314 100644 --- a/glslc/test/CMakeLists.txt +++ b/glslc/test/CMakeLists.txt @@ -5,5 +5,6 @@ if(${SHADERC_ENABLE_TESTS}) add_test(NAME glslc_tests COMMAND ${PYTHON_EXE} ${CMAKE_CURRENT_SOURCE_DIR}/glslc_test_framework.py - $ --test-dir ${CMAKE_CURRENT_SOURCE_DIR}) + $ $ + --test-dir ${CMAKE_CURRENT_SOURCE_DIR}) endif() diff --git a/glslc/test/expect.py b/glslc/test/expect.py index 00e31d4..cfd0524 100644 --- a/glslc/test/expect.py +++ b/glslc/test/expect.py @@ -21,6 +21,7 @@ methods in the mixin classes. import difflib import os import re +import subprocess from glslc_test_framework import GlslCTest @@ -212,6 +213,33 @@ class ValidObjectFile(SuccessfulReturn, CorrectObjectFilePreamble): return True, '' +class ValidObjectFileWithAssemblySubstr(SuccessfulReturn, CorrectObjectFilePreamble): + """Mixin class for checking that every input file generates a valid object + file following the object file naming rule, there is no output on + stdout/stderr, and the disassmbly contains a specified substring per input.""" + + def check_object_file_disassembly(self, status): + for an_input in status.inputs: + object_filename = get_object_filename(an_input.filename) + obj_file = str(os.path.join(status.directory, object_filename)) + success, message = self.verify_object_file_preamble(obj_file) + if not success: + return False, message + cmd = [status.test_manager.disassembler_path, '--no-color', obj_file] + process = subprocess.Popen( + args=cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, cwd=status.directory) + output = process.communicate(None) + disassembly = output[0] + if not isinstance(an_input.assembly_substr, str): + return False, "Missing assembly_substr member" + if an_input.assembly_substr not in disassembly: + return False, ('Incorrect disassembly output:\n{asm}\n' + 'Expected substring not found:\n{exp}'.format( + asm=disassembly, exp=an_input.assembly_substr)) + return True, '' + + class ValidNamedObjectFile(SuccessfulReturn, CorrectObjectFilePreamble): """Mixin class for checking that a list of object files with the given names are correctly generated, and there is no output on stdout/stderr. @@ -280,6 +308,32 @@ class ValidAssemblyFile(SuccessfulReturn, CorrectAssemblyFilePreamble): return True, '' +class ValidAssemblyFileWithSubstr(ValidAssemblyFile): + """Mixin class for checking that every input file generates a valid assembly + file following the assembly file naming rule, there is no output on + stdout/stderr, and all assembly files have the given substring specified + by expected_assembly_substr. + + To mix in this class, subclasses need to provde expected_assembly_substr + as the expected substring. + """ + + def check_assembly_with_substr(self, status): + for input_filename in status.input_filenames: + assembly_filename = get_assembly_filename(input_filename) + success, message = self.verify_assembly_file_preamble( + os.path.join(status.directory, assembly_filename)) + if not success: + return False, message + with open(assembly_filename, 'r') as f: + content = f.read() + if self.expected_assembly_substr not in convert_to_unix_line_endings(content): + return False, ('Incorrect assembly output:\n{asm}\n' + 'Expected substring not found:\n{exp}'.format( + asm=content, exp=self.expected_assembly_substr)) + return True, '' + + class ValidNamedAssemblyFile(SuccessfulReturn, CorrectAssemblyFilePreamble): """Mixin class for checking that a list of assembly files with the given names are correctly generated, and there is no output on stdout/stderr. diff --git a/glslc/test/expect_nosetest.py b/glslc/test/expect_nosetest.py index dc33e4d..567b0a0 100644 --- a/glslc/test/expect_nosetest.py +++ b/glslc/test/expect_nosetest.py @@ -41,20 +41,20 @@ class TestStdoutMatchADotC(expect.StdoutMatch): def nosetest_stdout_match_regex_has_match(): test = TestStdoutMatchADotC() - status = TestStatus(returncode=0, stdout='0abc1', stderr=None, - directory=None, input_filenames=None) + status = TestStatus(test_manager=None, returncode=0, stdout='0abc1', + stderr=None, directory=None, inputs=None, input_filenames=None) assert_true(test.check_stdout_match(status)[0]) def nosetest_stdout_match_regex_no_match(): test = TestStdoutMatchADotC() - status = TestStatus(returncode=0, stdout='ab', stderr=None, - directory=None, input_filenames=None) + status = TestStatus(test_manager=None, returncode=0, stdout='ab', + stderr=None, directory=None, inputs=None, input_filenames=None) assert_false(test.check_stdout_match(status)[0]) def nosetest_stdout_match_regex_empty_stdout(): test = TestStdoutMatchADotC() - status = TestStatus(returncode=0, stdout='', stderr=None, - directory=None, input_filenames=None) + status = TestStatus(test_manager=None, returncode=0, stdout='', stderr=None, + directory=None, inputs=None, input_filenames=None) assert_false(test.check_stdout_match(status)[0]) diff --git a/glslc/test/glslc_test_framework.py b/glslc/test/glslc_test_framework.py index 9454a66..6bf43a7 100755 --- a/glslc/test/glslc_test_framework.py +++ b/glslc/test/glslc_test_framework.py @@ -28,7 +28,7 @@ case is then run by the following steps: The transformed list elements are then supplied as glslc arguments. 3. If the environment member variable exists, its write() method will be invoked. - 4. All expected_* member varibles will be inspected and all placeholders in + 4. All expected_* member variables will be inspected and all placeholders in them will be expanded by calling instantiate_for_expectation() on those placeholders. After placeholder expansion, if the expected_* variable is a list, its element will be joined together with '' to form a single @@ -141,12 +141,15 @@ class GlslCTest: class TestStatus: """A struct for holding run status of a test case.""" - def __init__(self, returncode, stdout, stderr, directory, input_filenames): + def __init__(self, test_manager, returncode, stdout, stderr, directory, inputs, input_filenames): + self.test_manager = test_manager self.returncode = returncode self.stdout = stdout self.stderr = stderr # temporary directory where the test runs self.directory = directory + # List of inputs, as PlaceHolder objects. + self.inputs = inputs # the names of input shader files (potentially including paths) self.input_filenames = input_filenames @@ -198,8 +201,9 @@ def inside_glslc_testsuite(testsuite_name): class TestManager: """Manages and runs a set of tests.""" - def __init__(self, executable_path): + def __init__(self, executable_path, disassembler_path): self.executable_path = executable_path + self.disassembler_path = disassembler_path self.num_successes = 0 self.num_failures = 0 self.num_tests = 0 @@ -236,7 +240,8 @@ class TestCase: def __init__(self, test, test_manager): self.test = test self.test_manager = test_manager - self.file_shaders = [] # filenames of shader files + self.inputs = [] # inputs, as PlaceHolder objects. + self.file_shaders = [] # filenames of shader files. self.stdin_shader = None # text to be passed to glslc as stdin def setUp(self): @@ -250,8 +255,8 @@ class TestCase: if isinstance(arg, PlaceHolder) else arg for arg in self.test.glslc_args] # Get all shader files' names - self.file_shaders = [ - arg.filename for arg in glslc_args if isinstance(arg, PlaceHolder)] + self.inputs = [arg for arg in glslc_args if isinstance(arg, PlaceHolder)] + self.file_shaders = [arg.filename for arg in self.inputs] if 'environment' in get_all_variables(self.test): self.test.environment.write(self.directory) @@ -294,8 +299,9 @@ class TestCase: cwd=self.directory) output = process.communicate(self.stdin_shader) test_status = TestStatus( + self.test_manager, process.returncode, output[0], output[1], - self.directory, self.file_shaders) + self.directory, self.inputs, self.file_shaders) run_results = [getattr(self.test, test_method)(test_status) for test_method in get_all_test_methods( self.test.__class__)] @@ -313,6 +319,8 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('glslc', metavar='path/to/glslc', type=str, nargs=1, help='Path to glslc') + parser.add_argument('spirvdis', metavar='path/to/glslc', type=str, nargs=1, + help='Path to spirv-dis') parser.add_argument('--leave-output', action='store_const', const=1, help='Do not clean up temporary directories') parser.add_argument('--test-dir', nargs=1, @@ -322,7 +330,7 @@ def main(): root_dir = os.getcwd() if args.test_dir: root_dir = args.test_dir[0] - manager = TestManager(args.glslc[0]) + manager = TestManager(args.glslc[0], args.spirvdis[0]) if args.leave_output: manager.leave_output = True for root, _, filenames in os.walk(root_dir): diff --git a/glslc/test/option_dash_x.py b/glslc/test/option_dash_x.py index 43b8b96..3645340 100644 --- a/glslc/test/option_dash_x.py +++ b/glslc/test/option_dash_x.py @@ -50,14 +50,6 @@ class TestDashXGlslOnHlslShader(expect.ErrorMessageSubstr): " require version 140 or higher\n"] -@inside_glslc_testsuite('OptionDashX') -class TestDashXHlslOnHlslShader(expect.ValidObjectFile): - """Tests -x hlsl on an HLSL shader.""" - - shader = FileShader(HLSL_VERTEX_SHADER, '.vert') - glslc_args = ['-x', 'hlsl', '-c', shader] - - @inside_glslc_testsuite('OptionDashX') class TestDashXHlslOnGlslShader(expect.ErrorMessageSubstr): """Tests -x hlsl on a GLSL shader.""" diff --git a/glslc/test/option_fentry_point.py b/glslc/test/option_fentry_point.py new file mode 100644 index 0000000..5d8f96f --- /dev/null +++ b/glslc/test/option_fentry_point.py @@ -0,0 +1,109 @@ +# Copyright 2016 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. + +import expect +from glslc_test_framework import inside_glslc_testsuite +from placeholder import FileShader + +MINIMAL_SHADER = "#version 140\nvoid main(){}" +# This one is valid GLSL but not valid HLSL. +GLSL_VERTEX_SHADER = "#version 140\nvoid main(){ gl_Position = vec4(1.0);}" +# This one is valid HLSL but not valid GLSL. +HLSL_VERTEX_SHADER = "float4 EntryPoint() : SV_POSITION { return float4(1.0); }" +HLSL_VERTEX_SHADER_WITH_MAIN = "float4 main() : SV_POSITION { return float4(1.0); }" +HLSL_VERTEX_SHADER_WITH_FOOBAR = "float4 Foobar() : SV_POSITION { return float4(1.0); }" + +# Expected assembly code within certain shaders. +ASSEMBLY_ENTRY_POINT = "OpEntryPoint Vertex %EntryPoint \"EntryPoint\"" +ASSEMBLY_MAIN = "OpEntryPoint Vertex %main \"main\"" +ASSEMBLY_FOOBAR = "OpEntryPoint Vertex %Foobar \"Foobar\"" + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestEntryPointDefaultsToMainForGlsl(expect.ValidAssemblyFileWithSubstr): + """Tests that entry point name defaults to "main" in a GLSL shader.""" + + shader = FileShader(GLSL_VERTEX_SHADER, '.vert') + glslc_args = ['-S', shader] + expected_assembly_substr = ASSEMBLY_MAIN + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestEntryPointDefaultsToMainForHlsl(expect.ValidAssemblyFileWithSubstr): + """Tests that entry point name defaults to "main" in an HLSL shader.""" + + shader = FileShader(HLSL_VERTEX_SHADER_WITH_MAIN, '.vert') + glslc_args = ['-x', 'hlsl', '-S', shader] + expected_assembly_substr = ASSEMBLY_MAIN + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestFEntryPointMainOnGlslShader(expect.ValidAssemblyFileWithSubstr): + """Tests -fentry-point=main with a GLSL shader.""" + + shader = FileShader(GLSL_VERTEX_SHADER, '.vert') + glslc_args = ['-fentry-point=main', '-S', shader] + expected_assembly_substr = ASSEMBLY_MAIN + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestFEntryPointMainOnHlslShader(expect.ValidAssemblyFileWithSubstr): + """Tests -x hlsl on an HLSL shader with -fentry-point=main and -S.""" + + shader = FileShader(HLSL_VERTEX_SHADER, '.vert') + glslc_args = ['-x', 'hlsl', '-fentry-point=main', '-S', shader] + expected_assembly_substr = ASSEMBLY_MAIN + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestFEntryPointSpecifiedOnHlslShaderInDisassembly(expect.ValidObjectFileWithAssemblySubstr): + """Tests -x hlsl on an HLSL shader with -fentry-point=EntryPoint.""" + + shader = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT) + glslc_args = ['-x', 'hlsl', '-fentry-point=EntryPoint', '-c', shader] + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestFEntryPointAffectsSubsequentShaderFiles(expect.ValidObjectFileWithAssemblySubstr): + """Tests -x hlsl affects several subsequent shader source files.""" + + shader1 = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT) + shader2 = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT) + glslc_args = ['-x', 'hlsl', '-fentry-point=EntryPoint', '-c', shader1, shader2] + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestFEntryPointOverridesItself(expect.ValidObjectFileWithAssemblySubstr): + """Tests that a later -fentry-point option overrides an earlier use.""" + + shader = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT) + glslc_args = ['-x', 'hlsl', '-fentry-point=foobar', '-fentry-point=EntryPoint', + '-c', shader] + + +@inside_glslc_testsuite('OptionFEntryPoint') +class TestFEntryPointDefaultAndTwoOthers(expect.ValidObjectFileWithAssemblySubstr): + """Tests three shaders with different entry point names. The first uses "main" + with default entry point processing, and the remaining shaders get their + own -fentry-point argument.""" + + shaderMain = FileShader(HLSL_VERTEX_SHADER_WITH_MAIN, '.vert', + assembly_substr=ASSEMBLY_MAIN) + shaderEntryPoint = FileShader(HLSL_VERTEX_SHADER, '.vert', + assembly_substr=ASSEMBLY_ENTRY_POINT) + shaderFoobar = FileShader(HLSL_VERTEX_SHADER_WITH_FOOBAR, '.vert', + assembly_substr=ASSEMBLY_FOOBAR) + glslc_args = ['-x', 'hlsl', '-c', shaderMain, + '-fentry-point=EntryPoint', shaderEntryPoint, + '-fentry-point=Foobar', shaderFoobar] diff --git a/glslc/test/parameter_tests.py b/glslc/test/parameter_tests.py index ff450b1..cbb6f11 100644 --- a/glslc/test/parameter_tests.py +++ b/glslc/test/parameter_tests.py @@ -61,6 +61,9 @@ Options: Treat subsequent input files as having stage . Valid stages are vertex, fragment, tesscontrol, tesseval, geometry, and compute. + -fentry-point= + Specify the entry point name for HLSL compilation, for + all subsequent source files. Default is "main". -g Generate source-level debug information. Currently this option has no effect. --help Display available options. diff --git a/glslc/test/placeholder.py b/glslc/test/placeholder.py index 9c5bcfc..8a701bf 100644 --- a/glslc/test/placeholder.py +++ b/glslc/test/placeholder.py @@ -59,12 +59,15 @@ class PlaceHolder(object): class FileShader(PlaceHolder): """Stands for a shader whose source code is in a file.""" - def __init__(self, source, suffix): + def __init__(self, source, suffix, assembly_substr=None): assert isinstance(source, str) assert isinstance(suffix, str) self.source = source self.suffix = suffix self.filename = None + # If provided, this is a substring which is expected to be in + # the disassembly of the module generated from this input file. + self.assembly_substr = assembly_substr def instantiate_for_glslc_args(self, testcase): """Creates a temporary file and writes the source into it. -- cgit v1.2.3 From 1ef0a89bcda32ab4befab6992752eac4c05f2c41 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 17 Nov 2016 10:52:48 -0500 Subject: Support resource limits in C, C++ API --- libshaderc/include/shaderc/shaderc.h | 91 ++++++++++++++++++ libshaderc/include/shaderc/shaderc.hpp | 5 + libshaderc/src/shaderc.cc | 19 ++++ libshaderc/src/shaderc_cpp_test.cc | 48 +++++++++ libshaderc/src/shaderc_test.cc | 52 ++++++++++ libshaderc_util/include/libshaderc_util/compiler.h | 23 ++++- .../include/libshaderc_util/resources.h | 5 +- .../include/libshaderc_util/resources.inc | 107 +++++++++++++++++++++ libshaderc_util/src/compiler.cc | 36 +++++-- libshaderc_util/src/compiler_test.cc | 70 ++++++++++++++ 10 files changed, 445 insertions(+), 11 deletions(-) create mode 100644 libshaderc_util/include/libshaderc_util/resources.inc diff --git a/libshaderc/include/shaderc/shaderc.h b/libshaderc/include/shaderc/shaderc.h index 64d94ea..26d5421 100644 --- a/libshaderc/include/shaderc/shaderc.h +++ b/libshaderc/include/shaderc/shaderc.h @@ -86,6 +86,93 @@ typedef enum { shaderc_optimization_level_size, // optimize towards reducing code size } shaderc_optimization_level; +// Resource limits. +typedef enum { + shaderc_limit_max_lights, + shaderc_limit_max_clip_planes, + shaderc_limit_max_texture_units, + shaderc_limit_max_texture_coords, + shaderc_limit_max_vertex_attribs, + shaderc_limit_max_vertex_uniform_components, + shaderc_limit_max_varying_floats, + shaderc_limit_max_vertex_texture_image_units, + shaderc_limit_max_combined_texture_image_units, + shaderc_limit_max_texture_image_units, + shaderc_limit_max_fragment_uniform_components, + shaderc_limit_max_draw_buffers, + shaderc_limit_max_vertex_uniform_vectors, + shaderc_limit_max_varying_vectors, + shaderc_limit_max_fragment_uniform_vectors, + shaderc_limit_max_vertex_output_vectors, + shaderc_limit_max_fragment_input_vectors, + shaderc_limit_min_program_texel_offset, + shaderc_limit_max_program_texel_offset, + shaderc_limit_max_clip_distances, + shaderc_limit_max_compute_work_group_count_x, + shaderc_limit_max_compute_work_group_count_y, + shaderc_limit_max_compute_work_group_count_z, + shaderc_limit_max_compute_work_group_size_x, + shaderc_limit_max_compute_work_group_size_y, + shaderc_limit_max_compute_work_group_size_z, + shaderc_limit_max_compute_uniform_components, + shaderc_limit_max_compute_texture_image_units, + shaderc_limit_max_compute_image_uniforms, + shaderc_limit_max_compute_atomic_counters, + shaderc_limit_max_compute_atomic_counter_buffers, + shaderc_limit_max_varying_components, + shaderc_limit_max_vertex_output_components, + shaderc_limit_max_geometry_input_components, + shaderc_limit_max_geometry_output_components, + shaderc_limit_max_fragment_input_components, + shaderc_limit_max_image_units, + shaderc_limit_max_combined_image_units_and_fragment_outputs, + shaderc_limit_max_combined_shader_output_resources, + shaderc_limit_max_image_samples, + shaderc_limit_max_vertex_image_uniforms, + shaderc_limit_max_tess_control_image_uniforms, + shaderc_limit_max_tess_evaluation_image_uniforms, + shaderc_limit_max_geometry_image_uniforms, + shaderc_limit_max_fragment_image_uniforms, + shaderc_limit_max_combined_image_uniforms, + shaderc_limit_max_geometry_texture_image_units, + shaderc_limit_max_geometry_output_vertices, + shaderc_limit_max_geometry_total_output_components, + shaderc_limit_max_geometry_uniform_components, + shaderc_limit_max_geometry_varying_components, + shaderc_limit_max_tess_control_input_components, + shaderc_limit_max_tess_control_output_components, + shaderc_limit_max_tess_control_texture_image_units, + shaderc_limit_max_tess_control_uniform_components, + shaderc_limit_max_tess_control_total_output_components, + shaderc_limit_max_tess_evaluation_input_components, + shaderc_limit_max_tess_evaluation_output_components, + shaderc_limit_max_tess_evaluation_texture_image_units, + shaderc_limit_max_tess_evaluation_uniform_components, + shaderc_limit_max_tess_patch_components, + shaderc_limit_max_patch_vertices, + shaderc_limit_max_tess_gen_level, + shaderc_limit_max_viewports, + shaderc_limit_max_vertex_atomic_counters, + shaderc_limit_max_tess_control_atomic_counters, + shaderc_limit_max_tess_evaluation_atomic_counters, + shaderc_limit_max_geometry_atomic_counters, + shaderc_limit_max_fragment_atomic_counters, + shaderc_limit_max_combined_atomic_counters, + shaderc_limit_max_atomic_counter_bindings, + shaderc_limit_max_vertex_atomic_counter_buffers, + shaderc_limit_max_tess_control_atomic_counter_buffers, + shaderc_limit_max_tess_evaluation_atomic_counter_buffers, + shaderc_limit_max_geometry_atomic_counter_buffers, + shaderc_limit_max_fragment_atomic_counter_buffers, + shaderc_limit_max_combined_atomic_counter_buffers, + shaderc_limit_max_atomic_counter_buffer_size, + shaderc_limit_max_transform_feedback_buffers, + shaderc_limit_max_transform_feedback_interleaved_components, + shaderc_limit_max_cull_distances, + shaderc_limit_max_combined_clip_and_cull_distances, + shaderc_limit_max_samples, +} shaderc_limit; + // Usage examples: // // Aggressively release compiler resources, but spend time in initialization @@ -255,6 +342,10 @@ void shaderc_compile_options_set_target_env(shaderc_compile_options_t options, void shaderc_compile_options_set_warnings_as_errors( shaderc_compile_options_t options); +// Sets a resource limit. +void shaderc_compile_options_set_limit( + shaderc_compile_options_t options, shaderc_limit limit, int value); + // An opaque handle to the results of a call to any shaderc_compile_into_*() // function. typedef struct shaderc_compilation_result* shaderc_compilation_result_t; diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp index a3facfc..3023ebb 100644 --- a/libshaderc/include/shaderc/shaderc.hpp +++ b/libshaderc/include/shaderc/shaderc.hpp @@ -243,6 +243,11 @@ class CompileOptions { shaderc_compile_options_set_warnings_as_errors(options_); } + // Sets a resource limit. + void SetLimit(shaderc_limit limit, int value) { + shaderc_compile_options_set_limit(options_, limit, value); + } + private: CompileOptions& operator=(const CompileOptions& other) = delete; shaderc_compile_options_t options_; diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc index 15d16d2..c7b6ef2 100644 --- a/libshaderc/src/shaderc.cc +++ b/libshaderc/src/shaderc.cc @@ -238,6 +238,20 @@ shaderc_util::Compiler::TargetEnv GetCompilerTargetEnv(shaderc_target_env env) { return shaderc_util::Compiler::TargetEnv::Vulkan; } +// 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(0); +} + } // anonymous namespace struct shaderc_compile_options { @@ -346,6 +360,11 @@ void shaderc_compile_options_set_warnings_as_errors( 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); +} + shaderc_compiler_t shaderc_compiler_initialize() { static shaderc_util::GlslangInitializer* initializer = new shaderc_util::GlslangInitializer; diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc index 6917e59..bf5aa33 100644 --- a/libshaderc/src/shaderc_cpp_test.cc +++ b/libshaderc/src/shaderc_cpp_test.cc @@ -1100,4 +1100,52 @@ TEST( HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\"")); } +// Returns a fragment shader accessing a texture with the given +// offset. +std::string ShaderWithTexOffset(int offset) { + std::ostringstream oss; + oss << + "#version 150\n" + "uniform sampler1D tex;\n" + "void main() { vec4 x = textureOffset(tex, 1.0, " << offset << "); }\n"; + return oss.str(); +} + +// Ensure compilation is sensitive to limit setting. Sample just +// two particular limits. +TEST_F(CppInterface, LimitsTexelOffsetDefault) { + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-9).c_str(), + shaderc_glsl_fragment_shader, + options_)); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-8).c_str(), + shaderc_glsl_fragment_shader, + options_)); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(7).c_str(), + shaderc_glsl_fragment_shader, + options_)); + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(8).c_str(), + shaderc_glsl_fragment_shader, + options_)); +} + +TEST_F(CppInterface, LimitsTexelOffsetLowerMinimum) { + options_.SetLimit(shaderc_limit_min_program_texel_offset, -99); + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-100).c_str(), + shaderc_glsl_fragment_shader, + options_)); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-99).c_str(), + shaderc_glsl_fragment_shader, + options_)); +} + +TEST_F(CppInterface, LimitsTexelOffsetHigherMaximum) { + options_.SetLimit(shaderc_limit_max_program_texel_offset, 10); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(10).c_str(), + shaderc_glsl_fragment_shader, + options_)); + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(11).c_str(), + shaderc_glsl_fragment_shader, + options_)); +} + } // anonymous namespace diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc index bde5cf0..927a53d 100644 --- a/libshaderc/src/shaderc_test.cc +++ b/libshaderc/src/shaderc_test.cc @@ -1373,4 +1373,56 @@ TEST(EntryPointTest, LangHlslOnHlslVertexSucceedsWithGivenEntryPointName) { << std::string(shaderc_result_get_bytes(compilation.result())); } +// Returns a fragment shader accessing a texture with the given +// offset. +std::string ShaderWithTexOffset(int offset) { + std::ostringstream oss; + oss << + "#version 150\n" + "uniform sampler1D tex;\n" + "void main() { vec4 x = textureOffset(tex, 1.0, " << offset << "); }\n"; + return oss.str(); +} + +// Ensure compilation is sensitive to limit setting. Sample just +// two particular limits. +TEST_F(CompileStringTest, LimitsTexelOffsetDefault) { + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-9).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-8).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(7).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(8).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); +} + +TEST_F(CompileStringTest, LimitsTexelOffsetLowerMinimum) { + shaderc_compile_options_set_limit(options_.get(), + shaderc_limit_min_program_texel_offset, + -99); + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-100).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-99).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); +} + +TEST_F(CompileStringTest, LimitsTexelOffsetHigherMaximum) { + shaderc_compile_options_set_limit(options_.get(), + shaderc_limit_max_program_texel_offset, + 10); + EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(10).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); + EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(11).c_str(), + shaderc_glsl_fragment_shader, + options_.get())); +} + } // anonymous namespace diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h index fc47766..50ab01c 100644 --- a/libshaderc_util/include/libshaderc_util/compiler.h +++ b/libshaderc_util/include/libshaderc_util/compiler.h @@ -26,6 +26,7 @@ #include "counting_includer.h" #include "file_finder.h" #include "mutex.h" +#include "resources.h" #include "string_piece.h" namespace shaderc_util { @@ -117,6 +118,13 @@ class Compiler { Size, // Optimization towards reducing code size. }; + // Resource limits. These map to the "max*" fields in glslang::TBuiltInResource. + enum class Limit { +#define RESOURCE(NAME,FIELD,CNAME) NAME, +#include "resources.inc" +#undef RESOURCE + }; + // Creates an default compiler instance targeting at Vulkan environment. Uses // version 110 and no profile specification as the default for GLSL. Compiler() @@ -130,7 +138,8 @@ class Compiler { generate_debug_info_(false), enabled_opt_passes_(), target_env_(TargetEnv::Vulkan), - source_language_(SourceLanguage::GLSL) {} + source_language_(SourceLanguage::GLSL), + limits_(kDefaultTBuiltInResource) {} // Requests that the compiler place debug information into the object code, // such as identifier names and line numbers. @@ -163,14 +172,19 @@ class Compiler { // subsequent CompileShader() calls. void SetForcedVersionProfile(int version, EProfile profile); + // Sets a resource limit. + void SetLimit(Limit limit, int value); + + // Returns the current limit. + int GetLimit(Limit limit) const; + // Compiles the shader source in the input_source_string parameter. // // If the forced_shader stage parameter is not EShLangCount then // the shader is assumed to be of the given stage. // // For HLSL compilation, entry_point_name is the null-terminated string for - // the - // entry point. For GLSL compilation, entry_point_name is ignored, and + // the entry point. For GLSL compilation, entry_point_name is ignored, and // compilation assumes the entry point is named "main". // // The stage_callback function will be called if a shader_stage has @@ -310,6 +324,9 @@ class Compiler { // The source language. Defaults to GLSL. SourceLanguage source_language_; + + // The resource limits to be used. + TBuiltInResource limits_; }; // Converts a string to a vector of uint32_t by copying the content of a given diff --git a/libshaderc_util/include/libshaderc_util/resources.h b/libshaderc_util/include/libshaderc_util/resources.h index 5b185b8..a8f635b 100644 --- a/libshaderc_util/include/libshaderc_util/resources.h +++ b/libshaderc_util/include/libshaderc_util/resources.h @@ -15,10 +15,13 @@ #ifndef LIBSHADERC_UTIL_RESOURCES_H_ #define LIBSHADERC_UTIL_RESOURCES_H_ -struct TBuiltInResource; +// We want TBuiltInResource +#include "glslang/Include/ResourceLimits.h" namespace shaderc_util { +using TBuiltInResource = ::TBuiltInResource; + // A set of suitable defaults. extern const TBuiltInResource kDefaultTBuiltInResource; diff --git a/libshaderc_util/include/libshaderc_util/resources.inc b/libshaderc_util/include/libshaderc_util/resources.inc new file mode 100644 index 0000000..8e86f01 --- /dev/null +++ b/libshaderc_util/include/libshaderc_util/resources.inc @@ -0,0 +1,107 @@ +// Copyright 2016 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. + +// These are the resource limits in a glslang::TBuiltInResource. +// The first field is the string name to be used in a configuration setting. +// The second field is the fieldname in TBuiltInResource. +// The third field is the enum name fragment for shaderc_limit. +// +// TODO(dneto): Consider using a single list of names, but use a Python script +// to generate *this* file. The original data file would have the first field, +// then generate the second field by lowering the case of the first letter, and +// generate the third field by taking the second field, and converting a +// lower-to-upper case transition into an underscore with lower-case. +RESOURCE(MaxLights,maxLights,max_lights) +RESOURCE(MaxClipPlanes,maxClipPlanes,max_clip_planes) +RESOURCE(MaxTextureUnits,maxTextureUnits,max_texture_units) +RESOURCE(MaxTextureCoords,maxTextureCoords,max_texture_coords) +RESOURCE(MaxVertexAttribs,maxVertexAttribs,max_vertex_attribs) +RESOURCE(MaxVertexUniformComponents,maxVertexUniformComponents,max_vertex_uniform_components) +RESOURCE(MaxVaryingFloats,maxVaryingFloats,max_varying_floats) +RESOURCE(MaxVertexTextureImageUnits,maxVertexTextureImageUnits,max_vertex_texture_image_units) +RESOURCE(MaxCombinedTextureImageUnits,maxCombinedTextureImageUnits,max_combined_texture_image_units) +RESOURCE(MaxTextureImageUnits,maxTextureImageUnits,max_texture_image_units) +RESOURCE(MaxFragmentUniformComponents,maxFragmentUniformComponents,max_fragment_uniform_components) +RESOURCE(MaxDrawBuffers,maxDrawBuffers,max_draw_buffers) +RESOURCE(MaxVertexUniformVectors,maxVertexUniformVectors,max_vertex_uniform_vectors) +RESOURCE(MaxVaryingVectors,maxVaryingVectors,max_varying_vectors) +RESOURCE(MaxFragmentUniformVectors,maxFragmentUniformVectors,max_fragment_uniform_vectors) +RESOURCE(MaxVertexOutputVectors,maxVertexOutputVectors,max_vertex_output_vectors) +RESOURCE(MaxFragmentInputVectors,maxFragmentInputVectors,max_fragment_input_vectors) +RESOURCE(MinProgramTexelOffset,minProgramTexelOffset,min_program_texel_offset) +RESOURCE(MaxProgramTexelOffset,maxProgramTexelOffset,max_program_texel_offset) +RESOURCE(MaxClipDistances,maxClipDistances,max_clip_distances) +RESOURCE(MaxComputeWorkGroupCountX,maxComputeWorkGroupCountX,max_compute_work_group_count_x) +RESOURCE(MaxComputeWorkGroupCountY,maxComputeWorkGroupCountY,max_compute_work_group_count_y) +RESOURCE(MaxComputeWorkGroupCountZ,maxComputeWorkGroupCountZ,max_compute_work_group_count_z) +RESOURCE(MaxComputeWorkGroupSizeX,maxComputeWorkGroupSizeX,max_compute_work_group_size_x) +RESOURCE(MaxComputeWorkGroupSizeY,maxComputeWorkGroupSizeY,max_compute_work_group_size_y) +RESOURCE(MaxComputeWorkGroupSizeZ,maxComputeWorkGroupSizeZ,max_compute_work_group_size_z) +RESOURCE(MaxComputeUniformComponents,maxComputeUniformComponents,max_compute_uniform_components) +RESOURCE(MaxComputeTextureImageUnits,maxComputeTextureImageUnits,max_compute_texture_image_units) +RESOURCE(MaxComputeImageUniforms,maxComputeImageUniforms,max_compute_image_uniforms) +RESOURCE(MaxComputeAtomicCounters,maxComputeAtomicCounters,max_compute_atomic_counters) +RESOURCE(MaxComputeAtomicCounterBuffers,maxComputeAtomicCounterBuffers,max_compute_atomic_counter_buffers) +RESOURCE(MaxVaryingComponents,maxVaryingComponents,max_varying_components) +RESOURCE(MaxVertexOutputComponents,maxVertexOutputComponents,max_vertex_output_components) +RESOURCE(MaxGeometryInputComponents,maxGeometryInputComponents,max_geometry_input_components) +RESOURCE(MaxGeometryOutputComponents,maxGeometryOutputComponents,max_geometry_output_components) +RESOURCE(MaxFragmentInputComponents,maxFragmentInputComponents,max_fragment_input_components) +RESOURCE(MaxImageUnits,maxImageUnits,max_image_units) +RESOURCE(MaxCombinedImageUnitsAndFragmentOutputs,maxCombinedImageUnitsAndFragmentOutputs,max_combined_image_units_and_fragment_outputs) +RESOURCE(MaxCombinedShaderOutputResources,maxCombinedShaderOutputResources,max_combined_shader_output_resources) +RESOURCE(MaxImageSamples,maxImageSamples,max_image_samples) +RESOURCE(MaxVertexImageUniforms,maxVertexImageUniforms,max_vertex_image_uniforms) +RESOURCE(MaxTessControlImageUniforms,maxTessControlImageUniforms,max_tess_control_image_uniforms) +RESOURCE(MaxTessEvaluationImageUniforms,maxTessEvaluationImageUniforms,max_tess_evaluation_image_uniforms) +RESOURCE(MaxGeometryImageUniforms,maxGeometryImageUniforms,max_geometry_image_uniforms) +RESOURCE(MaxFragmentImageUniforms,maxFragmentImageUniforms,max_fragment_image_uniforms) +RESOURCE(MaxCombinedImageUniforms,maxCombinedImageUniforms,max_combined_image_uniforms) +RESOURCE(MaxGeometryTextureImageUnits,maxGeometryTextureImageUnits,max_geometry_texture_image_units) +RESOURCE(MaxGeometryOutputVertices,maxGeometryOutputVertices,max_geometry_output_vertices) +RESOURCE(MaxGeometryTotalOutputComponents,maxGeometryTotalOutputComponents,max_geometry_total_output_components) +RESOURCE(MaxGeometryUniformComponents,maxGeometryUniformComponents,max_geometry_uniform_components) +RESOURCE(MaxGeometryVaryingComponents,maxGeometryVaryingComponents,max_geometry_varying_components) +RESOURCE(MaxTessControlInputComponents,maxTessControlInputComponents,max_tess_control_input_components) +RESOURCE(MaxTessControlOutputComponents,maxTessControlOutputComponents,max_tess_control_output_components) +RESOURCE(MaxTessControlTextureImageUnits,maxTessControlTextureImageUnits,max_tess_control_texture_image_units) +RESOURCE(MaxTessControlUniformComponents,maxTessControlUniformComponents,max_tess_control_uniform_components) +RESOURCE(MaxTessControlTotalOutputComponents,maxTessControlTotalOutputComponents,max_tess_control_total_output_components) +RESOURCE(MaxTessEvaluationInputComponents,maxTessEvaluationInputComponents,max_tess_evaluation_input_components) +RESOURCE(MaxTessEvaluationOutputComponents,maxTessEvaluationOutputComponents,max_tess_evaluation_output_components) +RESOURCE(MaxTessEvaluationTextureImageUnits,maxTessEvaluationTextureImageUnits,max_tess_evaluation_texture_image_units) +RESOURCE(MaxTessEvaluationUniformComponents,maxTessEvaluationUniformComponents,max_tess_evaluation_uniform_components) +RESOURCE(MaxTessPatchComponents,maxTessPatchComponents,max_tess_patch_components) +RESOURCE(MaxPatchVertices,maxPatchVertices,max_patch_vertices) +RESOURCE(MaxTessGenLevel,maxTessGenLevel,max_tess_gen_level) +RESOURCE(MaxViewports,maxViewports,max_viewports) +RESOURCE(MaxVertexAtomicCounters,maxVertexAtomicCounters,max_vertex_atomic_counters) +RESOURCE(MaxTessControlAtomicCounters,maxTessControlAtomicCounters,max_tess_control_atomic_counters) +RESOURCE(MaxTessEvaluationAtomicCounters,maxTessEvaluationAtomicCounters,max_tess_evaluation_atomic_counters) +RESOURCE(MaxGeometryAtomicCounters,maxGeometryAtomicCounters,max_geometry_atomic_counters) +RESOURCE(MaxFragmentAtomicCounters,maxFragmentAtomicCounters,max_fragment_atomic_counters) +RESOURCE(MaxCombinedAtomicCounters,maxCombinedAtomicCounters,max_combined_atomic_counters) +RESOURCE(MaxAtomicCounterBindings,maxAtomicCounterBindings,max_atomic_counter_bindings) +RESOURCE(MaxVertexAtomicCounterBuffers,maxVertexAtomicCounterBuffers,max_vertex_atomic_counter_buffers) +RESOURCE(MaxTessControlAtomicCounterBuffers,maxTessControlAtomicCounterBuffers,max_tess_control_atomic_counter_buffers) +RESOURCE(MaxTessEvaluationAtomicCounterBuffers,maxTessEvaluationAtomicCounterBuffers,max_tess_evaluation_atomic_counter_buffers) +RESOURCE(MaxGeometryAtomicCounterBuffers,maxGeometryAtomicCounterBuffers,max_geometry_atomic_counter_buffers) +RESOURCE(MaxFragmentAtomicCounterBuffers,maxFragmentAtomicCounterBuffers,max_fragment_atomic_counter_buffers) +RESOURCE(MaxCombinedAtomicCounterBuffers,maxCombinedAtomicCounterBuffers,max_combined_atomic_counter_buffers) +RESOURCE(MaxAtomicCounterBufferSize,maxAtomicCounterBufferSize,max_atomic_counter_buffer_size) +RESOURCE(MaxTransformFeedbackBuffers,maxTransformFeedbackBuffers,max_transform_feedback_buffers) +RESOURCE(MaxTransformFeedbackInterleavedComponents,maxTransformFeedbackInterleavedComponents,max_transform_feedback_interleaved_components) +RESOURCE(MaxCullDistances,maxCullDistances,max_cull_distances) +RESOURCE(MaxCombinedClipAndCullDistances,maxCombinedClipAndCullDistances,max_combined_clip_and_cull_distances) +RESOURCE(MaxSamples,maxSamples,max_samples) diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc index a170a4c..574ccfd 100644 --- a/libshaderc_util/src/compiler.cc +++ b/libshaderc_util/src/compiler.cc @@ -91,6 +91,29 @@ EShMessages GetMessageRules(shaderc_util::Compiler::TargetEnv env, } // anonymous namespace namespace shaderc_util { + +void Compiler::SetLimit(Compiler::Limit limit, int value) { + switch (limit) { +#define RESOURCE(NAME, FIELD, CNAME) \ + case Limit::NAME: \ + limits_.FIELD = value; \ + break; +#include "libshaderc_util/resources.inc" +#undef RESOURCE + } +} + +int Compiler::GetLimit(Compiler::Limit limit) const { + switch (limit) { +#define RESOURCE(NAME, FIELD, CNAME) \ + case Limit::NAME: \ + return limits_.FIELD; +#include "libshaderc_util/resources.inc" +#undef RESOURCE + } + return 0; // Unreachable +} + std::tuple, size_t> Compiler::Compile( const string_piece& input_source_string, EShLanguage forced_shader_stage, const std::string& error_tag, const char* entry_point_name, @@ -183,10 +206,10 @@ std::tuple, size_t> Compiler::Compile( shader.setEntryPoint(entry_point_name); // TODO(dneto): Generate source-level debug info if requested. - bool success = shader.parse( - &shaderc_util::kDefaultTBuiltInResource, default_version_, - default_profile_, force_version_profile_, kNotForwardCompatible, - GetMessageRules(target_env_, source_language_), includer); + bool success = + shader.parse(&limits_, default_version_, default_profile_, + force_version_profile_, kNotForwardCompatible, + GetMessageRules(target_env_, source_language_), includer); success &= PrintFilteredErrors(error_tag, error_stream, warnings_as_errors_, suppress_warnings_, shader.getInfoLog(), @@ -306,9 +329,8 @@ std::tuple Compiler::PreprocessShader( std::string preprocessed_shader; const bool success = shader.preprocess( - &shaderc_util::kDefaultTBuiltInResource, default_version_, - default_profile_, force_version_profile_, kNotForwardCompatible, rules, - &preprocessed_shader, includer); + &limits_, default_version_, default_profile_, force_version_profile_, + kNotForwardCompatible, rules, &preprocessed_shader, includer); if (success) { return std::make_tuple(true, preprocessed_shader, shader.getInfoLog()); diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc index 3af7c22..9938848 100644 --- a/libshaderc_util/src/compiler_test.cc +++ b/libshaderc_util/src/compiler_test.cc @@ -25,6 +25,7 @@ namespace { using shaderc_util::Compiler; using ::testing::HasSubstr; +using ::testing::Eq; // A trivial vertex shader const char kVertexShader[] = @@ -360,4 +361,73 @@ TEST_F(CompilerTest, EntryPointParameterTakesEffectForHLSL) { << assembly; } +// A test case for setting resource limits. +struct SetLimitCase { + Compiler::Limit limit; + int default_value; + int value; +}; + +using LimitTest = testing::TestWithParam; + +TEST_P(LimitTest, Sample) { + Compiler compiler; + EXPECT_THAT(compiler.GetLimit(GetParam().limit), + Eq(GetParam().default_value)); + compiler.SetLimit(GetParam().limit, GetParam().value); + EXPECT_THAT(compiler.GetLimit(GetParam().limit), Eq(GetParam().value)); +} + +#define CASE(LIMIT, DEFAULT, NEW) \ + { Compiler::Limit::LIMIT, DEFAULT, NEW } +INSTANTIATE_TEST_CASE_P( + CompilerTest, LimitTest, + // See resources.cc for the defaults. + testing::ValuesIn(std::vector{ + // clang-format off + // This is just a sampling of the possible values. + CASE(MaxLights, 8, 99), + CASE(MaxClipPlanes, 6, 10929), + CASE(MaxTessControlAtomicCounters, 0, 72), + CASE(MaxSamples, 4, 8), + // clang-format on + }), ); +#undef CASE + +// Returns a fragment shader accessing a texture with the given +// offset. +std::string ShaderWithTexOffset(int offset) { + std::ostringstream oss; + oss << "#version 150\n" + "uniform sampler1D tex;\n" + "void main() { vec4 x = textureOffset(tex, 1.0, " + << offset << "); }\n"; + return oss.str(); +} + +// Ensure compilation is sensitive to limit setting. Sample just +// two particular limits. The default minimum texel offset is -8, +// and the default maximum texel offset is 7. +TEST_F(CompilerTest, TexelOffsetDefaults) { + const EShLanguage stage = EShLangFragment; + EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(-9), stage)); + EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(-8), stage)); + EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(7), stage)); + EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(8), stage)); +} + +TEST_F(CompilerTest, TexelOffsetLowerTheMinimum) { + const EShLanguage stage = EShLangFragment; + compiler_.SetLimit(Compiler::Limit::MinProgramTexelOffset, -99); + EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(-100), stage)); + EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(-99), stage)); +} + +TEST_F(CompilerTest, TexelOffsetRaiseTheMaximum) { + const EShLanguage stage = EShLangFragment; + compiler_.SetLimit(Compiler::Limit::MaxProgramTexelOffset, 100); + EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(100), stage)); + EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(101), stage)); +} + } // anonymous namespace -- cgit v1.2.3 From 9d52054b282c5db65e1271828c6f7f14a4802705 Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 18 Nov 2016 14:43:25 -0500 Subject: Indicate Shaderc's level of stability. --- CHANGES | 1 + README.md | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4cf6bd4..d0519d3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ Revision history for Shaderc v2016.2-dev 2016-10-12 + - Describe Shaderc's level of stability. - Support HLSL compilation, exposing functionality in Glslang. - Supported in C, C++ API - glslc accepts "-x hlsl", and assumes .hlsl files are HLSL. diff --git a/README.md b/README.md index ab68e49..c3410cd 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,9 @@ to provide: ## Status -Shaderc is approaching maturity, but is still subject to incompatible changes. +Shaderc has maintained backward compatibility for quite some time, and we +don't anticipate any breaking changes. +Ongoing enhancements are described in the [CHANGES](CHANGES) file. Shaderc has been shipping in the [Android NDK](https://developer.android.com/ndk/index.html) since version r12b. -- cgit v1.2.3 From 2df47b51d83ad83cbc2e7f8ff2b56776293e8958 Mon Sep 17 00:00:00 2001 From: David Neto Date: Sat, 12 Nov 2016 13:55:21 -0800 Subject: Add -flimit to glslc to support shader resource limits. glslc -flimit= ignores language options. Those aren't really resource limits. But they do appear in glslangValidator configuration files. Ignore them. Add -flimit-file to read resource limits from a file. Add --show-limits to show default values, and valid input format. Add ParseResourceLimits internal function. --- CHANGES | 7 ++ glslc/CMakeLists.txt | 3 + glslc/README.asciidoc | 47 ++++++++++++-- glslc/src/main.cc | 75 ++++++++++++++++++++- glslc/src/resource_parse.cc | 97 ++++++++++++++++++++++++++++ glslc/src/resource_parse.h | 60 +++++++++++++++++ glslc/src/resource_parse_test.cc | 75 +++++++++++++++++++++ glslc/test/option_flimit.py | 136 +++++++++++++++++++++++++++++++++++++++ glslc/test/parameter_tests.py | 107 +++++++++++++++++++++++++++++- 9 files changed, 594 insertions(+), 13 deletions(-) create mode 100644 glslc/src/resource_parse.cc create mode 100644 glslc/src/resource_parse.h create mode 100644 glslc/src/resource_parse_test.cc create mode 100644 glslc/test/option_flimit.py diff --git a/CHANGES b/CHANGES index d0519d3..05d6d96 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,13 @@ v2016.2-dev 2016-10-12 - glslc accepts "-x hlsl", and assumes .hlsl files are HLSL. - glslc accepts "-fentry-point=" to set entry point name, overriding default value "main". + - Support setting shader resource limits in C, C++ APIs, and in + glslc + - glslc adds -flimit= + - glslc adds --show-limits to display defaults and valid resource + limit syntax. + - glslc adds "-flimit-file " support to read Glslang resource + configuration files, i.e. the output of "glslangValidator -c". v2016.1 2016-10-12 - C API for assembling now takes an options object diff --git a/glslc/CMakeLists.txt b/glslc/CMakeLists.txt index ba4d4c5..8f21aa2 100644 --- a/glslc/CMakeLists.txt +++ b/glslc/CMakeLists.txt @@ -7,6 +7,8 @@ add_library(glslc STATIC src/file.h src/file_includer.cc src/file_includer.h + src/resource_parse.h + src/resource_parse.cc src/shader_stage.cc src/shader_stage.h src/dependency_info.cc @@ -31,6 +33,7 @@ shaderc_add_tests( LINK_LIBS glslc shaderc_util shaderc TEST_NAMES file + resource_parse stage) shaderc_add_asciidoc(glslc_doc_README README) diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc index a8f22c9..b1551cd 100644 --- a/glslc/README.asciidoc +++ b/glslc/README.asciidoc @@ -11,10 +11,15 @@ Clang-compatible arguments. == Synopsis ---- +glslc [--help] + +glslc [--show-limits] + glslc [-c|-S|-E] [-x ...] [-std=standard] - [-fshader-stage=...] [-fentry-point=...] + [-flimit=...] + [-fshader-stage=...] [--target-env=...] [-g] [-O0|-Os] @@ -110,6 +115,12 @@ Otherwise, `--help` tells the glslc compiler to display all available options and exit. +==== `--show-limits` + +`--show-limits` shows default resource limits for shader compilation. The syntax +is the same as accepted by `-flimit=` and for the contents of the file specified +by `-flimit-file`. + ==== `-o` `-o` lets you specify the output file's name. It cannot be used when there are @@ -117,6 +128,34 @@ multiple files generated. A filename of `-` represents standard output. === Language and Mode Selection Options +[[option-f-entry-point]] +==== `-fentry-point=` + +`-fentry-point=` lets you specify the entry point name. This is only +significant for HLSL compilation. The default is "main". + +[[option-f-limit]] +==== `-flimit=` + +`-flimit=` lets you specify resource limits. +The argument should be a sequence of limit name, integer value pairs. Tokens +should be separated by whitespace. If the same limit is specified several +times, only the last setting takes effect. + +Use `--show-limits` to show the default values, and example syntax. + +This option affects all compiled shaders. + +[[option-f-limit-file]] +==== `-flimit-file` + +`-flimit-file ` lets you specify resource limits in a file. +The syntax of the file contents is the same as the argument to `-flimit=` and +the output of `--show-limits`. This option accepts Glslang resource configuration +files, e.g. as emitted by `glslangValidator -c`. + +This option affects all compiled shaders. + [[option-f-shader-stage]] ==== `-fshader-stage=` @@ -151,12 +190,6 @@ command line, please put SPIR-V assembly files ahead of the first `-fshader-stage=`, since `-fshader-stage=` only affects the treatment of subsequent files. -[[option-f-entry-point]] -==== `-fentry-point=` - -`-fentry-point=` lets you specify the entry point name. This is only -significant for HLSL compilation. The default is "main". - ==== `-std=` `-std=` lets you specify a shader version and profile on the command diff --git a/glslc/src/main.cc b/glslc/src/main.cc index 571e65f..108212d 100644 --- a/glslc/src/main.cc +++ b/glslc/src/main.cc @@ -21,12 +21,15 @@ #include #include +#include "libshaderc_util/compiler.h" +#include "libshaderc_util/io.h" #include "libshaderc_util/string_piece.h" #include "shaderc/shaderc.h" #include "spirv-tools/libspirv.h" #include "file.h" #include "file_compiler.h" +#include "resource_parse.h" #include "shader_stage.h" using shaderc_util::string_piece; @@ -46,13 +49,21 @@ Options: -Dmacro[=defn] Add an implicit macro definition. -E Outputs only the results of the preprocessing step. Output defaults to standard output. + -fentry-point= + Specify the entry point name for HLSL compilation, for + all subsequent source files. Default is "main". + -flimit= + Specify resource limits. Each limit is specified by a limit + name followed by an integer value. Tokens should be + separated by whitespace. If the same limit is specified + several times, only the last setting takes effect. + --show-limits Display available limit names and their default values. + -flimit-file + Set limits as specified in the given file. -fshader-stage= Treat subsequent input files as having stage . Valid stages are vertex, fragment, tesscontrol, tesseval, geometry, and compute. - -fentry-point= - Specify the entry point name for HLSL compilation, for - all subsequent source files. Default is "main". -g Generate source-level debug information. Currently this option has no effect. --help Display available options. @@ -110,6 +121,22 @@ bool GetOptionArgument(int argc, char** argv, int* index, } } +// Sets resource limits according to the given string. The string +// should be formated as required for ParseResourceSettings. +// Returns true on success. Otherwise returns false and sets err +// to a descriptive error message. +bool SetResourceLimits(const std::string& str, shaderc::CompileOptions* options, + std::string* err) { + std::vector settings; + if (!ParseResourceSettings(str, &settings, err)) { + return false; + } + for (const auto& setting : settings) { + options->SetLimit(setting.limit, setting.value); + } + return true; +} + const char kBuildVersion[] = #include "build-version.inc" ; @@ -131,6 +158,20 @@ int main(int argc, char** argv) { if (arg == "--help") { ::PrintHelp(&std::cout); return 0; + } else if (arg == "--show-limits") { + shaderc_util::Compiler default_compiler; +// The static cast here depends on us keeping the shaderc_limit enum in +// lockstep with the shaderc_util::Compiler::Limit enum. The risk of mismatch +// is low since both are generated from the same resources.inc file. +#define RESOURCE(NAME, FIELD, ENUM) \ + std::cout << #NAME << " " \ + << default_compiler.GetLimit( \ + static_cast( \ + shaderc_limit_##ENUM)) \ + << std::endl; +#include "libshaderc_util/resources.inc" +#undef RESOURCE + return 0; } else if (arg == "--version") { std::cout << kBuildVersion << std::endl; std::cout << "Target: " << spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0) @@ -156,6 +197,34 @@ int main(int argc, char** argv) { } else if (arg.starts_with("-fentry-point=")) { current_entry_point_name = arg.substr(std::strlen("-fentry-point=")).str(); + } else if (arg.starts_with("-flimit=")) { + std::string err; + if (!SetResourceLimits(arg.substr(std::strlen("-flimit=")).str(), + &compiler.options(), &err)) { + std::cerr << "glslc: error: -flimit error: " << err << std::endl; + return 1; + } + } else if (arg.starts_with("-flimit-file")) { + std::string err; + string_piece limits_file; + if (!GetOptionArgument(argc, argv, &i, "-flimit-file", &limits_file)) { + std::cerr << "glslc: error: argument to '-flimit-file' is missing" + << std::endl; + return 1; + } + std::vector contents; + if (!shaderc_util::ReadFile(limits_file.str(), &contents)) { + std::cerr << "glslc: cannot read limits file: " << limits_file + << std::endl; + return 1; + } + if (!SetResourceLimits( + string_piece(contents.data(), contents.data() + contents.size()) + .str(), + &compiler.options(), &err)) { + std::cerr << "glslc: error: -flimit-file error: " << err << std::endl; + return 1; + } } else if (arg.starts_with("-std=")) { const string_piece standard = arg.substr(std::strlen("-std=")); int version; diff --git a/glslc/src/resource_parse.cc b/glslc/src/resource_parse.cc new file mode 100644 index 0000000..7109333 --- /dev/null +++ b/glslc/src/resource_parse.cc @@ -0,0 +1,97 @@ +// Copyright 2016 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 "resource_parse.h" + +#include +#include +#include +#include +#include + +namespace { + +// Converts a limit string to a limit enum. Returns true on successful +// conversion. +bool StringToLimit(const std::string& str, shaderc_limit* limit) { + const char* cstr = str.c_str(); +#define RESOURCE(NAME, FIELD, ENUM) \ + if (0 == std::strcmp(#NAME, cstr)) { \ + *limit = shaderc_limit_##ENUM; \ + return true; \ + } +#include "libshaderc_util/resources.inc" +#undef RESOURCE + return false; +} + +// Returns true if we should ignore the setting. +bool IgnoreSetting(const std::string& str) { + const std::string ignore_list[] = { + "nonInductiveForLoops", + "whileLoops", + "doWhileLoops", + "generalUniformIndexing", + "generalAttributeMatrixVectorIndexing", + "generalVaryingIndexing", + "generalSamplerIndexing", + "generalVariableIndexing", + "generalConstantMatrixVectorIndexing", + }; + return std::find(std::begin(ignore_list), std::end(ignore_list), str) != + std::end(ignore_list); +} + +} // anonymous namespace + +namespace glslc { + +bool ParseResourceSettings(const std::string& input, + std::vector* limits, + std::string* err) { + auto failure = [err, limits](std::string msg) { + *err = msg; + limits->clear(); + return false; + }; + std::istringstream input_stream(input); + std::istream_iterator pos((input_stream)); + limits->clear(); + + while (pos != std::istream_iterator()) { + const std::string limit_name = *pos++; + shaderc_limit limit = static_cast(0); + bool ignore = IgnoreSetting(limit_name); + if (!ignore) { + if (!StringToLimit(limit_name, &limit)) + return failure(std::string("invalid resource limit: " + limit_name)); + } + + if (pos == std::istream_iterator()) + return failure(std::string("missing value after limit: ") + limit_name); + + const std::string value_str = *pos; + int value; + std::istringstream value_stream(value_str); + value_stream >> value; + if (value_stream.bad() || !value_stream.eof() || value_stream.fail()) + return failure(std::string("invalid integer: ") + value_str); + + if (!ignore) limits->push_back({limit, value}); + ++pos; + } + + return true; +} +} // anonymous namespace diff --git a/glslc/src/resource_parse.h b/glslc/src/resource_parse.h new file mode 100644 index 0000000..9794ce4 --- /dev/null +++ b/glslc/src/resource_parse.h @@ -0,0 +1,60 @@ +// Copyright 2016 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. + +#ifndef GLSLC_RESOURCE_PARSE_H +#define GLSLC_RESOURCE_PARSE_H + +#include +#include + +#include "shaderc/shaderc.h" + +namespace glslc { + +// A resource limit setting. +struct ResourceSetting { + shaderc_limit limit; + int value; +}; + + +// Returns true when two resource setting structures are equal. +inline bool operator==(const ResourceSetting& lhs, const ResourceSetting& rhs) { + return (lhs.limit == rhs.limit) && (lhs.value == rhs.value); +} + + +// Parses a resource limit setting string. On success, returns true and populates +// the limits parameter. On failure returns failure and emits a message to err. +// The setting string should be a seqeuence of pairs, where each pair +// is a limit name followed by a decimal integer. Tokens should be separated +// by whitespace. In particular, this function accepts Glslang's configuration +// file syntax. If a limit is mentioned multiple times, then the last setting +// takes effect. Ignore settings for: +// nonInductiveForLoops +// whileLoops +// doWhileLoops +// generalUniformIndexing +// generalAttributeMatrixVectorIndexing +// generalVaryingIndexing +// generalSamplerIndexing +// generalVariableIndexing +// generalConstantMatrixVectorIndexing +bool ParseResourceSettings(const std::string& input, + std::vector* limits, + std::string* err); +} // namespace glslc + + +#endif // GLSLC_FILE_H_ diff --git a/glslc/src/resource_parse_test.cc b/glslc/src/resource_parse_test.cc new file mode 100644 index 0000000..42c877b --- /dev/null +++ b/glslc/src/resource_parse_test.cc @@ -0,0 +1,75 @@ +// Copyright 2017 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 "resource_parse.h" + +#include + +namespace { + +using glslc::ParseResourceSettings; +using glslc::ResourceSetting; +using testing::Eq; + +struct ResourceSettingsCase { + std::string input; + bool success; + std::vector settings; + std::string message; +}; + +using ParseResourceSettingsTest = ::testing::TestWithParam; + +TEST_P(ParseResourceSettingsTest, Sample) { + std::vector settings; + std::string err; + const bool succeeded = ParseResourceSettings(GetParam().input, &settings, &err); + EXPECT_THAT(succeeded, Eq(GetParam().success)); + EXPECT_THAT(settings, Eq(GetParam().settings)); + EXPECT_THAT(err, Eq(GetParam().message)); +} + +INSTANTIATE_TEST_CASE_P(ParseResources, ParseResourceSettingsTest, + ::testing::ValuesIn(std::vector{ + {"", true, {}, ""}, + {" \t \t \n ", true, {}, ""}, + {" blorp blam", false, {}, "invalid resource limit: blorp"}, + {"MaxLightsxyz", false, {}, "invalid resource limit: MaxLightsxyz"}, + {"MaxLights", false, {}, "missing value after limit: MaxLights"}, + {"MaxLights x", false, {}, "invalid integer: x"}, + {"MaxLights 99x", false, {}, "invalid integer: 99x"}, + {"MaxLights 12 blam", false, {}, "invalid resource limit: blam"}, + {"MaxLights 12", true, {{shaderc_limit_max_lights, 12}}, ""}, + // Test negative number + {"MinProgramTexelOffset -9", true, {{shaderc_limit_min_program_texel_offset, -9}}, ""}, + // Test leading, intervening, and trailing whitespace + {" \tMaxLights \n 12 \t ", true, {{shaderc_limit_max_lights, 12}}, ""}, + // Test more than one limit setting. + {"MinProgramTexelOffset -10 MaxLights 4", true, {{shaderc_limit_min_program_texel_offset, -10}, {shaderc_limit_max_lights, 4}}, ""}, + // Check ignore cases. + {"nonInductiveForLoops", false, {}, "missing value after limit: nonInductiveForLoops"}, + {"nonInductiveForLoops 1", true, {}, ""}, + {"whileLoops 1", true, {}, ""}, + {"doWhileLoops 1", true, {}, ""}, + {"generalUniformIndexing 1", true, {}, ""}, + {"generalAttributeMatrixVectorIndexing 1", true, {}, ""}, + {"generalVaryingIndexing 1", true, {}, ""}, + {"generalSamplerIndexing 1", true, {}, ""}, + {"generalVariableIndexing 1", true, {}, ""}, + {"generalConstantMatrixVectorIndexing 1", true, {}, ""}, + // Check an ignore case with a regular case + {"whileLoops 1 MaxLights 99", true, {{shaderc_limit_max_lights, 99}}, ""}, + }), ); + +} // anonymous namespace diff --git a/glslc/test/option_flimit.py b/glslc/test/option_flimit.py new file mode 100644 index 0000000..0fbfd9d --- /dev/null +++ b/glslc/test/option_flimit.py @@ -0,0 +1,136 @@ +# Copyright 2016 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. + +import expect +from environment import File, Directory +from glslc_test_framework import inside_glslc_testsuite +from placeholder import FileShader + + +def shader_source_with_tex_offset(offset): + """Returns a vertex shader using a texture access with the given offset.""" + + return """#version 150 + uniform sampler1D tex; + void main() { vec4 x = textureOffset(tex, 1.0, """ + str(offset) + "); }" + + +def shader_with_tex_offset(offset): + """Returns a vertex FileShader using a texture access with the given offset.""" + + return FileShader(shader_source_with_tex_offset(offset), ".vert") + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitNoEqual(expect.ErrorMessage): + """Tests -flimit without equal.""" + + glslc_args = ['-flimit'] + expected_error = ["glslc: error: unknown argument: '-flimit'\n"] + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitJustEqual(expect.ValidObjectFile): + """Tests -flimit= with no argument.""" + + shader = shader_with_tex_offset(0); + glslc_args = ['-c', shader, '-flimit='] + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitJustEqualMaxOffset(expect.ValidObjectFile): + """Tests -flimit= with no argument. The shader uses max offset.""" + + shader = shader_with_tex_offset(7); + glslc_args = ['-c', shader, '-flimit='] + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitJustEqualMinOffset(expect.ValidObjectFile): + """Tests -flimit= with no argument. The shader uses min offset.""" + + shader = shader_with_tex_offset(-8); + glslc_args = ['-c', shader, '-flimit='] + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitJustEqualBelowMinOffset(expect.ErrorMessageSubstr): + """Tests -flimit= with no argument. The shader uses below min default offset.""" + + shader = shader_with_tex_offset(-9); + glslc_args = ['-c', shader, '-flimit='] + expected_error_substr = ["'texel offset' : value is out of range"] + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitLowerThanDefaultMinOffset(expect.ValidObjectFile): + """Tests -flimit= with lower than default argument. The shader uses below min offset.""" + + shader = shader_with_tex_offset(-9); + glslc_args = ['-c', shader, '-flimit= MinProgramTexelOffset -9 '] + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitIgnoredLangFeatureSettingSample(expect.ValidObjectFile): + """Tests -flimit= an ignored option.""" + + shader = FileShader("#version 150\nvoid main() { while(true); }", '.vert') + glslc_args = ['-c', shader, '-flimit=whileLoops 0'] + + +@inside_glslc_testsuite('OptionFLimit') +class TestFLimitLowerThanDefaultMinOffset(expect.ValidObjectFile): + """Tests -flimit= with lower than default argument. The shader uses that offset.""" + + shader = shader_with_tex_offset(-9); + glslc_args = ['-c', shader, '-flimit= MinProgramTexelOffset -9 '] + + +@inside_glslc_testsuite('OptionFLimitFile') +class TestFLimitFileNoArg(expect.ErrorMessage): + """Tests -flimit-file without an argument""" + + shader = shader_with_tex_offset(-9); + glslc_args = ['-c', shader, '-flimit-file'] + expected_error = "glslc: error: argument to '-flimit-file' is missing\n" + + +@inside_glslc_testsuite('OptionFLimitFile') +class TestFLimitFileMissingFile(expect.ErrorMessageSubstr): + """Tests -flimit-file without an argument""" + + shader = shader_with_tex_offset(-9); + glslc_args = ['-c', shader, '-flimit-file', 'i do not exist'] + expected_error_substr = "glslc: error: cannot open input file: 'i do not exist'"; + + +@inside_glslc_testsuite('OptionFLimitFile') +class TestFLimitFileSetsLowerMinTexelOffset(expect.ValidObjectFile): + """Tests -flimit-file with lower than default argument. The shader uses that offset.""" + + limits_file = File('limits.txt', 'MinProgramTexelOffset -9') + shader = File('shader.vert', shader_source_with_tex_offset(-9)); + environment = Directory('.', [limits_file, shader]) + glslc_args = ['-c', shader.name, '-flimit-file', limits_file.name] + + +@inside_glslc_testsuite('OptionFLimitFile') +class TestFLimitFileInvalidContents(expect.ErrorMessage): + """Tests -flimit-file bad file contents.""" + + limits_file = File('limits.txt', 'thisIsBad') + shader = File('shader.vert', shader_source_with_tex_offset(-9)); + environment = Directory('.', [limits_file, shader]) + glslc_args = ['-c', shader.name, '-flimit-file', limits_file.name] + expected_error = 'glslc: error: -flimit-file error: invalid resource limit: thisIsBad\n' diff --git a/glslc/test/parameter_tests.py b/glslc/test/parameter_tests.py index cbb6f11..b00d75f 100644 --- a/glslc/test/parameter_tests.py +++ b/glslc/test/parameter_tests.py @@ -57,13 +57,21 @@ Options: -Dmacro[=defn] Add an implicit macro definition. -E Outputs only the results of the preprocessing step. Output defaults to standard output. + -fentry-point= + Specify the entry point name for HLSL compilation, for + all subsequent source files. Default is "main". + -flimit= + Specify resource limits. Each limit is specified by a limit + name followed by an integer value. Tokens should be + separated by whitespace. If the same limit is specified + several times, only the last setting takes effect. + --show-limits Display available limit names and their default values. + -flimit-file + Set limits as specified in the given file. -fshader-stage= Treat subsequent input files as having stage . Valid stages are vertex, fragment, tesscontrol, tesseval, geometry, and compute. - -fentry-point= - Specify the entry point name for HLSL compilation, for - all subsequent source files. Default is "main". -g Generate source-level debug information. Currently this option has no effect. --help Display available options. @@ -182,3 +190,96 @@ class StdinWithoutShaderStage(expect.StdoutMatch, expect.StderrMatch): expected_stderr = [ "glslc: error: '-': -fshader-stage required when input is from " 'standard input "-"\n'] + + +@inside_glslc_testsuite('Parameters') +class LimitsHelp(expect.StdoutMatch, expect.StderrMatch): + """Tests --show-limits shows correct output.""" + + glslc_args = ['--show-limits'] + + expected_stderr = '' + expected_stdout = """MaxLights 8 +MaxClipPlanes 6 +MaxTextureUnits 2 +MaxTextureCoords 8 +MaxVertexAttribs 16 +MaxVertexUniformComponents 4096 +MaxVaryingFloats 60 +MaxVertexTextureImageUnits 16 +MaxCombinedTextureImageUnits 80 +MaxTextureImageUnits 16 +MaxFragmentUniformComponents 1024 +MaxDrawBuffers 2 +MaxVertexUniformVectors 256 +MaxVaryingVectors 15 +MaxFragmentUniformVectors 256 +MaxVertexOutputVectors 16 +MaxFragmentInputVectors 15 +MinProgramTexelOffset -8 +MaxProgramTexelOffset 7 +MaxClipDistances 8 +MaxComputeWorkGroupCountX 65535 +MaxComputeWorkGroupCountY 65535 +MaxComputeWorkGroupCountZ 65535 +MaxComputeWorkGroupSizeX 1024 +MaxComputeWorkGroupSizeY 1024 +MaxComputeWorkGroupSizeZ 64 +MaxComputeUniformComponents 512 +MaxComputeTextureImageUnits 16 +MaxComputeImageUniforms 8 +MaxComputeAtomicCounters 8 +MaxComputeAtomicCounterBuffers 1 +MaxVaryingComponents 60 +MaxVertexOutputComponents 64 +MaxGeometryInputComponents 64 +MaxGeometryOutputComponents 128 +MaxFragmentInputComponents 128 +MaxImageUnits 8 +MaxCombinedImageUnitsAndFragmentOutputs 8 +MaxCombinedShaderOutputResources 8 +MaxImageSamples 0 +MaxVertexImageUniforms 0 +MaxTessControlImageUniforms 0 +MaxTessEvaluationImageUniforms 0 +MaxGeometryImageUniforms 0 +MaxFragmentImageUniforms 8 +MaxCombinedImageUniforms 8 +MaxGeometryTextureImageUnits 16 +MaxGeometryOutputVertices 256 +MaxGeometryTotalOutputComponents 1024 +MaxGeometryUniformComponents 512 +MaxGeometryVaryingComponents 60 +MaxTessControlInputComponents 128 +MaxTessControlOutputComponents 128 +MaxTessControlTextureImageUnits 16 +MaxTessControlUniformComponents 1024 +MaxTessControlTotalOutputComponents 4096 +MaxTessEvaluationInputComponents 128 +MaxTessEvaluationOutputComponents 128 +MaxTessEvaluationTextureImageUnits 16 +MaxTessEvaluationUniformComponents 1024 +MaxTessPatchComponents 120 +MaxPatchVertices 32 +MaxTessGenLevel 64 +MaxViewports 16 +MaxVertexAtomicCounters 0 +MaxTessControlAtomicCounters 0 +MaxTessEvaluationAtomicCounters 0 +MaxGeometryAtomicCounters 0 +MaxFragmentAtomicCounters 8 +MaxCombinedAtomicCounters 8 +MaxAtomicCounterBindings 1 +MaxVertexAtomicCounterBuffers 0 +MaxTessControlAtomicCounterBuffers 0 +MaxTessEvaluationAtomicCounterBuffers 0 +MaxGeometryAtomicCounterBuffers 0 +MaxFragmentAtomicCounterBuffers 0 +MaxCombinedAtomicCounterBuffers 1 +MaxAtomicCounterBufferSize 32 +MaxTransformFeedbackBuffers 4 +MaxTransformFeedbackInterleavedComponents 64 +MaxCullDistances 8 +MaxCombinedClipAndCullDistances 8 +MaxSamples 4 +""" -- cgit v1.2.3 From 427daa53ff38cc2dfd408aa5799a6b8177b5d4d6 Mon Sep 17 00:00:00 2001 From: David Neto Date: Mon, 28 Nov 2016 11:40:49 -0500 Subject: Update tests for more strict glslang Glslang now warns when an HLSL shader entry point can't be found that either matches the default of "main" or one specified via -fentry-point. --- glslc/test/option_dash_x.py | 3 ++- glslc/test/option_fentry_point.py | 14 +++++++++----- glslc/test/option_shader_stage.py | 3 ++- glslc/test/option_std.py | 3 ++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/glslc/test/option_dash_x.py b/glslc/test/option_dash_x.py index 3645340..0288017 100644 --- a/glslc/test/option_dash_x.py +++ b/glslc/test/option_dash_x.py @@ -20,7 +20,8 @@ MINIMAL_SHADER = "#version 140\nvoid main(){}" # This one is valid GLSL but not valid HLSL. GLSL_VERTEX_SHADER = "#version 140\nvoid main(){ gl_Position = vec4(1.0);}" # This one is valid HLSL but not valid GLSL. -HLSL_VERTEX_SHADER = "float4 EntryPoint() : SV_POSITION { return float4(1.0); }" +# Use entry point "main" so we don't have to specify -fentry-point +HLSL_VERTEX_SHADER = "float4 main() : SV_POSITION { return float4(1.0); }" @inside_glslc_testsuite('OptionDashX') class TestDashXNoArg(expect.ErrorMessage): diff --git a/glslc/test/option_fentry_point.py b/glslc/test/option_fentry_point.py index 5d8f96f..8625732 100644 --- a/glslc/test/option_fentry_point.py +++ b/glslc/test/option_fentry_point.py @@ -58,17 +58,21 @@ class TestFEntryPointMainOnGlslShader(expect.ValidAssemblyFileWithSubstr): @inside_glslc_testsuite('OptionFEntryPoint') -class TestFEntryPointMainOnHlslShader(expect.ValidAssemblyFileWithSubstr): - """Tests -x hlsl on an HLSL shader with -fentry-point=main and -S.""" +class TestFEntryPointMainOnHlslShaderNotMatchingSource(expect.ValidObjectFileWithWarning): + """Tests -x hlsl on an HLSL shader with -fentry-point=main + not matching the source.""" shader = FileShader(HLSL_VERTEX_SHADER, '.vert') - glslc_args = ['-x', 'hlsl', '-fentry-point=main', '-S', shader] - expected_assembly_substr = ASSEMBLY_MAIN + glslc_args = ['-x', 'hlsl', '-fentry-point=main', '-c', shader] + expected_warning = [shader, + ': warning: Linking vertex stage: Entry point not found\n' + '1 warning generated.\n'] @inside_glslc_testsuite('OptionFEntryPoint') class TestFEntryPointSpecifiedOnHlslShaderInDisassembly(expect.ValidObjectFileWithAssemblySubstr): - """Tests -x hlsl on an HLSL shader with -fentry-point=EntryPoint.""" + """Tests -x hlsl on an HLSL shader with -fentry-point=EntryPoint + matching source.""" shader = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT) glslc_args = ['-x', 'hlsl', '-fentry-point=EntryPoint', '-c', shader] diff --git a/glslc/test/option_shader_stage.py b/glslc/test/option_shader_stage.py index 5114173..6b2ec0b 100644 --- a/glslc/test/option_shader_stage.py +++ b/glslc/test/option_shader_stage.py @@ -25,7 +25,8 @@ def simple_vertex_shader(): def simple_hlsl_vertex_shader(): - return """float4 EntryPoint() : SV_POSITION { return float4(1.0); } """ + # Use "main" so we don't have to specify -fentry-point + return """float4 main() : SV_POSITION { return float4(1.0); } """ def simple_fragment_shader(): diff --git a/glslc/test/option_std.py b/glslc/test/option_std.py index 865a4d2..b01d584 100644 --- a/glslc/test/option_std.py +++ b/glslc/test/option_std.py @@ -29,7 +29,8 @@ def core_frag_shader_without_version(): def hlsl_compute_shader_with_barriers(): - return 'void Entry() { AllMemoryBarrierWithGroupSync(); }' + # Use "main" to avoid the need for -fentry-point + return 'void main() { AllMemoryBarrierWithGroupSync(); }' @inside_glslc_testsuite('OptionStd') -- cgit v1.2.3