First Commit

This commit is contained in:
2025-11-18 14:18:26 -07:00
parent 33eb6e3707
commit 27277ec342
6106 changed files with 3571167 additions and 0 deletions

74
3rdparty/shaderc/glslc/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,74 @@
# Copyright 2020 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.
find_package(Threads)
add_library(glslc STATIC
src/file_compiler.cc
src/file_compiler.h
src/file.cc
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
src/dependency_info.h
)
shaderc_default_compile_options(glslc)
target_include_directories(glslc PUBLIC ${glslang_SOURCE_DIR})
if (SHADERC_ENABLE_WGSL_OUTPUT)
if (IS_DIRECTORY "${tint_SOURCE_DIR}/include")
target_include_directories(glslc PRIVATE "${tint_SOURCE_DIR}/include")
target_include_directories(glslc PRIVATE "${tint_SOURCE_DIR}")
endif()
# Turn on features in the tint/tint.h header
add_definitions(-DTINT_BUILD_SPV_READER=1 -DTINT_BUILD_WGSL_WRITER=1)
add_definitions(-DSHADERC_ENABLE_WGSL_OUTPUT=1)
endif(SHADERC_ENABLE_WGSL_OUTPUT)
target_link_libraries(glslc PRIVATE
glslang SPIRV # Glslang libraries
$<$<BOOL:${SHADERC_ENABLE_WGSL_OUTPUT}>:libtint> # Tint libraries, optional
shaderc_util shaderc # internal Shaderc libraries
${CMAKE_THREAD_LIBS_INIT})
add_executable(glslc_exe src/main.cc)
shaderc_default_compile_options(glslc_exe)
target_include_directories(glslc_exe PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/.. ${spirv-tools_SOURCE_DIR}/include)
set_target_properties(glslc_exe PROPERTIES OUTPUT_NAME glslc)
target_link_libraries(glslc_exe PRIVATE glslc shaderc_util shaderc)
add_dependencies(glslc_exe build-version)
shaderc_add_tests(
TEST_PREFIX glslc
LINK_LIBS glslc shaderc_util shaderc
TEST_NAMES
file
resource_parse
stage)
shaderc_add_asciidoc(glslc_doc_README README)
if(SHADERC_ENABLE_INSTALL)
install(TARGETS glslc_exe
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
endif(SHADERC_ENABLE_INSTALL)
add_subdirectory(test)

732
3rdparty/shaderc/glslc/README.asciidoc vendored Normal file
View File

@@ -0,0 +1,732 @@
= glslc Manual
:toc:
:toclevels: 3
:numbered:
:source-highlighter: pygments
== Name
`glslc` - A command-line GLSL/HLSL to SPIR-V compiler with
Clang-compatible arguments.
== Synopsis
----
glslc [--help]
glslc [-h]
glslc [--show-limits]
glslc [-c|-S|-E]
[-x ...] [-std=standard]
[ ... options for resource bindings ... ]
[-fhlsl-16bit-types]
[-fhlsl-offsets]
[-fhlsl-functionality1]
[-fentry-point=<name>]
[-fauto-map-locations]
[-finvert-y]
[-flimit=...]
[-flimit-file <resource-limits-file>]
[-fshader-stage=...]
[--target-env=...]
[--target-spv=...]
[-g]
[-O0|-Os]
[-Idirectory...]
[-Dmacroname[=value]...]
[-w] [-Werror]
[-o outfile]
shader...
----
== Description
=== Input file languages
glslc accepts both GLSL/HLSL source and SPIR-V assembly files as inputs.
==== Shader stage specification
glslc provides three ways to specify the shader stage of a GLSL source file:
`-fshader-stage=<stage>`, `#pragma shader_stage(<stage>)`, and file extension.
The `-fshader-stage=` option overrides `#pragma shader_stage()`, which overrides
the file extension.
Shader stages can be specified by naming a file with an appropriate extension
as shown in the following table. `-fshader-stage=` and `#pragma shader_stage()`,
on the other hand, enable you to specify shader stages from the command line
and within the source file. Possible ``stage``s for them are also listed in
the following table. Details about `-fshader-stage=` can be found in
<<option-fshader-stage,its own section>>.
[[shader-stage-selection]]
.Shader Stage Selection
|===
|Shader Stage |Shader File Extension |`<stage>`
|vertex |`.vert` |`vertex`
|fragment |`.frag` |`fragment`
|tesselation control |`.tesc` |`tesscontrol`
|tesselation evaluation |`.tese` |`tesseval`
|geometry |`.geom` |`geometry`
|compute |`.comp` |`compute`
|===
`#pragma shader_stage()` relies on the `#pragma` preprocessor directive; thus,
the token inside `shader_stage()` is not subject to preprocessor macro
expansion. It must be exactly one of the ``stage``s in the above table.
`#pragma shader_stage()` behaves as follows:
* The first `#pragma shader_stage()` directive in a translation unit must
precede any non-preprocessor tokens.
* If there is more than one `#pragma shader_stage()` directive in the same
translation unit, all the ``stage``s specified must be the same. Otherwise,
glslc will issue an error.
==== SPIR-V assembly files
SPIR-V assembly input files should follow the
https://github.com/KhronosGroup/SPIRV-Tools/blob/master/syntax.md[syntax]
defined in the https://github.com/KhronosGroup/SPIRV-Tools[SPIRV-Tools]
project and have the `.spvasm` extension. Command line options treat SPIR-V
assembly files differently; some may ignore them, e.g., `<<option-cap-e,-E>>`,
`<<option-cap-s,-S>>`, and some may even treat them not as SPIR-V assembly
files, e.g., `<<shader-stage-with-spirv-assembly,-fshader-stage\=>>`.
[[output-file-naming]]
=== Output file naming
If a name is specified via `-o`, the output file will be given that name.
Otherwise,
* If a compilation stage selection option is given (`-S` or `-c`), there will
be one output file generated per input shader file. The generated output file
will end with a file extension that matches the compilation stage, which is
`.spvasm` for `-S` and `.spv` for `-c`. The name will depend on the original
file's name and extension.
** If the input file has a <<shader-stage-selection,shader stage selection
extension>>, the output file will be named as by appending the file extension
for the compilation stage to the input file's name. E.g., `glslc -c foo.vert`
will generate `foo.vert.spv`, and `glslc -S bar.frag` will generate
`bar.frag.spvasm`.
** Otherwise, the output file will be named as by replacing the input file's
file extension, if any, with the file extension for the compilation stage.
E.g., `glslc -c foo` will generate `foo.spv`, and `glslc -S bar.glsl` will
generate `bar.spvasm`.
* If no compilation stage is selected, the output file will be named `a.spv`.
== Command Line Options
=== Overall Options
==== `--help`, `-h`
Option `--help` or `-h` 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
multiple files generated. A filename of `-` represents standard output.
=== Language and Mode Selection Options
[[option-finvert-y]]
==== `-finvert-y`
Inverts position.Y output in a vertex shader.
[[option-flimit]]
==== `-flimit=`
`-flimit=<resource-limits>` 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-flimit-file]]
==== `-flimit-file`
`-flimit-file <resource-limits-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-fshader-stage]]
==== `-fshader-stage=`
`-fshader-stage=<stage>` lets you specify the shader stage for one or more
inputs from the command line.
Possible values for ``<stage>`` are listed in the <<shader-stage-selection,
Shader Stage Selection>> table.
`-fshader-stage=` behaves as follows:
* `-fshader-stage=` sets the shader stage for subsequent input files. It does
not affect the stages of any preceding inputs on the command line.
* When supplying more than one `-fshader-stage=` argument, the most recent
argument preceding an input file applies.
* A shader file not ending with <<shader-stage-selection,known shader file
extensions>> must have a `-fshader-stage=` argument ahead of it to specify
its stage.
* If there is a `-fshader-stage=` before a file in which there is a `#pragma
shader_stage()` directive, the directive is ignored and the `-fshader-stage=`
argument is used instead.
* If there is a `-fshader-stage=` before a file with a known shader file
extension, the file extension is ignored and the `-fshader-stage=` argument
is used instead.
[[shader-stage-with-spirv-assembly]]
CAUTION: `-fshader-stage=` overrides file extension; that means it should not
be used together with SPIR-V assembly files because glslc will treat the given
SPIR-V assembly files as GLSL source code of the given shader stage. If you
need to supply both SPIR-V assembly files and `-fshader-stage=` on the same
command line, please put SPIR-V assembly files ahead of the first
`-fshader-stage=`, since `-fshader-stage=` only affects the treatment of
subsequent files.
==== `-std=`
`-std=<value>` lets you specify a shader version and profile on the command
line. ``<value>`` can be any valid concatenation of a GLSL version number and
profile, e.g., `310es`, `450core`, etc. The profile can be omitted as allowed by
GLSL, e.g., `450`.
`-std=` behaves as follows:
* `-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`
directive in an input file, `glslc` will issue a warning.
* If multiple `-std=` arguments are specified on the command line, only the last
one takes effect.
CAUTION: `-std=` does not affect the `#version` directive in the preprocessed
output. That is, when `-std=` specifies a version different from the shader
source code, the `#version` directive in preprocessed output will still be the
one in the source code. But `-std=` does affect the behavior of `#line`
directives in the preprocessed output. Behavior of `#line` directives will
follow the version specified by `-std=`.
==== `--target-env=`
`--target-env=<value>` lets you specify a target environment on the command line.
This affects the generation of warnings and errors. The ``<value>`` can be one of
the following:
* `vulkan`: create SPIR-V under Vulkan 1.0 semantics.
* `vulkan1.0`: create SPIR-V under Vulkan 1.0 semantics.
* `vulkan1.1`: create SPIR-V under Vulkan 1.1 semantics.
* `vulkan1.2`: create SPIR-V under Vulkan 1.2 semantics.
* `opengl`: create SPIR-V under OpenGL 4.5 semantics.
* `opengl4.5`: create SPIR-V under OpenGL 4.5 semantics.
Generated code uses SPIR-V 1.0, except for code compiled for Vulkan 1.1, which uses
SPIR-V 1.3, and code compiled for Vulkan 1.2, which uses SPIR-V 1.5.
If this option is not specified, a default of `vulkan1.0` is used.
Note: Support for OpenGL compatibility profile, `opengl_compat`, has been removed.
==== `--target-spv=`
`--target-spv=<value>` lets you specify the SPIR-V version to be used by the generated
module. The default is to use the highest version of SPIR-V required to be supported
by the target environment. The defaults for specific Vulkan target environments are
as follows: SPIR-V 1.0 for Vulkan 1.0, SPIR-V 1.3 for Vulkan 1.1, and SPIR-V 1.5 for
Vulkan 1.2.
The ``<value>`` can be one of the following:
* `spv1.0`
* `spv1.1`
* `spv1.2`
* `spv1.3`
* `spv1.4`
* `spv1.5`
* `spv1.6`
==== `-x`
`-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'.
Note: HLSL compilation will use HLSL packing (offset) rules for variables
that are vertex shader outputs, and inputs and outputs of both geometry
and pixel shaders.
[[compilation-stage-selection-options]]
=== Compilation Stage Selection Options
==== `-c`
`-c` tells the glslc compiler to run the preprocessing and compiling stage.
Each input shader file results in a SPIR-V binary file; these SPIR-V binary
files are named by the rules in the <<output-file-naming,Output File Naming>>
section.
[[option-cap-e]]
==== `-E`
`-E` tells the glslc compiler to run only the preprocessing stage. It overrides
`-c` and `-S`. Preprocessed output is written to standard output, while
preprocessing errors are written to standard error. If multiple input shader
files are given, their preprocessed output are all written to standard output,
in the order specified on the command line.
glslc will do nothing for SPIR-V assembly files with this option.
[[option-cap-s]]
==== `-S`
`-S` tells the glslc compiler to run the preprocessing, compiling, and then
disassembling stage. It overrides `-c`. Each input shader file results in a
SPIR-V assembly file; these SPIR-V assembly files are named by the rules in the
<<output-file-naming,Output File Naming>> section.
glslc will do nothing for SPIR-V assembly files with this option.
==== No Compilation Stage Selection
If none of the above options is given, the glslc compiler will run
preprocessing, compiling, and linking stages.
WARNING: Linking of multiple input shader files are not supported yet.
=== Preprocessor Options
==== `-D`
`-Dmacroname[=[value]]` lets you define a preprocessor macro before input shader
files are preprocessed. If `value` is omitted, the macro is defined with an
empty value.
==== `-I`
`-Idirectory` or `-I directory` adds the specified directory to the search path
for include files. The directory may be an absolute path or a relative path to
the current working directory.
=== Code Generation Options
==== `-g`
Requests that the compiler place source-level debug information into the object
code, such as identifier names and line numbers.
This option restrains `-O` from turning on the strip-debug-info optimization
pass.
NOTE: Currently this option has no effect. Full functionality depends on
glslang support for generating debug info.
==== `-O0`, `-Os`
`-O` specifies which optimization level to use:
* `-O0` means "no optimization". This level generates the most debuggable code.
* `-O` means the default optimization level for better performance.
* `-Os` enables optimizations to reduce code size.
==== `-mfmt=<format>`
`-mfmt=<format>` selects output format for compilation output in SPIR-V binary
code form. Supported options are listed in the
<<binary-output-format-options,binary output format options>> table. This
option is only valid to be used when the compilation output is SPIR-V binary
code. Specifying any options listed below when the output is not SPIR-V binary
code, like disassembly (with `-S` specified), text (with `-M`, `-MM` or `-E`
specified) will trigger an error.
[[binary-output-format-options]]
.Binary Output Format Options
[cols="20%,80%"]
|===
|Format option |Description
|bin |Output SPIR-V binary code as a sequence of binary 32-bitwords
in host native endianness. This is the default format for
SPIR-V binary compilation output.
|num |Output SPIR-V binary code as a text file containing a list of
comma-separated hex numbers. +
Example: `glslc -c -mfmt=num main.vert -o output_file.txt` +
Content of the output_file.txt: +
0x07230203,0x00010000,0x00080001,0x00000006...
|c |Output SPIR-V binary code as a text file containing C-style +
initializer list. +
This is just wrapping the output of `num` option with curly
brackets. +
Example: `glslc -c -mfmt=c main.vert -o output_file.txt` +
Content of output_file.txt: +
{0x07230203, 0x00010000, 0x00080001, 0x00000006...}
|===
[[option-fhlsl-16bit-types]]
==== `-fhlsl-16bit-types`
Enables 16bit types for HLSL compilation.
[[option-fhlsl-offsets]]
==== `-fhlsl-offsets`
Use HLSL packing rules instead of GLSL rules when determining offsets of
members of blocks. This option is always on when compiling for HLSL.
[[option-fhlsl-functionality1]]
==== `-fhlsl-functionality1`
Enable extension `SPV_GOOGLE_hlsl_functionality1`, and instructs the compiler
to:
- Annotate HLSL semantic string decorations on interface objects
- Explicitly record the association of a UAV resource with its companion counter buffer.
This option can also be spelled with an underscore: `-fhlsl_functionality1`.
[[option-fentry-point]]
==== `-fentry-point=<name>`
`-fentry-point=<name>` lets you specify the entry point name. This is only
significant for HLSL compilation. The default is "main".
[[option-fauto-map-locations]]
==== `-fauto-map-locations`
For GLSL compilation, option `-fauto-map-locations` directs the compiler to automatically
assign location numbers to user-defined stage input and output variables if not explicitly
specified by the shader source.
For HLSL compilation, this option is on by default.
Client APIs normally require adjacent stages to agree on their I/O interface.
The compiler only sees one stage at a time, so it is strongly recommended that
you avoid relying on this option to assign locations.
Instead, an explicit binding number should be specified in the shader source, as follows:
* In a GLSL shader, use a `location` layout qualifier:
----
layout(location = 1) in vec4 x;
----
* In an HLSL shader, use a `vk::location` attribute:
----
[[vk::location(1)]] float4 FooShader(
[[vk::location(0)]] float4 a,
[[vk::location(2)]] float4 b) : COLOR0 {
return a + b;
}
----
[[option-fpreserve-bindings
==== `-fpreserve-bindings`
Directs the optimizer to preserve bindings declarations, even when those
bindings are known to be unused.
=== Warning and Error Options
==== `-w`
`-w` suppresses all warning output from `glslc`. Any warning that would have
been generated is silently ignored.
==== `-Werror`
`-Werror` forces any warning to be treated as an error in `glslc`. This means
that all `warning:` messages are shown as `error:` and any warnings will cause
a non-zero exit code from `glslc`. If `-w` is specified the warnings
generated are suppressed before they are converted to errors.
=== Dependency Generation Options
==== `-M` or `-MM`
`-M` generates *make* dependencies. It outputs a rule suitable for *make*
describing the dependencies of the input file. Instead of outputting the result
of preprocessing, the preprocessor outputs one *make* rule containing the
SPIR-V object file name for that source file, a colon, and the names of all the
included files.
Unless specified explicitly (with `-MT`), the SPIR-V object file name in the
generated *make* rules follows the rules of <<output-file-naming,Output File
Naming>> as in `-c` compilation stage.
Specifying `-M` implies `-E`, and suppresses warnings with an implicit `-w`.
By default the output will be written to stdout, unless `-MF` or `-o` is
specified.
The dependency info file name can be specified by `-o` and `-MF` options. When
both are specified, `-o` option is ignored.
Specifying multiple input files is valid when the *make* rules are written to
stdout, which means neither `-MF` nor `-o` is specified. When `-o` or `-MF` is
specified, only one input file is allowed.
`-MM` is an alias for `-M`.
E.g., `glslc -M main.vert` will dump `main.vert.spv: main.vert <other included
files>` to stdout. More examples are listed in
<<dependency-generation-examples,Dependency Generation Examples>>
==== `-MD`
`-MD` tells the glslc compiler to both compile the source and generate *make*
dependencies. Dependencies are written to a file whose name is determined as
follows: If option `-MF` is specified, use its argument. Otherwise, use the
filename formed by appending *.d* to the name of the file containing
compilation results.
Specifying multiple input files is valid when neither `-MF` nor `-o` is
specified. When `-o` or `-MF` is specified, only one input file is allowed.
E.g., `glslc -c -MD main.vert` will generate `main.vert.spv` as the SPIR-V
object file and `main.vert.spv.d` as the dependency info file. More examples
are listed in <<dependency-generation-examples,Dependency Generation Examples>>
==== `-MF`
`-MF` lets you specify the dependency info file name when used with `-M` or
`-MD`. This option is invalid when used with multiple input files.
E.g., `glslc -c -MD main.vert -MF dep_info` will generate `main.vert.spv` as
the SPIR-V object file and `dep_info` as the dependency info file.
==== `-MT`
`-MT` lets you specify the target of the rule emitted by dependency generation
when used with `-M` or `-MD`. This option is invalid when used with multiple
input files.
E.g., `glslc -M main.vert -MT target` will dump following dependency info to
stdout: `target: main.vert <other dependent files>`.
[[dependency-generation-examples]]
.Dependency Generation Examples
|===
|Command Line Input|Compilation Output File|Dependency Output File|Dependency Info
|glslc -M main.vert | <NA> | <Stdout> | main.vert.spv: main.vert
.2+|glslc -M a.vert b.vert | <NA> | <Stdout> | a.vert.spv: a.vert
| <NA> | <Stdout> | b.vert.spv: b.vert
|glslc -M main.vert -o dep_info | <NA> | dep_info | main.vert.spv: main.vert
|glslc -M main.vert -MF dep_info| <NA> | dep_info | main.vert.spv: main.vert
|glslc -M main.vert -MT target | <NA> | <Stdout> | target: main.vert
|glslc -MD main.vert |a.spv |main.vert.spv.d|main.vert.spv: main.vert
|glslc -c -MD main.vert |main.vert.spv|main.vert.spv.d|main.vert.spv: main.vert
.2+|glslc -c -MD a.vert b.vert | a.vert.spv | a.vert.spv.d | a.vert.spv: a.vert
| b.vert.spv | b.vert.spv.d | b.vert.spv: b.vert
|glslc -S -MD main.vert |main.vert.spvasm |main.vert.spvasm.d |main.vert.spvasm: main.vert
|glslc -c -MD main.vert -MF dep_info |main.vert.spv|dep_info|main.vert.spv: main.vert
|glslc -c -MD main.vert -o obj |obj |obj.d |obj: main.vert
|glslc -c -MD main.vert -o obj -MF dep_info -MT target|obj|dep_info|target: main.vert
|===
=== Resource Binding Options
[[option-fauto-bind-uniforms]]
==== `-fauto-bind-uniforms`
Option `-fauto-bind-uniforms` directs the compiler to automatically assign
binding numbers to uniform variables, when an explicit binding is not
specified in the shader source.
An explicit binding number can be specified in the shader source by using
a `binding` layout qualifier. For example:
----
layout(binding = 12) uniform texture2D;
----
[[option-fhlsl-iomap]]
==== `-fhlsl-iomap`
Option `-fhlsl-iomap` directs the compiler to use HLSL register
assignments as binding values.
[[option-fimage-binding-base]]
==== `-fimage-binding-base`
Option `-fimage-binding-base [stage] base` sets the lowest automatically
assigned binding for images. If a stage is specified, only affects the specified
stage.
For HLSL, sets one less than the base.
[[option-fsampler-binding-base]]
==== `-fsampler-binding-base`
Option `-fsampler-binding-base [stage] base` sets the lowest automatically
assigned binding for samplers. If a stage is specified, only affects the specified
stage.
For HLSL, sets one less than the base.
[[option-ftexture-binding-base]]
==== `-ftexture-binding-base`
Option `-ftexture-binding-base [stage] base` sets the lowest automatically
assigned binding for textures. If a stage is specified, only affects the specified
stage.
For HLSL, sets one less than the base.
[[option-fubo-binding-base]]
==== `-fubo-binding-base`
Option `-fubo-binding-base [stage] base` sets the lowest automatically
assigned binding for Uniform Buffer Objects (GLSL) or Cbuffers (HLSL).
If a stage is specified, only affects the specified stage.
For HLSL, sets one less than the base.
[[option-fcbuffer-binding-base]]
==== `-fcbuffer-binding-base`
Option `-fcbuffer-binding-base [stage] base` is the same as
`-fubo-binding-base [stage] base`.
[[option-fssbo-binding-base]]
==== `-fssbo-binding-base`
Option `-fssbo-binding-base [stage] base` sets the lowest automatically
assigned binding for Shader Storage Buffer Objects (GLSL).
If a stage is specified, only affects the specified stage.
This only affects GLSL compilation.
[[option-fuav-binding-base]]
==== `-fuav-binding-base`
Option `-fuav-binding-base [stage] base` sets one less than the lowest
automatically assigned binding for Unordered Access Views (UAV).
If a stage is specified, only affects the specified stage.
This only affects HLSL compilation.
[[option-fregister-set-binding]]
==== `-fresource-set-binding`
Option `-fresource-set-binding [stage] <reg0> <set0> <binding0>` sets
the descriptor set and binding for an HLSL resource, by register name.
To specify settings for more registers, append their triples consisting
of register name, descriptor set, and binding.
Example:
----
# For a texture in register t1, use set 1 binding 0.
# For a texture in register t2, use set 1 binding 3
glslc -x hlsl foo.frag -fresource-set-binding t1 1 0 t2 1 3
----
If a stage is specified, only affects the specified stage.
----
# Same as the previous example, but the settings only apply
# to fragment (pixel) shaders.
glslc -x hlsl foo.frag -fresource-set-binding frag t1 1 0 t2 1 3
----
== Divergence from and extensions to GLSL specifications
=== Source-filename-based `#line` and `\\__FILE__`
This section describes how the glslc compiler extends the syntax for the `#line`
directive and the `\\__FILE__` macro. By default, the glslc compiler enables
the `GL_GOOGLE_cpp_style_line_directive` extension. It will generate this
extended syntax in the preprocessed output (obtained via the `-E` option).
WARNING: This section is still evolving. Expect changes.
GLSL specifications have a notion of source strings.
[quote, Section 3.2 of both version 3.30 and 4.50]
____
The source for a single shader is an array of strings of characters from the
character set. A single shader is made from the concatenation of these strings.
____
With the above notion, the second parameter to the `#line` directive should
be a constant integer expressions representing the source string number. Also
the `\\__FILE__` macro will "substitute a decimal integer constant that says
which source string number is currently being processed."
The glslc compiler implements the standard `#line` and `\\__FILE__` syntax. It
also provides an extension, `GL_GOOGLE_cpp_style_line_directive`, to allow
source filenames to be used instead of integer source string indices.
Specifically, the `#line` directive can have, after macro substitution, one of
the following three forms:
[source,glsl]
----
#line line-number
#line line-number integer-source-string-index
#line line-number "source-filename"
----
where `source-filename` can be any combinations of characters except double
quotation marks. (Note that according to the GLSL specification, "there are
no escape sequences or other uses of the backslash beyond use as the
line-continuation character".)
And if source-filename-based `#line` is used, the `\\__FILE__` macro expands to
a string whose contents are the filename quoted with double quotation marks.
The filename is dertermined as the last of
* The filename given to the glslc compiler,
* The filename argument of the most recent `#line` directive, if any.
[[include-directive]]
=== `#include`
The glslc compiler extends GLSL with the include syntax by turning on the
`GL_GOOGLE_include_directive` extension. It will preprocess and substitute
`#include` directives properly with the following behaviors.
WARNING: This section is still evolving. Expect changes.
If `#include` directives are used in a shader, there will be an `#extension
GL_GOOGLE_include_directive : enable` line generated into the preprocessed
output.
The `GL_GOOGLE_cpp_style_line_directive` extension is implicitly turned on by
the `GL_GOOGLE_include_directive` extension.
The file argument to `#include` must be enclosed in double quotes. It must be a
relative path, using whatever path separator the OS supports. However, the last
path element -- the name of the file itself -- must not contain either '/' or
'\', regardless of which path separator is used. This will not be flagged as an
error but will instead trigger undefined behavior. For example, let's say there
is a file named `f\ilename.vert` on a Unix OS. It is not possible to craft a
`#include` that includes that file.
Furthermore, it is not possible to escape any characters in a `#include`
directive, so the file argument cannot contain any special characters that need
escaping in C.
The file argument is a relative path that is matched first against the including
file's own directory and then against all `-I` arguments in order of their
appearance on the command line. If the file cannot be found, `glslc` aborts
with an error.

View File

@@ -0,0 +1,104 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dependency_info.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include "file.h"
#include "libshaderc_util/io_shaderc.h"
namespace glslc {
DependencyInfoDumpingHandler::DependencyInfoDumpingHandler() : mode_(not_set) {}
bool DependencyInfoDumpingHandler::DumpDependencyInfo(
std::string compilation_output_file_name, std::string source_file_name,
std::string* compilation_output_ptr,
const std::unordered_set<std::string>& dependent_files) {
std::string dep_target_label = GetTarget(compilation_output_file_name);
std::string dep_file_name =
GetDependencyFileName(compilation_output_file_name);
// Dump everything to a string stream first, then dump its content to either
// a file or compilation output string, depends on current dumping mode.
std::stringstream dep_string_stream;
// dump target label and the source_file_name.
dep_string_stream << dep_target_label << ": " << source_file_name;
// dump the dependent file names.
for (auto& dependent_file_name : dependent_files) {
dep_string_stream << " " << dependent_file_name;
}
dep_string_stream << std::endl;
if (mode_ == dump_as_compilation_output) {
compilation_output_ptr->assign(dep_string_stream.str());
} else if (mode_ == dump_as_extra_file) {
std::ofstream potential_file_stream_for_dep_info_dump;
std::ostream* dep_file_stream = shaderc_util::GetOutputStream(
dep_file_name, &potential_file_stream_for_dep_info_dump, &std::cerr);
*dep_file_stream << dep_string_stream.str();
if (dep_file_stream->fail()) {
std::cerr << "glslc: error: error writing dependent_files info to output "
"file: '"
<< dep_file_name << "'" << std::endl;
return false;
}
} else {
// mode_ should not be 'not_set', we should never be here.
return false;
}
return true;
}
std::string DependencyInfoDumpingHandler::GetTarget(
const std::string& compilation_output_file_name) {
if (!user_specified_dep_target_label_.empty()) {
return user_specified_dep_target_label_;
}
return compilation_output_file_name;
}
std::string DependencyInfoDumpingHandler::GetDependencyFileName(
const std::string& compilation_output_file_name) {
if (!user_specified_dep_file_name_.empty()) {
return user_specified_dep_file_name_;
}
return compilation_output_file_name + ".d";
}
bool DependencyInfoDumpingHandler::IsValid(std::string* error_msg_ptr,
size_t num_files) {
if (DumpingModeNotSet()) {
*error_msg_ptr =
"to generate dependencies you must specify either -M (-MM) or -MD";
return false;
}
if (!user_specified_dep_file_name_.empty() ||
!user_specified_dep_target_label_.empty()) {
if (num_files > 1) {
*error_msg_ptr =
"to specify dependency info file name or dependency info target, "
"only one input file is allowed.";
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,136 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GLSLC_DEPENDENCY_INFO_H
#define GLSLC_DEPENDENCY_INFO_H
#include <unordered_set>
#include <string>
#include <string>
namespace glslc {
// An object to handle everything about dumping dependency info. Internally it
// has two valid dumping mode: 1) Dump to extra dependency info files, such as
// *.d files. This mode is used when we want to generate dependency info and
// also compile. 2) Overwrite the original compilation output and dump
// dependency info as compilation output. This mode is used when we do not want
// to compile the source code and want the dependency info only.
class DependencyInfoDumpingHandler {
public:
DependencyInfoDumpingHandler();
// Sets the dependency target explicitly. It's the same as the argument to
// -MT.
void SetTarget(const std::string& target_label) {
user_specified_dep_target_label_ = target_label;
}
// Sets the name of the file where dependency info will be written.
void SetDependencyFileName(const std::string& dep_file_name) {
user_specified_dep_file_name_ = dep_file_name;
}
// Dump depdendency info to a) an extra dependency info file, b) an string
// which holds the compilation output. The choice depends on the dump
// mode of the handler. Returns true if dumping is succeeded, false otherwise.
//
// The dependency file name and target are deduced based on 1) user
// specified dependency file name and target name, 2) the output filename when
// the compiler is in 'does not need linking' and 'not preprocessing-only'
// mode. It is passed through compilation_output_file_name.
//
// When the handler is set to dump dependency info as extra dependency info
// files, this method will open a file with the dependency file name and write
// the dependency info to it. Error messages caused by writing to the file are
// emitted to stderr.
//
// When the handler is set to dump dependency info as compilation output, the
// compilation output string, which is passed through compilation_output_ptr,
// will be cleared and this method will write dependency info to it. Then the
// dependency info should be emitted as normal compilation output.
//
// If the dump mode is not set when this method is called, return false.
bool DumpDependencyInfo(std::string compilation_output_file_name,
std::string source_file_name,
std::string* compilation_output_ptr,
const std::unordered_set<std::string>& dependent_files);
// Sets to always dump dependency info as an extra file, instead of the normal
// compilation output. This means the output name specified by -o options
// won't be used for the dependency info file.
void SetDumpToExtraDependencyInfoFiles() { mode_ = dump_as_extra_file; }
// Sets to dump dependency info as normal compilation output. The dependency
// info will be either saved in a file with -o option specified file, or, if
// no output file name specified, to stdout.
void SetDumpAsNormalCompilationOutput() {
mode_ = dump_as_compilation_output;
}
// Returns true if the handler's dumping mode is set to dump dependency info
// as extra dependency info files.
bool DumpingToExtraDependencyInfoFiles() {
return mode_ == dump_as_extra_file;
}
// Returns true if the handler's dumping mode is set to dump dependency info
// as normal compilation output.
bool DumpingAsCompilationOutput() {
return mode_ == dump_as_compilation_output;
}
// Returns true if the handler's dumping mode is not set.
bool DumpingModeNotSet() { return mode_ == not_set; }
// Returns true if the handler is at valid state for dumping dependency info.
bool IsValid(std::string* error_msg_ptr, size_t num_files);
private:
typedef enum {
// not_set mode tells that the dumping mode is not set yet, so the handler
// is not ready for dumping dependency info. Calling DumpDependencyInfo when
// the handler is in this mode will cause failure.
not_set = 0,
// Dumping dependency info as normal compilation output mode. In this mode,
// the dependency info will be dumped as compilation output by overwriting
// the string which holds the compilation output.
dump_as_compilation_output,
// Dumping dependency info as extra dependency info files mode. In this
// mode, dependency info will be dumped to a user specified dependency info
// file or a *.d file. Compilation output will still be generated along with
// the dependency info.
dump_as_extra_file,
} dump_mode;
// Returns the target file label to be used in depdendency info file. If -MT
// defined a label, use that string as the label. Otherwise returns the
// compilation output filename deduced in 'doesn't need linking' and 'not
// preprocessing-only' mode.
std::string GetTarget(const std::string& compilation_output_file_name);
// Returns the dependency file name to be used. If -MF defined a file name
// before, use it. Othwise, returns a filename formed by appending .d to the
// output filename deduced in 'doesn't need linking' and 'no
// preprocessing-only' mode.
std::string GetDependencyFileName(
const std::string& compilation_output_file_name);
std::string user_specified_dep_file_name_;
std::string user_specified_dep_target_label_;
dump_mode mode_;
};
}
#endif // GLSLC_DEPENDENCY_INFO_H

26
3rdparty/shaderc/glslc/src/file.cc vendored Normal file
View File

@@ -0,0 +1,26 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "file.h"
namespace glslc {
shaderc_util::string_piece GetFileExtension(
const shaderc_util::string_piece& filename) {
size_t dot_pos = filename.find_last_of(".");
if (dot_pos == shaderc_util::string_piece::npos) return "";
return filename.substr(dot_pos + 1);
}
} // namespace glslc

46
3rdparty/shaderc/glslc/src/file.h vendored Normal file
View File

@@ -0,0 +1,46 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GLSLC_FILE_H_
#define GLSLC_FILE_H_
#include "libshaderc_util/string_piece.h"
namespace glslc {
// Given a file name, returns its extension. If no extension exists,
// returns an empty string_piece.
shaderc_util::string_piece GetFileExtension(
const shaderc_util::string_piece& filename);
// Returns true if the given file name ends with a known shader file extension.
inline bool IsStageFile(const shaderc_util::string_piece& filename) {
const shaderc_util::string_piece extension =
glslc::GetFileExtension(filename);
return extension == "vert" || extension == "frag" || extension == "tesc" ||
extension == "tese" || extension == "geom" || extension == "comp";
}
// 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
#endif // GLSLC_FILE_H_

View File

@@ -0,0 +1,435 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "file_compiler.h"
#include <cassert>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
#include "tint/tint.h"
#endif // SHADERC_ENABLE_WGSL_OUTPUT==1
#include "file.h"
#include "file_includer.h"
#include "shader_stage.h"
#include "libshaderc_util/io_shaderc.h"
#include "libshaderc_util/message.h"
namespace {
using shaderc_util::string_piece;
// A helper function to emit SPIR-V binary code as a list of hex numbers in
// text form. Returns true if a non-empty compilation result is emitted
// successfully. Return false if nothing should be emitted, either because the
// compilation result is empty, or the compilation output is not SPIR-V binary
// code.
template <typename CompilationResultType>
bool EmitSpirvBinaryAsCommaSeparatedNumbers(const CompilationResultType& result,
std::ostream* out) {
// Return early if the compilation output is not in SPIR-V binary code form.
if (!std::is_same<CompilationResultType,
shaderc::SpvCompilationResult>::value)
return false;
// Return early if the compilation result is empty.
if (result.cbegin() == result.cend()) return false;
std::ios::fmtflags output_stream_flag_cache(out->flags());
*out << std::hex << std::setfill('0');
auto RI = result.cbegin();
*out << "0x" << std::setw(8) << *RI++;
for (size_t counter = 1; RI != result.cend(); RI++, counter++) {
*out << ",";
// Break line for every four words.
if (counter % 4 == 0) {
*out << std::endl;
}
*out << "0x" << std::setw(8) << *RI;
}
out->flags(output_stream_flag_cache);
return true;
}
} // anonymous namespace
namespace glslc {
bool FileCompiler::CompileShaderFile(const InputFileSpec& input_file) {
std::vector<char> input_data;
std::string path = input_file.name;
if (!shaderc_util::ReadFile(path, &input_data)) {
return false;
}
std::string output_file_name = GetOutputFileName(input_file.name);
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>.
error_file_name = "<stdin>";
}
string_piece source_string = "";
if (!input_data.empty()) {
source_string = {&input_data.front(),
&input_data.front() + input_data.size()};
}
std::unique_ptr<FileIncluder> includer(
new FileIncluder(&include_file_finder_));
// Get a reference to the dependency trace before we pass the ownership to
// shaderc::CompileOptions.
const auto& used_source_files = includer->file_path_trace();
options_.SetIncluder(std::move(includer));
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.name, output_file_name,
error_file_name, used_source_files);
} else {
return true;
}
}
// 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(input_file.language);
switch (output_type_) {
case OutputType::SpirvBinary: {
const auto result = compiler_.CompileGlslToSpv(
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, output_file_name,
error_file_name, used_source_files);
}
case OutputType::SpirvAssemblyText: {
const auto result = compiler_.CompileGlslToSpvAssembly(
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, output_file_name,
error_file_name, used_source_files);
}
case OutputType::PreprocessedText: {
const auto result = compiler_.PreprocessGlsl(
source_string.data(), source_string.size(), input_file.stage,
error_file_name.data(), options_);
return EmitCompiledResult(result, input_file.name, output_file_name,
error_file_name, used_source_files);
}
}
return false;
}
template <typename CompilationResultType>
bool FileCompiler::EmitCompiledResult(
const CompilationResultType& result, const std::string& input_file,
const std::string& output_file_name, string_piece error_file_name,
const std::unordered_set<std::string>& used_source_files) {
total_errors_ += result.GetNumErrors();
total_warnings_ += result.GetNumWarnings();
bool compilation_success =
result.GetCompilationStatus() == shaderc_compilation_status_success;
// Handle the error message for failing to deduce the shader kind.
if (result.GetCompilationStatus() ==
shaderc_compilation_status_invalid_stage) {
auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name);
if (glsl_or_hlsl_extension != "") {
std::cerr << "glslc: error: "
<< "'" << error_file_name << "': "
<< "." << glsl_or_hlsl_extension
<< " file encountered but no -fshader-stage specified ahead";
} else if (error_file_name == "<stdin>") {
std::cerr
<< "glslc: error: '-': -fshader-stage required when input is from "
"standard "
"input \"-\"";
} else {
std::cerr << "glslc: error: "
<< "'" << error_file_name << "': "
<< "file not recognized: File format not recognized";
}
std::cerr << "\n";
return false;
}
// Get a string_piece which refers to the normal compilation output for now.
// This string_piece might be redirected to the dependency info to be dumped
// later, if the handler is instantiated to dump as normal compilation output,
// and the original compilation output should be blocked. Otherwise it won't
// be touched. The main output stream dumps this string_piece later.
string_piece compilation_output(
reinterpret_cast<const char*>(result.cbegin()),
reinterpret_cast<const char*>(result.cend()));
// If we have dependency info dumping handler instantiated, we should dump
// dependency info first. This may redirect the compilation output
// string_piece to dependency info.
std::string potential_dependency_info_output;
if (dependency_info_dumping_handler_) {
if (!dependency_info_dumping_handler_->DumpDependencyInfo(
GetCandidateOutputFileName(input_file), error_file_name.data(),
&potential_dependency_info_output, used_source_files)) {
return false;
}
if (!potential_dependency_info_output.empty()) {
// If the potential_dependency_info_output string is not empty, it means
// we should dump dependency info as normal compilation output. Redirect
// the compilation output string_piece to the dependency info stored in
// potential_dependency_info_output to make it happen.
compilation_output = potential_dependency_info_output;
}
}
std::ostream* out = nullptr;
std::ofstream potential_file_stream;
if (compilation_success) {
out = shaderc_util::GetOutputStream(output_file_name,
&potential_file_stream, &std::cerr);
if (!out || out->fail()) {
// An error message has already been emitted to the stderr stream.
return false;
}
// Write compilation output to output file. If an output format for SPIR-V
// binary code is specified, it is handled here.
switch (binary_emission_format_) {
case SpirvBinaryEmissionFormat::Unspecified:
case SpirvBinaryEmissionFormat::Binary:
// The output format is unspecified or specified as binary output.
// On Windows, the output stream must be set to binary mode. By
// default the standard output stream is set to text mode, which
// translates newlines (\n) to carriage-return newline pairs
// (\r\n).
if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout();
out->write(compilation_output.data(), compilation_output.size());
if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout();
break;
case SpirvBinaryEmissionFormat::Numbers:
// The output format is specified to be a list of hex numbers, the
// compilation output must be in SPIR-V binary code form.
assert(output_type_ == OutputType::SpirvBinary);
if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
// Only emits the end-of-line character when the emitted compilation
// result is not empty.
*out << std::endl;
}
break;
case SpirvBinaryEmissionFormat::CInitList:
// The output format is specified to be a C-style initializer list, the
// compilation output must be in SPIR-V binary code form.
assert(output_type_ == OutputType::SpirvBinary);
if (result.begin() != result.end()) {
// Only emits the '{' when the compilation result is not empty.
*out << "{";
}
if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
// Only emits the end-of-line character when the emitted compilation
// result is not empty.
*out << "}" << std::endl;
}
break;
case SpirvBinaryEmissionFormat::WGSL: {
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
tint::Context ctx;
tint::reader::spirv::Parser spv_reader(
&ctx, std::vector<uint32_t>(result.begin(), result.end()));
if (!spv_reader.Parse()) {
std::cout << "error: failed to convert SPIR-V binary to WGSL: "
<< spv_reader.error() << std::endl;
return false;
}
tint::writer::wgsl::Generator wgsl_writer(spv_reader.module());
if (!wgsl_writer.Generate()) {
std::cout << "error: failed to convert to WGSL: "
<< wgsl_writer.error() << std::endl;
return false;
}
*out << wgsl_writer.result();
#endif // SHADERC_ENABLE_WGSL_OUTPUT==1
break;
}
}
}
// Write error message to std::cerr.
std::cerr << result.GetErrorMessage();
if (out && out->fail()) {
// Something wrong happened on output.
if (out == &std::cout) {
std::cerr << "glslc: error: error writing to standard output"
<< std::endl;
} else {
std::cerr << "glslc: error: error writing to output file: '"
<< output_file_name_ << "'" << std::endl;
}
return false;
}
return compilation_success;
}
void FileCompiler::AddIncludeDirectory(const std::string& path) {
include_file_finder_.search_path().push_back(path);
}
void FileCompiler::SetIndividualCompilationFlag() {
if (output_type_ != OutputType::SpirvAssemblyText) {
needs_linking_ = false;
file_extension_ = ".spv";
}
}
void FileCompiler::SetDisassemblyFlag() {
if (!PreprocessingOnly()) {
output_type_ = OutputType::SpirvAssemblyText;
needs_linking_ = false;
file_extension_ = ".spvasm";
}
}
void FileCompiler::SetPreprocessingOnlyFlag() {
output_type_ = OutputType::PreprocessedText;
needs_linking_ = false;
if (output_file_name_.empty()) {
output_file_name_ = "-";
}
}
bool FileCompiler::ValidateOptions(size_t num_files) {
if (num_files == 0) {
std::cerr << "glslc: error: no input files" << std::endl;
return false;
}
if (num_files > 1 && needs_linking_) {
std::cerr << "glslc: error: linking multiple files is not supported yet. "
"Use -c to compile files individually."
<< std::endl;
return false;
}
// If we are outputting many object files, we cannot specify -o. Also
// if we are preprocessing multiple files they must be to stdout.
if (num_files > 1 && ((!PreprocessingOnly() && !needs_linking_ &&
!output_file_name_.empty()) ||
(PreprocessingOnly() && output_file_name_ != "-"))) {
std::cerr << "glslc: error: cannot specify -o when generating multiple"
" output files"
<< std::endl;
return false;
}
// If we have dependency info dumping handler instantiated, we should check
// its validity.
if (dependency_info_dumping_handler_) {
std::string dependency_info_dumping_hander_error_msg;
if (!dependency_info_dumping_handler_->IsValid(
&dependency_info_dumping_hander_error_msg, num_files)) {
std::cerr << "glslc: error: " << dependency_info_dumping_hander_error_msg
<< std::endl;
return false;
}
}
// If the output format is specified to be a binary, a list of hex numbers or
// a C-style initializer list, the output must be in SPIR-V binary code form.
if (binary_emission_format_ != SpirvBinaryEmissionFormat::Unspecified) {
if (output_type_ != OutputType::SpirvBinary) {
std::cerr << "glslc: error: cannot emit output as a ";
switch (binary_emission_format_) {
case SpirvBinaryEmissionFormat::Binary:
std::cerr << "binary";
break;
case SpirvBinaryEmissionFormat::Numbers:
std::cerr << "list of hex numbers";
break;
case SpirvBinaryEmissionFormat::CInitList:
std::cerr << "C-style initializer list";
break;
case SpirvBinaryEmissionFormat::WGSL:
std::cerr << "WGSL source program";
break;
case SpirvBinaryEmissionFormat::Unspecified:
// The compiler should never be here at runtime. This case is added to
// complete the switch cases.
break;
}
std::cerr << " when only preprocessing the source" << std::endl;
return false;
}
if (dependency_info_dumping_handler_ &&
dependency_info_dumping_handler_->DumpingAsCompilationOutput()) {
std::cerr << "glslc: error: cannot dump dependency info when specifying "
"any binary output format"
<< std::endl;
return false;
}
}
if (binary_emission_format_ == SpirvBinaryEmissionFormat::WGSL) {
#if SHADERC_ENABLE_WGSL_OUTPUT != 1
std::cerr << "glslc: error: can't output WGSL: glslc was built without "
"WGSL output support"
<< std::endl;
return false;
#endif
}
return true;
}
void FileCompiler::OutputMessages() {
shaderc_util::OutputMessages(&std::cerr, total_warnings_, total_errors_);
}
std::string FileCompiler::GetOutputFileName(std::string input_filename) {
if (output_file_name_.empty()) {
return needs_linking_ ? std::string("a.spv")
: GetCandidateOutputFileName(input_filename);
} else {
return output_file_name_.str();
}
}
std::string FileCompiler::GetCandidateOutputFileName(
std::string input_filename) {
if (!output_file_name_.empty() && !PreprocessingOnly()) {
return output_file_name_.str();
}
std::string extension = file_extension_;
if (PreprocessingOnly() || needs_linking_) {
extension = ".spv";
}
std::string candidate_output_file_name =
IsStageFile(input_filename)
? shaderc_util::GetBaseFileName(input_filename) + extension
: shaderc_util::GetBaseFileName(
input_filename.substr(0, input_filename.find_last_of('.')) +
extension);
return candidate_output_file_name;
}
} // namesapce glslc

View File

@@ -0,0 +1,234 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GLSLC_FILE_COMPILER_H
#define GLSLC_FILE_COMPILER_H
#include <string>
#include "libshaderc_util/file_finder.h"
#include "libshaderc_util/string_piece.h"
#include "shaderc/shaderc.hpp"
#include "dependency_info.h"
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 {
public:
enum class SpirvBinaryEmissionFormat {
Unspecified, // No binary output format specified, this is the only valid
// option when the compilation output is not in SPIR-V binary
// code form.
Binary, // Emits SPIR-V binary code directly.
Numbers, // Emits SPIR-V binary code as a list of hex numbers.
CInitList, // Emits SPIR-V binary code as a C-style initializer list
// of hex numbers.
WGSL, // Emits SPIR-V module converted to WGSL source text.
// Requires a build with Tint support.
};
FileCompiler()
: output_type_(OutputType::SpirvBinary),
binary_emission_format_(SpirvBinaryEmissionFormat::Unspecified),
needs_linking_(true),
total_warnings_(0),
total_errors_(0) {}
// 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.
//
// If version/profile has been forced, the shader's version/profile is set to
// that value regardless of the #version directive in the source code.
//
// Any errors/warnings found in the shader source will be output to std::cerr
// and increment the counts reported by OutputMessages().
bool CompileShaderFile(const InputFileSpec& input_file);
// Adds a directory to be searched when processing #include directives.
//
// Best practice: if you add an empty string before any other path, that will
// correctly resolve both absolute paths and paths relative to the current
// working directory.
void AddIncludeDirectory(const std::string& path);
// Sets the output filename. A name of "-" indicates standard output.
void SetOutputFileName(const shaderc_util::string_piece& file) {
output_file_name_ = file;
}
// Sets the format for SPIR-V binary compilation output.
void SetSpirvBinaryOutputFormat(SpirvBinaryEmissionFormat format) {
binary_emission_format_ = format;
}
// Returns false if any options are incompatible. The num_files parameter
// represents the number of files that will be compiled.
bool ValidateOptions(size_t num_files);
// Outputs to std::cerr the number of warnings and errors if there are any.
void OutputMessages();
// Sets the flag to indicate individual compilation mode. In this mode, all
// files are compiled individually and written to separate output files
// instead of linked together. This method also disables linking and sets the
// output file extension to ".spv". Disassembly mode and preprocessing only
// mode override this mode and flags.
void SetIndividualCompilationFlag();
// Sets the flag to indicate disassembly mode. In this mode, the compiler
// emits disassembled textual output, instead of outputting object files.
// This method also sets the output file extension to ".spvasm" and disables
// linking. This mode overrides individual compilation mode, and preprocessing
// only mode overrides this mode.
void SetDisassemblyFlag();
// Sets the flag to indicate preprocessing only mode. In this mode, instead of
// outputting object files, the compiler emits the preprocessed source files.
// This method disables linking and sets the output file to stdout. This mode
// overrides disassembly mode and individual compilation mode.
void SetPreprocessingOnlyFlag();
// Gets the reference of the compiler options which reflects the command-line
// arguments.
shaderc::CompileOptions& options() { return options_; }
// Gets a pointer which points to the dependency info dumping hander. Creates
// such a handler if such one does not exist.
DependencyInfoDumpingHandler* GetDependencyDumpingHandler() {
if (!dependency_info_dumping_handler_) {
dependency_info_dumping_handler_.reset(
new DependencyInfoDumpingHandler());
}
return dependency_info_dumping_handler_.get();
}
private:
enum class OutputType {
SpirvBinary, // A binary module, as defined by the SPIR-V specification.
SpirvAssemblyText, // Assembly syntax defined by the SPIRV-Tools project.
PreprocessedText, // Preprocessed source code.
};
// Emits the compilation output from the given result to the given output
// file and returns true if the result represents a successful compilation
// step. Otherwise returns false, possibly emits messages to the standard
// error stream, and does not produce an output file. Accumulates error
// and warning counts for use by the OutputMessages() method.
template <typename CompilationResultType>
bool EmitCompiledResult(
const CompilationResultType& result, const std::string& input_file_name,
const std::string& output_file_name,
shaderc_util::string_piece error_file_name,
const std::unordered_set<std::string>& used_source_files);
// Returns the final file name to be used for the output file.
//
// If an output file name is specified by the SetOutputFileName(), use that
// argument as the final output file name.
//
// If the user did not specify an output filename:
// If linking is not required, and the input filename has a
// standard stage extension (e.g. .vert) then returns the input filename
// without directory names but with the result extenstion (e.g. .spv or
// .spvasm) appended.
//
// If linking is not required, and the input file name does not have a
// standard stage extension, then also returns the directory-stripped input
// filename, but replaces its extension with the result extension. (If the
// resolved input filename does not have an extension, then appends the
// result extension.)
//
// If linking is required and output filename is not specified, returns
// "a.spv".
std::string GetOutputFileName(std::string input_filename);
// Returns the candidate output file name deduced from input file name and
// user specified output file name. It is computed as follows:
//
// If the user did specify an output filename and the compiler is not in
// preprocessing-only mode, then returns that file name.
//
// If the user did not specify an output filename:
// If the input filename has a standard stage extension (e.g. .vert) then
// returns the input filename without directory names but with the result
// extenstion (e.g. .spv or .spvasm) appended.
//
// If the input file name does not have a standard stage extension, then also
// returns the directory-stripped input filename, but replaces its extension
// with the result extension. (If the resolved input filename does not have
// an extension, then appends the result extension.)
//
// When a resolved extension is not available because the compiler is in
// preprocessing-only mode or the compilation requires linking, use .spv as
// the extension.
std::string GetCandidateOutputFileName(std::string input_filename);
// Returns true if the compiler's output is preprocessed text.
bool PreprocessingOnly() {
return output_type_ == OutputType::PreprocessedText;
}
// Performs actual SPIR-V compilation on the contents of input files.
shaderc::Compiler compiler_;
// Reflects the command-line arguments and goes into
// compiler_.CompileGlslToSpv().
shaderc::CompileOptions options_;
// What kind of output will be produced?
OutputType output_type_;
// The Flag to indicate to which format the output SPIR-V binary code should
// be emitted.
SpirvBinaryEmissionFormat binary_emission_format_;
// A FileFinder used to substitute #include directives in the source code.
shaderc_util::FileFinder include_file_finder_;
// Indicates whether linking is needed to generate the final output.
bool needs_linking_;
// The ownership of dependency dumping handler.
std::unique_ptr<DependencyInfoDumpingHandler>
dependency_info_dumping_handler_ = nullptr;
// Reflects the type of file being generated.
std::string file_extension_;
// Name of the file where the compilation output will go.
shaderc_util::string_piece output_file_name_;
// Counts warnings encountered in all compilations via this object.
size_t total_warnings_;
// Counts errors encountered in all compilations via this object.
size_t total_errors_;
};
} // namespace glslc
#endif // GLSLC_FILE_COMPILER_H

View File

@@ -0,0 +1,66 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "file_includer.h"
#include <mutex>
#include <utility>
#include "libshaderc_util/io_shaderc.h"
namespace glslc {
shaderc_include_result* MakeErrorIncludeResult(const char* message) {
return new shaderc_include_result{"", 0, message, strlen(message)};
}
FileIncluder::~FileIncluder() = default;
shaderc_include_result* FileIncluder::GetInclude(
const char* requested_source, shaderc_include_type include_type,
const char* requesting_source, size_t) {
const std::string full_path =
(include_type == shaderc_include_type_relative)
? file_finder_.FindRelativeReadableFilepath(requesting_source,
requested_source)
: file_finder_.FindReadableFilepath(requested_source);
if (full_path.empty())
return MakeErrorIncludeResult("Cannot find or open include file.");
// In principle, several threads could be resolving includes at the same
// time. Protect the included_files.
// Read the file and save its full path and contents into stable addresses.
FileInfo* new_file_info = new FileInfo{full_path, {}};
if (!shaderc_util::ReadFile(full_path, &(new_file_info->contents))) {
return MakeErrorIncludeResult("Cannot read file");
}
included_files_.insert(full_path);
return new shaderc_include_result{
new_file_info->full_path.data(), new_file_info->full_path.length(),
new_file_info->contents.data(), new_file_info->contents.size(),
new_file_info};
}
void FileIncluder::ReleaseInclude(shaderc_include_result* include_result) {
FileInfo* info = static_cast<FileInfo*>(include_result->user_data);
delete info;
delete include_result;
}
} // namespace glslc

View File

@@ -0,0 +1,74 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GLSLC_FILE_INCLUDER_H_
#define GLSLC_FILE_INCLUDER_H_
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <unordered_set>
#include "libshaderc_util/file_finder.h"
#include "shaderc/shaderc.hpp"
namespace glslc {
// An includer for files implementing shaderc's includer interface. It responds
// to the file including query from the compiler with the full path and content
// of the file to be included. In the case that the file is not found or cannot
// be opened, the full path field of in the response will point to an empty
// string, and error message will be passed to the content field.
// This class provides the basic thread-safety guarantee.
class FileIncluder : public shaderc::CompileOptions::IncluderInterface {
public:
explicit FileIncluder(const shaderc_util::FileFinder* file_finder)
: file_finder_(*file_finder) {}
~FileIncluder() override;
// Resolves a requested source file of a given type from a requesting
// source into a shaderc_include_result whose contents will remain valid
// until it's released.
shaderc_include_result* GetInclude(const char* requested_source,
shaderc_include_type type,
const char* requesting_source,
size_t include_depth) override;
// Releases an include result.
void ReleaseInclude(shaderc_include_result* include_result) override;
// Returns a reference to the member storing the set of included files.
const std::unordered_set<std::string>& file_path_trace() const {
return included_files_;
}
private:
// Used by GetInclude() to get the full filepath.
const shaderc_util::FileFinder& file_finder_;
// The full path and content of a source file.
struct FileInfo {
const std::string full_path;
std::vector<char> contents;
};
// The set of full paths of included files.
std::unordered_set<std::string> included_files_;
};
} // namespace glslc
#endif // GLSLC_FILE_INCLUDER_H_

96
3rdparty/shaderc/glslc/src/file_test.cc vendored Normal file
View File

@@ -0,0 +1,96 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "file.h"
#include <gmock/gmock.h>
namespace {
using glslc::GetFileExtension;
using glslc::IsStageFile;
using glslc::GetGlslOrHlslExtension;
using shaderc_util::string_piece;
using testing::Eq;
class FileExtensionTest : public testing::Test {
protected:
string_piece empty = "";
string_piece dot = ".";
string_piece no_ext = "shader";
string_piece trailing_dot = "shader.";
string_piece vert_ext = "shader.vert";
string_piece frag_ext = "shader.frag";
string_piece tesc_ext = "shader.tesc";
string_piece tese_ext = "shader.tese";
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) {
EXPECT_EQ("", GetFileExtension(empty));
EXPECT_EQ("", GetFileExtension(dot));
EXPECT_EQ("", GetFileExtension(no_ext));
EXPECT_EQ("", GetFileExtension(trailing_dot));
EXPECT_EQ("vert", GetFileExtension(vert_ext));
EXPECT_EQ("frag", GetFileExtension(frag_ext));
EXPECT_EQ("tesc", GetFileExtension(tesc_ext));
EXPECT_EQ("tese", GetFileExtension(tese_ext));
EXPECT_EQ("geom", GetFileExtension(geom_ext));
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, 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) {
EXPECT_FALSE(IsStageFile(empty));
EXPECT_FALSE(IsStageFile(dot));
EXPECT_FALSE(IsStageFile(no_ext));
EXPECT_FALSE(IsStageFile(trailing_dot));
EXPECT_TRUE(IsStageFile(vert_ext));
EXPECT_TRUE(IsStageFile(frag_ext));
EXPECT_TRUE(IsStageFile(tesc_ext));
EXPECT_TRUE(IsStageFile(tese_ext));
EXPECT_TRUE(IsStageFile(geom_ext));
EXPECT_TRUE(IsStageFile(comp_ext));
EXPECT_FALSE(IsStageFile(glsl_ext));
EXPECT_FALSE(IsStageFile(multi_dot));
}
} // anonymous namespace

695
3rdparty/shaderc/glslc/src/main.cc vendored Normal file
View File

@@ -0,0 +1,695 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cassert>
#include <cctype>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <list>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include "file.h"
#include "file_compiler.h"
#include "libshaderc_util/args.h"
#include "libshaderc_util/compiler.h"
#include "libshaderc_util/io_shaderc.h"
#include "libshaderc_util/string_piece.h"
#include "resource_parse.h"
#include "shader_stage.h"
#include "shaderc/env.h"
#include "shaderc/shaderc.h"
#include "spirv-tools/libspirv.h"
using shaderc_util::string_piece;
namespace {
// Prints the help message.
void PrintHelp(std::ostream* out) {
*out << R"(glslc - Compile shaders into SPIR-V
Usage: glslc [options] file...
An input file of - represents standard input.
Options:
-c Only run preprocess, compile, and assemble steps.
-Dmacro[=defn] Add an implicit macro definition.
-E Outputs only the results of the preprocessing step.
Output defaults to standard output.
-fauto-bind-uniforms
Automatically assign bindings to uniform variables that
don't have an explicit 'binding' layout in the shader
source.
-fauto-map-locations
Automatically assign locations to uniform variables that
don't have an explicit 'location' layout in the shader
source.
-fauto-combined-image-sampler
Removes sampler variables and converts existing textures
to combined image-samplers.
-fentry-point=<name>
Specify the entry point name for HLSL compilation, for
all subsequent source files. Default is "main".
-fhlsl-16bit-types
Enable 16-bit type support for HLSL.
-fhlsl_functionality1, -fhlsl-functionality1
Enable extension SPV_GOOGLE_hlsl_functionality1 for HLSL
compilation.
-fhlsl-iomap Use HLSL IO mappings for bindings.
-fhlsl-offsets Use HLSL offset rules for packing members of blocks.
Affects only GLSL. HLSL rules are always used for HLSL.
-finvert-y Invert position.Y output in vertex shader.
-flimit=<settings>
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.
-flimit-file <file>
Set limits as specified in the given file.
-fnan-clamp Generate code for max and min builtins so that, when given
a NaN operand, the other operand is returned. Similarly,
the clamp builtin will favour the non-NaN operands, as if
clamp were implemented as a composition of max and min.
-fpreserve-bindings
Preserve all binding declarations, even if those bindings
are not used.
-fresource-set-binding [stage] <reg0> <set0> <binding0>
[<reg1> <set1> <binding1>...]
Explicitly sets the descriptor set and binding for
HLSL resources, by register name. Optionally restrict
it to a single stage.
-fcbuffer-binding-base [stage] <value>
Same as -fubo-binding-base.
-fimage-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
images. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fsampler-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
samplers Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fssbo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
shader storage buffer objects (SSBO). Optionally only set
it for a single shader stage. Only affects GLSL.
-ftexture-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
textures. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fuav-binding-base [stage] <value>
For automatically assigned bindings for unordered access
views (UAV), the register number is added to this base to
determine the binding number. Optionally only set it for
a single shader stage. Only affects HLSL.
-fubo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
uniform buffer objects (UBO). Optionally only set it for
a single shader stage.
For HLSL, the resource register number is added to this
base.
-fshader-stage=<stage>
Treat subsequent input files as having stage <stage>.
Valid stages are vertex, vert, fragment, frag, tesscontrol,
tesc, tesseval, tese, geometry, geom, compute, and comp.
-g Generate source-level debug information.
-h Display available options.
--help Display available options.
-I <value> Add directory to include search path.
-mfmt=<format> 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 are:
bin - SPIR-V binary words. This is the default.
c - Binary words as C initializer list of 32-bit ints
num - List of comma-separated 32-bit hex integers
-M Generate make dependencies. Implies -E and -w.
-MM An alias for -M.
-MD Generate make dependencies and compile.
-MF <file> Write dependency output to the given file.
-MT <target> Specify the target of the rule emitted by dependency
generation.
-O Optimize the generated SPIR-V code for better performance.
-Os Optimize the generated SPIR-V code for smaller size.
-O0 Disable optimization.
-o <file> Write output to <file>.
A file name of '-' represents standard output.
-std=<value> Version and profile for GLSL input files. Possible values
are concatenations of version and profile, e.g. 310es,
450core, etc. Ignored for HLSL files.
-S Emit SPIR-V assembly instead of binary.
--show-limits Display available limit names and their default values.
--target-env=<environment>
Set the target client environment, and the semantics
of warnings and errors. An optional suffix can specify
the client version. Values are:
vulkan1.0 # The default
vulkan1.1
vulkan1.2
vulkan1.3
vulkan # Same as vulkan1.0
opengl4.5
opengl # Same as opengl4.5
--target-spv=<spirv-version>
Set the SPIR-V version to be used for the generated SPIR-V
module. The default is the highest version of SPIR-V
required to be supported for the target environment.
For example, default for vulkan1.0 is spv1.0, and
the default for vulkan1.1 is spv1.3,
the default for vulkan1.2 is spv1.5.
the default for vulkan1.3 is spv1.6.
Values are:
spv1.0, spv1.1, spv1.2, spv1.3, spv1.4, spv1.5, spv1.6
--version Display compiler version information.
-w Suppresses all warning messages.
-Werror Treat all warnings as errors.
-x <language> Treat subsequent input files as having type <language>.
Valid languages are: glsl, hlsl.
For files ending in .hlsl the default is hlsl.
Otherwise the default is glsl.
)";
}
// 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<glslc::ResourceSetting> 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"
;
// Gets an optional stage name followed by required offset argument. Returns
// false and emits a message to *errs if any errors occur. After calling this
// function, *index will be the index of the last command line argument
// consumed. If no stage name is provided, then *stage contains
// shaderc_glsl_infer_from_source.
bool GetOptionalStageThenOffsetArgument(const shaderc_util::string_piece option,
std::ostream* errs, int argc,
char** argv, int* index,
shaderc_shader_kind* shader_kind,
uint32_t* offset) {
int& argi = *index;
if (argi + 1 >= argc) {
*errs << "glslc: error: Option " << option
<< " requires at least one argument" << std::endl;
return false;
}
auto stage = glslc::MapStageNameToForcedKind(argv[argi + 1]);
if (stage != shaderc_glsl_infer_from_source) {
++argi;
if (argi + 1 >= argc) {
*errs << "glslc: error: Option " << option << " with stage "
<< argv[argi - 1] << " requires an offset argument" << std::endl;
return false;
}
}
if (!shaderc_util::ParseUint32(argv[argi + 1], offset)) {
*errs << "glslc: error: invalid offset value " << argv[argi + 1] << " for "
<< option << std::endl;
return false;
}
++argi;
*shader_kind = stage;
return true;
}
} // anonymous namespace
int main(int argc, char** argv) {
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;
// Shader stage for a single option.
shaderc_shader_kind arg_stage = shaderc_glsl_infer_from_source;
// Binding base for a single option.
uint32_t arg_base = 0;
// What kind of uniform variable are we setting the binding base for?
shaderc_uniform_kind u_kind = shaderc_uniform_kind_buffer;
// Sets binding base for the given uniform kind. If stage is
// shader_glsl_infer_from_source then set it for all shader stages.
auto set_binding_base = [&compiler](
shaderc_shader_kind stage, shaderc_uniform_kind kind, uint32_t base) {
if (stage == shaderc_glsl_infer_from_source)
compiler.options().SetBindingBase(kind, base);
else
compiler.options().SetBindingBaseForStage(stage, kind, base);
};
for (int i = 1; i < argc; ++i) {
const string_piece arg = argv[i];
if (arg == "--help" || arg == "-h") {
::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_util::Compiler::Limit>( \
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)
<< std::endl;
return 0;
} else if (arg.starts_with("-o")) {
string_piece file_name;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-o", &file_name)) {
std::cerr
<< "glslc: error: argument to '-o' is missing (expected 1 value)"
<< std::endl;
return 1;
}
compiler.SetOutputFileName(file_name);
} else if (arg.starts_with("-fshader-stage=")) {
const string_piece stage = arg.substr(std::strlen("-fshader-stage="));
current_fshader_stage = glslc::GetForcedShaderKindFromCmdLine(arg);
if (current_fshader_stage == shaderc_glsl_infer_from_source) {
std::cerr << "glslc: error: stage not recognized: '" << stage << "'"
<< std::endl;
return 1;
}
} else if (arg == "-fauto-bind-uniforms") {
compiler.options().SetAutoBindUniforms(true);
} else if (arg == "-fauto-combined-image-sampler") {
compiler.options().SetAutoSampledTextures(true);
} else if (arg == "-fauto-map-locations") {
compiler.options().SetAutoMapLocations(true);
} else if (arg == "-fhlsl-iomap") {
compiler.options().SetHlslIoMapping(true);
} else if (arg == "-fhlsl-offsets") {
compiler.options().SetHlslOffsets(true);
} else if (arg == "-fhlsl_functionality1" ||
arg == "-fhlsl-functionality1") {
compiler.options().SetHlslFunctionality1(true);
} else if (arg == "-fhlsl-16bit-types") {
compiler.options().SetHlsl16BitTypes(true);
} else if (arg == "-finvert-y") {
compiler.options().SetInvertY(true);
} else if (arg == "-fnan-clamp") {
compiler.options().SetNanClamp(true);
} else if (arg.starts_with("-fpreserve-bindings")) {
compiler.options().SetPreserveBindings(true);
} else if (((u_kind = shaderc_uniform_kind_image),
(arg == "-fimage-binding-base")) ||
((u_kind = shaderc_uniform_kind_texture),
(arg == "-ftexture-binding-base")) ||
((u_kind = shaderc_uniform_kind_sampler),
(arg == "-fsampler-binding-base")) ||
((u_kind = shaderc_uniform_kind_buffer),
(arg == "-fubo-binding-base")) ||
((u_kind = shaderc_uniform_kind_buffer),
(arg == "-fcbuffer-binding-base")) ||
((u_kind = shaderc_uniform_kind_storage_buffer),
(arg == "-fssbo-binding-base")) ||
((u_kind = shaderc_uniform_kind_unordered_access_view),
(arg == "-fuav-binding-base"))) {
if (!GetOptionalStageThenOffsetArgument(arg, &std::cerr, argc, argv, &i,
&arg_stage, &arg_base))
return 1;
set_binding_base(arg_stage, u_kind, arg_base);
} else if (arg == "-fresource-set-binding") {
auto need_three_args_err = []() {
std::cerr << "glsc: error: Option -fresource-set-binding"
<< " requires at least 3 arguments" << std::endl;
return 1;
};
if (i + 1 >= argc) return need_three_args_err();
auto stage = glslc::MapStageNameToForcedKind(argv[i + 1]);
if (stage != shaderc_glsl_infer_from_source) {
++i;
}
bool seen_triple = false;
while (i + 3 < argc && argv[i + 1][0] != '-' && argv[i + 2][0] != '-' &&
argv[i + 3][0] != '-') {
seen_triple = true;
uint32_t set = 0;
if (!shaderc_util::ParseUint32(argv[i + 2], &set)) {
std::cerr << "glslc: error: Invalid set number: " << argv[i + 2]
<< std::endl;
return 1;
}
uint32_t binding = 0;
if (!shaderc_util::ParseUint32(argv[i + 3], &binding)) {
std::cerr << "glslc: error: Invalid binding number: " << argv[i + 3]
<< std::endl;
return 1;
}
if (stage == shaderc_glsl_infer_from_source) {
compiler.options().SetHlslRegisterSetAndBinding(
argv[i + 1], argv[i + 2], argv[i + 3]);
} else {
compiler.options().SetHlslRegisterSetAndBindingForStage(
stage, argv[i + 1], argv[i + 2], argv[i + 3]);
}
i += 3;
}
if (!seen_triple) return need_three_args_err();
} 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 (!shaderc_util::GetOptionArgument(argc, argv, &i, "-flimit-file",
&limits_file)) {
std::cerr << "glslc: error: argument to '-flimit-file' is missing"
<< std::endl;
return 1;
}
std::vector<char> 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;
shaderc_profile profile;
if (!shaderc_parse_version_profile(standard.begin(), &version,
&profile)) {
std::cerr << "glslc: error: invalid value '" << standard
<< "' in '-std=" << standard << "'" << std::endl;
return 1;
}
compiler.options().SetForcedVersionProfile(version, profile);
} else if (arg.starts_with("--target-env=")) {
shaderc_target_env target_env = shaderc_target_env_default;
const string_piece target_env_str =
arg.substr(std::strlen("--target-env="));
uint32_t version = 0; // Will default appropriately.
if (target_env_str == "vulkan") {
target_env = shaderc_target_env_vulkan;
} else if (target_env_str == "vulkan1.0") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_0;
} else if (target_env_str == "vulkan1.1") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_1;
} else if (target_env_str == "vulkan1.2") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_2;
} else if (target_env_str == "vulkan1.3") {
target_env = shaderc_target_env_vulkan;
version = shaderc_env_version_vulkan_1_3;
} else if (target_env_str == "opengl") {
target_env = shaderc_target_env_opengl;
} else if (target_env_str == "opengl4.5") {
target_env = shaderc_target_env_opengl;
version = shaderc_env_version_opengl_4_5;
} else if (target_env_str == "opengl_compat") {
target_env = shaderc_target_env_opengl_compat;
std::cerr << "glslc: error: opengl_compat is no longer supported"
<< std::endl;
return 1;
} else {
std::cerr << "glslc: error: invalid value '" << target_env_str
<< "' in '--target-env=" << target_env_str << "'"
<< std::endl;
return 1;
}
compiler.options().SetTargetEnvironment(target_env, version);
} else if (arg.starts_with("--target-spv=")) {
shaderc_spirv_version ver = shaderc_spirv_version_1_0;
const string_piece ver_str = arg.substr(std::strlen("--target-spv="));
if (ver_str == "spv1.0") {
ver = shaderc_spirv_version_1_0;
} else if (ver_str == "spv1.1") {
ver = shaderc_spirv_version_1_1;
} else if (ver_str == "spv1.2") {
ver = shaderc_spirv_version_1_2;
} else if (ver_str == "spv1.3") {
ver = shaderc_spirv_version_1_3;
} else if (ver_str == "spv1.4") {
ver = shaderc_spirv_version_1_4;
} else if (ver_str == "spv1.5") {
ver = shaderc_spirv_version_1_5;
} else if (ver_str == "spv1.6") {
ver = shaderc_spirv_version_1_6;
} else {
std::cerr << "glslc: error: invalid value '" << ver_str
<< "' in '--target-spv=" << ver_str << "'" << std::endl;
return 1;
}
compiler.options().SetTargetSpirv(ver);
} else if (arg.starts_with("-mfmt=")) {
const string_piece binary_output_format =
arg.substr(std::strlen("-mfmt="));
if (binary_output_format == "bin") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::Binary);
} else if (binary_output_format == "num") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::Numbers);
} else if (binary_output_format == "c") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::CInitList);
} else if (binary_output_format == "wgsl") {
compiler.SetSpirvBinaryOutputFormat(
glslc::FileCompiler::SpirvBinaryEmissionFormat::WGSL);
} else {
std::cerr << "glslc: error: invalid value '" << binary_output_format
<< "' in '-mfmt=" << binary_output_format << "'" << std::endl;
return 1;
}
} else if (arg.starts_with("-x")) {
string_piece option_arg;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-x", &option_arg)) {
std::cerr
<< "glslc: error: argument to '-x' is missing (expected 1 value)"
<< std::endl;
success = false;
} else {
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();
} else if (arg == "-E") {
compiler.SetPreprocessingOnlyFlag();
} else if (arg == "-M" || arg == "-MM") {
// -M implies -E and -w
compiler.SetPreprocessingOnlyFlag();
compiler.options().SetSuppressWarnings();
if (compiler.GetDependencyDumpingHandler()->DumpingModeNotSet()) {
compiler.GetDependencyDumpingHandler()
->SetDumpAsNormalCompilationOutput();
} else {
std::cerr << "glslc: error: both -M (or -MM) and -MD are specified. "
"Only one should be used at one time."
<< std::endl;
return 1;
}
} else if (arg == "-MD") {
if (compiler.GetDependencyDumpingHandler()->DumpingModeNotSet()) {
compiler.GetDependencyDumpingHandler()
->SetDumpToExtraDependencyInfoFiles();
} else {
std::cerr << "glslc: error: both -M (or -MM) and -MD are specified. "
"Only one should be used at one time."
<< std::endl;
return 1;
}
} else if (arg == "-MF") {
string_piece dep_file_name;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-MF",
&dep_file_name)) {
std::cerr
<< "glslc: error: missing dependency info filename after '-MF'"
<< std::endl;
return 1;
}
compiler.GetDependencyDumpingHandler()->SetDependencyFileName(
std::string(dep_file_name.data(), dep_file_name.size()));
} else if (arg == "-MT") {
string_piece dep_file_name;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-MT",
&dep_file_name)) {
std::cerr << "glslc: error: missing dependency info target after '-MT'"
<< std::endl;
return 1;
}
compiler.GetDependencyDumpingHandler()->SetTarget(
std::string(dep_file_name.data(), dep_file_name.size()));
} else if (arg == "-S") {
compiler.SetDisassemblyFlag();
} else if (arg.starts_with("-D")) {
const size_t length = arg.size();
if (length <= 2) {
std::cerr << "glslc: error: argument to '-D' is missing" << std::endl;
} else {
const string_piece argument = arg.substr(2);
// Get the exact length of the macro string.
size_t equal_sign_loc = argument.find_first_of('=');
size_t name_length = equal_sign_loc != shaderc_util::string_piece::npos
? equal_sign_loc
: argument.size();
const string_piece name_piece = argument.substr(0, name_length);
if (name_piece.starts_with("GL_")) {
std::cerr
<< "glslc: error: names beginning with 'GL_' cannot be defined: "
<< arg << std::endl;
return 1;
}
if (name_piece.find("__") != string_piece::npos) {
std::cerr
<< "glslc: warning: names containing consecutive underscores "
"are reserved: "
<< arg << std::endl;
}
const string_piece value_piece =
(equal_sign_loc == string_piece::npos ||
equal_sign_loc == argument.size() - 1)
? ""
: argument.substr(name_length + 1);
// TODO(deki): check arg for newlines.
compiler.options().AddMacroDefinition(
name_piece.data(), name_piece.size(), value_piece.data(),
value_piece.size());
}
} else if (arg.starts_with("-I")) {
string_piece option_arg;
if (!shaderc_util::GetOptionArgument(argc, argv, &i, "-I", &option_arg)) {
std::cerr
<< "glslc: error: argument to '-I' is missing (expected 1 value)"
<< std::endl;
success = false;
} else {
compiler.AddIncludeDirectory(option_arg.str());
}
} else if (arg == "-g") {
compiler.options().SetGenerateDebugInfo();
} else if (arg.starts_with("-O")) {
if (arg == "-O") {
compiler.options().SetOptimizationLevel(
shaderc_optimization_level_performance);
} else if (arg == "-Os") {
compiler.options().SetOptimizationLevel(
shaderc_optimization_level_size);
} else if (arg == "-O0") {
compiler.options().SetOptimizationLevel(
shaderc_optimization_level_zero);
} else {
std::cerr << "glslc: error: invalid value '"
<< arg.substr(std::strlen("-O")) << "' in '" << arg << "'"
<< std::endl;
return 1;
}
} else if (arg == "-w") {
compiler.options().SetSuppressWarnings();
} else if (arg == "-Werror") {
compiler.options().SetWarningsAsErrors();
} else if (!(arg == "-") && arg[0] == '-') {
std::cerr << "glslc: error: "
<< (arg[1] == '-' ? "unsupported option" : "unknown argument")
<< ": '" << arg << "'" << std::endl;
return 1;
} else {
if (arg == "-") {
if (has_stdin_input) {
std::cerr << "glslc: error: specifying standard input \"-\" as input "
<< "more than once is not allowed." << std::endl;
return 1;
}
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(glslc::InputFileSpec{
arg.str(), (current_fshader_stage == shaderc_glsl_infer_from_source
? glslc::DeduceDefaultShaderKindFromFileName(arg)
: current_fshader_stage),
language, current_entry_point_name});
}
}
if (!compiler.ValidateOptions(input_files.size())) return 1;
if (!success) return 1;
for (const auto& input_file : input_files) {
success &= compiler.CompileShaderFile(input_file);
}
compiler.OutputMessages();
return success ? 0 : 1;
}

View File

@@ -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 <algorithm>
#include <cstring>
#include <iterator>
#include <sstream>
#include <vector>
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<ResourceSetting>* 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<std::string> pos((input_stream));
limits->clear();
while (pos != std::istream_iterator<std::string>()) {
const std::string limit_name = *pos++;
shaderc_limit limit = static_cast<shaderc_limit>(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<std::string>())
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

View File

@@ -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 <string>
#include <vector>
#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<ResourceSetting>* limits,
std::string* err);
} // namespace glslc
#endif // GLSLC_FILE_H_

View File

@@ -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 <gmock/gmock.h>
namespace {
using glslc::ParseResourceSettings;
using glslc::ResourceSetting;
using testing::Eq;
struct ResourceSettingsCase {
std::string input;
bool success;
std::vector<ResourceSetting> settings;
std::string message;
};
using ParseResourceSettingsTest = ::testing::TestWithParam<ResourceSettingsCase>;
TEST_P(ParseResourceSettingsTest, Sample) {
std::vector<ResourceSetting> 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_SUITE_P(ParseResources, ParseResourceSettingsTest,
::testing::ValuesIn(std::vector<ResourceSettingsCase>{
{"", 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

View File

@@ -0,0 +1,100 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "shader_stage.h"
#include "file.h"
using shaderc_util::string_piece;
namespace {
// Maps an identifier to a shader stage.
struct StageMapping {
const char* id;
shaderc_shader_kind stage;
};
} // anonymous namespace
namespace glslc {
shaderc_shader_kind MapStageNameToForcedKind(const string_piece& stage_name) {
const StageMapping string_to_kind[] = {
{"vertex", shaderc_glsl_vertex_shader},
{"vert", shaderc_glsl_vertex_shader},
{"fragment", shaderc_glsl_fragment_shader},
{"frag", shaderc_glsl_fragment_shader},
{"tesscontrol", shaderc_glsl_tess_control_shader},
{"tesc", shaderc_glsl_tess_control_shader},
{"tesseval", shaderc_glsl_tess_evaluation_shader},
{"tese", shaderc_glsl_tess_evaluation_shader},
{"geometry", shaderc_glsl_geometry_shader},
{"geom", shaderc_glsl_geometry_shader},
{"compute", shaderc_glsl_compute_shader},
{"comp", shaderc_glsl_compute_shader},
{"rgen", shaderc_glsl_raygen_shader },
{"rahit", shaderc_glsl_anyhit_shader },
{"rchit", shaderc_glsl_closesthit_shader },
{"rmiss", shaderc_glsl_miss_shader },
{"rint", shaderc_glsl_intersection_shader },
{"rcall", shaderc_glsl_callable_shader },
{"task", shaderc_glsl_task_shader },
{"mesh", shaderc_glsl_mesh_shader },
};
for (const auto& entry : string_to_kind) {
if (stage_name == entry.id) return entry.stage;
}
return shaderc_glsl_infer_from_source;
}
shaderc_shader_kind GetForcedShaderKindFromCmdLine(
const shaderc_util::string_piece& f_shader_stage_str) {
size_t equal_pos = f_shader_stage_str.find_first_of("=");
if (equal_pos == std::string::npos) return shaderc_glsl_infer_from_source;
return MapStageNameToForcedKind(f_shader_stage_str.substr(equal_pos + 1));
}
shaderc_shader_kind DeduceDefaultShaderKindFromFileName(
const string_piece file_name) {
// Add new stage types here.
static const StageMapping kStringToStage[] = {
{"vert", shaderc_glsl_default_vertex_shader},
{"frag", shaderc_glsl_default_fragment_shader},
{"tesc", shaderc_glsl_default_tess_control_shader},
{"tese", shaderc_glsl_default_tess_evaluation_shader},
{"geom", shaderc_glsl_default_geometry_shader},
{"comp", shaderc_glsl_default_compute_shader},
{"spvasm", shaderc_spirv_assembly},
{"rgen", shaderc_glsl_default_raygen_shader },
{"rahit", shaderc_glsl_default_anyhit_shader },
{"rchit", shaderc_glsl_default_closesthit_shader },
{"rmiss", shaderc_glsl_default_miss_shader },
{"rint", shaderc_glsl_default_intersection_shader },
{"rcall", shaderc_glsl_default_callable_shader },
{"task", shaderc_glsl_default_task_shader },
{"mesh", shaderc_glsl_default_mesh_shader },
};
const string_piece extension = glslc::GetFileExtension(file_name);
shaderc_shader_kind stage = shaderc_glsl_infer_from_source;
for (const auto& entry : kStringToStage) {
if (extension == entry.id) stage = entry.stage;
}
return stage;
}
} // namespace glslc

View File

@@ -0,0 +1,42 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GLSLC_SHADER_STAGE_H_
#define GLSLC_SHADER_STAGE_H_
#include <ostream>
#include "libshaderc_util/string_piece.h"
#include "shaderc/shaderc.h"
namespace glslc {
// Maps a shader stage name to a forced shader stage enum value. Returns
// 'shaderc_glsl_infer_from_source' if the stage name is unrecognized.
shaderc_shader_kind MapStageNameToForcedKind(
const shaderc_util::string_piece& f_shader_stage_str);
// Parse the string piece from command line to get the force shader stage.
// If the 'f_shader_stage_str' cannot be parsed to a valid force shader stage,
// returns 'shaderc_glsl_infer_from_source'. Requires the string to begin with
// '='.
shaderc_shader_kind GetForcedShaderKindFromCmdLine(
const shaderc_util::string_piece& f_shader_stage_str);
// Parse the file name extension to get the default shader kind.
shaderc_shader_kind DeduceDefaultShaderKindFromFileName(
shaderc_util::string_piece file_name);
} // namespace glslc
#endif // GLSLC_SHADER_STAGE_H_

View File

@@ -0,0 +1,92 @@
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Some of the tests here check code paths that are not checked by
// integration tests.
// Generally, these would be conditions not generated by the Glslang
// compiler. It's easier to write these unit tests than to inject
// a dependency on a fake compiler.
#include <sstream>
#include <gtest/gtest.h>
#include "shaderc/shaderc.h"
#include "shader_stage.h"
using shaderc_util::string_piece;
namespace {
TEST(DeduceDefaultShaderKindFromFileName, ValidStage) {
std::stringstream error_stream;
EXPECT_EQ(shaderc_glsl_default_vertex_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.vert"));
EXPECT_EQ(shaderc_glsl_default_fragment_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.frag"));
EXPECT_EQ(shaderc_glsl_default_geometry_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.geom"));
EXPECT_EQ(shaderc_glsl_default_tess_control_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.tesc"));
EXPECT_EQ(shaderc_glsl_default_tess_evaluation_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.tese"));
EXPECT_EQ(shaderc_glsl_default_compute_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.comp"));
EXPECT_EQ(shaderc_glsl_default_raygen_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rgen"));
EXPECT_EQ(shaderc_glsl_default_anyhit_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rahit"));
EXPECT_EQ(shaderc_glsl_default_closesthit_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rchit"));
EXPECT_EQ(shaderc_glsl_default_miss_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rmiss"));
EXPECT_EQ(shaderc_glsl_default_intersection_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rint"));
EXPECT_EQ(shaderc_glsl_default_callable_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.rcall"));
EXPECT_EQ(shaderc_glsl_default_task_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.task"));
EXPECT_EQ(shaderc_glsl_default_mesh_shader,
glslc::DeduceDefaultShaderKindFromFileName("a.mesh"));
}
TEST(DeduceDefaultShaderKindFromFileName, InvalidStage) {
std::stringstream error_stream;
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("a.glsl"));
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("-"));
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("a.foo"));
EXPECT_EQ(shaderc_glsl_infer_from_source,
glslc::DeduceDefaultShaderKindFromFileName("no-file-extension"));
}
} // anonymous namespace

View File

@@ -0,0 +1,28 @@
# Copyright 2020 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.
add_test(NAME shaderc_expect_unittests
COMMAND ${Python_EXECUTABLE} -m unittest expect_unittest.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_test(NAME shaderc_glslc_test_framework_unittests
COMMAND ${Python_EXECUTABLE} -m unittest glslc_test_framework_unittest.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(${SHADERC_ENABLE_TESTS})
add_test(NAME glslc_tests
COMMAND ${Python_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/glslc_test_framework.py
$<TARGET_FILE:glslc_exe> $<TARGET_FILE:spirv-dis>
--test-dir ${CMAKE_CURRENT_SOURCE_DIR})
endif()

140
3rdparty/shaderc/glslc/test/assembly.py vendored Normal file
View File

@@ -0,0 +1,140 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def assembly_comments():
return """
; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0"""
def empty_main_assembly():
return assembly_comments() + """
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %4 "main"
OpSource ESSL 310
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd"""
def empty_main():
return '#version 310 es\nvoid main() {}'
@inside_glslc_testsuite('SpirvAssembly')
class TestAssemblyFileAsOnlyParameter(expect.ValidNamedObjectFile):
"""Tests that glslc accepts a SPIR-V assembly file as the only parameter."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = [shader]
expected_object_filenames = ('a.spv',)
@inside_glslc_testsuite('SpirvAssembly')
class TestDashCAssemblyFile(expect.ValidObjectFile):
"""Tests that -c works with SPIR-V assembly file."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestAssemblyFileWithOnlyComments(expect.ValidObjectFile):
"""Tests that glslc accepts an assembly file with only comments inside."""
shader = FileShader(assembly_comments(), '.spvasm')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestEmptyAssemblyFile(expect.ValidObjectFile):
"""Tests that glslc accepts an empty assembly file."""
shader = FileShader('', '.spvasm')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestDashEAssemblyFile(expect.SuccessfulReturn, expect.NoGeneratedFiles):
"""Tests that -E works with SPIR-V assembly file."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-E', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestDashSAssemblyFile(expect.SuccessfulReturn, expect.NoGeneratedFiles):
"""Tests that -S works with SPIR-V assembly file."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-S', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestMultipleAssemblyFiles(expect.ValidObjectFile):
"""Tests that glslc accepts multiple SPIR-V assembly files."""
shader1 = FileShader(empty_main_assembly(), '.spvasm')
shader2 = FileShader(empty_main_assembly(), '.spvasm')
shader3 = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', shader1, shader2, shader3]
@inside_glslc_testsuite('SpirvAssembly')
class TestHybridInputFiles(expect.ValidObjectFile):
"""Tests that glslc accepts a mix of SPIR-V assembly files and
GLSL source files."""
shader1 = FileShader(empty_main_assembly(), '.spvasm')
shader2 = FileShader(empty_main(), '.vert')
shader3 = FileShader(empty_main(), '.frag')
glslc_args = ['-c', shader1, shader2, shader3]
@inside_glslc_testsuite('SpirvAssembly')
class TestShaderStageWithAssemblyFile(expect.ErrorMessage):
"""Tests that assembly files don't work with -fshader-stage"""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
expected_error = [
shader, ": error: #version: Desktop shaders for Vulkan SPIR-V require "
"version 140 or higher\n",
shader, ":2: error: 'extraneous semicolon' :",
" not supported for this version or the enabled extensions\n",
shader, ":2: error: '' : syntax error, unexpected IDENTIFIER\n",
'3 errors generated.\n']
@inside_glslc_testsuite('SpirvAssembly')
class TestStdWithAssemblyFile(expect.ValidObjectFile):
"""Tests that --std= doesn't affect the processing of assembly files."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', '-std=310es', shader]

View File

@@ -0,0 +1,72 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Classes for conveniently specifying a test environment.
These classes have write() methods that create objects in a test's environment.
For instance, File creates a file, and Directory creates a directory with some
files or subdirectories in it.
Example:
test.environment = Directory('.', [
File('a.vert', 'void main(){}'),
Directory('subdir', [
File('b', 'b content'),
File('c', 'c content')
])
])
In general, these classes don't clean up the disk content they create. They
were written in a test framework that handles clean-up at a higher level.
"""
import os
class Directory:
"""Specifies a directory or a subdirectory."""
def __init__(self, name, content):
"""content is a list of File or Directory objects."""
self.name = name
self.content = content
@staticmethod
def create(path):
"""Creates a directory path if it doesn't already exist."""
try:
os.makedirs(path)
except OSError: # Handles both pre-existence and a racing creation.
if not os.path.isdir(path):
raise
def write(self, parent):
"""Creates a self.name directory within parent (which is a string path) and
recursively writes the content in it.
"""
full_path = os.path.join(parent, self.name)
Directory.create(full_path)
for c in self.content:
c.write(full_path)
class File:
"""Specifies a file by name and content."""
def __init__(self, name, content):
self.name = name
self.content = content
def write(self, directory):
"""Writes content to directory/name."""
with open(os.path.join(directory, self.name), 'w') as f:
f.write(self.content)

View File

@@ -0,0 +1,59 @@
# 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.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
@inside_glslc_testsuite('ErrorNoObject')
class ErrorGeneratesNoObjectFile(expect.NoObjectFile,
expect.NoOutputOnStdout,
expect.ErrorMessageSubstr):
"""Tests that on error, no object file is generated."""
shader = FileShader('#version 150\nBad', '.frag')
glslc_args = ['-c', shader]
expected_error_substr = ['syntax error']
@inside_glslc_testsuite('ErrorNoObject')
class FailureToMakeOutputFileIsErrorWithNoOutputFile(
expect.NoNamedOutputFiles,
expect.NoOutputOnStdout,
expect.ErrorMessageSubstr):
"""Tests that if we fail to make an output file, no file is generated,
and we have certain error messages."""
shader = FileShader('#version 150\nvoid main() {}', '.frag')
bad_file = '/file/should/not/exist/today'
glslc_args = ['-c', shader, '-o', bad_file]
expected_output_filenames = [bad_file]
expected_error_substr = ['cannot open output file']
@inside_glslc_testsuite('ErrorNoObject')
class FailureToMakeOutputFileAsCurrentDirIsErrorWithNoOutputFile(
expect.NoNamedOutputFiles,
expect.NoOutputOnStdout,
expect.ErrorMessageSubstr):
"""Tests that if we fail to make an output file because it is the current
directory, then no file is generated, and we have certain error messages."""
shader = FileShader('#version 150\nvoid main() {}', '.frag')
bad_file = '.' # Current directory
glslc_args = ['-c', shader, '-o', bad_file]
expected_output_filenames = [bad_file]
expected_error_substr = ['cannot open output file']

707
3rdparty/shaderc/glslc/test/expect.py vendored Normal file
View File

@@ -0,0 +1,707 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A number of common glslc result checks coded in mixin classes.
A test case can use these checks by declaring their enclosing mixin classes
as superclass and providing the expected_* variables required by the check_*()
methods in the mixin classes.
"""
import difflib
import functools
import os
import re
import subprocess
import sys
from glslc_test_framework import GlslCTest
from builtins import bytes
GLSLANG_GENERATOR_VERSION=11
SHADERC_GENERATOR_NUMBER=13
SHADERC_GENERATOR_WORD=(SHADERC_GENERATOR_NUMBER << 16) + GLSLANG_GENERATOR_VERSION
ASSEMBLER_GENERATOR_WORD=(7<<16)
def convert_to_string(input):
if type(input) is not str:
if sys.version_info[0] == 2:
return input.decode('utf-8')
elif sys.version_info[0] == 3:
return str(input,
encoding='utf-8',
errors='ignore') if input is not None else input
else:
raise Exception(
'Unable to determine if running Python 2 or 3 from {}'.format(
sys.version_info))
else:
return input
def convert_to_unix_line_endings(source):
"""Converts all line endings in source to be unix line endings."""
return source.replace('\r\n', '\n').replace('\r', '\n')
def substitute_file_extension(filename, extension):
"""Substitutes file extension, respecting known shader extensions.
foo.vert -> foo.vert.[extension] [similarly for .frag, .comp, etc.]
foo.glsl -> foo.[extension]
foo.unknown -> foo.[extension]
foo -> foo.[extension]
"""
if filename[-5:] not in ['.vert', '.frag', '.tesc', '.tese',
'.geom', '.comp', '.spvasm']:
return filename.rsplit('.', 1)[0] + '.' + extension
else:
return filename + '.' + extension
def get_object_filename(source_filename):
"""Gets the object filename for the given source file."""
return substitute_file_extension(source_filename, 'spv')
def get_assembly_filename(source_filename):
"""Gets the assembly filename for the given source file."""
return substitute_file_extension(source_filename, 'spvasm')
def verify_file_non_empty(filename):
"""Checks that a given file exists and is not empty."""
if not os.path.isfile(filename):
return False, 'Cannot find file: ' + filename
if not os.path.getsize(filename):
return False, 'Empty file: ' + filename
return True, ''
class ReturnCodeIsZero(GlslCTest):
"""Mixin class for checking that the return code is zero."""
def check_return_code_is_zero(self, status):
if status.returncode:
return False, 'Non-zero return code: {ret}\n'.format(
ret=status.returncode)
return True, ''
class NoOutputOnStdout(GlslCTest):
"""Mixin class for checking that there is no output on stdout."""
def check_no_output_on_stdout(self, status):
if status.stdout:
return False, 'Non empty stdout: {out}\n'.format(out=status.stdout)
return True, ''
class NoOutputOnStderr(GlslCTest):
"""Mixin class for checking that there is no output on stderr."""
def check_no_output_on_stderr(self, status):
if status.stderr:
return False, 'Non empty stderr: {err}\n'.format(err=status.stderr)
return True, ''
class SuccessfulReturn(ReturnCodeIsZero, NoOutputOnStdout, NoOutputOnStderr):
"""Mixin class for checking that return code is zero and no output on
stdout and stderr."""
pass
class NoGeneratedFiles(GlslCTest):
"""Mixin class for checking that there is no file generated."""
def check_no_generated_files(self, status):
all_files = os.listdir(status.directory)
input_files = status.input_filenames
if all([f.startswith(status.directory) for f in input_files]):
all_files = [os.path.join(status.directory, f) for f in all_files]
generated_files = set(all_files) - set(input_files)
if len(generated_files) == 0:
return True, ''
else:
return False, 'Extra files generated: {}'.format(generated_files)
class CorrectBinaryLengthAndPreamble(GlslCTest):
"""Provides methods for verifying preamble for a SPIR-V binary."""
def verify_binary_length_and_header(self, binary, spv_version = 0x10000):
"""Checks that the given SPIR-V binary has valid length and header.
Returns:
False, error string if anything is invalid
True, '' otherwise
Args:
binary: a bytes object containing the SPIR-V binary
spv_version: target SPIR-V version number, with same encoding
as the version word in a SPIR-V header.
"""
def read_word(binary, index, little_endian):
"""Reads the index-th word from the given binary file."""
word = binary[index * 4:(index + 1) * 4]
if little_endian:
word = reversed(word)
return functools.reduce(lambda w, b: (w << 8) | b, word, 0)
def check_endianness(binary):
"""Checks the endianness of the given SPIR-V binary.
Returns:
True if it's little endian, False if it's big endian.
None if magic number is wrong.
"""
first_word = read_word(binary, 0, True)
if first_word == 0x07230203:
return True
first_word = read_word(binary, 0, False)
if first_word == 0x07230203:
return False
return None
num_bytes = len(binary)
if num_bytes % 4 != 0:
return False, ('Incorrect SPV binary: size should be a multiple'
' of words')
if num_bytes < 20:
return False, 'Incorrect SPV binary: size less than 5 words'
preamble = binary[0:19]
little_endian = check_endianness(preamble)
# SPIR-V module magic number
if little_endian is None:
return False, 'Incorrect SPV binary: wrong magic number'
# SPIR-V version number
version = read_word(preamble, 1, little_endian)
# TODO(dneto): Recent Glslang uses version word 0 for opengl_compat
# profile
if version != spv_version and version != 0:
return False, 'Incorrect SPV binary: wrong version number'
# Shaderc-over-Glslang (0x000d....) or
# SPIRV-Tools (0x0007....) generator number
if read_word(preamble, 2, little_endian) != SHADERC_GENERATOR_WORD and \
read_word(preamble, 2, little_endian) != ASSEMBLER_GENERATOR_WORD:
return False, ('Incorrect SPV binary: wrong generator magic '
'number')
# reserved for instruction schema
if read_word(preamble, 4, little_endian) != 0:
return False, 'Incorrect SPV binary: the 5th byte should be 0'
return True, ''
class CorrectObjectFilePreamble(CorrectBinaryLengthAndPreamble):
"""Provides methods for verifying preamble for a SPV object file."""
def verify_object_file_preamble(self, filename, spv_version = 0x10000):
"""Checks that the given SPIR-V binary file has correct preamble."""
success, message = verify_file_non_empty(filename)
if not success:
return False, message
with open(filename, 'rb') as object_file:
object_file.seek(0, os.SEEK_END)
num_bytes = object_file.tell()
object_file.seek(0)
binary = bytes(object_file.read())
return self.verify_binary_length_and_header(binary, spv_version)
return True, ''
class CorrectAssemblyFilePreamble(GlslCTest):
"""Provides methods for verifying preamble for a SPV assembly file."""
def verify_assembly_file_preamble(self, filename):
success, message = verify_file_non_empty(filename)
if not success:
return False, message
with open(filename) as assembly_file:
line1 = assembly_file.readline()
line2 = assembly_file.readline()
line3 = assembly_file.readline()
if (line1 != '; SPIR-V\n' or
line2 != '; Version: 1.0\n' or
(not line3.startswith('; Generator: Google Shaderc over Glslang;'))):
return False, 'Incorrect SPV assembly'
return True, ''
class ValidObjectFile(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.0
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename))
if not success:
return False, message
return True, ''
class ValidObjectFile1_3(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.3
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10300)
if not success:
return False, message
return True, ''
class ValidObjectFile1_4(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.4
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10400)
if not success:
return False, message
return True, ''
class ValidObjectFile1_5(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.5
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10500)
if not success:
return False, message
return True, ''
class ValidObjectFile1_6(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.6
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10600)
if not success:
return False, message
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 bytes(an_input.assembly_substr, 'utf-8') 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.
To mix in this class, subclasses need to provide expected_object_filenames
as the expected object filenames.
"""
def check_object_file_preamble(self, status):
for object_filename in self.expected_object_filenames:
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename))
if not success:
return False, message
return True, ''
class ValidFileContents(GlslCTest):
"""Mixin class to test that a specific file contains specific text
To mix in this class, subclasses need to provide expected_file_contents as
the contents of the file and target_filename to determine the location."""
def check_file(self, status):
target_filename = os.path.join(status.directory, self.target_filename)
if not os.path.isfile(target_filename):
return False, 'Cannot find file: ' + target_filename
with open(target_filename, 'r') as target_file:
file_contents = target_file.read()
if isinstance(self.expected_file_contents, str):
if file_contents == self.expected_file_contents:
return True, ''
return False, ('Incorrect file output: \n{act}\n'
'Expected:\n{exp}'
'With diff:\n{diff}'.format(
act=file_contents,
exp=self.expected_file_contents,
diff='\n'.join(list(difflib.unified_diff(
self.expected_file_contents.split('\n'),
file_contents.split('\n'),
fromfile='expected_output',
tofile='actual_output')))))
elif isinstance(self.expected_file_contents, type(re.compile(''))):
if self.expected_file_contents.search(file_contents):
return True, ''
return False, (
'Incorrect file output: \n{act}\n'
'Expected matching regex pattern:\n{exp}'.format(
act=file_contents,
exp=self.expected_file_contents.pattern))
return False, ('Could not open target file ' + target_filename +
' for reading')
class ValidAssemblyFile(SuccessfulReturn, CorrectAssemblyFilePreamble):
"""Mixin class for checking that every input file generates a valid assembly
file following the assembly file naming rule, and there is no output on
stdout/stderr."""
def check_assembly_file_preamble(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
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 ValidAssemblyFileWithoutSubstr(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 no assembly files have the given substring specified
by unexpected_assembly_substr.
To mix in this class, subclasses need to provde unexpected_assembly_substr
as the substring we expect not to see.
"""
def check_assembly_for_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.unexpected_assembly_substr in convert_to_unix_line_endings(content):
return False, ('Incorrect assembly output:\n{asm}\n'
'Unexpected substring found:\n{unexp}'.format(
asm=content, exp=self.unexpected_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.
To mix in this class, subclasses need to provide expected_assembly_filenames
as the expected assembly filenames.
"""
def check_object_file_preamble(self, status):
for assembly_filename in self.expected_assembly_filenames:
success, message = self.verify_assembly_file_preamble(
os.path.join(status.directory, assembly_filename))
if not success:
return False, message
return True, ''
class ErrorMessage(GlslCTest):
"""Mixin class for tests that fail with a specific error message.
To mix in this class, subclasses need to provide expected_error as the
expected error message.
The test should fail if the subprocess was terminated by a signal.
"""
def check_has_error_message(self, status):
if not status.returncode:
return False, ('Expected error message, but returned success from '
'glslc')
if status.returncode < 0:
# On Unix, a negative value -N for Popen.returncode indicates
# termination by signal N.
# https://docs.python.org/2/library/subprocess.html
return False, ('Expected error message, but glslc was terminated by '
'signal ' + str(status.returncode))
if not status.stderr:
return False, 'Expected error message, but no output on stderr'
if self.expected_error != convert_to_unix_line_endings(convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{act}\n'
'Expected:\n{exp}'.format(
act=status.stderr, exp=self.expected_error))
return True, ''
class ErrorMessageSubstr(GlslCTest):
"""Mixin class for tests that fail with a specific substring in the error
message.
To mix in this class, subclasses need to provide expected_error_substr as
the expected error message substring.
The test should fail if the subprocess was terminated by a signal.
"""
def check_has_error_message_as_substring(self, status):
if not status.returncode:
return False, ('Expected error message, but returned success from '
'glslc')
if status.returncode < 0:
# On Unix, a negative value -N for Popen.returncode indicates
# termination by signal N.
# https://docs.python.org/2/library/subprocess.html
return False, ('Expected error message, but glslc was terminated by '
'signal ' + str(status.returncode))
if not status.stderr:
return False, 'Expected error message, but no output on stderr'
if self.expected_error_substr not in convert_to_unix_line_endings(convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{act}\n'
'Expected substring not found in stderr:\n{exp}'.format(
act=status.stderr, exp=self.expected_error_substr))
return True, ''
class WarningMessage(GlslCTest):
"""Mixin class for tests that succeed but have a specific warning message.
To mix in this class, subclasses need to provide expected_warning as the
expected warning message.
"""
def check_has_warning_message(self, status):
if status.returncode:
return False, ('Expected warning message, but returned failure from'
' glslc')
if not status.stderr:
return False, 'Expected warning message, but no output on stderr'
if self.expected_warning != convert_to_unix_line_endings(convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{act}\n'
'Expected:\n{exp}'.format(
act=status.stderr, exp=self.expected_warning))
return True, ''
class ValidObjectFileWithWarning(
NoOutputOnStdout, CorrectObjectFilePreamble, WarningMessage):
"""Mixin class for checking that every input file generates a valid object
file following the object file naming rule, with a specific warning message.
"""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename))
if not success:
return False, message
return True, ''
class ValidAssemblyFileWithWarning(
NoOutputOnStdout, CorrectAssemblyFilePreamble, WarningMessage):
"""Mixin class for checking that every input file generates a valid assembly
file following the assembly file naming rule, with a specific warning
message."""
def check_assembly_file_preamble(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
return True, ''
class StdoutMatch(GlslCTest):
"""Mixin class for tests that can expect output on stdout.
To mix in this class, subclasses need to provide expected_stdout as the
expected stdout output.
For expected_stdout, if it's True, then they expect something on stdout but
will not check what it is. If it's a string, expect an exact match. If it's
anything else, expect expected_stdout.search(stdout) to be true.
"""
def check_stdout_match(self, status):
# "True" in this case means we expect something on stdout, but we do not
# care what it is, we want to distinguish this from "blah" which means we
# expect exactly the string "blah".
if self.expected_stdout is True:
if not status.stdout:
return False, 'Expected something on stdout'
elif type(self.expected_stdout) == str:
if self.expected_stdout != convert_to_unix_line_endings(
convert_to_string(status.stdout)):
return False, ('Incorrect stdout output:\n{ac}\n'
'Expected:\n{ex}'.format(
ac=status.stdout, ex=self.expected_stdout))
else:
if not self.expected_stdout.search(convert_to_unix_line_endings(
convert_to_string(status.stdout))):
return False, ('Incorrect stdout output:\n{ac}\n'
'Expected to match regex:\n{ex}'.format(
ac=convert_to_string(status.stdout),
ex=self.expected_stdout.pattern))
return True, ''
class StderrMatch(GlslCTest):
"""Mixin class for tests that can expect output on stderr.
To mix in this class, subclasses need to provide expected_stderr as the
expected stderr output.
For expected_stderr, if it's True, then they expect something on stderr,
but will not check what it is. If it's a string, expect an exact match.
"""
def check_stderr_match(self, status):
# "True" in this case means we expect something on stderr, but we do not
# care what it is, we want to distinguish this from "blah" which means we
# expect exactly the string "blah".
if self.expected_stderr is True:
if not status.stderr:
return False, 'Expected something on stderr'
else:
if self.expected_stderr != convert_to_unix_line_endings(
convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{ac}\n'
'Expected:\n{ex}'.format(
ac=status.stderr, ex=self.expected_stderr))
return True, ''
class StdoutNoWiderThan80Columns(GlslCTest):
"""Mixin class for tests that require stdout to 80 characters or narrower.
To mix in this class, subclasses need to provide expected_stdout as the
expected stdout output.
"""
def check_stdout_not_too_wide(self, status):
if not status.stdout:
return True, ''
else:
for line in status.stdout.splitlines():
if len(line) > 80:
return False, ('Stdout line longer than 80 columns: %s'
% line)
return True, ''
class NoObjectFile(GlslCTest):
"""Mixin class for checking that no input file has a corresponding object
file."""
def check_no_object_file(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
full_object_file = os.path.join(status.directory, object_filename)
print("checking %s" % full_object_file)
if os.path.isfile(full_object_file):
return False, ('Expected no object file, but found: %s'
% full_object_file)
return True, ''
class NoNamedOutputFiles(GlslCTest):
"""Mixin class for checking that no specified output files exist.
The expected_output_filenames member should be full pathnames."""
def check_no_named_output_files(self, status):
for object_filename in self.expected_output_filenames:
if os.path.isfile(object_filename):
return False, ('Expected no output file, but found: %s'
% object_filename)
return True, ''

View File

@@ -0,0 +1,83 @@
# Copyright 2019 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.
"""Tests for the expect module."""
import expect
from glslc_test_framework import TestStatus
import re
import unittest
class TestStdoutMatchADotC(expect.StdoutMatch):
expected_stdout = re.compile('a.c')
class TestExpect(unittest.TestCase):
def test_get_object_name(self):
"""Tests get_object_filename()."""
source_and_object_names = [('a.vert', 'a.vert.spv'),
('b.frag', 'b.frag.spv'),
('c.tesc', 'c.tesc.spv'),
('d.tese', 'd.tese.spv'),
('e.geom', 'e.geom.spv'),
('f.comp', 'f.comp.spv'),
('file', 'file.spv'), ('file.', 'file.spv'),
('file.uk',
'file.spv'), ('file.vert.',
'file.vert.spv'),
('file.vert.bla',
'file.vert.spv')]
actual_object_names = [
expect.get_object_filename(f[0]) for f in source_and_object_names
]
expected_object_names = [f[1] for f in source_and_object_names]
self.assertEqual(actual_object_names, expected_object_names)
def test_stdout_match_regex_has_match(self):
test = TestStdoutMatchADotC()
status = TestStatus(
test_manager=None,
returncode=0,
stdout=b'0abc1',
stderr=None,
directory=None,
inputs=None,
input_filenames=None)
self.assertTrue(test.check_stdout_match(status)[0])
def test_stdout_match_regex_no_match(self):
test = TestStdoutMatchADotC()
status = TestStatus(
test_manager=None,
returncode=0,
stdout=b'ab',
stderr=None,
directory=None,
inputs=None,
input_filenames=None)
self.assertFalse(test.check_stdout_match(status)[0])
def test_stdout_match_regex_empty_stdout(self):
test = TestStdoutMatchADotC()
status = TestStatus(
test_manager=None,
returncode=0,
stdout=b'',
stderr=None,
directory=None,
inputs=None,
input_filenames=None)
self.assertFalse(test.check_stdout_match(status)[0])

View File

@@ -0,0 +1,86 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import GlslCTest, inside_glslc_testsuite
from placeholder import FileShader
def empty_es_310_shader():
return '#version 310 es\n void main() {}\n'
@inside_glslc_testsuite('FileExtension')
class VerifyVertExtension(expect.ValidObjectFile):
"""Tests glslc accepts vertex shader extension (.vert)."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyFragExtension(expect.ValidObjectFile):
"""Tests glslc accepts fragment shader extension (.frag)."""
shader = FileShader(empty_es_310_shader(), '.frag')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyTescExtension(expect.ValidObjectFile):
"""Tests glslc accepts tessellation control shader extension (.tesc)."""
shader = FileShader(
'#version 440 core\n layout(vertices = 3) out;\n void main() {}',
'.tesc')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyTeseExtension(expect.ValidObjectFile):
"""Tests glslc accepts tessellation evaluation shader extension (.tese)."""
shader = FileShader(
'#version 440 core\n layout(triangles) in;\n void main() {}', '.tese')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyGeomExtension(expect.ValidObjectFile):
"""Tests glslc accepts geomtry shader extension (.geom)."""
shader = FileShader(
'#version 150 core\n layout (triangles) in;\n'
'layout (line_strip, max_vertices = 4) out;\n void main() {}',
'.geom')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyCompExtension(expect.ValidObjectFile):
"""Tests glslc accepts compute shader extension (.comp)."""
shader = FileShader(empty_es_310_shader(), '.comp')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class InvalidExtension(expect.ErrorMessage):
"""Tests the error message if a file extension cannot be determined."""
shader = FileShader('#version 150\n', '.fraga')
glslc_args = ['-c', shader]
expected_error = [
"glslc: error: '", shader,
"': file not recognized: File format not recognized\n"]

View File

@@ -0,0 +1,355 @@
#!/usr/bin/env python
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Manages and runs tests from the current working directory.
This will traverse the current working directory and look for python files that
contain subclasses of GlslCTest.
If a class has an @inside_glslc_testsuite decorator, an instance of that
class will be created and serve as a test case in that testsuite. The test
case is then run by the following steps:
1. A temporary directory will be created.
2. The glslc_args member variable will be inspected and all placeholders in it
will be expanded by calling instantiate_for_glslc_args() on placeholders.
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 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
string. These expected_* variables are to be used by the check_*() methods.
5. glslc will be run with the arguments supplied in glslc_args.
6. All check_*() member methods will be called by supplying a TestStatus as
argument. Each check_*() method is expected to return a (Success, Message)
pair where Success is a boolean indicating success and Message is an error
message.
7. If any check_*() method fails, the error message is outputted and the
current test case fails.
If --leave-output was not specified, all temporary files and directories will
be deleted.
"""
import argparse
import fnmatch
import inspect
import os
import shutil
import subprocess
import sys
import tempfile
from collections import defaultdict
from placeholder import PlaceHolder
EXPECTED_BEHAVIOR_PREFIX = 'expected_'
VALIDATE_METHOD_PREFIX = 'check_'
def get_all_variables(instance):
"""Returns the names of all the variables in instance."""
return [v for v in dir(instance) if not callable(getattr(instance, v))]
def get_all_methods(instance):
"""Returns the names of all methods in instance."""
return [m for m in dir(instance) if callable(getattr(instance, m))]
def get_all_superclasses(cls):
"""Returns all superclasses of a given class. Omits root 'object' superclass.
Returns:
A list of superclasses of the given class. The order guarantees that
* A Base class precedes its derived classes, e.g., for "class B(A)", it
will be [..., A, B, ...].
* When there are multiple base classes, base classes declared first
precede those declared later, e.g., for "class C(A, B), it will be
[..., A, B, C, ...]
"""
classes = []
for superclass in cls.__bases__:
for c in get_all_superclasses(superclass):
if c is not object and c not in classes:
classes.append(c)
for superclass in cls.__bases__:
if superclass is not object and superclass not in classes:
classes.append(superclass)
return classes
def get_all_test_methods(test_class):
"""Gets all validation methods.
Returns:
A list of validation methods. The order guarantees that
* A method defined in superclass precedes one defined in subclass,
e.g., for "class A(B)", methods defined in B precedes those defined
in A.
* If a subclass has more than one superclass, e.g., "class C(A, B)",
then methods defined in A precedes those defined in B.
"""
classes = get_all_superclasses(test_class)
classes.append(test_class)
all_tests = [m for c in classes
for m in get_all_methods(c)
if m.startswith(VALIDATE_METHOD_PREFIX)]
unique_tests = []
for t in all_tests:
if t not in unique_tests:
unique_tests.append(t)
return unique_tests
class GlslCTest:
"""Base class for glslc test cases.
Subclasses define test cases' facts (shader source code, glslc command,
result validation), which will be used by the TestCase class for running
tests. Subclasses should define glslc_args (specifying glslc command
arguments), and at least one check_*() method (for result validation) for
a full-fledged test case. All check_*() methods should take a TestStatus
parameter and return a (Success, Message) pair, in which Success is a
boolean indicating success and Message is an error message. The test passes
iff all check_*() methods returns true.
Often, a test case class will delegate the check_* behaviors by inheriting
from other classes.
"""
def name(self):
return self.__class__.__name__
class TestStatus:
"""A struct for holding run status of a test case."""
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
class GlslCTestException(Exception):
"""GlslCTest exception class."""
pass
def inside_glslc_testsuite(testsuite_name):
"""Decorator for subclasses of GlslCTest.
This decorator checks that a class meets the requirements (see below)
for a test case class, and then puts the class in a certain testsuite.
* The class needs to be a subclass of GlslCTest.
* The class needs to have glslc_args defined as a list.
* The class needs to define at least one check_*() methods.
* All expected_* variables required by check_*() methods can only be
of bool, str, or list type.
* Python runtime will throw an exception if the expected_* member
attributes required by check_*() methods are missing.
"""
def actual_decorator(cls):
if not inspect.isclass(cls):
raise GlslCTestException('Test case should be a class')
if not issubclass(cls, GlslCTest):
raise GlslCTestException(
'All test cases should be subclasses of GlslCTest')
if 'glslc_args' not in get_all_variables(cls):
raise GlslCTestException('No glslc_args found in the test case')
if not isinstance(cls.glslc_args, list):
raise GlslCTestException('glslc_args needs to be a list')
if not any([
m.startswith(VALIDATE_METHOD_PREFIX)
for m in get_all_methods(cls)]):
raise GlslCTestException(
'No check_*() methods found in the test case')
if not all([
isinstance(v, (bool, str, list))
for v in get_all_variables(cls)]):
raise GlslCTestException(
'expected_* variables are only allowed to be bool, str, or '
'list type.')
cls.parent_testsuite = testsuite_name
return cls
return actual_decorator
class TestManager:
"""Manages and runs a set of tests."""
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
self.leave_output = False
self.tests = defaultdict(list)
def notify_result(self, test_case, success, message):
"""Call this to notify the manager of the results of a test run."""
self.num_successes += 1 if success else 0
self.num_failures += 0 if success else 1
counter_string = str(
self.num_successes + self.num_failures) + '/' + str(self.num_tests)
print('%-10s %-40s ' % (counter_string, test_case.test.name()) +
('Passed' if success else '-Failed-'))
if not success:
print(' '.join(test_case.command))
print(message)
def add_test(self, testsuite, test):
"""Add this to the current list of test cases."""
self.tests[testsuite].append(TestCase(test, self))
self.num_tests += 1
def run_tests(self):
for suite in self.tests:
print('Glslc test suite: "{suite}"'.format(suite=suite))
for x in self.tests[suite]:
x.runTest()
class TestCase:
"""A single test case that runs in its own directory."""
def __init__(self, test, test_manager):
self.test = test
self.test_manager = test_manager
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):
"""Creates environment and instantiates placeholders for the test case."""
self.directory = tempfile.mkdtemp(dir=os.getcwd())
glslc_args = self.test.glslc_args
# Instantiate placeholders in glslc_args
self.test.glslc_args = [
arg.instantiate_for_glslc_args(self)
if isinstance(arg, PlaceHolder) else arg
for arg in self.test.glslc_args]
# Get all shader files' names
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)
expectations = [v for v in get_all_variables(self.test)
if v.startswith(EXPECTED_BEHAVIOR_PREFIX)]
# Instantiate placeholders in expectations
for expectation_name in expectations:
expectation = getattr(self.test, expectation_name)
if isinstance(expectation, list):
expanded_expections = [
element.instantiate_for_expectation(self)
if isinstance(element, PlaceHolder) else element
for element in expectation]
setattr(
self.test, expectation_name,
''.join(expanded_expections))
elif isinstance(expectation, PlaceHolder):
setattr(self.test, expectation_name,
expectation.instantiate_for_expectation(self))
def tearDown(self):
"""Removes the directory if we were not instructed to do otherwise."""
if not self.test_manager.leave_output:
shutil.rmtree(self.directory)
def runTest(self):
"""Sets up and runs a test, reports any failures and then cleans up."""
self.setUp()
success = False
message = ''
try:
self.command = [self.test_manager.executable_path]
self.command.extend(self.test.glslc_args)
process = subprocess.Popen(
args=self.command, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
cwd=self.directory)
output = process.communicate(self.stdin_shader)
test_status = TestStatus(
self.test_manager,
process.returncode, output[0], output[1],
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__)]
success, message = list(zip(*run_results))
success = all(success)
message = '\n'.join(message)
except Exception as e:
success = False
message = str(e)
self.test_manager.notify_result(self, success, message)
self.tearDown()
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,
help='Directory to gather the tests from')
args = parser.parse_args()
default_path = sys.path
root_dir = os.getcwd()
if args.test_dir:
root_dir = args.test_dir[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):
for filename in fnmatch.filter(filenames, '*.py'):
if filename.endswith('unittest.py'):
# Skip unit tests, which are for testing functions of
# the test framework.
continue
sys.path = default_path
sys.path.append(root)
try:
mod = __import__(os.path.splitext(filename)[0])
for _, obj, in inspect.getmembers(mod):
if inspect.isclass(obj) and hasattr(obj, 'parent_testsuite'):
manager.add_test(obj.parent_testsuite, obj())
except:
print("Failed to load " + filename)
raise
manager.run_tests()
if manager.num_failures > 0:
sys.exit(-1)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,159 @@
# Copyright 2019 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.
"""Tests for the glslc_test_framework module."""
from glslc_test_framework import get_all_test_methods, get_all_superclasses
import unittest
# Classes to be used in testing get_all_{superclasses|test_methods}()
class Root:
def check_root(self):
pass
class A(Root):
def check_a(self):
pass
class B(Root):
def check_b(self):
pass
class C(Root):
def check_c(self):
pass
class D(Root):
def check_d(self):
pass
class E(Root):
def check_e(self):
pass
class H(B, C, D):
def check_h(self):
pass
class I(E):
def check_i(self):
pass
class O(H, I):
def check_o(self):
pass
class U(A, O):
def check_u(self):
pass
class X(U, A):
def check_x(self):
pass
class R1:
def check_r1(self):
pass
class R2:
def check_r2(self):
pass
class Multi(R1, R2):
def check_multi(self):
pass
class TestSpirvTestFramework(unittest.TestCase):
def test_get_all_superclasses(self):
self.assertEqual(get_all_superclasses(A), [Root])
self.assertEqual(get_all_superclasses(B), [Root])
self.assertEqual(get_all_superclasses(C), [Root])
self.assertEqual(get_all_superclasses(D), [Root])
self.assertEqual(get_all_superclasses(E), [Root])
self.assertEqual(get_all_superclasses(H), [Root, B, C, D])
self.assertEqual(get_all_superclasses(I), [Root, E])
self.assertEqual(get_all_superclasses(O), [Root, B, C, D, E, H, I])
self.assertEqual(get_all_superclasses(
U), [Root, B, C, D, E, H, I, A, O])
self.assertEqual(get_all_superclasses(
X), [Root, B, C, D, E, H, I, A, O, U])
self.assertEqual(get_all_superclasses(Multi), [R1, R2])
def test_get_all_methods(self):
self.assertEqual(get_all_test_methods(A), ['check_root', 'check_a'])
self.assertEqual(get_all_test_methods(B), ['check_root', 'check_b'])
self.assertEqual(get_all_test_methods(C), ['check_root', 'check_c'])
self.assertEqual(get_all_test_methods(D), ['check_root', 'check_d'])
self.assertEqual(get_all_test_methods(E), ['check_root', 'check_e'])
self.assertEqual(
get_all_test_methods(H),
['check_root', 'check_b', 'check_c', 'check_d', 'check_h'])
self.assertEqual(get_all_test_methods(
I), ['check_root', 'check_e', 'check_i'])
self.assertEqual(
get_all_test_methods(O), [
'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h',
'check_i', 'check_o'
])
self.assertEqual(
get_all_test_methods(U), [
'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h',
'check_i', 'check_a', 'check_o', 'check_u'
])
self.assertEqual(
get_all_test_methods(X), [
'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h',
'check_i', 'check_a', 'check_o', 'check_u', 'check_x'
])
self.assertEqual(
get_all_test_methods(Multi), ['check_r1', 'check_r2', 'check_multi'])

555
3rdparty/shaderc/glslc/test/include.py vendored Normal file
View File

@@ -0,0 +1,555 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import SpecializedString
from environment import File, Directory
@inside_glslc_testsuite('Include')
class VerifyIncludeOneSibling(expect.StdoutMatch):
"""Tests #including a sibling file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b"\n'),
File('b', 'content b\n')])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "b"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyIncludeNotFound(expect.ErrorMessage):
"""Tests #including a not existing sibling file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b"\n')])
glslc_args = ['-E', 'a.vert']
expected_error = [
"a.vert:3: error: '#include' : Cannot find or open include file. for header name: b\n",
'1 error generated.\n'
]
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeOneSibling(expect.ValidObjectFile):
"""Tests #including a sibling file via full compilation."""
environment = Directory('.', [
File('a.vert', '#version 140\nvoid foo(){}\n#include "b"\n'),
File('b', 'void main(){foo();}\n')])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeWithoutNewline(expect.ErrorMessageSubstr):
"""Tests a #include without a newline."""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b"'),
File('b', 'content b\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = 'expected newline after header name: b'
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeWithoutNewline(expect.ValidObjectFile):
"""Tests a #include without a newline via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
void main
#include "b"
"""),
File('b',
"""#define PAR ()
PAR{}
""")])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeTwoSiblings(expect.StdoutMatch):
"""Tests #including two sibling files."""
environment = Directory('.', [
File('b.vert', '#version 140\n#include "a"\ncontent b\n#include "c"\n'),
File('a', 'content a\n'),
File('c', 'content c\n')])
glslc_args = ['-E', 'b.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "b.vert"
#line 0 "a"
content a
#line 2 "b.vert"
content b
#line 0 "c"
content c
#line 4 "b.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeTwoSiblings(expect.ValidObjectFile):
"""Tests #including two sibling files via full compilation."""
environment = Directory('.', [
File('b.vert',
"""#version 140
#include "a"
void bfun(){afun();}
#include "c"
"""),
File('a',
"""void afun(){}
#define BODY {}
"""),
File('c', 'void main() BODY\n')])
glslc_args = ['b.vert']
@inside_glslc_testsuite('Include')
class VerifyNestedIncludeAmongSiblings(expect.StdoutMatch):
"""Tests #include inside #included sibling files."""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b"\ncontent a\n'),
File('b', 'content b\n#include "c"\n'),
File('c', 'content c\n')])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b"
content b
#line 0 "c"
content c
#line 2 "b"
#line 2 "a.vert"
content a
"""
@inside_glslc_testsuite('Include')
class VerifyCompileNestedIncludeAmongSiblings(expect.ValidObjectFile):
"""Tests #include inside #included sibling files via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
#define BODY {}
#include "b"
void main(){cfun();}
"""),
File('b',
"""void bfun() BODY
#include "c"
"""),
File('c',
"""#define BF bfun()
void cfun(){BF;}
""")])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeSubdir(expect.StdoutMatch):
"""Tests #including a file from a subdirectory."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a1\n#include "subdir/a"\ncontent a2\n'),
Directory('subdir', [File('a', 'content suba\n')])])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a1
#line 0 "subdir/a"
content suba
#line 3 "a.vert"
content a2
"""
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeSubdir(expect.ValidObjectFile):
"""Tests #including a file from a subdirectory via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
#define BODY {}
#include "subdir/a"
void afun()BODY
"""),
Directory('subdir', [File('a', 'void main() BODY\n')])])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeDeepSubdir(expect.StdoutMatch):
"""Tests #including a file from a subdirectory nested a few levels down."""
environment = Directory('.', [
File('a.vert',
'#version 140\ncontent a1\n#include "dir/subdir/subsubdir/a"\ncontent a2\n'),
Directory('dir', [
Directory('subdir', [
Directory('subsubdir', [File('a', 'content incl\n')])])])])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a1
#line 0 "dir/subdir/subsubdir/a"
content incl
#line 3 "a.vert"
content a2
"""
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeDeepSubdir(expect.ValidObjectFile):
"""Tests #including a file from a subdirectory nested a few levels down
via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
#define BODY {}
#include "dir/subdir/subsubdir/a"
void afun()BODY
"""),
Directory('dir', [
Directory('subdir', [
Directory('subsubdir', [File('a', 'void main() BODY\n')])])])])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class TestWrongPoundVersionInIncludingFile(expect.ValidObjectFileWithWarning):
"""Tests that warning message for #version directive in the including file
has the correct filename."""
environment = Directory('.', [
File('a.vert', '#version 100000000\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-c', '-std=400', 'a.vert']
expected_warning = [
'a.vert: warning: (version, profile) forced to be (400, none),'
' while in source code it is (100000000, none)\n'
'1 warning generated.\n'
]
# TODO(antiagainst): now #version in included files results in an error.
# Fix this after #version in included files are supported.
# TODO(dneto): I'm not sure what the expected result should be.
@inside_glslc_testsuite('Include')
class TestWrongPoundVersionInIncludedFile(expect.ErrorMessage):
"""Tests that warning message for #version directive in the included file
has the correct filename."""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b.glsl"\nvoid main() {}'),
File('b.glsl', '#version 10000000\n')])
glslc_args = ['-E', 'a.vert']
expected_error = [
"b.glsl:1: error: '#version' : must occur first in shader\n",
'1 error generated.\n'
]
@inside_glslc_testsuite('Include')
class VerifyRelativeInclude(expect.StdoutMatch):
"""Tests #including a relative sibling."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
Directory('foo', [
File('b.glsl', '#include "c.glsl"\ncontent b\n'),
File('c.glsl', 'content c\n')
])])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyNestedRelativeInclude(expect.StdoutMatch):
"""Tests #including a relative child file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
Directory('foo', [
File('b.glsl', '#include "bar/c.glsl"\ncontent b\n'),
Directory('bar', [
File('c.glsl', 'content c\n')
])
])
])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/bar/c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeIncludeWithDashI(expect.StdoutMatch):
"""Tests #including a relative file from a -I directory."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "bar/b.glsl"\n'),
Directory('foo', [
Directory('bar', [
File('b.glsl', '#include "c.glsl"\ncontent b\n'),
]),
File('c.glsl', 'content c\n')
])
])
glslc_args = ['-E', 'a.vert', '-Ifoo']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/bar/b.glsl"
#line 0 "foo/c.glsl"
content c
#line 1 "foo/bar/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeOverridesDashI(expect.StdoutMatch):
"""Tests that relative includes override -I parameters."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
File('b.glsl', 'content base_b\n'),
Directory('foo', [
File('b.glsl', '#include "c.glsl"\ncontent b\n'),
File('c.glsl', 'content c\n')
])
])
glslc_args = ['-E', 'a.vert', '-Ifoo']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "b.glsl"
content base_b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeParent(expect.StdoutMatch):
"""Tests #including a parent file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
File('c.glsl', 'content c\n'),
Directory('foo', [
File('b.glsl', '#include "../c.glsl"\ncontent b\n')
])
])
glslc_args = ['-E', 'a.vert', '-Ifoo']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/../c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeNeighbourDirectory(expect.StdoutMatch):
"""Tests #including a relative file in a neighbour directory."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
Directory('foo', [
File('b.glsl', '#include "../bar/c.glsl"\ncontent b\n')
]),
Directory('bar', [
File('c.glsl', 'content c\n')
])
])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/../bar/c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeOnlyToSelf(expect.ErrorMessage):
"""Tests that a relative includes are only relative to yourself."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
File('c.glsl', 'content c\n'),
Directory('foo', [
File('b.glsl', '#include "c.glsl"\ncontent b\n')
]),
])
glslc_args = ['-E', 'a.vert']
expected_error = [
"foo/b.glsl:1: error: '#include' : "
'Cannot find or open include file. for header name: c.glsl\n',
'1 error generated.\n'
]
@inside_glslc_testsuite('Include')
class VerifyRelativeFromAbsolutePath(expect.StdoutMatch):
"""Tests that absolute files can relatively include."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
File('b.glsl', 'content b\n')
])
glslc_args = ['-E', SpecializedString('$directory/a.vert')]
expected_stdout = SpecializedString(
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "$directory/a.vert"
content a
#line 0 "$directory/b.glsl"
content b
#line 3 "$directory/a.vert"
""")
@inside_glslc_testsuite('Include')
class VerifyDashIAbsolutePath(expect.StdoutMatch):
"""Tests that -I parameters can be absolute paths."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
Directory('foo', {
File('b.glsl', 'content b\n')
})
])
glslc_args = ['-E', 'a.vert', '-I', SpecializedString('$directory/foo')]
expected_stdout = SpecializedString(
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "$directory/foo/b.glsl"
content b
#line 3 "a.vert"
""")

303
3rdparty/shaderc/glslc/test/line.py vendored Normal file
View File

@@ -0,0 +1,303 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from environment import Directory, File
from glslc_test_framework import inside_glslc_testsuite
@inside_glslc_testsuite('#line')
class TestPoundVersion310InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior of version 310
(specifying the line number for the next line) when we find a
#version 310 directive in the including file."""
environment = Directory('.', [
File('a.vert', '#version 310 es\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 310 es
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 3 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundVersion150InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior of version 150
(specifying the line number for itself) when we find a #version 150
directive in the including file."""
environment = Directory('.', [
File('a.vert', '#version 150\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 150
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b.glsl"
void main() { }
#line 2 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundVersionSyntaxErrorInIncludingFile(expect.ErrorMessageSubstr):
"""Tests that error message for #version directive has the correct
filename and line number."""
environment = Directory('.', [
File('a.vert', '#version abc def\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = [
"a.vert:1: error: '#version' : must occur first in shader\n",
"a.vert:1: error: '#version' : must be followed by version number\n",
"a.vert:1: error: '#version' : bad profile name; use es, core, or "
"compatibility\n",
]
# TODO(antiagainst): now #version in included files results in an error.
# Fix this after #version in included files are supported.
@inside_glslc_testsuite('#line')
class TestPoundVersion310InIncludedFile(expect.ErrorMessageSubstr):
"""Tests that #line directives follows the behavior of version 310
(specifying the line number for the next line) when we find a
#version 310 directive in the included file."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\nvoid main() {}'),
File('b.glsl', '#version 310 es\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = [
"b.glsl:1: error: '#version' : must occur first in shader\n"
]
# TODO(antiagainst): now #version in included files results in an error.
# Fix this after #version in included files are supported.
@inside_glslc_testsuite('#line')
class TestPoundVersion150InIncludedFile(expect.ErrorMessageSubstr):
"""Tests that #line directives follows the behavior of version 150
(specifying the line number for itself) when we find a #version 150
directive in the included file."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\nvoid main() {}'),
File('b.glsl', '#version 150\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = [
"b.glsl:1: error: '#version' : must occur first in shader\n"
]
@inside_glslc_testsuite('#line')
class TestSpaceAroundPoundVersion310InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that spaces around #version & #include directive doesn't matter."""
environment = Directory('.', [
File('a.vert', '\t # \t version 310 \t es\n#\tinclude "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 310 es
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 3 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestSpaceAroundPoundVersion150InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that spaces around #version & #include directive doesn't matter."""
environment = Directory('.', [
File('a.vert', ' \t #\t\tversion\t 150\t \n# include \t "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 150
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b.glsl"
void main() { }
#line 2 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundLineWithForcedVersion310(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior for the version
specified via command-line."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', '-std=310es', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 2 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundLineWithForcedVersion150(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior for the version
specified via command-line."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', '-std=150', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b.glsl"
void main() { }
#line 1 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundLineWithForcedDifferentVersion(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior for the version
specified via command-line, even if there is a version specification
in the source code."""
environment = Directory('.', [
File('a.vert', '#version 150\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', '-std=310es', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 150
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 3 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestErrorsFromMultipleFiles(expect.ErrorMessage):
"""Tests that errors from different files have the correct error message
filename specification."""
including_file = '''#version 310 es
#include "error.glsl"
int no_return() {}
#include "main.glsl"
'''
environment = Directory('.', [
File('a.vert', including_file),
File('error.glsl', 'int unknown_identifier(int) { return a; }'),
File('main.glsl', 'void main() {\n int b = 1.5;\n}')])
glslc_args = ['-c', 'a.vert']
expected_error = [
"error.glsl:1: error: 'a' : undeclared identifier\n",
"error.glsl:1: error: 'return' : type does not match, or is not "
"convertible to, the function's return type\n",
"a.vert:3: error: '' : function does not return a value: no_return\n",
"main.glsl:2: error: '=' : cannot convert from ' const float' to "
"' temp highp int'\n",
"4 errors generated.\n"]
@inside_glslc_testsuite('#line')
class TestExplicitPoundLineWithPoundInclude(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line works correctly in the presence of #include (which
itself will generate some #line directives."""
including_file = '''#version 310 es
#line 10000 "injected.glsl"
int plus1(int a) { return a + 1; }
#include "inc.glsl"
int plus2(int a) { return a + 2; }
#line 55555
#include "main.glsl"
'''
environment = Directory('.', [
File('a.vert', including_file),
File('inc.glsl', 'int inc(int a) { return a + 1; }'),
File('main.glsl', 'void main() {\n gl_Position = vec4(1.);\n}')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = '''#version 310 es
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 10000 "injected.glsl"
int plus1(int a) { return a + 1; }
#line 1 "inc.glsl"
int inc(int a) { return a + 1; }
#line 10002 "injected.glsl"
int plus2(int a) { return a + 2; }
#line 55555
#line 1 "main.glsl"
void main() {
gl_Position = vec4(1.);
}
#line 55556 "injected.glsl"
'''

View File

@@ -0,0 +1,311 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
@inside_glslc_testsuite('ErrorMessages')
class MultipleErrors(expect.ErrorMessage):
"""Test Multiple error messages generated."""
shader = FileShader('#version 140\nint main() {}', '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: 'int' : entry point cannot return a value\n",
shader, ":2: error: '' : function does not return a value: main\n",
'2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class OneError(expect.ErrorMessage):
"""Tests that only one error message is generated correctly."""
shader = FileShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""", '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '' : function does not return a value: a\n",
'1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class ManyLineError(expect.ErrorMessage):
"""Tests that only one error message is generated correctly."""
shader = FileShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""", '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ":12: error: '' : function does not return a value: a\n",
'1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class GlobalWarning(expect.WarningMessage):
"""Tests that a warning message without file/line number is emitted."""
shader = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (400, none),'
' while in source code it is (550, none)\n1 warning generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedGlobalWarning(expect.SuccessfulReturn):
"""Tests that warning messages without file/line numbers are suppressed
with -w."""
shader = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader, '-w']
@inside_glslc_testsuite('ErrorMessages')
class GlobalWarningAsError(expect.ErrorMessage):
"""Tests that with -Werror an error warning message without file/line
number is emitted instead of a warning."""
shader = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader, '-Werror']
expected_error= [
shader, ': error: (version, profile) forced to be (400, none),'
' while in source code it is (550, none)\n1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningOnLine(expect.WarningMessage):
"""Tests that a warning message with a file/line number is emitted."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader]
expected_warning = [
shader, ':2: warning: attribute deprecated in version 130; ',
'may be removed in future release\n1 warning generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedWarningOnLine(expect.SuccessfulReturn):
"""Tests that a warning message with a file/line number is suppressed in the
presence of -w."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-w']
@inside_glslc_testsuite('ErrorMessages')
class WarningOnLineAsError(expect.ErrorMessage):
"""Tests that with -Werror an error message with a file/line
number is emitted instead of a warning."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-Werror']
expected_error = [
shader, ':2: error: attribute deprecated in version 130; ',
'may be removed in future release\n1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningAndError(expect.ErrorMessage):
"""Tests that both warnings and errors are emitted together."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
int main() {
}
""", '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ':2: warning: attribute deprecated in version 130; ',
'may be removed in future release\n',
shader, ":3: error: 'int' : entry point cannot return a value\n",
shader, ":3: error: '' : function does not return a value: main\n",
'1 warning and 2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedWarningAndError(expect.ErrorMessage):
"""Tests that only warnings are suppressed in the presence of -w."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
int main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-w']
expected_error = [
shader, ":3: error: 'int' : entry point cannot return a value\n",
shader, ":3: error: '' : function does not return a value: main\n",
'2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningAsErrorAndError(expect.ErrorMessage):
"""Tests that with -Werror an warnings and errors are emitted as errors."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
int main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-Werror']
expected_error = [
shader, ':2: error: attribute deprecated in version 130; ',
'may be removed in future release\n',
shader, ":3: error: 'int' : entry point cannot return a value\n",
shader, ":3: error: '' : function does not return a value: main\n",
'3 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class StdinErrorMessages(expect.StdoutMatch, expect.StderrMatch):
"""Tests that error messages using input from stdin are correct."""
shader = StdinShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""")
glslc_args = ['-c', '-fshader-stage=vertex', shader]
expected_stdout = ''
expected_stderr = [
"<stdin>:2: error: '' : function does not return a value: a\n",
'1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningAsErrorMultipleFiles(expect.ErrorMessage):
"""Tests that with -Werror multiple files emit errors instead of warnings.
"""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
shader2 = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader, '-Werror', shader2]
expected_error = [
shader, ':2: error: attribute deprecated in version 130; ',
'may be removed in future release\n',
shader2, ': error: (version, profile) forced to be (400, none),'
' while in source code it is (550, none)\n',
'2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedWarningAsError(expect.SuccessfulReturn):
"""Tests that nothing is returned in the presence of -w -Werror."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-w', '-Werror']
@inside_glslc_testsuite('ErrorMessages')
class MultipleSuppressed(expect.SuccessfulReturn):
"""Tests that multiple -w arguments are supported."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-w', '-c', shader, '-w', '-w', '-w']
@inside_glslc_testsuite('ErrorMessages')
class MultipleSuppressedFiles(expect.SuccessfulReturn):
"""Tests that -w suppresses warnings from all files."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
shader2 = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-w', '-c', shader, shader2]

View File

@@ -0,0 +1,365 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDNoArg(expect.ErrorMessage):
"""Tests -D without macroname."""
glslc_args = ['-D']
expected_error = [
"glslc: error: argument to '-D' is missing\n",
'glslc: error: no input files\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDXeqY(expect.ValidObjectFile):
"""Tests -DX=Y."""
shader = FileShader('#version 150\nvoid main(){X=vec4(1.);}', '.vert')
glslc_args = ['-c', '-DX=gl_Position', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDXeq(expect.ValidObjectFile):
"""Tests -DX=."""
shader = FileShader('#version 150\nvoid main(){X}', '.vert')
glslc_args = ['-c', '-DX=', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDX(expect.ValidObjectFile):
"""Tests -DX."""
shader = FileShader('#version 150\nvoid main(){X}', '.vert')
glslc_args = ['-c', '-DX', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDeq(expect.ErrorMessage):
"""Tests -D=.
This is actually allowed by clang, though the resulting #define
causes a preprocessing error.
"""
shader = FileShader('#version 150\nvoid main(){}', '.vert')
glslc_args = ['-c', '-D=', shader]
# TODO(antiagainst): figure out what should we report as the line number
# for errors in predefined macros and fix here.
expected_error = [
"<command line>:2: error: '#define' : must be followed by macro name\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestMultipleDashCapD(expect.ValidObjectFile):
"""Tests multiple -D occurrences."""
shader = FileShader('#version 150\nvoid main(){X Y a=Z;}', '.vert')
glslc_args = ['-c', '-DX', '-DY=int', '-DZ=(1+2)', shader]
@inside_glslc_testsuite('OptionCapD')
class TestMultipleDashCapDOfSameName(expect.ValidObjectFile):
"""Tests multiple -D occurrences with same macro name."""
shader = FileShader('#version 150\nvoid main(){X Y a=Z;}', '.vert')
glslc_args = ['-c', '-DX=main', '-DY=int', '-DZ=(1+2)', '-DX', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDGL_(expect.ErrorMessage):
"""Tests that we cannot -D macros beginning with GL_."""
shader = FileShader('#version 150\nvoid main(){}', '.vert')
glslc_args = ['-DGL_ES=1', shader]
expected_error = [
"glslc: error: names beginning with 'GL_' cannot be "
'defined: -DGL_ES=1\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDReservedMacro(expect.WarningMessage):
"""Tests that we cannot -D GLSL's predefined macros."""
shader = FileShader('#version 150\nvoid main(){}', '.vert')
# Consecutive underscores are banned anywhere in the name.
glslc_args = [
'-D__LINE__=1', '-Dmid__dle', '-Dend__', '-D_single_is_valid_', shader]
w = 'glslc: warning: names containing consecutive underscores are reserved: '
expected_warning = [w, '-D__LINE__=1\n', w, '-Dmid__dle\n', w, '-Dend__\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithVersion(expect.ErrorMessage):
"""Tests -D works well when #version is present."""
shader = FileShader(
"""#version 310 es
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', shader]
expected_error = [
shader, ":3: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithCommentBeforeVersion(expect.ErrorMessage):
"""Tests -D works well with #version preceded by comments."""
shader = FileShader(
"""// comment 1
/*
* comment 2
*/
#version 450 core
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', shader]
expected_error = [
shader, ":7: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithCommentAfterVersion(expect.ErrorMessage):
"""Tests -D works well with #version followed by comments."""
shader = FileShader(
"""
#version 150 core /*
comment
*/
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', shader]
expected_error = [
shader, ":7: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashStd(expect.ErrorMessageSubstr):
"""Tests -D works well with -std."""
shader = FileShader('void main(){X}\nvoid foo(){Y}', '.vert')
glslc_args = ['-DX=', '-DY=return 3;', '-std=310es', shader]
expected_error_substr = [
shader, ":2: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashStdAndVersion(expect.ErrorMessage):
"""Tests -D works well with both -std and #version."""
shader = FileShader(
"""#version 310 es
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', '-std=450core', shader]
expected_error = [
shader, ': warning: (version, profile) forced to be (450, ',
'core), while in source code it is (310, es)\n',
shader, ":3: error: 'return' : void function cannot return a value\n",
'1 warning and 1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashStdAndVersionAndComments(expect.ErrorMessage):
"""Tests -D works well with -std, #version, and comments around it."""
shader = FileShader(
"""// comment before
#version 310 es /* comment after
*/
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', '-std=450core', shader]
expected_error = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n',
shader, ":7: error: 'return' : void function cannot return a value\n",
'1 warning and 1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashE(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E outputs expanded -D macros."""
shader = FileShader(
"""
void main(){Y}
""", '.vert')
glslc_args = ['-DY=return 3;', '-E', '-std=450core', shader]
expected_stdout = [
"""
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEIfDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX #ifdefs correctly."""
shader = FileShader(
"""
#ifdef X
void f() { }
#else
void f() { int x; }
#endif
void main(){ return 3; }
""", '.vert')
glslc_args = ['-DX', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEIfNDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX #ifndefs correctly."""
shader = FileShader(
"""
#ifndef X
void f() { }
#else
void f() { int x; }
#endif
void main(){ return 3; }
""", '.vert')
glslc_args = ['-DX', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { int x; }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEEqIfDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX= #ifdefs correctly."""
shader = FileShader(
"""
#ifdef X
void f() { }
#else
void f() { int x; }
#endif
void main() { return 3; }
""", '.vert')
glslc_args = ['-DX=', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEEqIfNDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX= #ifndefs correctly."""
shader = FileShader(
"""
#ifndef X
void f() { }
#else
void f() { int x; }
#endif
void main(){ return 3; }
""", '.vert')
glslc_args = ['-DX=', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { int x; }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEFunctionMacro(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -D function macros correctly."""
shader = FileShader(
"""
void main(){ return FOO(3); }
""", '.vert')
glslc_args = ['-DFOO(x)=(2*x+1)*x*x', '-E', '-std=450core', shader]
expected_stdout = [
"""
void main() { return(2 * 3 + 1) * 3 * 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashENestedMacro(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes referencing -D options correctly."""
shader = FileShader(
"""
void main() { return X; }
""", '.vert')
glslc_args = ['-DY=4', '-DX=Y', '-E', '-std=450core', shader]
expected_stdout = [
"""
void main() { return 4; }
"""]

View File

@@ -0,0 +1,348 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
@inside_glslc_testsuite('OptionCapE')
class TestDashCapENoDefs(expect.StdoutMatch):
"""Tests -E without any defines."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEGlslFileAccepted(expect.StdoutMatch):
"""Tests -E if we provide a .glsl file without an explicit stage."""
shader = FileShader('#version 140\nvoid main(){}', '.glsl')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapESingleDefine(expect.StdoutMatch):
"""Tests -E with command-line define."""
shader = FileShader('#version 140\nvoid main(){ int a = X; }', '.vert')
expected_stdout = '#version 140\nvoid main() { int a = 4; }\n'
glslc_args = ['-DX=4', '-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEExpansion(expect.StdoutMatch):
"""Tests -E with macro expansion."""
shader = FileShader('''#version 140
#define X 4
void main() {
int a = X;
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
int a = 4;
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEFunctionMacro(expect.StdoutMatch):
"""Tests -E with function-style macro expansion."""
shader = FileShader('''#version 140
#define X(A) 4+A
void main() {
int a = X(1);
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
int a = 4 + 1;
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEPragma(expect.StdoutMatch):
"""Tests -E to make sure pragmas get retained."""
shader = FileShader('''#version 140
#pragma optimize(off)
void main() {
}
''', '.vert')
expected_stdout = '''#version 140
#pragma optimize(off)
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEExtension(expect.StdoutMatch):
"""Tests -E to make sure extensions get retained."""
shader = FileShader('''#version 140
#extension foo: require
void main() {
}
''', '.vert')
expected_stdout = '''#version 140
#extension foo : require
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapELine(expect.StdoutMatch):
"""Tests -E to make sure line numbers get retained."""
shader = FileShader('''#version 140
#define X 4
#line X
#line 2 3
void main() {
}
''', '.vert')
expected_stdout = '''#version 140
#line 4
#line 2 3
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEError(expect.ErrorMessage):
"""Tests -E to make sure #errors get retained."""
shader = FileShader('''#version 140
#if 1
#error This is an error
#endif
void main() {
}
''', '.vert')
expected_error = [
shader, ':3: error: \'#error\' : This is an error\n',
'1 error generated.\n']
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEStdin(expect.StdoutMatch):
"""Tests to make sure -E works with stdin."""
shader = StdinShader('''#version 140
void main() {
}
''')
expected_stdout = '''#version 140
void main() {
}
'''
glslc_args = ['-E', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEStdinDoesNotRequireShaderStage(expect.StdoutMatch):
"""Tests to make sure -E works with stdin even when no shader-stage
is specified."""
shader = StdinShader('''#version 140
void main() {
}
''')
expected_stdout = '''#version 140
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEMultipleFiles(expect.StdoutMatch):
"""Tests to make sure -E works with multiple files."""
shader = StdinShader('''#version 140
void main() {
}
''')
shader2 = FileShader('''#version 140
void function() {
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
}
#version 140
void function() {
}
'''
glslc_args = ['-E', '-fshader-stage=vertex', shader, shader2]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEMultipleFilesWithoutStage(expect.StdoutMatch):
"""Tests to make sure -E works with multiple files even if we do not
specify a stage."""
shader = StdinShader('''#version 140
void main() {
}
''')
shader2 = FileShader('''#version 140
void function() {
}
''', '.glsl')
expected_stdout = '''#version 140
void main() {
}
#version 140
void function() {
}
'''
glslc_args = ['-E', shader, shader2]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEOutputFile(expect.SuccessfulReturn, expect.ValidFileContents):
"""Tests to make sure -E works with output files."""
shader = FileShader('''#version 140
void function() {
}
''', '.vert')
expected_file_contents = '''#version 140
void function() {
}
'''
target_filename = 'foo'
glslc_args = ['-E', shader, '-ofoo']
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEWithS(expect.StdoutMatch):
"""Tests -E in the presence of -S."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', '-S', shader]
@inside_glslc_testsuite('OptionCapE')
class TestMultipileDashCapE(expect.StdoutMatch):
"""Tests that using -E multiple times works."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', '-E', shader, '-E']
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEAfterFile(expect.StdoutMatch):
"""Tests that using -E after the filename also works."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = [shader, '-E']
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEWithDashC(expect.StdoutMatch):
"""Tests to make sure -E works in the presence of -c."""
shader = FileShader('''#version 140
void main() {
}
''', '.vert')
shader2 = FileShader('''#version 140
void function() {
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
}
#version 140
void function() {
}
'''
glslc_args = ['-E', '-c', shader, shader2]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEWithPPErrors(expect.ErrorMessage):
"""Tests to make sure -E outputs error messages for preprocessing errors."""
shader = FileShader('''#version 310 es
#extension s enable // missing :
#defin A // Bad define
#if X // In glsl X must be defined for X to work.
// Lack of endif.
void main() {
}
''', '.vert')
expected_error = [
shader, ':2: error: \'#extension\' : \':\' missing after extension',
' name\n',
shader, ':3: error: \'#\' : invalid directive: defin\n',
shader, ':4: error: \'preprocessor evaluation\' : undefined macro in',
' expression not allowed in es profile X\n',
shader, ':8: error: \'\' : missing #endif\n',
'4 errors generated.\n']
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEStdinErrors(expect.ErrorMessage):
"""Tests that -E outputs error messages correctly for stdin input."""
shader = StdinShader('''#version 310 es
#extension s enable // missing :
void main() {
}
''')
expected_error = [
'<stdin>:2: error: \'#extension\' : \':\' missing after extension',
' name\n',
'1 error generated.\n']
glslc_args = ['-E', shader]

View File

@@ -0,0 +1,754 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
import os.path
import sys
from environment import File, Directory
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
from glslc_test_framework import GlslCTest
MINIMAL_SHADER = '#version 140\nvoid main() {}'
EMPTY_SHADER_IN_CURDIR = Directory('.', [File('shader.vert', MINIMAL_SHADER)])
EMPTY_SHADER_IN_SUBDIR = Directory('subdir',
[File('shader.vert', MINIMAL_SHADER)])
def process_test_specified_dependency_info_rules(test_specified_rules):
"""A helper function to process the expected dependency info rules
specified in tests before checking the actual dependency rule output.
This is required because the filename and path of temporary files created
through FileShader is unknown at the time the expected dependency info rules
are declared.
Note this function process the given rule list in-place.
"""
for rule in test_specified_rules:
# If the 'target' value is not a hard-coded file name but a
# FileShader, we need its full path, append extension to it and
# strip the directory component from it to get the complete target
# name.
if isinstance(rule['target'], FileShader):
rule['target'] = rule['target'].filename
if 'target_extension' in rule:
if rule['target_extension'] is not None:
rule['target'] = rule['target'] + rule['target_extension']
rule.pop('target_extension')
rule['target'] = os.path.basename(rule['target'])
# The dependency set may have FileShader too, we need to replace
# them with their absolute paths.
dependent_file_name_set = set()
for dependent_file in rule['dependency']:
if isinstance(dependent_file, FileShader):
dependent_file_name_set.add(dependent_file.filename)
else:
dependent_file_name_set.add(dependent_file)
rule['dependency'] = dependent_file_name_set
def parse_text_rules(text_lines):
""" A helper function to read text lines and construct and returns a list of
dependency rules which can be used for comparison.
The list is built with the text order. Each rule is described in the
following way:
{'target': <target name>, 'dependency': <set of dependent filenames>}
"""
rules = []
for line in text_lines:
if line.strip() == "":
continue
rule = {'target': line.split(': ')[0].strip(),
'dependency': set(line.split(': ')[-1].strip().split(' '))}
rules.append(rule)
return rules
class DependencyInfoStdoutMatch(GlslCTest):
"""Mixin class for tests that can expect dependency info in Stdout.
To mix in this class, the subclass needs to provide
dependency_rules_expected as a list of dictionaries, each dictionary
describes one expected make rule for a target file. A expected rule should
be specified in the following way:
rule = {'target': <target name>,
'target_extension': <.spv, .spvasm or None>,
'dependency': <dependent file names>}
The 'target_extension' field is optional, its value will be appended to
'target' to get complete target name.
And the list 'dependency_rules_expected' is a list of such rules and the
order of the rules does matter.
"""
def check_stdout_dependency_info(self, status):
if not status.stdout:
return False, 'Expect dependency rules on stdout'
if sys.version_info[0] == 2:
rules = parse_text_rules(status.stdout.decode('utf-8').split('\n'))
elif sys.version_info[0] == 3:
rules = parse_text_rules(str(status.stdout,
encoding='utf-8',
errors='ignore').split('\n'))
process_test_specified_dependency_info_rules(
self.dependency_rules_expected)
if self.dependency_rules_expected != rules:
return False, ('Incorrect dependency info:\n{ac_rules}\n'
'Expected:\n{ex_rules}\n'
'Stdout output:\n{ac_stdout}\n'.format(
ac_rules=rules,
ex_rules=self.dependency_rules_expected,
ac_stdout=status.stdout))
return True, ''
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathNoInclude(DependencyInfoStdoutMatch):
"""Tests -M with single input file which doesn't contain #include and is
represented in relative path.
e.g. glslc -M shader.vert
=> shader.vert.spv: shader.vert
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', 'shader.vert']
dependency_rules_expected = [{'target': "shader.vert.spv",
'dependency': {"shader.vert"}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputAbsolutePathNoInclude(DependencyInfoStdoutMatch):
"""Tests -M with single input file which doesn't contain #include and is
represented in absolute path.
e.g. glslc -M /usr/local/shader.vert
=> shader.vert.spv: /usr/local/shader.vert
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-M', shader]
dependency_rules_expected = [{'target': shader,
'target_extension': '.spv',
'dependency': {shader}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithInclude(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which does contain #include and is
represented in relative path.
e.g. glslc -M a.vert
=> a.vert.spv: a.vert b.vert
"""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b.vert"\nvoid main(){}\n'),
File('b.vert', 'void foo(){}\n'),
])
glslc_args = ['-M', 'a.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert', 'b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithIncludeSubdir(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which does #include another file in a
subdirectory of current directory and is represented in relative path.
e.g. glslc -M a.vert
=> a.vert.spv: a.vert include/b.vert
"""
environment = Directory('.', [
File('a.vert', ('#version 140\n#include "include/b.vert"'
'\nvoid main(){}\n')),
Directory('include', [File('b.vert', 'void foo(){}\n')]),
])
glslc_args = ['-M', 'a.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert', 'include/b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithDashI(DependencyInfoStdoutMatch):
"""Tests -M with single input file works with -I option. The #include
directive does not specify 'include/' for the file to be include.
e.g. glslc -M a.vert -I include
=> a.vert.spv: a.vert include/b.vert
"""
environment = Directory('.', [
File('a.vert', ('#version 140\n#include "b.vert"'
'\nvoid main(){}\n')),
Directory('include', [File('b.vert', 'void foo(){}\n')]),
])
glslc_args = ['-M', 'a.vert', '-I', 'include']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert', 'include/b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithNestedInclude(
DependencyInfoStdoutMatch):
"""Tests -M with single input file under nested #include case. The input file
is represented in relative path.
e.g. glslc -M a.vert
=> a.vert.spv: a.vert b.vert c.vert
"""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b.vert"\nvoid main(){}\n'),
File('b.vert', 'void foo(){}\n#include "c.vert"\n'),
File('c.vert', 'void bar(){}\n'),
])
glslc_args = ['-M', 'a.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency':
{'a.vert', 'b.vert', 'c.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMultipleInputRelativePathNoInclude(
DependencyInfoStdoutMatch):
"""Tests -M with multiple input file which don't contain #include and are
represented in relative paths.
e.g. glslc -M a.vert b.vert
=> a.vert.spv: a.vert
b.vert.spv: b.vert
"""
environment = Directory('.', [
File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER),
])
glslc_args = ['-M', 'a.vert', 'b.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert'}},
{'target': 'b.vert.spv',
'dependency': {'b.vert'}}, ]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMultipleInputAbsolutePathNoInclude(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which doesn't contain #include and is
represented in absolute path.
e.g. glslc -M /usr/local/a.vert /usr/local/b.vert
=> a.vert.spv: /usr/local/a.vert
b.vert.spv: /usr/local/b.vert
"""
shader_a = FileShader(MINIMAL_SHADER, '.vert')
shader_b = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-M', shader_a, shader_b]
dependency_rules_expected = [{'target': shader_a,
'target_extension': '.spv',
'dependency': {shader_a}},
{'target': shader_b,
'target_extension': '.spv',
'dependency': {shader_b}}, ]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDashCapMT(DependencyInfoStdoutMatch):
"""Tests -MT works with -M. User can specify the target object name in the
generated dependency info.
e.g. glslc -M shader.vert -MT target
=> target: shader.vert
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', 'shader.vert', '-MT', 'target']
dependency_rules_expected = [{'target': 'target',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMInputAbsolutePathWithInclude(DependencyInfoStdoutMatch):
"""Tests -M have included files represented in absolute paths when the input
file is represented in absolute path.
E.g. Assume a.vert has '#include "b.vert"'
glslc -M /usr/local/a.vert
=> a.vert.spv: /usr/local/a.vert /usr/local/b.vert
"""
environment = Directory('.', [File('b.vert', 'void foo(){}\n')])
shader_main = FileShader(
'#version 140\n#include "b.vert"\nvoid main(){}\n', '.vert')
glslc_args = ['-M', shader_main]
dependency_rules_expected = [{
'target': shader_main,
'target_extension': '.spv',
'dependency': {shader_main}
# The dependency here is not complete. we can not get the absolute path
# of b.vert here. It will be added in check_stdout_dependency_info()
}]
def check_stdout_dependency_info(self, status):
# Add the absolute path of b.vert to the dependency set
self.dependency_rules_expected[0]['dependency'].add(os.path.dirname(
self.shader_main.filename) + '/b.vert')
return DependencyInfoStdoutMatch.check_stdout_dependency_info(self,
status)
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputAbsolutePathWithIncludeSubdir(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which does #include another file in a
subdirectory of current directory and is represented in absolute path.
e.g. glslc -M /usr/local/a.vert
=> a.vert.spv: /usr/local/a.vert /usr/local/include/b.vert
"""
environment = Directory('.', [
Directory('include', [File('b.vert', 'void foo(){}\n')]),
])
shader_main = FileShader('#version 140\n#include "include/b.vert"\n',
'.vert')
glslc_args = ['-M', shader_main]
dependency_rules_expected = [{
'target': shader_main,
'target_extension': '.spv',
'dependency': {shader_main}
# The dependency here is not complete. we can not get the absolute
# path of include/b.vert here. It will be added in
# check_stdout_dependency_info()
}]
def check_stdout_dependency_info(self, status):
# Add the absolute path of include/b.vert to the dependency set
self.dependency_rules_expected[0]['dependency'].add(os.path.dirname(
self.shader_main.filename) + '/include/b.vert')
return DependencyInfoStdoutMatch.check_stdout_dependency_info(self,
status)
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMOverridesOtherModes(DependencyInfoStdoutMatch):
"""Tests -M overrides other compiler mode options, includeing -E, -c and -S.
"""
environment = Directory('.', [
File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER),
])
glslc_args = ['-M', '-E', '-c', '-S', 'a.vert', 'b.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert'}},
{'target': 'b.vert.spv',
'dependency': {'b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMEquivalentToCapM(DependencyInfoStdoutMatch):
"""Tests that -MM behaves as -M.
e.g. glslc -MM shader.vert
=> shader.vert.spv: shader.vert
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MM', 'shader.vert']
dependency_rules_expected = [{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMImpliesDashCapE(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -M implies -E, a .glsl file without an explict stage should
not generate an error.
e.g. glslc -M shader.glsl
=> shader.spv: shader.glsl
<no error message should be generated>
"""
environment = Directory('.', [File('shader.glsl', MINIMAL_SHADER)])
glslc_args = ['-M', 'shader.glsl']
dependency_rules_expected = [{'target': 'shader.spv',
'dependency': {'shader.glsl'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMImpliesDashW(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -M implies -w, a deprecated attribute should not generate
warning message.
e.g. glslc -M shader.vert
=> shader.vert.spv: shader.vert
<no warning message should be generated>
"""
environment = Directory('.', [File(
'shader.vert', """#version 400
layout(location=0) attribute float x;
void main() {}""")])
glslc_args = ['-M', 'shader.vert']
dependency_rules_expected = [{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMImpliesDashCapE(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -M implies -E, a .glsl file without an explict stage should
not generate an error.
e.g. glslc -MM shader.glsl
=> shader.spv: shader.glsl
<no error message should be generated>
"""
environment = Directory('.', [File('shader.glsl', MINIMAL_SHADER)])
glslc_args = ['-MM', 'shader.glsl']
dependency_rules_expected = [{'target': 'shader.spv',
'dependency': {'shader.glsl'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMImpliesDashW(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -MM implies -w, a deprecated attribute should not generate
warning message.
e.g. glslc -MM shader.vert
=> shader.vert.spv: shader.vert
<no warning message should be generated>
"""
environment = Directory('.', [File(
'shader.vert', """
#version 400
layout(location = 0) attribute float x;
void main() {}""")])
glslc_args = ['-MM', 'shader.vert']
dependency_rules_expected = [{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMD(expect.ValidFileContents, expect.ValidNamedObjectFile):
"""Tests that -MD generates dependency info file and compilation output.
e.g. glslc -MD shader.vert
=> <a.spv: valid SPIR-V object file>
=> <shader.vert.spv.d: dependency info>
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', 'shader.vert']
expected_object_filenames = ('a.spv', )
target_filename = 'shader.vert.spv.d'
expected_file_contents = ['shader.vert.spv: shader.vert\n']
class DependencyInfoFileMatch(GlslCTest):
"""Mixin class for tests that can expect dependency info files.
To mix in this class, subclasses need to provide dependency_info_filenames
and dependency_info_files_expected_contents which are two lists.
list dependency_info_filenames contains the dependency info file names and
list dependency_info_files_expected_contents contains the expected matching
dependency rules.
The item order of the two lists should match, which means:
dependency_info_files_expected_contents[i] should describe the
dependency rules saved in dependency_info_filenames[i]
The content of each dependency info file is described in same 'list of dict'
structure explained in class DependencyInfoStdoutMatch's doc string.
"""
def check_dependency_info_files(self, status):
dep_info_files = \
[os.path.join(status.directory,
f) for f in self.dependency_info_filenames]
for i, df in enumerate(dep_info_files):
if not os.path.isfile(df):
return False, 'Cannot find file: ' + df
try:
with open(df, 'r') as dff:
content = dff.read()
rules = parse_text_rules(content.split('\n'))
process_test_specified_dependency_info_rules(
self.dependency_info_files_expected_contents[i])
if self.dependency_info_files_expected_contents[
i] != rules:
return False, (
'Incorrect dependency info:\n{ac_rules}\n'
'Expected:\n{ex_rules}\n'
'Incorrect file output:\n{ac_out}\n'
'Incorrect dependency info file:\n{ac_file}\n'.format(
ac_rules=rules,
ex_rules=self.dependency_rules_expected,
ac_stdout=content,
ac_file=df))
except IOError:
return False, ('Could not open dependency info file ' + df +
' for reading')
return True, ''
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMWorksWithDashO(DependencyInfoFileMatch):
"""Tests -M works with -o option. When user specifies an output file name
with -o, the dependency info should be dumped to the user specified output
file.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', 'shader.vert', '-o', 'dep_info']
dependency_info_filenames = ('dep_info', )
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append(
[{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}])
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDMultipleFile(expect.ValidNamedObjectFile,
DependencyInfoFileMatch):
"""Tests that -MD generates dependency info file for multiple files.
e.g. glslc -MD a.vert b.vert -c
=> <a.vert.spv: valid SPIR-V object file>
=> <a.vert.spv.d: dependency info: "a.vert.spv: a.vert">
=> <b.vert.spv: valid SPIR-V object file>
=> <b.vert.spv.d: dependency info: "b.vert.spv: b.vert">
"""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-c']
expected_object_filenames = ('a.vert.spv', 'b.vert.spv', )
dependency_info_filenames = ['a.vert.spv.d', 'b.vert.spv.d']
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append([{'target': 'a.vert.spv',
'dependency': {'a.vert'}}
])
dependency_info_files_expected_contents.append([{'target': 'b.vert.spv',
'dependency': {'b.vert'}}
])
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDMultipleFilePreprocessingOnlyMode(expect.StdoutMatch,
DependencyInfoFileMatch):
"""Tests that -MD generates dependency info file for multiple files in
preprocessing only mode.
e.g. glslc -MD a.vert b.vert -E
=> stdout: preprocess result of a.vert and b.vert
=> <a.vert.spv.d: dependency info: "a.vert.spv: a.vert">
=> <b.vert.spv.d: dependency info: "b.vert.spv: b.vert">
"""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-E']
dependency_info_filenames = ['a.vert.spv.d', 'b.vert.spv.d']
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append([{'target': 'a.vert.spv',
'dependency': {'a.vert'}}
])
dependency_info_files_expected_contents.append([{'target': 'b.vert.spv',
'dependency': {'b.vert'}}
])
expected_stdout = ("#version 140\nvoid main() { }\n"
"#version 140\nvoid main() { }\n")
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDMultipleFileDisassemblyMode(expect.ValidNamedAssemblyFile,
DependencyInfoFileMatch):
"""Tests that -MD generates dependency info file for multiple files in
disassembly mode.
e.g. glslc -MD a.vert b.vert -S
=> <a.vert.spvasm: valid SPIR-V assembly file>
=> <a.vert.spvasm.d: dependency info: "a.vert.spvasm: a.vert">
=> <b.vert.spvasm: valid SPIR-V assembly file>
=> <b.vert.spvasm.d: dependency info: "b.vert.spvasm: b.vert">
"""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-S']
expected_assembly_filenames = ('a.vert.spvasm', 'b.vert.spvasm', )
dependency_info_filenames = ['a.vert.spvasm.d', 'b.vert.spvasm.d']
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append([{'target': 'a.vert.spvasm',
'dependency': {'a.vert'}}
])
dependency_info_files_expected_contents.append([{'target': 'b.vert.spvasm',
'dependency': {'b.vert'}}
])
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMT(expect.ValidFileContents, expect.ValidNamedObjectFile):
"""Tests that -MT generates dependency info file with specified target label.
e.g. glslc -MD shader.vert -MT target_label
=> <a.spv: valid SPIR-V object file>
=> <shader.vert.spv.d: dependency info: "target_label: shader.vert">
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', 'shader.vert', '-MT', 'target_label']
expected_object_filenames = ('a.spv', )
target_filename = 'shader.vert.spv.d'
expected_file_contents = ['target_label: shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMF(expect.ValidFileContents, expect.ValidNamedObjectFile):
"""Tests that -MF dumps dependency info into specified file.
e.g. glslc -MD shader.vert -MF dep_file
=> <a.spv: valid SPIR-V object file>
=> <dep_file: dependency info: "shader.vert.spv: shader.vert">
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', 'shader.vert', '-MF', 'dep_file']
expected_object_filenames = ('a.spv', )
target_filename = 'dep_file'
expected_file_contents = ['shader.vert.spv: shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDSpecifyOutputFileName(expect.ValidFileContents,
expect.ValidNamedObjectFile):
"""Tests that -MD has the default dependency info file name and target
label correct when -o <output_file_name> appears in the command line.
The default dependency info file name and target label should be deduced
from the linking-disabled compilation output.
e.g. glslc -MD subdir/shader.vert -c -o output
=> <./output: valid SPIR-V object file>
=> <./output.d: dependency info: "output: shader.vert">
"""
environment = EMPTY_SHADER_IN_SUBDIR
glslc_args = ['-MD', 'subdir/shader.vert', '-c', '-o', 'output']
expected_object_filenames = ('output', )
target_filename = 'output.d'
expected_file_contents = ['output: subdir/shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDWithDashMFDashMTDashO(expect.ValidFileContents,
expect.ValidNamedObjectFile):
"""Tests that -MD, -MF, -MT and -o gernates dependency info file and
compilation output file correctly
e.g. glslc -MD subdir/shader.vert -c -o subdir/out -MF dep_info -MT label
=> <subdir/out: valid SPIR-V object file>
=> <dep_info: dependency info: "label: shader.vert">
"""
environment = EMPTY_SHADER_IN_SUBDIR
glslc_args = ['-MD', 'subdir/shader.vert', '-c', '-o', 'subdir/out', '-MF',
'dep_info', '-MT', 'label']
expected_object_filenames = ('subdir/out', )
target_filename = 'dep_info'
expected_file_contents = ['label: subdir/shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDWithDashMFDashMTDashODisassemblyMode(
expect.ValidFileContents, expect.ValidNamedAssemblyFile):
"""Tests that -MD, -MF, -MT and -o gernates dependency info file and
compilation output file correctly in disassembly mode
e.g. glslc -MD subdir/shader.vert -s -o subdir/out -MF dep_info -MT label
=> <subdir/out: valid SPIR-V object file>
=> <dep_info: dependency info: "label: shader.vert">
"""
environment = EMPTY_SHADER_IN_SUBDIR
glslc_args = ['-MD', 'subdir/shader.vert', '-S', '-o', 'subdir/out', '-MF',
'dep_info', '-MT', 'label']
expected_assembly_filenames = ('subdir/out', )
target_filename = 'dep_info'
expected_file_contents = ['label: subdir/shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorSetBothDashCapMAndDashCapMD(expect.StderrMatch):
"""Tests that when both -M (or -MM) and -MD are specified, glslc should exit
with an error message complaining the case and neither dependency info
output nor compilation output. This test has -MD before -M flag.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', '-M', 'shader.vert']
expected_stderr = ['glslc: error: both -M (or -MM) and -MD are specified. '
'Only one should be used at one time.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorSetBothDashCapMDAndDashCapM(expect.StderrMatch):
"""Tests that when both -M (or -MM) and -MD are specified, glslc should exit
with an error message complaining the case and neither dependency info
output nor compilation output. This test has -M before -MD flag.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', '-MD', 'shader.vert']
expected_stderr = ['glslc: error: both -M (or -MM) and -MD are specified. '
'Only one should be used at one time.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMFWithMultipleInputFiles(expect.StderrMatch):
"""Tests that when -MF option is specified, only one input file should be
provided."""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-c', '-MF', 'dep_info']
expected_stderr = ['glslc: error: '
'to specify dependency info file name or dependency '
'info target, only one input file is allowed.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMTWithMultipleInputFiles(expect.StderrMatch):
"""Tests that when -MT option is specified, only one input file should be
provided."""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-M', 'a.vert', 'b.vert', '-c', '-MT', 'target']
expected_stderr = ['glslc: error: '
'to specify dependency info file name or dependency '
'info target, only one input file is allowed.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMFMissingDashMAndDashMD(expect.StderrMatch):
"""Tests that when only -MF is specified while -M and -MD are not specified,
glslc should emit an error complaining that the user must specifiy either
-M (-MM) or -MD to generate dependency info.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MF', 'dep_info', 'shader.vert', '-c']
expected_stderr = ['glslc: error: '
'to generate dependencies you must specify either -M '
'(-MM) or -MD\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMTMissingDashMAndMDWith(expect.StderrMatch):
"""Tests that when only -MF and -MT is specified while -M and -MD are not
specified, glslc should emit an error complaining that the user must
specifiy either -M (-MM) or -MD to generate dependency info.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MF', 'dep_info', '-MT', 'target', 'shader.vert', '-c']
expected_stderr = ['glslc: error: '
'to generate dependencies you must specify either -M '
'(-MM) or -MD\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorMissingDependencyInfoFileName(expect.StderrMatch):
"""Tests that dependency file name is missing when -MF is specified."""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['target', 'shader.vert', '-c', '-MF']
expected_stderr = ['glslc: error: '
'missing dependency info filename after \'-MF\'\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorMissingDependencyTargetName(expect.StderrMatch):
"""Tests that dependency target name is missing when -MT is specified."""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['target', 'shader.vert', '-c', '-MT']
expected_stderr = ['glslc: error: '
'missing dependency info target after \'-MT\'\n']

View File

@@ -0,0 +1,165 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
def simple_vertex_shader():
return """#version 310 es
void main() {
gl_Position = vec4(1., 2., 3., 4.);
}"""
def simple_fragment_shader():
return """#version 310 es
void main() {
gl_FragDepth = 10.;
}"""
def simple_compute_shader():
return """#version 310 es
void main() {
uvec3 temp = gl_WorkGroupID;
}"""
@inside_glslc_testsuite('OptionDashCapS')
class TestSingleDashCapSSingleFile(expect.ValidAssemblyFile):
"""Tests that -S works with a single file."""
shader = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-S', shader]
@inside_glslc_testsuite('OptionDashCapS')
class TestSingleFileSingleDashCapS(expect.ValidAssemblyFile):
"""Tests that the position of -S doesn't matter."""
shader = FileShader(simple_vertex_shader(), '.vert')
glslc_args = [shader, '-S']
@inside_glslc_testsuite('OptionDashCapS')
class TestSingleDashCapSMultipleFiles(expect.ValidAssemblyFile):
"""Tests that -S works with multiple files."""
shader1 = FileShader(simple_vertex_shader(), '.vert')
shader2 = FileShader(simple_vertex_shader(), '.vert')
shader3 = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-S', shader1, shader2, shader3]
@inside_glslc_testsuite('OptionDashCapS')
class TestMultipleDashCapSSingleFile(expect.ValidAssemblyFile):
"""Tests that multiple -Ss works as one."""
shader = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-S', '-S', shader, '-S']
@inside_glslc_testsuite('OptionDashCapS')
class TestMultipleDashCapSMultipleFiles(expect.ValidAssemblyFile):
"""Tests a mix of -Ss and files."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
shader3 = FileShader(simple_compute_shader(), '.comp')
glslc_args = ['-S', shader1, '-S', '-S', shader2, '-S', shader3, '-S']
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashC(expect.ValidAssemblyFile):
"""Tests that -S overwrites -c."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-c', '-S', shader1, '-c', '-c', shader2]
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashFShaderStage(expect.ValidAssemblyFile):
"""Tests that -S works with -fshader-stage=."""
shader1 = FileShader(simple_fragment_shader(), '.glsl')
shader2 = FileShader(simple_vertex_shader(), '.glsl')
shader3 = FileShader(simple_compute_shader(), '.glsl')
glslc_args = ['-S',
'-fshader-stage=fragment', shader1,
'-fshader-stage=vertex', shader2,
'-fshader-stage=compute', shader3]
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashStd(expect.ValidAssemblyFileWithWarning):
"""Tests that -S works with -std=."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
shader3 = FileShader(simple_compute_shader(), '.comp')
glslc_args = ['-S', '-std=450', shader1, shader2, shader3]
w = (': warning: (version, profile) forced to be (450, none), '
'while in source code it is (310, es)\n')
expected_warning = [
shader1, w, shader2, w, shader3, w, '3 warnings generated.\n']
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashOSingleFile(expect.SuccessfulReturn,
expect.CorrectAssemblyFilePreamble):
"""Tests that -S works with -o on a single file."""
shader = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-S', '-o', 'blabla', shader]
def check_output_blabla(self, status):
output_name = os.path.join(status.directory, 'blabla')
return self.verify_assembly_file_preamble(output_name)
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashOMultipleFiles(expect.ErrorMessage):
"""Tests that -S works with -o on a single file."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-S', '-o', 'blabla', shader1, shader2]
expected_error = ['glslc: error: cannot specify -o when '
'generating multiple output files\n']
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithStdIn(expect.ValidAssemblyFile):
"""Tests that -S works with stdin."""
shader = StdinShader(simple_fragment_shader())
glslc_args = ['-S', '-fshader-stage=fragment', shader]
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithStdOut(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that -S works with stdout."""
shader = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-S', '-o', '-', shader]
expected_stdout = True
expected_stderr = ''

View File

@@ -0,0 +1,55 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def empty_es_310_shader():
return '#version 310 es\n void main() {}\n'
@inside_glslc_testsuite('OptionC')
class TestSingleDashCSingleFile(expect.ValidObjectFile):
"""Tests that glslc accepts -c [filename]."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('OptionC')
class TestSingleFileSingleDashC(expect.ValidObjectFile):
"""Tests that glslc accepts [filename] -c."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = [shader, '-c']
@inside_glslc_testsuite('OptionC')
class TestMultipleFiles(expect.ValidObjectFile):
"""Tests that glslc accepts -c and multiple source files."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.frag')
glslc_args = ['-c', shader1, shader2]
@inside_glslc_testsuite('OptionC')
class TestMultipleDashC(expect.ValidObjectFile):
"""Tests that glslc accepts multiple -c and treated them as one."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', shader1, '-c', '-c', shader2]

View File

@@ -0,0 +1,180 @@
# 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
MINIMAL_SHADER = '#version 310 es\nvoid main() {}'
EMPTY_SHADER_IN_CWD = Directory('.', [File('shader.vert', MINIMAL_SHADER)])
ASSEMBLY_WITH_DEBUG_SOURCE = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 7
; Schema: 0
OpCapability Shader
%2 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
%1 = OpString "shader.vert"
OpSource ESSL 310 %1 "// OpModuleProcessed entry-point main
// OpModuleProcessed client vulkan100
// OpModuleProcessed target-env vulkan1.0
// OpModuleProcessed entry-point main
#line 1
#version 310 es
void main() {}"
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
%void = OpTypeVoid
%4 = OpTypeFunction %void
OpLine %1 2 11
%main = OpFunction %void None %4
%6 = OpLabel
OpLine %1 2 0
OpReturn
OpFunctionEnd
"""
]
ASSEMBLY_O0 = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
"""]
ASSEMBLY_O = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %4 "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%4 = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
"""]
ASSEMBLY_Os = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %4 "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%4 = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
"""]
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapO0(expect.ValidFileContents):
"""Tests that -O0 works."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-O0', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_O0
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOPerformance(expect.ValidFileContents):
"""Tests -O works."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-O', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_O
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOs(expect.ValidFileContents):
"""Tests that -Os works."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-Os', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_Os
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOOverriding(expect.ValidFileContents):
"""Tests that if there are multiple -O's, only the last one takes effect."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-Os', '-O0', '-Os', '-O0', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_O0
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOWithDashG(expect.ValidFileContents):
"""Tests that -g restrains -O from turning on strip debug info."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-Os', '-g', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_WITH_DEBUG_SOURCE
@inside_glslc_testsuite('OptionDashCapO')
class TestDashGWithDashCapO(expect.ValidFileContents):
"""Tests that -g restrains -O from turning on strip debug info."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-g', '-Os', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_WITH_DEBUG_SOURCE
@inside_glslc_testsuite('OptionDashCapO')
class TestWrongOptLevel(expect.NoGeneratedFiles, expect.ErrorMessage):
"""Tests erroring out with wrong optimization level."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-c', '-O2', shader]
expected_error = "glslc: error: invalid value '2' in '-O2'\n"

View File

@@ -0,0 +1,44 @@
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader with uniforms without explicit bindings.
GLSL_SHADER = """#version 450
layout(set=0, binding=0)
buffer B { float x; vec3 y; } my_ssbo;
void main() {
my_ssbo.x = 1.0;
}"""
@inside_glslc_testsuite('OptionFHlslOffsets')
class StandardOffsetsByDefault(expect.ValidAssemblyFileWithSubstr):
"""Tests that standard GLSL packign is used by default."""
shader = FileShader(GLSL_SHADER, '.vert')
glslc_args = ['-S', shader]
expected_assembly_substr = "OpMemberDecorate %B 1 Offset 16"
@inside_glslc_testsuite('OptionFHlslOffsets')
class HlslOffsetsWhenRequested(expect.ValidAssemblyFileWithSubstr):
"""Tests that standard GLSL packign is used by default."""
shader = FileShader(GLSL_SHADER, '.vert')
glslc_args = ['-S', '-fhlsl-offsets', shader]
expected_assembly_substr = "OpMemberDecorate %B 1 Offset 4"

View File

@@ -0,0 +1,69 @@
# Copyright 2019 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
# A GLSL shader using the clamp, max, and min builtin functions.
GLSL_FRAG_SHADER_WITH_CLAMP = """#version 450
layout(location=0) in vec4 i;
layout(location=0) out vec4 o;
void main() {
o = clamp(i, vec4(0.5), vec4(1.0))
+ max(i, vec4(0.5))
+ min(i, vec4(0.5));
}
"""
@inside_glslc_testsuite('OptionFNanClamp')
class TestClampMapsToFClampByDefault(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 FClamp'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMaxMapsToFMaxByDefault(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 FMax'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMinMapsToFMinByDefault(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 FMin'
@inside_glslc_testsuite('OptionFNanClamp')
class TestClampMapsToNClampWithFlag(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', '-fnan-clamp', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 NClamp'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMaxMapsToNMaxWithFlag(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', '-fnan-clamp', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 NMax'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMinMapsToNMinWithFlag(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', '-fnan-clamp', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 NMin'

View File

@@ -0,0 +1,55 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def empty_es_310_shader():
return '#version 310 es\n void main() {}\n'
@inside_glslc_testsuite('OptionG')
class TestSingleDashGSingleFile(expect.ValidObjectFile):
"""Tests that glslc accepts -g [filename]. Need -c for now too."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', '-g', shader]
@inside_glslc_testsuite('OptionG')
class TestSingleFileSingleDashG(expect.ValidObjectFile):
"""Tests that glslc accepts [filename] -g -c."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = [shader, '-g', '-c']
@inside_glslc_testsuite('OptionG')
class TestMultipleFiles(expect.ValidObjectFile):
"""Tests that glslc accepts -g and multiple source files."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.frag')
glslc_args = ['-c', shader1, '-g', shader2]
@inside_glslc_testsuite('OptionG')
class TestMultipleDashG(expect.ValidObjectFile):
"""Tests that glslc accepts multiple -g and treated them as one."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', '-g', shader1, '-g', '-g', shader2]

View File

@@ -0,0 +1,98 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, TempFileName
from builtins import bytes
@inside_glslc_testsuite('OptionDashO')
class TestOptionDashOConcatenatedArg(expect.SuccessfulReturn,
expect.CorrectObjectFilePreamble):
"""Tests that we can concatenate -o and the output filename."""
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = ['-ofoo', shader]
def check_output_foo(self, status):
output_name = os.path.join(status.directory, 'foo')
return self.verify_object_file_preamble(output_name)
@inside_glslc_testsuite('OptionDashO')
class ManyOutputFilesWithDashO(expect.ErrorMessage):
"""Tests -o and -c with several files generates an error."""
shader1 = FileShader('', '.vert')
shader2 = FileShader('', '.frag')
glslc_args = ['-o', 'foo', '-c', shader1, shader2]
expected_error = [
'glslc: error: cannot specify -o when '
'generating multiple output files\n']
@inside_glslc_testsuite('OptionDashO')
class OutputFileLocation(expect.SuccessfulReturn,
expect.CorrectObjectFilePreamble):
"""Tests that the -o flag puts a file in a new location."""
shader = FileShader('#version 310 es\nvoid main() {}', '.frag')
glslc_args = [shader, '-o', TempFileName('a.out')]
def check_output_a_out(self, status):
output_name = os.path.join(status.directory, 'a.out')
return self.verify_object_file_preamble(output_name)
@inside_glslc_testsuite('OptionDashO')
class DashOMissingArgumentIsAnError(expect.ErrorMessage):
"""Tests that -o without an argument is an error."""
glslc_args = ['-o']
expected_error = ['glslc: error: argument to \'-o\' is missing ' +
'(expected 1 value)\n']
@inside_glslc_testsuite('OptionDashO')
class OutputFileBinaryAvoidsCRLFTranslation(expect.ReturnCodeIsZero,
expect.NoOutputOnStderr,
expect.NoGeneratedFiles,
expect.CorrectBinaryLengthAndPreamble):
"""Tests that the -o flag emits a binary file without CR/LF translation.
"""
# A shader whose compiled output has three bytes that are newlines.
# If the output stream converts the newlines to CR/LF, then we end up
# with a file that is 4k + 3 bytes long. That will be caught by the
# object file checks.
SHADER_WITH_THREE_NEWLINES_IN_BINARY = """#version 450
layout(location = 0) out uint ovar;
void main() { ovar = 9; }
"""
shader = FileShader(SHADER_WITH_THREE_NEWLINES_IN_BINARY, '.vert')
glslc_args = [shader, '-o', '-']
def check_stdout_binary(self, status):
binary = bytes(status.stdout)
newlines = [x for x in binary if x == ord('\n')]
num_newlines = len(newlines)
if num_newlines % 4 == 0:
return False, "Bad test. Need nontrivial number of newlines"
if num_newlines != 2:
return False, ("Update this test. Expected 3 newlines in the "
"binary, but found {}").format(num_newlines)
return self.verify_binary_length_and_header(bytes(status.stdout))

View File

@@ -0,0 +1,145 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
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 GLSL but without leading #version. Should result in
# a parser error when compiled as HLSL.
GLSL_VERTEX_SHADER_WITHOUT_VERSION = "void main(){ gl_Position = vec4(1.0);}"
# This one is valid HLSL but not valid GLSL.
# 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):
"""Tests -x with nothing."""
glslc_args = ['-x']
expected_error = [
"glslc: error: argument to '-x' is missing (expected 1 value)\n",
'glslc: error: no input files\n']
@inside_glslc_testsuite('OptionDashX')
class TestDashXGlslOnGlslShader(expect.ValidObjectFile):
"""Tests -x glsl on a GLSL shader."""
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 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: '#version' : invalid preprocessor command\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXHlslOnGlslShaderWithoutVertex(expect.ErrorMessageSubstr):
"""Tests -x hlsl on a GLSL shader without leading #version."""
shader = FileShader(GLSL_VERTEX_SHADER_WITHOUT_VERSION, '.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."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-x', 'gl', shader]
expected_error = ["glslc: error: language not recognized: 'gl'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestMultipleDashX(expect.ValidObjectFile):
"""Tests that multiple -x works with a single language."""
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]."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-x', 'glsl', '-x', 'foo', shader]
expected_error = ["glslc: error: language not recognized: 'foo'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestMultipleDashXWrongCorrect(expect.ErrorMessage):
"""Tests -x [wrong-language] -x glsl."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-xbar', '-x', 'glsl', shader]
expected_error = ["glslc: error: language not recognized: 'bar'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXGlslConcatenated(expect.ValidObjectFile):
"""Tests -xglsl."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-xglsl', shader, '-c']
@inside_glslc_testsuite('OptionDashX')
class TestDashXWrongParamConcatenated(expect.ErrorMessage):
"""Tests -x concatenated with a wrong language."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-xsl', shader]
expected_error = ["glslc: error: language not recognized: 'sl'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXEmpty(expect.ErrorMessage):
"""Tests -x ''."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-x', '', shader]
expected_error = ["glslc: error: language not recognized: ''\n"]

View File

@@ -0,0 +1,44 @@
# 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
import re
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsShaderc(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'shaderc'."""
glslc_args = ['--version']
expected_stdout = re.compile('^shaderc')
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsSpirvTools(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'spirv-tools'."""
glslc_args = ['--version']
expected_stdout = re.compile('\nspirv-tools')
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsGlslang(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'glslang'."""
glslc_args = ['--version']
expected_stdout = re.compile('\nglslang')
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsTarget(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'Target:'."""
glslc_args = ['--version']
expected_stdout = re.compile('\nTarget: SPIR-V \d+\.\d+')

View File

@@ -0,0 +1,431 @@
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader with uniforms without explicit bindings.
GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS = """#version 450
#extension GL_ARB_sparse_texture2 : enable
uniform texture2D my_tex;
uniform sampler my_sam;
layout(rgba32f) uniform image2D my_img;
layout(rgba32f) uniform imageBuffer my_imbuf;
uniform block { float x; float y; } my_ubo;
buffer B { float z; } my_ssbo;
void main() {
texture(sampler2D(my_tex,my_sam),vec2(1.0));
vec4 t;
sparseImageLoadARB(my_img,ivec2(0),t);
imageLoad(my_imbuf,42);
float x = my_ubo.x;
my_ssbo.z = 1.1;
}"""
# An HLSL shader with uniforms without explicit bindings.
# The counter buffer has an associated counter that needs a
# binding. Compile this shader with --auto-bind-uniforms to
# give it a binding, since Glslang does not support attribute
# [[vk::counter_binding(N))]].
# See https://github.com/KhronosGroup/glslang/issues/1616
HLSL_SHADER_WITHOUT_BINDINGS = """
SamplerState s1 : register(s1);
SamplerComparisonState s2 : register(s2);
Texture1D t1 : register(t11);
Texture2D <float4> t2 : register(t12);
Texture3D <float2> t3 : register(t13);
StructuredBuffer<float4> t4 : register(t14);
ByteAddressBuffer t5 : register(t15);
Buffer<float4> t6 : register(t16);
RWTexture1D <float4> u1 : register(u21);
RWTexture1D <float4> u2 : register(u22);
RWTexture1D <float4> u3 : register(u23);
RWBuffer <float4> u4 : register(u24);
RWByteAddressBuffer u5 : register(u25);
RWStructuredBuffer<float> u6 : register(u26);
AppendStructuredBuffer<float> u7 : register(u27);
ConsumeStructuredBuffer<float> u8 : register(u28);
float4 main() : SV_Target0 {
s1;
s2;
t1;
t2;
t3;
t4[2];
t5.Load(8);
t6;
u1;
u2;
u3;
u4[1];
u5.Load(15);
u6[2];
u7;
u8;
return float4(u8.Consume() + t2.SampleCmp(s2, 1.0, 2.0)) + t1.Sample(s1, 1.0)
+ t6.Load(1);
}
"""
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class UniformBindingsNotCreatedByDefault(expect.ErrorMessageSubstr):
"""Tests that compilation fails when uniforms have no binding."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader]
expected_error_substr = "sampler/texture/image requires layout(binding=X)"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FAutoBindingUniformsGeneratesBindings(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler generates bindings for uniforms upon request ."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms']
# Sufficient to just check one of the uniforms.
expected_assembly_substr = "OpDecorate %my_sam Binding 1"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseOptionRespectedOnImage(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base value is respected on images."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseOptionRespectedOnImageBuffer(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base value is respected on image buffers."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_imbuf Binding 45"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-ftexture-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_tex Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fsampler-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_sam Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseOptionRespectedOnBuffer(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fubo-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fubo-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_ubo Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FCbufferBindingBaseOptionRespectedOnBuffer(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fcbuffer-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fcbuffer-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_ubo Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -fimage-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fimage-binding-base']
expected_error_substr = "error: Option -fimage-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -ftexture-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-ftexture-binding-base']
expected_error_substr = "error: Option -ftexture-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -fsampler-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fsampler-binding-base']
expected_error_substr = "error: Option -fsampler-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -fubo-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fubo-binding-base']
expected_error_substr = "error: Option -fubo-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseNeedsNumberValueIfNotStage(expect.ErrorMessageSubstr):
"""Tests that -fimage-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fimage-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -fimage-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseNeedsNumberValue(expect.ErrorMessageSubstr):
"""Tests that -ftexture-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-ftexture-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -ftexture-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseNeedsNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fsampler-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fsampler-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -fsampler-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseNeedsNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fubo-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fubo-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -fubo-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fimage-binding-base requires an unsigned number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fimage-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -fimage-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -ftexture-binding-base requires an unsigned number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-ftexture-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -ftexture-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fsampler-binding-base requires an unsigned value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fsampler-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -fsampler-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fubo-binding-base requires an unsigned value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fubo-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -fubo-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseForVertOptionRespectedOnImageCompileAsVert(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base with vert stage value is respected on images."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', 'vert', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseForVertOptionIgnoredOnImageCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base with vert stage value is ignored when cmopiled as
fragment."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', 'vert', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 2"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseForFragOptionRespectedOnImageCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base with frag stage value is respected on images."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', 'frag', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSsboBindingBaseRespectedOnSsboCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fssbo-binding-base with frag stage value is respected on SSBOs."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fssbo-binding-base', '100']
expected_assembly_substr = "OpDecorate %my_ssbo Binding 100"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSsboBindingBaseForFragOptionRespectedOnSsboCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fssbo-binding-base with frag stage value is respected on SSBOs."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fssbo-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %my_ssbo Binding 100"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSsboBindingBaseForFragOptionIgnoredOnSsboCompileAsVert(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fssbo-binding-base with frag stage value is ignored on SSBOs
when compiling as a vertex shader."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fssbo-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %my_ssbo Binding 5"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class AutomaticHlslIoMapping(expect.ValidAssemblyFileWithSubstr):
"""Tests that HLSL IO Mapping uses the register values in the source code."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = "OpDecorate %u8 Binding 28"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFSamplerBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base sets binding base for samplers in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fsampler-binding-base', '100']
expected_assembly_substr = "OpDecorate %s2 Binding 102"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFSamplerBindingBaseForFragOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base for frag sets binding base for samplers
in HLSL compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fsampler-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %s2 Binding 102"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFSamplerBindingBaseForComputeOptionIgnoredWhenCompilingAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base for compute is ignored when compiling
as a fragment shader."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fsampler-binding-base', 'compute', '100']
expected_assembly_substr = "OpDecorate %s2 Binding 2"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFTextureBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base sets binding base for textures in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-ftexture-binding-base', '100']
expected_assembly_substr = "OpDecorate %t6 Binding 116"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFTextureBindingBaseForFragOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base for frag sets binding base for textures
in HLSL compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-ftexture-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %t6 Binding 116"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFTextureBindingBaseForComputeOptionIgnoredWhenCompilingAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base for compute is ignored when compiling
as a fragment shader."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-ftexture-binding-base', 'compute', '100']
expected_assembly_substr = "OpDecorate %t6 Binding 16"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFUavBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fuav-binding-base sets binding base for UAVs in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fuav-binding-base', '100']
expected_assembly_substr = "OpDecorate %u8 Binding 128"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFUavBindingBaseForFragOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fuav-binding-base for frag sets binding base for UAVs in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fuav-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %u8 Binding 128"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFUavBindingBaseForComputeOptionIgnoredWhenCompilingAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fuav-binding-base for compute is ignored when compiling
as a fragment shader."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fuav-binding-base', 'compute', '100']
expected_assembly_substr = "OpDecorate %u8 Binding 28"

View File

@@ -0,0 +1,59 @@
# Copyright 2018 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
# A GLSL shader with a separate sampler and texture2D object
GLSL_SHADER_SEPARATE_IMAGE_SAMPLER = """#version 460
layout (location=0) in vec2 in_UV;
layout (location=0) out vec4 out_Color;
layout (set=0,binding=0) uniform sampler u_Sampler;
layout (set=0,binding=0) uniform texture2D u_Tex;
void main() {
out_Color = texture(sampler2D(u_Tex, u_Sampler), in_UV);
}"""
# An HLSL fragment shader with the usual Texture2D and SamplerState pair
HLSL_SHADER_SEPARATE_IMAGE_SAMPLER = """
Texture2D u_Tex;
SamplerState u_Sampler;
float4 Frag(float2 uv) : COLOR0 {
return u_Tex.Sample(u_Sampler, uv);
}"""
@inside_glslc_testsuite('OptionFAutoCombinedImageSampler')
class FAutoCombinedImageSamplerCheckGLSL(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler combines GLSL sampler and texture2D objects."""
shader = FileShader(GLSL_SHADER_SEPARATE_IMAGE_SAMPLER, '.frag')
glslc_args = ['-S', '-fauto-combined-image-sampler', shader]
expected_assembly_substr = """%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
%11 = OpTypeSampledImage %10
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
%u_Tex = OpVariable %_ptr_UniformConstant_11 UniformConstant"""
@inside_glslc_testsuite('OptionFAutoCombinedImageSampler')
class FAutoCombinedImageSamplerCheckHLSL(expect.ValidAssemblyFileWithSubstr):
"""Tests that the HLSL compiler combines HLSL Texture2D and SamplerState objects into SPIRV SampledImage."""
shader = FileShader(HLSL_SHADER_SEPARATE_IMAGE_SAMPLER, '.hlsl')
glslc_args = ['-S', '-fshader-stage=frag', '-fentry-point=Frag', '-fauto-combined-image-sampler', shader]
expected_assembly_substr = """%14 = OpTypeImage %float 2D 0 0 0 1 Unknown
%15 = OpTypeSampledImage %14
%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
%u_Tex = OpVariable %_ptr_UniformConstant_15 UniformConstant"""

View File

@@ -0,0 +1,87 @@
# Copyright 2018 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
# A GLSL shader with inputs and outputs explicit locations.
GLSL_SHADER_IO_WITHOUT_LOCATIONS = """#version 310 es
in vec4 m_in;
in vec4 m_in1;
out vec4 m_out;
out vec4 m_out1;
void main() {
m_out = m_in;
m_out1 = m_in1;
}"""
# An HLSL fragment shader with inputs and outputs explicit locations.
HLSL_SHADER_IO_WITHOUT_LOCATIONS = """
float4 Foo(float4 a, float4 b) : COLOR0 {
return a + b;
}"""
@inside_glslc_testsuite('OptionFAutoMapLocations')
class MissingLocationsResultsInError(expect.ErrorMessageSubstr):
"""Tests that compilation fails when inputs or outputs have no location."""
shader = FileShader(GLSL_SHADER_IO_WITHOUT_LOCATIONS, '.vert')
glslc_args = ['-S', shader]
expected_error_substr = "SPIR-V requires location for user input/output"
@inside_glslc_testsuite('OptionFAutoMapLocations')
class FAutoMapLocationsGeneratesLocationsCheckInput(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler generates locations upon request: Input 0"""
shader = FileShader(GLSL_SHADER_IO_WITHOUT_LOCATIONS, '.vert')
glslc_args = ['-S', shader, '-fauto-map-locations']
expected_assembly_substr = "OpDecorate %m_in Location 0"
@inside_glslc_testsuite('OptionFAutoMapLocations')
class FAutoMapLocationsGeneratesLocationsCheckOutput0(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler generates locations upon request: Output 0"""
shader = FileShader(GLSL_SHADER_IO_WITHOUT_LOCATIONS, '.vert')
glslc_args = ['-S', shader, '-fauto-map-locations']
expected_assembly_substr = "OpDecorate %m_out Location 0"
# Currently Glslang only generates Location 0.
# See https://github.com/KhronosGroup/glslang/issues/1261
# TODO(dneto): Write tests that check Location 1 is generated for inputs and
# outputs.
# Glslang's HLSL compiler automatically assigns locations inptus and outputs.
@inside_glslc_testsuite('OptionFAutoMapLocations')
class HLSLCompilerGeneratesLocationsCheckInput0(expect.ValidAssemblyFileWithSubstr):
"""Tests that the HLSL compiler generates locations automatically: Input 0."""
shader = FileShader(HLSL_SHADER_IO_WITHOUT_LOCATIONS, '.hlsl')
glslc_args = ['-S', '-fshader-stage=frag', '-fentry-point=Foo', shader]
expected_assembly_substr = "OpDecorate %a Location 0"
@inside_glslc_testsuite('OptionFAutoMapLocations')
class HLSLCompilerGeneratesLocationsCheckOutput(expect.ValidAssemblyFileWithSubstr):
"""Tests that the HLSL compiler generates locations automatically: Output."""
shader = FileShader(HLSL_SHADER_IO_WITHOUT_LOCATIONS, '.hlsl')
glslc_args = ['-S', '-fshader-stage=frag', '-fentry-point=Foo', shader]
expected_assembly_substr = "OpDecorate %_entryPointOutput Location 0"

View File

@@ -0,0 +1,113 @@
# 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 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', '-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
matching source."""
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]

View File

@@ -0,0 +1,46 @@
# Copyright 2018 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
HLSL_SHADER_WITH_HALF_TYPE = """
float4 main() : SV_Target0 {
half h0 = (half)0.0;
half h1 = (half)1.0;
half h2 = (half)2.0;
half h3 = (half)3.0;
half4 v = (half4)(h0,h1,h2,h3) * (half)2.0;
return (float4)(v);
}
"""
@inside_glslc_testsuite('OptionFHlsl16BitTypes')
class TestHlsl16BitTypes_EnablesCapability(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_16bit_types enables the 16bit floating point capability."""
shader = FileShader(HLSL_SHADER_WITH_HALF_TYPE, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-16bit-types', '-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpCapability Float16';
@inside_glslc_testsuite('OptionFHlsl16BitTypes')
class TestHlsl16BitTypes_CreatesType(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_16bit_types creates the 16bit floating point capability."""
shader = FileShader(HLSL_SHADER_WITH_HALF_TYPE, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-16bit-types', '-fauto-bind-uniforms', shader]
expected_assembly_substr = '= OpTypeFloat 16';

View File

@@ -0,0 +1,71 @@
# Copyright 2018 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
# An HLSL shader with a counter buffer with a counter increment.
# Glslang doesn't automatically assign a binding to the counter, and
# it doesn't understand [[vk::counter_binding(n)]], so compile this
# with --auto-bind-uniforms.
# See https://github.com/KhronosGroup/glslang/issues/1616
HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER = """
RWStructuredBuffer<int> Ainc;
float4 main() : SV_Target0 {
return float4(Ainc.IncrementCounter(), 0, 1, 2);
}
"""
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslFunctionality1MentionsExtension(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_functionality1 enabled SPV_GOOGLE_hlsl_functionality1."""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpExtension "SPV_GOOGLE_hlsl_functionality1"'
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslFunctionality1DecoratesCounter(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_functionality1 decorates the output target"""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpDecorateString'
## Next tests use the option with the hypen instead of underscore.
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslHyphenFunctionality1MentionsExtension(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl-functionality1 enabled SPV_GOOGLE_hlsl_functionality1."""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpExtension "SPV_GOOGLE_hlsl_functionality1"'
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslHyphenFunctionality1DecoratesCounter(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl-functionality1 decorates the output target"""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpDecorateString'

View File

@@ -0,0 +1,378 @@
# 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 450
layout (binding=0) 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'
## Mesh shading
def mesh_shader_with_params(kwargs):
"""Returns a mesh shader as a FileShader, with given parameters"""
import sys
source = """#version 450
#extension {} : enable
layout(local_size_x={}) in;
layout(local_size_y={}) in;
layout(local_size_z={}) in;
layout(triangles) out;
layout(max_vertices={}) out;
layout(max_primitives={}) out;
layout(triangles) out;
void main() {{ }}
""".format(kwargs['extension'],kwargs['x'],kwargs['y'],kwargs['z'],kwargs['max_vert'],kwargs['max_prim'])
return FileShader(source,".mesh")
def task_shader_with_params(kwargs):
"""Returns a task shader as a FileShader, with given parameters"""
import sys
source = """#version 450
#extension {} : enable
layout(local_size_x={}) in;
layout(local_size_y={}) in;
layout(local_size_z={}) in;
void main() {{ }}
""".format(kwargs['extension'],kwargs['x'],kwargs['y'],kwargs['z'])
return FileShader(source,".task")
def meshDefaults(nv_or_ext,show=False):
result = dict({
# See Glslang's glslang/ResourceLimits/ResourceLimits.cpp
'nv': { 'extension': 'GL_NV_mesh_shader', 'x': 32, 'y': 1, 'z': 1, 'max_vert': 256, 'max_prim': 512 },
'ext': { 'extension': 'GL_EXT_mesh_shader', 'x': 128, 'y': 128, 'z': 128, 'max_vert': 256, 'max_prim': 256 }
})[nv_or_ext]
if show:
import sys
print(result,file=sys.stderr)
return result
## GL_NV_mesh_shader
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_X_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_NV 32']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_X_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_NV 31']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Y_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_NV 1']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Y_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['y'] = 3
shader = mesh_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_NV 2']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Z_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_NV 1']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Z_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['z'] = 3
shader = mesh_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_NV 2']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxVert_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesNV 256']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxVert_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'max_vertices' : too large, must be less than gl_MaxMeshOutputVerticesNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesNV 255']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxPrim_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesNV 512']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxPrim_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'max_primitives' : too large, must be less than gl_MaxMeshOutputPrimitivesNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesNV 511']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_X_ok(expect.ValidObjectFile):
shader = task_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_NV 32']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_X_bad(expect.ErrorMessageSubstr):
shader = task_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_NV 31']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Y_ok(expect.ValidObjectFile):
shader = task_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_NV 1']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Y_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['y'] = 3
shader = task_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_NV 2']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Z_ok(expect.ValidObjectFile):
shader = task_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_NV 1']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Z_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['z'] = 3
shader = task_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_NV 2']
# TODO: Test MaxMeshViewCountNV
## GL_EXT_mesh_shader
## It requires SPIR-V 1.4
s14 = '--target-spv=spv1.4'
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_X_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_X_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Y_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Y_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Z_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Z_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxVert_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesEXT 256', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxVert_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'max_vertices' : too large, must be less than gl_MaxMeshOutputVerticesEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesEXT 255', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxPrim_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesEXT 256', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxPrim_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'max_primitives' : too large, must be less than gl_MaxMeshOutputPrimitivesEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesEXT 255', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_X_ok(expect.ValidObjectFile1_4):
shader = task_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_X_bad(expect.ErrorMessageSubstr):
shader = task_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Y_ok(expect.ValidObjectFile1_4):
shader = task_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Y_bad(expect.ErrorMessageSubstr):
import sys
d = meshDefaults('ext',True)
print("TaskShader_EXT_Y_bad {}".format(str(d)),file=sys.stderr)
shader = task_shader_with_params(meshDefaults('ext',True))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Z_ok(expect.ValidObjectFile1_4):
shader = task_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Z_bad(expect.ErrorMessageSubstr):
shader = task_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_EXT 127', s14]
# TODO: Test MaxMeshViewCountEXT

View File

@@ -0,0 +1,70 @@
# Copyright 2023 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
# A GLSL shader with unused bindings.
GLSL_SHADER_WITH_UNUSED_BINDINGS = """#version 450
layout(binding=0) buffer InputA { vec4 x[]; } inputA;
layout(binding=1) buffer InputB { vec4 x[]; } inputB;
layout(binding=2) buffer Output { vec4 x[]; } outputO;
void main() {}
"""
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFPreserveBindingsInputA(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler preserves bindings when optimizations are
enabled."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader, '-fpreserve-bindings']
# Check the first buffer.
expected_assembly_substr = "Binding 0"
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFPreserveBindingsInputB(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler preserves bindings when optimizations are
enabled."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader, '-fpreserve-bindings']
# Check the first buffer.
expected_assembly_substr = "Binding 1"
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFPreserveBindingsOutputO(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler preserves bindings when optimizations are
enabled."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader, '-fpreserve-bindings']
# Check the first buffer.
expected_assembly_substr = "Binding 2"
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFNoPreserveBindings(expect.ValidAssemblyFileWithoutSubstr):
"""Tests that the compiler removes bindings when -fpreserve-bindings is not
set."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader]
# Check that all binding decorations are gone.
unexpected_assembly_substr = "OpDecorate"

View File

@@ -0,0 +1,121 @@
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# An HLSL shader with uniforms without explicit bindings.
HLSL_SHADER = """
Buffer<float4> t4 : register(t4);
Buffer<float4> t5 : register(t5);
float4 main() : SV_Target0 {
return float4(t4.Load(0) + t5.Load(1));
}
"""
NEED_THREE_ARGS_ERR = "error: Option -fresource-set-binding requires at least 3 arguments"
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForFragRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on specific shader two textures"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9', '16',
't5', '17', '18']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 9
OpDecorate %t4 Binding 16
OpDecorate %t5 DescriptorSet 17
OpDecorate %t5 Binding 18"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForFragRespectedJustOneTriple(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on specific shader just one texture specified."""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9', '16']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 9
OpDecorate %t4 Binding 16
OpDecorate %t5 DescriptorSet 0
OpDecorate %t5 Binding 5"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForWrongStageIgnored(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on wrong shader ignored"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'vert',
't4', '9', '16',
't5', '17', '18']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 0
OpDecorate %t4 Binding 4
OpDecorate %t5 DescriptorSet 0
OpDecorate %t5 Binding 5"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForAllRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on all stages respected"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding',
't4', '9', '16',
't5', '17', '18']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 9
OpDecorate %t4 Binding 16
OpDecorate %t5 DescriptorSet 17
OpDecorate %t5 Binding 18"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingTooFewArgs(expect.ErrorMessageSubstr):
"""Tests -fresource-set-binding with too few arguments"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9']
expected_error_substr = NEED_THREE_ARGS_ERR
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingInvalidSetNumber(expect.ErrorMessageSubstr):
"""Tests -fresource-set-binding with inavlid set number"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '-9', '16']
expected_error_substr = NEED_THREE_ARGS_ERR
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingInvalidBindingNumber(expect.ErrorMessageSubstr):
"""Tests -fresource-set-binding with inavlid binding number"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9', '-16']
expected_error_substr = NEED_THREE_ARGS_ERR

View File

@@ -0,0 +1,195 @@
# 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
import re
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
MINIMAL_SHADER = '#version 140\nvoid main() {}'
# Regular expression patterns for the minimal shader. The magic number should
# match exactly, and there should not be a trailing comma at the end of the
# list. When -mfmt=c is specified, curly brackets should be presented.
MINIMAL_SHADER_NUM_FORMAT_PATTERN = "^0x07230203.*[0-9a-f]$"
MINIMAL_SHADER_C_FORMAT_PATTERN = "^\{0x07230203.*[0-9a-f]\}"
ERROR_SHADER = '#version 140\n#error\nvoid main() {}'
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCWorksWithDashC(expect.ValidFileContents):
"""Tests that -mfmt=c works with -c for single input file. SPIR-V binary
code output should be emitted as a C-style initializer list in the output
file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-c', '-mfmt=c', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumWorksWithDashC(expect.ValidFileContents):
"""Tests that -mfmt=num works with -c for single input file. SPIR-V binary
code output should be emitted as a list of hex numbers in the output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-c', '-mfmt=num', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtBinWorksWithDashC(expect.ValidObjectFile):
"""Tests that -mfmt=bin works with -c for single input file. This test
should simply have the SPIR-V binary generated.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-c', '-mfmt=bin']
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCWithLinking(expect.ValidFileContents):
"""Tests that -mfmt=c works when linkding is enabled (no -c specified).
SPIR-V binary code should be emitted as a C-style initializer list in the
output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c']
target_filename = 'a.spv'
expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumWithLinking(expect.ValidFileContents):
"""Tests that -mfmt=num works when linkding is enabled (no -c specified).
SPIR-V binary code should be emitted as a C-style initializer list in the
output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num']
target_filename = 'a.spv'
expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCErrorWhenOutputDisasembly(expect.ErrorMessage):
"""Tests that specifying '-mfmt=c' when the compiler is set to
disassembly mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c', '-S', '-o', 'output_file']
expected_error = ("glslc: error: cannot emit output as a C-style "
"initializer list when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumErrorWhenOutputDisasembly(expect.ErrorMessage):
"""Tests that specifying '-mfmt=num' when the compiler is set to
disassembly mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num', '-S', '-o', 'output_file']
expected_error = (
"glslc: error: cannot emit output as a list of hex numbers "
"when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtBinErrorWhenOutputDisasembly(expect.ErrorMessage):
"""Tests that specifying '-mfmt=bin' when the compiler is set to
disassembly mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=bin', '-S', '-o', 'output_file']
expected_error = ("glslc: error: cannot emit output as a binary "
"when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumErrorWhenOutputPreprocess(expect.ErrorMessage):
"""Tests that specifying '-mfmt=num' when the compiler is set to
preprocessing only mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num', '-E', '-o', 'output_file']
expected_error = (
"glslc: error: cannot emit output as a list of hex numbers "
"when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCErrorWithDashCapM(expect.ErrorMessage):
"""Tests that specifying '-mfmt=c' should trigger an error when the
compiler is set to dump dependency info as the output (-M or -MM is
specified).
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c', '-M', '-o', 'output_file']
expected_error = ("glslc: error: cannot emit output as a C-style "
"initializer list when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCWorksWithDashCapMD(expect.ValidFileContents):
"""Tests that -mfmt=c works with '-c -MD'. SPIR-V binary code
should be emitted as a C-style initializer list in the output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c', '-c', '-MD', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumWorksWithDashCapMD(expect.ValidFileContents):
"""Tests that -mfmt=num works with '-c -MD'. SPIR-V binary code
should be emitted as a C-style initializer list in the output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num', '-c', '-MD', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCExitsElegantlyWithErrorInShader(expect.ErrorMessage):
"""Tests that the compiler fails elegantly with -mfmt=c when there are
errors in the input shader.
"""
shader = FileShader(ERROR_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c']
expected_error = [shader, ':3: error: \'#error\' :\n',
'1 error generated.\n']
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumExitsElegantlyWithErrorInShader(expect.ErrorMessage):
"""Tests that the compiler fails elegantly with -mfmt=num when there are
errors in the input shader.
"""
shader = FileShader(ERROR_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num']
expected_error = [shader, ':3: error: \'#error\' :\n',
'1 error generated.\n']
@inside_glslc_testsuite('OptionMfmt')
class TestFmtBinExitsElegantlyWithErrorInShader(expect.ErrorMessage):
"""Tests that the compiler fails elegantly with -mfmt=binary when there are
errors in the input shader.
"""
shader = FileShader(ERROR_SHADER, '.vert')
glslc_args = [shader, '-mfmt=bin']
expected_error = [shader, ':3: error: \'#error\' :\n',
'1 error generated.\n']

View File

@@ -0,0 +1,224 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def simple_vertex_shader():
return """#version 310 es
void main() {
gl_Position = vec4(1., 2., 3., 4.);
}"""
def simple_hlsl_vertex_shader():
# Use "main" so we don't have to specify -fentry-point
return """float4 main() : SV_POSITION { return float4(1.0); } """
def simple_fragment_shader():
return """#version 310 es
void main() {
gl_FragDepth = 10.;
}"""
def simple_tessellation_control_shader():
return """#version 440 core
layout(vertices = 3) out;
void main() { }"""
def simple_tessellation_evaluation_shader():
return """#version 440 core
layout(triangles) in;
void main() { }"""
def simple_geometry_shader():
return """#version 150 core
layout (triangles) in;
layout (line_strip, max_vertices = 4) out;
void main() { }"""
def simple_compute_shader():
return """#version 310 es
void main() {
uvec3 temp = gl_WorkGroupID;
}"""
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithGlslExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with .glsl extension."""
shader = FileShader(simple_vertex_shader(), '.glsl')
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."""
shader = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-c', '-fshader-stage=fragment', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithUnknownExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with unknown extension."""
shader = FileShader(simple_vertex_shader(), '.unknown')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithNoExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with no extension."""
shader = FileShader(simple_vertex_shader(), '')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestAllShaderStages(expect.ValidObjectFile):
"""Tests all possible -fshader-stage values."""
shader1 = FileShader(simple_vertex_shader(), '.glsl')
shader2 = FileShader(simple_fragment_shader(), '.glsl')
shader3 = FileShader(simple_tessellation_control_shader(), '.glsl')
shader4 = FileShader(simple_tessellation_evaluation_shader(), '.glsl')
shader5 = FileShader(simple_geometry_shader(), '.glsl')
shader6 = FileShader(simple_compute_shader(), '.glsl')
glslc_args = [
'-c',
'-fshader-stage=vertex', shader1,
'-fshader-stage=fragment', shader2,
'-fshader-stage=tesscontrol', shader3,
'-fshader-stage=tesseval', shader4,
'-fshader-stage=geometry', shader5,
'-fshader-stage=compute', shader6]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageOverwriteFileExtension(expect.ValidObjectFile):
"""Tests -fshader-stage has precedence over file extension."""
# a vertex shader camouflaged with .frag extension
shader = FileShader(simple_vertex_shader(), '.frag')
# Command line says it's vertex shader. Should compile successfully
# as a vertex shader.
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageLatterOverwriteFormer(expect.ValidObjectFile):
"""Tests a latter -fshader-stage overwrite a former one."""
shader = FileShader(simple_vertex_shader(), '.glsl')
glslc_args = [
'-c', '-fshader-stage=fragment', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithMultipleFiles(expect.ValidObjectFile):
"""Tests -fshader-stage covers all subsequent files."""
shader1 = FileShader(simple_vertex_shader(), '.glsl')
# a vertex shader with .frag extension
shader2 = FileShader(simple_vertex_shader(), '.frag')
shader3 = FileShader(simple_vertex_shader(), '.a_vert_shader')
glslc_args = ['-c', '-fshader-stage=vertex', shader1, shader2, shader3]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageMultipleShaderStage(expect.ValidObjectFile):
"""Tests multiple -fshader-stage."""
shader1 = FileShader(simple_vertex_shader(), '.glsl')
shader2 = FileShader(simple_fragment_shader(), '.frag')
shader3 = FileShader(simple_vertex_shader(), '.a_vert_shader')
glslc_args = [
'-c',
'-fshader-stage=vertex', shader1,
'-fshader-stage=fragment', shader2,
'-fshader-stage=vertex', shader3]
@inside_glslc_testsuite('OptionShaderStage')
class TestFileExtensionBeforeShaderStage(expect.ValidObjectFile):
"""Tests that file extensions before -fshader-stage are not affected."""
# before -fshader-stage
shader1 = FileShader(simple_vertex_shader(), '.vert')
# after -fshader-stage
shader2 = FileShader(simple_fragment_shader(), '.frag')
shader3 = FileShader(simple_fragment_shader(), '.vert')
glslc_args = ['-c', shader1, '-fshader-stage=fragment', shader2, shader3]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWrongShaderStageValue(expect.ErrorMessage):
"""Tests that wrong shader stage value results in an error."""
shader = FileShader(simple_vertex_shader(), '.glsl')
glslc_args = ['-c', '-fshader-stage=unknown', shader]
expected_error = ["glslc: error: stage not recognized: 'unknown'\n"]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageGlslExtensionMissingShaderStage(expect.ErrorMessage):
"""Tests that missing -fshader-stage for .glsl extension results in
an error."""
shader = FileShader(simple_vertex_shader(), '.glsl')
glslc_args = ['-c', shader]
expected_error = [
"glslc: error: '", shader,
"': .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
an error."""
shader = FileShader(simple_vertex_shader(), '.a_vert_shader')
glslc_args = ['-c', shader]
expected_error = [
"glslc: error: '", shader,
"': file not recognized: File format not recognized\n"]

View File

@@ -0,0 +1,312 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def core_vert_shader_without_version():
# gl_ClipDistance doesn't exist in es profile (at least until 3.10).
return 'void main() { gl_ClipDistance[0] = 5.; }'
def core_frag_shader_without_version():
# gl_SampleID appears in core profile from 4.00.
# gl_sampleID doesn't exsit in es profile (at least until 3.10).
return 'void main() { int temp = gl_SampleID; }'
def hlsl_compute_shader_with_barriers():
# Use "main" to avoid the need for -fentry-point
return 'void main() { AllMemoryBarrierWithGroupSync(); }'
@inside_glslc_testsuite('OptionStd')
class TestStdNoArg(expect.ErrorMessage):
"""Tests -std alone."""
glslc_args = ['-std']
expected_error = ["glslc: error: unknown argument: '-std'\n"]
@inside_glslc_testsuite('OptionStd')
class TestStdEqNoArg(expect.ErrorMessage):
"""Tests -std= with no argument."""
glslc_args = ['-std=']
expected_error = ["glslc: error: invalid value '' in '-std='\n"]
@inside_glslc_testsuite('OptionStd')
class TestStdEqSpaceArg(expect.ErrorMessage):
"""Tests -std= <version-profile>."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=', '450core', shader]
expected_error = ["glslc: error: invalid value '' in '-std='\n"]
# TODO(dneto): The error message changes with different versions of glslang.
@inside_glslc_testsuite('OptionStd')
class TestMissingVersionAndStd(expect.ErrorMessageSubstr):
"""Tests that missing both #version and -std results in errors."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', shader]
expected_error_substr = ['error:']
@inside_glslc_testsuite('OptionStd')
class TestMissingVersionButHavingStd(expect.ValidObjectFile):
"""Tests that correct -std fixes missing #version."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=450core', shader]
@inside_glslc_testsuite('OptionStd')
class TestGLSL460(expect.ValidObjectFile):
"""Tests that GLSL version 4.6 is supported."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=460', shader]
@inside_glslc_testsuite('OptionStd')
class TestGLSL460Core(expect.ValidObjectFile):
"""Tests that GLSL version 4.6 core profile is supported."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=460core', shader]
@inside_glslc_testsuite('OptionStd')
class TestESSL320(expect.ValidObjectFile):
"""Tests that ESSL version 3.2 is supported."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=320es', 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."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=310es', shader]
expected_error = [
shader, ":1: error: 'gl_SampleID' : required extension not requested: "
'GL_OES_sample_variables\n1 error generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestConflictingVersionAndStd(expect.ValidObjectFileWithWarning):
"""Tests that with both #version and -std, -std takes precedence."""
# Wrong #version here on purpose.
shader = FileShader(
'#version 310 es\n' + core_frag_shader_without_version(), '.frag')
# -std overwrites the wrong #version.
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestMultipleStd(expect.ValidObjectFile):
"""Tests that for multiple -std, the last one takes effect."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=100', '-std=310es', shader, '-std=450core']
@inside_glslc_testsuite('OptionStd')
class TestMultipleFiles(expect.ValidObjectFileWithWarning):
"""Tests that -std covers all files."""
shader1 = FileShader(core_frag_shader_without_version(), '.frag')
shader2 = FileShader(core_vert_shader_without_version(), '.vert')
shader3 = FileShader(
'#version 310 es\n' + core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=450core', shader1, shader2, shader3]
expected_warning = [
shader3, ': warning: (version, profile) forced to be (450, '
'core), while in source code it is (310, es)\n'
'1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestUnkownProfile(expect.ErrorMessage):
"""Tests that -std rejects unknown profile."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=450google', shader]
expected_error = [
"glslc: error: invalid value '450google' in '-std=450google'\n"]
@inside_glslc_testsuite('OptionStd')
class TestUnkownVersion(expect.ErrorMessage):
"""Tests that -std rejects unknown version."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=42core', shader]
expected_error = [
"glslc: error: invalid value '42core' in '-std=42core'\n"]
@inside_glslc_testsuite('OptionStd')
class TestTotallyWrongStdValue(expect.ErrorMessage):
"""Tests that -std rejects totally wrong -std value."""
shader = FileShader(core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=wrong42', shader]
expected_error = [
"glslc: error: invalid value 'wrong42' in '-std=wrong42'\n"]
@inside_glslc_testsuite('OptionStd')
class TestVersionInsideSlashSlashComment(expect.ValidObjectFileWithWarning):
"""Tests that -std substitutes the correct #version string."""
# The second #version string should be substituted and this shader
# should compile successfully with -std=450core.
shader = FileShader(
'// #version 310 es\n#version 310 es\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestVersionInsideSlashStarComment(expect.ValidObjectFileWithWarning):
"""Tests that -std substitutes the correct #version string."""
# The second #version string should be substituted and this shader
# should compile successfully with -std=450core.
shader = FileShader(
'/* #version 310 es */\n#version 310 es\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestCommentBeforeVersion(expect.ValidObjectFileWithWarning):
"""Tests that comments before #version (same line) is correctly handled."""
shader = FileShader(
'/* some comment */ #version 150\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, none), while '
'in source code it is (150, none)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestCommentAfterVersion(expect.ValidObjectFileWithWarning):
"""Tests that multiple-line comments after #version is correctly handled."""
shader = FileShader(
'#version 150 compatibility ' +
'/* start \n second line \n end */\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (150, compatibility)\n1 warning generated.\n']
# The following test case is disabled because of a bug in glslang.
# When checking non-newline whitespaces, glslang only recognizes
# ' ' and '\t', leaving '\v' and '\f' unhandled. The following test
# case exposes this problem. It should be turned on once a fix for
# glslang is landed.
#@inside_glslc_testsuite('OptionStd')
class TestSpaceAroundVersion(expect.ValidObjectFileWithWarning):
"""Tests that space around #version is correctly handled."""
shader = FileShader(
'\t \t # \t \f\f version \v \t\t 310 \v\v \t es \n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestVersionInsideCrazyComment(expect.ValidObjectFileWithWarning):
"""Tests that -std substitutes the correct #version string."""
# The fourth #version string should be substituted and this shader
# should compile successfully with -std=450core.
shader = FileShader(
'/* */ /* // /* #version 310 es */\n' + # /*-style comment
'// /* */ /* /* // #version 310 es\n' + # //-style comment
'///*////*//*/*/ #version 310 es*/\n' + # //-style comment
'#version 310 es\n' + core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestVersionMissingProfile(expect.ErrorMessage):
"""Tests that missing required profile in -std results in an error."""
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = ['-c', '-std=310', shader]
expected_error = [
shader, ': error: #version: versions 300, 310, and 320 require ',
"specifying the 'es' profile\n1 error generated.\n"]
@inside_glslc_testsuite('OptionStd')
class TestVersionRedundantProfile(expect.ErrorMessageSubstr):
"""Tests that adding non-required profile in -std results in an error."""
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = ['-c', '-std=100core', shader]
expected_error_substr = [
shader, ': error: #version: versions before 150 do not allow '
'a profile token\n']

View File

@@ -0,0 +1,197 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def opengl_compat_fragment_shader():
return """#version 330
uniform highp sampler2D tex;
void main() {
gl_FragColor = texture2D(tex, vec2(0.0, 0.0));
}"""
def opengl_vertex_shader():
return """#version 330
void main() { int t = gl_VertexID; }"""
def vulkan_vertex_shader():
return """#version 310 es
void main() { int t = gl_VertexIndex; }"""
def vulkan_compute_subgroup_shader():
"""Returns a compute shader that requires Vulkan 1.1"""
return """#version 450
#extension GL_KHR_shader_subgroup_basic : enable
void main() { subgroupBarrier(); }"""
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglCompatWithOpenGlCompatShader(expect.ErrorMessageSubstr):
"""Tests that compiling OpenGL Compatibility Fragment shader with
--target-env=opengl_compat works correctly"""
shader = FileShader(opengl_compat_fragment_shader(), '.frag')
glslc_args = ['--target-env=opengl_compat', '-c', shader]
expected_error_substr = "error: opengl_compat is no longer supported"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglWithOpenGlCompatShader(expect.ErrorMessageSubstr):
"""Tests the error message of compiling OpenGL Compatibility Fragment shader
with --target-env=opengl"""
shader = FileShader(opengl_compat_fragment_shader(), '.frag')
glslc_args = ['--target-env=opengl', shader]
# Glslang does not give a pretty message. Make sure we get an error.
expected_error_substr = "errors generated"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglCompatWithOpenGlVertexShader(expect.ErrorMessageSubstr):
"""Tests that compiling OpenGL vertex shader with --target-env=opengl_compat
generates valid SPIR-V code"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl_compat', '-c', shader]
expected_error_substr = "error: opengl_compat is no longer supported"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglWithOpenGlVertexShader(expect.ValidObjectFile):
"""Tests that compiling OpenGL vertex shader with --target-env=opengl
generates valid SPIR-V code"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestDefaultTargetEnvWithVulkanShader(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific shader with a default
target environment succeeds"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkanWithVulkan1_0ShaderSucceeds(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific Vulkan 1.0 shader succeeds with
--target-env=vulkan"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_0WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific Vulkan 1.0 shader succeeds with
--target-env=vulkan1.0"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.0', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_0WithVulkan1_1ShaderFails(expect.ErrorMessageSubstr):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.0', '-c', shader]
expected_error_substr = "error: 'subgroup op' : requires SPIR-V 1.3"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_1WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile1_3):
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.1', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_1WithVulkan1_1ShaderSucceeds(expect.ValidObjectFile1_3):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.1', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile1_5):
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.2', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_1ShaderSucceeds(expect.ValidObjectFile1_5):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.2', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile1_6):
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.3', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_1ShaderSucceeds(expect.ValidObjectFile1_6):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.3', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenGL4_5WithOpenGLShaderSucceeds(expect.ValidObjectFile):
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl4.5', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenGL4_6WithOpenGLShaderFailsUnsupported(expect.ErrorMessageSubstr):
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl4.6', '-c', shader]
expected_error_substr = "invalid value 'opengl4.6' in '--target-env=opengl4.6'"
# Note: Negative tests are covered in the libshaderc_util unit tests.
# For example, that an OpenGL-specific shader should fail to compile
# for Vulkan, or a Vulkan-specific shader should fail to compile for
# OpenGL.
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqNoArg(expect.ErrorMessage):
"""Tests the error message of assigning empty string to --target-env"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=', shader]
expected_error = ["glslc: error: invalid value ",
"'' in '--target-env='\n"]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvNoEqNoArg(expect.ErrorMessage):
"""Tests the error message of using --target-env without equal sign and
arguments"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-env'\n"]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvNoEqWithArg(expect.ErrorMessage):
"""Tests the error message of using --target-env without equal sign but
arguments"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env', 'opengl', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-env'\n"]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqWrongArg(expect.ErrorMessage):
"""Tests the error message of using --target-env with wrong argument"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=wrong_arg', shader]
expected_error = ["glslc: error: invalid value ",
"'wrong_arg' in '--target-env=wrong_arg'\n"]

View File

@@ -0,0 +1,125 @@
# Copyright 2019 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
def vulkan_vertex_shader():
return """#version 310 es
void main() { int t = gl_VertexIndex; }"""
def vulkan_compute_subgroup_shader():
"""Returns a compute shader that requires Vulkan 1.1 and SPIR-V 1.3"""
return """#version 450
#extension GL_KHR_shader_subgroup_basic : enable
void main() { subgroupBarrier(); }"""
@inside_glslc_testsuite('OptionTargetSpv')
class TestDefaultTargetSpvWithVulkanShader(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific shader with a default
target environment succeeds"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestDefaultTargetSpvWithShaderRequiringSpv1p3Fails(expect.ErrorMessageSubstr):
"""Tests that compiling a shader requiring SPIR-V 1.3 with default SPIR-V
target should fail.
"""
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['-c', shader]
expected_error_substr = ["error: 'subgroup op' : requires SPIR-V 1.3\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p2WithShaderRequiringSpv1p3Fails(expect.ErrorMessageSubstr):
"""Tests that compiling a shader requiring SPIR-V 1.3 but targeting 1.2
should fail.
"""
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-spv=spv1.2', '-c', shader]
expected_error_substr = ["error: 'subgroup op' : requires SPIR-V 1.3\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p3(expect.ValidObjectFile1_3):
"""Tests that compiling to spv1.3 succeeds and generates SPIR-V 1.3 binary."""
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-spv=spv1.3', '-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p4(expect.ValidObjectFile1_4):
"""Tests that compiling to spv1.4 succeeds and generates SPIR-V 1.4 binary."""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=spv1.4', '-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p5(expect.ValidObjectFile1_5):
"""Tests that compiling to spv1.5 succeeds and generates SPIR-V 1.5 binary."""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=spv1.5', '-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p5(expect.ValidObjectFile1_6):
"""Tests that compiling to spv1.6 succeeds and generates SPIR-V 1.6 binary."""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=spv1.6', '-c', shader]
### Option parsing error cases
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvNoArg(expect.ErrorMessage):
"""Tests the error message of assigning empty string to --target-spv"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=', shader]
expected_error = ["glslc: error: invalid value ",
"'' in '--target-spv='\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvNoEqNoArg(expect.ErrorMessage):
"""Tests the error message of using --target-spv without equal sign and
arguments"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-spv'\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvNoEqWithArg(expect.ErrorMessage):
"""Tests the error message of using --target-spv without equal sign but
arguments"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv', 'spv1.3', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-spv'\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvEqWrongArg(expect.ErrorMessage):
"""Tests the error message of using --target-spv with wrong argument"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=wrong_arg', shader]
expected_error = ["glslc: error: invalid value ",
"'wrong_arg' in '--target-spv=wrong_arg'\n"]

View File

@@ -0,0 +1,390 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader, TempFileName
@inside_glslc_testsuite('File')
class SimpleFileCompiled(expect.ValidObjectFile):
"""Tests whether or not a simple glsl file compiles."""
shader = FileShader('#version 310 es\nvoid main() {}', '.frag')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('File')
class NotSpecifyingOutputName(expect.SuccessfulReturn,
expect.CorrectObjectFilePreamble):
"""Tests that when there is no -o and -E/-S/-c specified, output as a.spv."""
shader = FileShader('#version 140\nvoid main() {}', '.frag')
glslc_args = [shader]
def check_output_a_spv(self, status):
output_name = os.path.join(status.directory, 'a.spv')
return self.verify_object_file_preamble(output_name)
@inside_glslc_testsuite('Parameters')
class HelpParameters(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests the --help flag outputs correctly and does not produce and error."""
glslc_args = ['--help']
expected_stdout = '''glslc - Compile shaders into SPIR-V
Usage: glslc [options] file...
An input file of - represents standard input.
Options:
-c Only run preprocess, compile, and assemble steps.
-Dmacro[=defn] Add an implicit macro definition.
-E Outputs only the results of the preprocessing step.
Output defaults to standard output.
-fauto-bind-uniforms
Automatically assign bindings to uniform variables that
don't have an explicit 'binding' layout in the shader
source.
-fauto-map-locations
Automatically assign locations to uniform variables that
don't have an explicit 'location' layout in the shader
source.
-fauto-combined-image-sampler
Removes sampler variables and converts existing textures
to combined image-samplers.
-fentry-point=<name>
Specify the entry point name for HLSL compilation, for
all subsequent source files. Default is "main".
-fhlsl-16bit-types
Enable 16-bit type support for HLSL.
-fhlsl_functionality1, -fhlsl-functionality1
Enable extension SPV_GOOGLE_hlsl_functionality1 for HLSL
compilation.
-fhlsl-iomap Use HLSL IO mappings for bindings.
-fhlsl-offsets Use HLSL offset rules for packing members of blocks.
Affects only GLSL. HLSL rules are always used for HLSL.
-finvert-y Invert position.Y output in vertex shader.
-flimit=<settings>
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.
-flimit-file <file>
Set limits as specified in the given file.
-fnan-clamp Generate code for max and min builtins so that, when given
a NaN operand, the other operand is returned. Similarly,
the clamp builtin will favour the non-NaN operands, as if
clamp were implemented as a composition of max and min.
-fpreserve-bindings
Preserve all binding declarations, even if those bindings
are not used.
-fresource-set-binding [stage] <reg0> <set0> <binding0>
[<reg1> <set1> <binding1>...]
Explicitly sets the descriptor set and binding for
HLSL resources, by register name. Optionally restrict
it to a single stage.
-fcbuffer-binding-base [stage] <value>
Same as -fubo-binding-base.
-fimage-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
images. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fsampler-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
samplers Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fssbo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
shader storage buffer objects (SSBO). Optionally only set
it for a single shader stage. Only affects GLSL.
-ftexture-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
textures. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fuav-binding-base [stage] <value>
For automatically assigned bindings for unordered access
views (UAV), the register number is added to this base to
determine the binding number. Optionally only set it for
a single shader stage. Only affects HLSL.
-fubo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
uniform buffer objects (UBO). Optionally only set it for
a single shader stage.
For HLSL, the resource register number is added to this
base.
-fshader-stage=<stage>
Treat subsequent input files as having stage <stage>.
Valid stages are vertex, vert, fragment, frag, tesscontrol,
tesc, tesseval, tese, geometry, geom, compute, and comp.
-g Generate source-level debug information.
-h Display available options.
--help Display available options.
-I <value> Add directory to include search path.
-mfmt=<format> 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 are:
bin - SPIR-V binary words. This is the default.
c - Binary words as C initializer list of 32-bit ints
num - List of comma-separated 32-bit hex integers
-M Generate make dependencies. Implies -E and -w.
-MM An alias for -M.
-MD Generate make dependencies and compile.
-MF <file> Write dependency output to the given file.
-MT <target> Specify the target of the rule emitted by dependency
generation.
-O Optimize the generated SPIR-V code for better performance.
-Os Optimize the generated SPIR-V code for smaller size.
-O0 Disable optimization.
-o <file> Write output to <file>.
A file name of '-' represents standard output.
-std=<value> Version and profile for GLSL input files. Possible values
are concatenations of version and profile, e.g. 310es,
450core, etc. Ignored for HLSL files.
-S Emit SPIR-V assembly instead of binary.
--show-limits Display available limit names and their default values.
--target-env=<environment>
Set the target client environment, and the semantics
of warnings and errors. An optional suffix can specify
the client version. Values are:
vulkan1.0 # The default
vulkan1.1
vulkan1.2
vulkan1.3
vulkan # Same as vulkan1.0
opengl4.5
opengl # Same as opengl4.5
--target-spv=<spirv-version>
Set the SPIR-V version to be used for the generated SPIR-V
module. The default is the highest version of SPIR-V
required to be supported for the target environment.
For example, default for vulkan1.0 is spv1.0, and
the default for vulkan1.1 is spv1.3,
the default for vulkan1.2 is spv1.5.
the default for vulkan1.3 is spv1.6.
Values are:
spv1.0, spv1.1, spv1.2, spv1.3, spv1.4, spv1.5, spv1.6
--version Display compiler version information.
-w Suppresses all warning messages.
-Werror Treat all warnings as errors.
-x <language> Treat subsequent input files as having type <language>.
Valid languages are: glsl, hlsl.
For files ending in .hlsl the default is hlsl.
Otherwise the default is glsl.
'''
expected_stderr = ''
@inside_glslc_testsuite('Parameters')
class HelpIsNotTooWide(expect.StdoutNoWiderThan80Columns):
"""Tests that --help output is not too wide."""
glslc_args = ['--help']
@inside_glslc_testsuite('Parameters')
class UnknownSingleLetterArgument(expect.ErrorMessage):
"""Tests that an unknown argument triggers an error message."""
glslc_args = ['-a']
expected_error = ["glslc: error: unknown argument: '-a'\n"]
@inside_glslc_testsuite('Parameters')
class UnknownMultiLetterArgument(expect.ErrorMessage):
"""Tests that an unknown argument triggers an error message."""
glslc_args = ['-zzz']
expected_error = ["glslc: error: unknown argument: '-zzz'\n"]
@inside_glslc_testsuite('Parameters')
class UnsupportedOption(expect.ErrorMessage):
"""Tests that an unsupported option triggers an error message."""
glslc_args = ['--unsupported-option']
expected_error = [
"glslc: error: unsupported option: '--unsupported-option'\n"]
@inside_glslc_testsuite('File')
class FileNotFound(expect.ErrorMessage):
"""Tests the error message if a file cannot be found."""
blabla_file = TempFileName('blabla.frag')
glslc_args = [blabla_file]
expected_error = [
"glslc: error: cannot open input file: '", blabla_file,
"': No such file or directory\n"]
@inside_glslc_testsuite('Unsupported')
class LinkingNotSupported(expect.ErrorMessage):
"""Tests the error message generated by linking not supported yet."""
shader1 = FileShader('#version 140\nvoid main() {}', '.vert')
shader2 = FileShader('#version 140\nvoid main() {}', '.frag')
glslc_args = [shader1, shader2]
expected_error = [
'glslc: error: linking multiple files is not supported yet. ',
'Use -c to compile files individually.\n']
@inside_glslc_testsuite('Unsupported')
class MultipleStdinUnsupported(expect.ErrorMessage):
"""Tests the error message generated by having more than one - input."""
glslc_args = ['-c', '-fshader-stage=vertex', '-', '-']
expected_error = [
'glslc: error: specifying standard input "-" as input more'
' than once is not allowed.\n']
@inside_glslc_testsuite('Parameters')
class StdinWithoutShaderStage(expect.StdoutMatch, expect.StderrMatch):
"""Tests that you must use -fshader-stage when specifying - as input."""
shader = StdinShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""")
glslc_args = [shader]
expected_stdout = ''
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 8
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
MaxMeshOutputVerticesNV 256
MaxMeshOutputPrimitivesNV 512
MaxMeshWorkGroupSizeX_NV 32
MaxMeshWorkGroupSizeY_NV 1
MaxMeshWorkGroupSizeZ_NV 1
MaxTaskWorkGroupSizeX_NV 32
MaxTaskWorkGroupSizeY_NV 1
MaxTaskWorkGroupSizeZ_NV 1
MaxMeshViewCountNV 4
MaxMeshOutputVerticesEXT 256
MaxMeshOutputPrimitivesEXT 256
MaxMeshWorkGroupSizeX_EXT 128
MaxMeshWorkGroupSizeY_EXT 128
MaxMeshWorkGroupSizeZ_EXT 128
MaxTaskWorkGroupSizeX_EXT 128
MaxTaskWorkGroupSizeY_EXT 128
MaxTaskWorkGroupSizeZ_EXT 128
MaxMeshViewCountEXT 4
MaxDualSourceDrawBuffersEXT 1
"""

View File

@@ -0,0 +1,143 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A number of placeholders and their rules for expansion when used in tests.
These placeholders, when used in glslc_args or expected_* variables of
GlslCTest, have special meanings. In glslc_args, they will be substituted by
the result of instantiate_for_glslc_args(), while in expected_*, by
instantiate_for_expectation(). A TestCase instance will be passed in as
argument to the instantiate_*() methods.
"""
import os
import tempfile
from string import Template
from builtins import bytes
class PlaceHolderException(Exception):
"""Exception class for PlaceHolder."""
pass
class PlaceHolder(object):
"""Base class for placeholders."""
def instantiate_for_glslc_args(self, testcase):
"""Instantiation rules for glslc_args.
This method will be called when the current placeholder appears in
glslc_args.
Returns:
A string to replace the current placeholder in glslc_args.
"""
raise PlaceHolderException('Subclass should implement this function.')
def instantiate_for_expectation(self, testcase):
"""Instantiation rules for expected_*.
This method will be called when the current placeholder appears in
expected_*.
Returns:
A string to replace the current placeholder in expected_*.
"""
raise PlaceHolderException('Subclass should implement this function.')
class FileShader(PlaceHolder):
"""Stands for a shader whose source code is in a file."""
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.
Returns:
The name of the temporary file.
"""
shader, self.filename = tempfile.mkstemp(
dir=testcase.directory, suffix=self.suffix)
shader_object = os.fdopen(shader, 'w')
shader_object.write(self.source)
shader_object.close()
return self.filename
def instantiate_for_expectation(self, testcase):
assert self.filename is not None
return self.filename
class StdinShader(PlaceHolder):
"""Stands for a shader whose source code is from stdin."""
def __init__(self, source):
assert isinstance(source, str)
self.source = source
self.filename = None
def instantiate_for_glslc_args(self, testcase):
"""Writes the source code back to the TestCase instance."""
testcase.stdin_shader = bytes(self.source, 'utf-8')
self.filename = '-'
return self.filename
def instantiate_for_expectation(self, testcase):
assert self.filename is not None
return self.filename
class TempFileName(PlaceHolder):
"""Stands for a temporary file's name."""
def __init__(self, filename):
assert isinstance(filename, str)
assert filename != ''
self.filename = filename
def instantiate_for_glslc_args(self, testcase):
return os.path.join(testcase.directory, self.filename)
def instantiate_for_expectation(self, testcase):
return os.path.join(testcase.directory, self.filename)
class SpecializedString(PlaceHolder):
"""Returns a string that has been specialized based on TestCase.
The string is specialized by expanding it as a string.Template
with all of the specialization being done with each $param replaced
by the associated member on TestCase.
"""
def __init__(self, filename):
assert isinstance(filename, str)
assert filename != ''
self.filename = filename
def instantiate_for_glslc_args(self, testcase):
return Template(self.filename).substitute(vars(testcase))
def instantiate_for_expectation(self, testcase):
return Template(self.filename).substitute(vars(testcase))

View File

@@ -0,0 +1,461 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from environment import Directory, File
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
VERTEX_ONLY_SHADER_WITH_PRAGMA = \
"""#version 310 es
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}"""
FRAGMENT_ONLY_SHADER_WITH_PRAGMA = \
"""#version 310 es
#pragma shader_stage(fragment)
void main() {
gl_FragDepth = 10.;
}"""
TESS_CONTROL_ONLY_SHADER_WITH_PRAGMA = \
"""#version 440 core
#pragma shader_stage(tesscontrol)
layout(vertices = 3) out;
void main() { }"""
TESS_EVAL_ONLY_SHADER_WITH_PRAGMA = \
"""#version 440 core
#pragma shader_stage(tesseval)
layout(triangles) in;
void main() { }"""
GEOMETRY_ONLY_SHDER_WITH_PRAGMA = \
"""#version 150 core
#pragma shader_stage(geometry)
layout (triangles) in;
layout (line_strip, max_vertices = 4) out;
void main() { }"""
COMPUTE_ONLY_SHADER_WITH_PRAGMA = \
"""#version 310 es
#pragma shader_stage(compute)
void main() {
uvec3 temp = gl_WorkGroupID;
}"""
# In the following tests,
# PSS stands for PragmaShaderStage, and OSS stands for OptionShaderStage.
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithGlslExtension(expect.ValidObjectFile):
"""Tests #pragma shader_stage() with .glsl extension."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithUnkownExtension(expect.ValidObjectFile):
"""Tests #pragma shader_stage() with unknown extension."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.unkown')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithStdin(expect.ValidObjectFile):
"""Tests #pragma shader_stage() with stdin."""
shader = StdinShader(VERTEX_ONLY_SHADER_WITH_PRAGMA)
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithSameShaderExtension(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() specifies the same stage as file
extesion."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSOverrideShaderExtension(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() overrides file extension."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.frag')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestOSSOverridePSS(expect.ValidObjectFile):
"""Tests that -fshader-stage overrides #pragma shader_stage()."""
# wrong pragma and wrong file extension
shader = FileShader(
"""#version 310 es
#pragma shader_stage(fragment)
void main() {
gl_Position = vec4(1.);
}""", '.frag')
# -fshader-stage to the rescue! ^.^
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestMultipleSamePSS(expect.ValidObjectFile):
"""Tests that multiple identical #pragma shader_stage() works."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(vertex)
#pragma shader_stage(vertex)
void main() {
#pragma shader_stage(vertex)
gl_Position = vec4(1.);
#pragma shader_stage(vertex)
}
#pragma shader_stage(vertex)
#pragma shader_stage(vertex)
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestConflictingPSS(expect.ErrorMessage):
"""Conflicting #pragma shader_stage() directives result in an error."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
#pragma shader_stage(fragment)
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":6: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'fragment' (was 'vertex' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestAllPSSValues(expect.ValidObjectFile):
"""Tests all possible #pragma shader_stage() values."""
shader1 = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader2 = FileShader(FRAGMENT_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader3 = FileShader(TESS_CONTROL_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader4 = FileShader(TESS_EVAL_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader5 = FileShader(GEOMETRY_ONLY_SHDER_WITH_PRAGMA, '.glsl')
shader6 = FileShader(COMPUTE_ONLY_SHADER_WITH_PRAGMA, '.glsl')
glslc_args = ['-c', shader1, shader2, shader3, shader4, shader5, shader6]
@inside_glslc_testsuite('PragmaShaderStage')
class TestWrongPSSValue(expect.ErrorMessage):
"""Tests that #pragma shader_stage([wrong-stage]) results in an error."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(superstage)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'superstage'\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestEmptyPSSValue(expect.ErrorMessage):
"""Tests that #pragma shader_stage([empty]) results in an error."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage()
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: ''\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestFirstPSSBeforeNonPPCode(expect.ErrorMessage):
"""Tests that the first #pragma shader_stage() should appear before
any non-preprocessing code."""
shader = FileShader(
"""#version 310 es
#ifndef REMOVE_UNUSED_FUNCTION
int inc(int i) { return i + 1; }
#endif
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":5: error: '#pragma': the first 'shader_stage' #pragma "
'must appear before any non-preprocessing code\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSMultipleErrors(expect.ErrorMessage):
"""Tests that if there are multiple errors, they are all reported."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(idontknow)
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
#pragma shader_stage(fragment)
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'idontknow'\n",
shader, ":3: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'vertex' (was 'idontknow' at ", shader, ':2)\n',
shader, ":7: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'fragment' (was 'idontknow' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestSpacesAroundPSS(expect.ValidObjectFile):
"""Tests that spaces around #pragma shader_stage() works."""
shader = FileShader(
"""#version 310 es
# pragma shader_stage ( vertex )
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestTabsAroundPSS(expect.ValidObjectFile):
"""Tests that tabs around #pragma shader_stage() works."""
shader = FileShader(
"""#version 310 es
\t\t#\tpragma\t\t\tshader_stage\t\t(\t\t\t\tvertex\t\t)\t\t\t\t
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithMacro(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() works with macros."""
shader = FileShader(
"""#version 310 es
#if 0
some random stuff here which can cause a problem
#else
# pragma shader_stage(vertex)
#endif
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithCmdLineMacroDef(expect.ValidObjectFile):
"""Tests that macro definitions passed in from command line work."""
shader = FileShader(
"""#version 310 es
#ifdef IS_A_VERTEX_SHADER
# pragma shader_stage(vertex)
#else
# pragma shader_stage(fragment)
#endif
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', '-DIS_A_VERTEX_SHADER', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestNoMacroExpansionInsidePSS(expect.ErrorMessage):
"""Tests that there is no macro expansion inside #pragma shader_stage()."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(STAGE_FROM_CMDLINE)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', '-DSTAGE_FROM_CMDLINE=vertex', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'STAGE_FROM_CMDLINE'\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithPoundLine310(expect.ErrorMessage):
"""Tests that #pragma shader_stage() works with #line."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(unknown)
#line 42
#pragma shader_stage(google)
#line 100
#pragma shader_stage(elgoog)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'unknown'\n",
shader, ":42: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'google' (was 'unknown' at ", shader, ':2)\n',
shader, ":100: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'elgoog' (was 'unknown' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithPoundLine150(expect.ErrorMessage):
"""Tests that #pragma shader_stage() works with #line.
For older desktop versions, a #line directive specify the line number of
the #line directive, not the next line.
"""
shader = FileShader(
"""#version 150
#pragma shader_stage(unknown)
#line 42
#pragma shader_stage(google)
#line 100
#pragma shader_stage(elgoog)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'unknown'\n",
shader, ":43: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'google' (was 'unknown' at ", shader, ':2)\n',
shader, ":101: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'elgoog' (was 'unknown' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class ErrorBeforePragma(expect.ErrorMessage):
"""Tests that errors before pragmas are emitted."""
shader = FileShader(
"""#version 310 es
#something
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [shader, ':2: error: \'#\' : invalid directive:',
' something\n'
'1 error generated.\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSfromIncludedFile(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() from included files works."""
environment = Directory('.', [
File('a.glsl', '#version 140\n#include "b.glsl"\n'
'void main() { gl_Position = vec4(1.); }\n'),
File('b.glsl', '#pragma shader_stage(vertex)')])
glslc_args = ['-c', 'a.glsl']
@inside_glslc_testsuite('PragmaShaderStage')
class TestConflictingPSSfromIncludingAndIncludedFile(expect.ErrorMessage):
"""Tests that conflicting #pragma shader_stage() from including and
included files results in an error with the correct location spec."""
environment = Directory('.', [
File('a.vert',
'#version 140\n'
'#pragma shader_stage(fragment)\n'
'void main() { gl_Position = vec4(1.); }\n'
'#include "b.glsl"\n'),
File('b.glsl', '#pragma shader_stage(vertex)')])
glslc_args = ['-c', 'a.vert']
expected_error = [
"b.glsl:1: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'vertex' (was 'fragment' at a.vert:2)\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithFileNameBasedPoundLine(expect.ErrorMessage):
"""Tests that #pragma shader_stage() works with filename-based #line."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(unknown)
#line 42 "abc"
#pragma shader_stage(google)
#line 100 "def"
#pragma shader_stage(elgoog)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'unknown'\n",
"abc:42: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'google' (was 'unknown' at ", shader, ':2)\n',
"def:100: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'elgoog' (was 'unknown' at ", shader, ':2)\n']

View File

@@ -0,0 +1,37 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
@inside_glslc_testsuite('StdInOut')
class VerifyStdinWorks(expect.ValidObjectFile):
"""Tests glslc accepts vertex shader extension (.vert)."""
shader = StdinShader('#version 140\nvoid main() { }')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('StdInOut')
class VerifyStdoutWorks(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = [shader, '-o', '-']
# We expect SOME stdout, we just do not care what.
expected_stdout = True
expected_stderr = ''

View File

@@ -0,0 +1,221 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os.path
import expect
from environment import File, Directory
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
MINIMAL_SHADER = '#version 140\nvoid main() {}'
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirNoArg(expect.ErrorMessage):
"""Tests -working-directory. Behavior cribbed from Clang."""
glslc_args = ['-working-directory']
expected_error = [
"glslc: error: argument to '-working-directory' is missing "
'(expected 1 value)\n',
'glslc: error: no input files\n']
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirEqNoArg(expect.ErrorMessage):
"""Tests -working-directory=<empty>. Behavior cribbed from Clang."""
glslc_args = ['-working-directory=']
expected_error = ['glslc: error: no input files\n']
EMPTY_SHADER_IN_SUBDIR = Directory(
'subdir', [File('shader.vert', MINIMAL_SHADER)])
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirEqNoArgCompileFile(expect.ValidNamedObjectFile):
"""Tests -working-directory=<empty> when compiling input file."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-c', '-working-directory=', 'subdir/shader.vert']
# Output file should be generated into subdir/.
expected_object_filenames = ('subdir/shader.vert.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestMultipleWorkDir(expect.ValidNamedObjectFile):
"""Tests that if there are multiple -working-directory=<dir> specified,
only the last one takes effect."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-c', '-working-directory=i-dont-exist',
'-working-directory', 'i-think/me-neither',
'-working-directory=subdir', 'shader.vert']
# Output file should be generated into subdir/.
expected_object_filenames = ('subdir/shader.vert.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirPosition(expect.ValidNamedObjectFile):
"""Tests that -working-directory=<dir> affects all files before and after
it on the command line."""
environment = Directory('subdir', [
File('shader.vert', MINIMAL_SHADER),
File('cool.frag', MINIMAL_SHADER),
File('bla.vert', MINIMAL_SHADER)
])
glslc_args = ['-c', 'shader.vert', 'bla.vert',
'-working-directory=subdir', 'cool.frag']
# Output file should be generated into subdir/.
expected_object_filenames = (
'subdir/shader.vert.spv', 'subdir/cool.frag.spv', 'subdir/bla.vert.spv')
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirDeepDir(expect.ValidNamedObjectFile):
"""Tests that -working-directory=<dir> works with directory hierarchies."""
environment = Directory('subdir', [
Directory('subsubdir', [
File('one.vert', MINIMAL_SHADER),
File('two.frag', MINIMAL_SHADER)
]),
File('zero.vert', MINIMAL_SHADER)
])
glslc_args = ['-c', 'zero.vert', 'subsubdir/one.vert',
'subsubdir/two.frag', '-working-directory=subdir']
# Output file should be generated into subdir/.
expected_object_filenames = (
'subdir/zero.vert.spv', 'subdir/subsubdir/one.vert.spv',
'subdir/subsubdir/two.frag.spv')
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirCompileFile(expect.ValidNamedObjectFile):
"""Tests -working-directory=<dir> when compiling input file."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-c', '-working-directory=subdir', 'shader.vert']
# Output file should be generated into subdir/.
expected_object_filenames = ('subdir/shader.vert.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirCompileFileOutput(expect.ValidNamedObjectFile):
"""Tests -working-directory=<dir> when compiling input file and specifying
output filename."""
environment = Directory('.', [
Directory('subdir', [
Directory('bin', []),
File('shader.vert', MINIMAL_SHADER)
])
])
glslc_args = ['-c', '-o', 'bin/spv', '-working-directory=subdir',
'shader.vert']
# Output file should be generated into subdir/bin/.
expected_object_filenames = ('subdir/bin/spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirArgNoEq(expect.ValidNamedObjectFile):
"""Tests -working-directory <dir>."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-working-directory', 'subdir', 'shader.vert']
expected_object_filenames = ('a.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirEqInArg(expect.ValidNamedObjectFile):
"""Tests -working-directory=<dir-with-equal-sign-inside>."""
environment = Directory('.', [
Directory('=subdir', [File('shader.vert', MINIMAL_SHADER)]),
])
glslc_args = ['-working-directory==subdir', 'shader.vert']
expected_object_filenames = ('a.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirCompileFileAbsolutePath(expect.ValidObjectFile):
"""Tests -working-directory=<dir> when compiling input file with absolute
path."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-c', '-working-directory=subdir', shader]
# The -working-directory flag should not affect the placement of the link file.
# The following tests ensure that.
class WorkDirDoesntAffectLinkedFile(expect.ValidNamedObjectFile):
"""A base class for tests asserting that -working-directory has no impact
on the location of the output link file.
"""
environment = Directory('.', [
Directory('subdir', [
File('shader.vert', MINIMAL_SHADER),
# Try to fake glslc into putting the linked file here, though it
# shouldn't (because -working-directory doesn't impact -o).
Directory('bin', [])]),
File('shader.vert', "fake file, doesn't compile."),
Directory('bin', [])])
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileDefaultLocation(WorkDirDoesntAffectLinkedFile):
"""Tests that -working-directory doesn't impact the default link-file
location.
"""
glslc_args = ['-working-directory=subdir', 'shader.vert']
expected_object_filenames = ('a.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileExplicit(WorkDirDoesntAffectLinkedFile):
"""Tests that -working-directory doesn't impact the named link-file
location.
"""
glslc_args = ['-o', 'b.spv', '-working-directory=subdir', 'shader.vert']
expected_object_filenames = ('b.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileInSubdir(WorkDirDoesntAffectLinkedFile):
"""Tests that -working-directory doesn't impact the link-file sent into an
existing subdirectory.
"""
glslc_args = ['-o', 'bin/spv', '-working-directory=subdir', 'shader.vert']
expected_object_filenames = ('bin/spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileInvalidPath(expect.ErrorMessage):
"""Tests that -working-directory doesn't impact the error generated for an
invalid -o path.
"""
environment = Directory('.', [
Directory('subdir', [
File('shader.vert', MINIMAL_SHADER),
Directory('missing', [])]), # Present here, but missing in parent.
File('shader.vert', "fake file, doesn't compile.")])
glslc_args = [
'-o', 'missing/spv', '-working-directory=subdir', 'shader.vert']
expected_error = ['glslc: error: cannot open output file: ',
"'missing/spv': No such file or directory\n"]