diff options
author | David Neto <dneto@google.com> | 2016-10-29 11:30:00 -0400 |
---|---|---|
committer | David Neto <dneto@google.com> | 2016-11-16 16:36:26 -0500 |
commit | 89eefb94d69e07576682e44cb3d55fa332ce2e91 (patch) | |
tree | 2239b78dfa98602d3515aee07d64c43843375ac1 | |
parent | 725a8fd2e7b98f45905f8ac791c62e6239ce2898 (diff) | |
download | shaderc-89eefb94d69e07576682e44cb3d55fa332ce2e91.tar.gz |
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.
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | glslc/README.asciidoc | 7 | ||||
-rw-r--r-- | glslc/src/file_compiler.cc | 34 | ||||
-rw-r--r-- | glslc/src/file_compiler.h | 21 | ||||
-rw-r--r-- | glslc/src/main.cc | 23 | ||||
-rw-r--r-- | glslc/test/CMakeLists.txt | 3 | ||||
-rw-r--r-- | glslc/test/expect.py | 54 | ||||
-rw-r--r-- | glslc/test/expect_nosetest.py | 12 | ||||
-rwxr-xr-x | glslc/test/glslc_test_framework.py | 24 | ||||
-rw-r--r-- | glslc/test/option_dash_x.py | 8 | ||||
-rw-r--r-- | glslc/test/option_fentry_point.py | 109 | ||||
-rw-r--r-- | glslc/test/parameter_tests.py | 3 | ||||
-rw-r--r-- | glslc/test/placeholder.py | 5 |
13 files changed, 245 insertions, 60 deletions
@@ -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=<name>" 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=<name>` lets you specify the entry point name. This is only +significant for HLSL compilation. The default is "main". + ==== `-std=` `-std=<value>` 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<char> 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 <stdin>. @@ -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 <stage>. Valid stages are vertex, fragment, tesscontrol, tesseval, geometry, and compute. + -fentry-point=<name> + 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<InputFileSpec> input_files; + std::vector<glslc::InputFileSpec> 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 - $<TARGET_FILE:glslc_exe> --test-dir ${CMAKE_CURRENT_SOURCE_DIR}) + $<TARGET_FILE:glslc_exe> $<TARGET_FILE:spirv-dis> + --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 @@ -51,14 +51,6 @@ class TestDashXGlslOnHlslShader(expect.ErrorMessageSubstr): @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 <stage>. Valid stages are vertex, fragment, tesscontrol, tesseval, geometry, and compute. + -fentry-point=<name> + 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. |