Merge remote-tracking branch 'aosp/upstream-master'
Pulls in the following:
4213a47 Fixed Android.mk for Windows.
c902a06 Enable test for failure of Vulkan shader targeting OpenGL
cdfb5ac Support Glslang with its new HLSL parser library
65d92e8 Test Vulkan-specific shaders
a18ea5b Enable dependency info dumping tests for abspath
aab7744 Remove revision from SPV_ENV_*.
d3bdf59 Add -I to the glslc synopsis.
afb959a Improve the #include behaviour description.
533ba9b Reflect ExtInstSet generation steps of SPIRV-Tools in Android.mk.
7c9ed1d Add new files appearing in SPIRV-Tools to Android.mk.
8468206 libspirv.h in SPIRV-Tools removed macros for version and revision.
9ede710 Add rules to build grammar tables in Android.mk for SPIRV-Tools.
e0d3d95 Enabled relative includes in glslc.
c15f6f3 Give spvContextCreate() a target environment.
d63c5e0 Update the interface to handle the new Glslang includer.
Change-Id: Id80cb4eb345ad51b4d4e1c80312f88063afb812c
diff --git a/Android.mk b/Android.mk
index 9a988b9..6d94a00 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,6 +10,7 @@
libshaderc.a \
libshaderc_util.a \
libSPIRV.a \
+ libHLSL.a \
libSPIRV-Tools.a
define gen_libshaderc
@@ -23,14 +24,14 @@
$(1)/libshaderc_combined.a: $(addprefix $(1)/, $(ALL_LIBS)) $(1)/combine.ar
@echo "[$(TARGET_ARCH_ABI)] Combine: libshaderc_combined.a <= $(ALL_LIBS)"
- @cd $(1) && $(2)ar -M < combine.ar && cd -
+ @cd $(1) && $(2)ar -M < combine.ar && cd $(ROOT_SHADERC_PATH)
@$(2)objcopy --strip-debug $(1)/libshaderc_combined.a
$(NDK_APP_LIBS_OUT)/$(APP_STL)/$(TARGET_ARCH_ABI)/libshaderc.a: \
$(1)/libshaderc_combined.a
$(call host-mkdir,$(NDK_APP_LIBS_OUT)/$(APP_STL)/$(TARGET_ARCH_ABI))
$(call host-cp,$(1)/libshaderc_combined.a \
- $(NDK_APP_LIBS_OUT)/$(APP_STL)/$(TARGET_ARCH_ABI)/libshaderc.a)
+ ,$(NDK_APP_LIBS_OUT)/$(APP_STL)/$(TARGET_ARCH_ABI)/libshaderc.a)
ifndef HEADER_TARGET
HEADER_TARGET=1
@@ -38,13 +39,13 @@
$(ROOT_SHADERC_PATH)/libshaderc/include/shaderc/shaderc.hpp
$(call host-mkdir,$(NDK_APP_LIBS_OUT)/../include/shaderc)
$(call host-cp,$(ROOT_SHADERC_PATH)/libshaderc/include/shaderc/shaderc.hpp \
- $(NDK_APP_LIBS_OUT)/../include/shaderc/shaderc.hpp)
+ ,$(NDK_APP_LIBS_OUT)/../include/shaderc/shaderc.hpp)
$(NDK_APP_LIBS_OUT)/../include/shaderc/shaderc.h: \
$(ROOT_SHADERC_PATH)/libshaderc/include/shaderc/shaderc.h
$(call host-mkdir,$(NDK_APP_LIBS_OUT)/../include/shaderc)
$(call host-cp,$(ROOT_SHADERC_PATH)/libshaderc/include/shaderc/shaderc.h \
- $(NDK_APP_LIBS_OUT)/../include/shaderc/shaderc.h)
+ ,$(NDK_APP_LIBS_OUT)/../include/shaderc/shaderc.h)
endif
libshaderc_combined: \
@@ -55,4 +56,3 @@
$(NDK_APP_LIBS_OUT)/../include/shaderc/shaderc.h
$(eval $(call gen_libshaderc,$(TARGET_OUT),$(TOOLCHAIN_PREFIX)))
-
diff --git a/glslc/CMakeLists.txt b/glslc/CMakeLists.txt
index f0a53fb..ba4d4c5 100644
--- a/glslc/CMakeLists.txt
+++ b/glslc/CMakeLists.txt
@@ -16,7 +16,7 @@
shaderc_default_compile_options(glslc)
target_include_directories(glslc PUBLIC ${glslang_SOURCE_DIR})
target_link_libraries(glslc PRIVATE glslang OSDependent OGLCompiler
- glslang SPIRV ${CMAKE_THREAD_LIBS_INIT})
+ HLSL glslang SPIRV ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(glslc PRIVATE shaderc_util shaderc)
add_executable(glslc_exe src/main.cc)
diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc
index 5ed1f91..1c4021b 100644
--- a/glslc/README.asciidoc
+++ b/glslc/README.asciidoc
@@ -12,6 +12,7 @@
----
glslc [-c|-S|-E]
[-Dmacroname[=value]...]
+ [-Idirectory...]
[-std=standard] [-x glsl]
[-fshader-stage=...]
[--target-env=...]
@@ -208,9 +209,9 @@
==== `-I`
-`-I` adds the specified directory to the search path for include files.
-
-WARNING: Implementation is not complete yet.
+`-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
@@ -378,11 +379,26 @@
WARNING: This section is still evolving. Expect changes.
-TODO: Expected behaviors of the `#include` directive.
-
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.
diff --git a/glslc/src/file_includer.cc b/glslc/src/file_includer.cc
index 9fbbeaa..ea42e81 100644
--- a/glslc/src/file_includer.cc
+++ b/glslc/src/file_includer.cc
@@ -14,35 +14,51 @@
#include "file_includer.h"
+#include <mutex>
+#include <utility>
+
#include "libshaderc_util/io.h"
namespace glslc {
-shaderc_includer_response* FileIncluder::GetInclude(const char* filename) {
- file_full_path_ = file_finder_.FindReadableFilepath(filename);
- source_files_used_.insert(file_full_path_);
- if (!file_full_path_.empty() &&
- shaderc_util::ReadFile(file_full_path_, &file_content_)) {
- response_ = {
- file_full_path_.c_str(), file_full_path_.length(), file_content_.data(),
- file_content_.size(),
- };
- } else {
- const char error_msg[] = "Cannot find or open include file.";
- file_content_.assign(std::begin(error_msg), std::end(error_msg));
- response_ = {
- "", 0u, file_content_.data(), file_content_.size(),
- };
- }
- return &response_;
+shaderc_include_result* MakeErrorIncludeResult(const char* message) {
+ return new shaderc_include_result{"", 0, message, strlen(message)};
}
-void FileIncluder::ReleaseInclude(shaderc_includer_response*) {
- response_ = {
- nullptr, 0u, nullptr, 0u,
- };
- file_content_.clear();
- file_full_path_.clear();
+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
diff --git a/glslc/src/file_includer.h b/glslc/src/file_includer.h
index 08cb8db..ae42730 100644
--- a/glslc/src/file_includer.h
+++ b/glslc/src/file_includer.h
@@ -15,10 +15,13 @@
#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"
@@ -30,26 +33,37 @@
// 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) {}
- shaderc_includer_response* GetInclude(const char* filename) override;
- void ReleaseInclude(shaderc_includer_response* data) 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 source_files_used_;
+ return included_files_;
};
private:
// Used by GetInclude() to get the full filepath.
const shaderc_util::FileFinder& file_finder_;
- // Only one response needs to be kept alive due to the implementation of
- // libshaderc's InternalFileIncluder::include_delegate, which make copies for
- // the full path and content.
- shaderc_includer_response response_;
- std::vector<char> file_content_;
- std::string file_full_path_;
- std::unordered_set<std::string> source_files_used_;
+ // 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
diff --git a/glslc/src/main.cc b/glslc/src/main.cc
index 5f84c87..38a85b2 100644
--- a/glslc/src/main.cc
+++ b/glslc/src/main.cc
@@ -112,8 +112,6 @@
bool success = true;
bool has_stdin_input = false;
- compiler.AddIncludeDirectory("");
-
for (int i = 1; i < argc; ++i) {
const string_piece arg = argv[i];
if (arg == "--help") {
@@ -121,9 +119,8 @@
return 0;
} else if (arg == "--version") {
std::cout << kBuildVersion << std::endl;
- std::cout << "Target: SPIR-V " << SPV_SPIRV_VERSION_MAJOR << "."
- << SPV_SPIRV_VERSION_MINOR << " rev "
- << SPV_SPIRV_VERSION_REVISION << 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;
diff --git a/glslc/test/glslc_test_framework.py b/glslc/test/glslc_test_framework.py
index e6f2f52..6a2a3b9 100755
--- a/glslc/test/glslc_test_framework.py
+++ b/glslc/test/glslc_test_framework.py
@@ -269,6 +269,10 @@
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."""
diff --git a/glslc/test/include.py b/glslc/test/include.py
index dfb1aa0..a965032 100644
--- a/glslc/test/include.py
+++ b/glslc/test/include.py
@@ -14,6 +14,7 @@
import expect
from glslc_test_framework import inside_glslc_testsuite
+from placeholder import SpecializedString
from environment import File, Directory
@@ -306,3 +307,255 @@
"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.\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"
+
+""")
diff --git a/glslc/test/option_dash_M.py b/glslc/test/option_dash_M.py
index f797f1c..b7d77ba 100644
--- a/glslc/test/option_dash_M.py
+++ b/glslc/test/option_dash_M.py
@@ -268,14 +268,8 @@
dependency_rules_expected = [{'target': 'target',
'dependency': {'shader.vert'}}]
-# TODO:(qining) Add tests for absolute input path with #include directives, the
-# dependent file should also be represented in absolute path.
-# e.g. glslc -M /usr/local/a.vert
-# => a.vert.spv: /usr/local/a.vert /usr/local/b.vert /usr/local/subdir/c.vert
-# These tests needs to be enabled after we have full-fledged includer.
-
-# @inside_glslc_testsuite('OptionsCapM')
+@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.
@@ -283,17 +277,28 @@
glslc -M /usr/local/a.vert
=> a.vert.spv: /usr/local/a.vert /usr/local/b.vert
"""
- shader_a = FileShader('#version 140\n#include "b.vert"\nvoid main(){}\n',
- '.vert')
- shader_b = FileShader('void foo(){}\n', '.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_a]
- dependency_rules_expected = [{'target': shader_a,
- 'target_extension': '.spv',
- 'dependency': {shader_a, shader_b}}]
+ 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')
+@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputAbsolutePathWithIncludeSubdir(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which does #include another file in a
diff --git a/glslc/test/option_dashdash_version.py b/glslc/test/option_dashdash_version.py
index c275f47..65ba0bd 100644
--- a/glslc/test/option_dashdash_version.py
+++ b/glslc/test/option_dashdash_version.py
@@ -41,4 +41,4 @@
class TestVersionContainsTarget(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'Target:'."""
glslc_args = ['--version']
- expected_stdout = re.compile('\nTarget: SPIR-V \d+\.\d+ rev \d+')
+ expected_stdout = re.compile('\nTarget: SPIR-V \d+\.\d+')
diff --git a/glslc/test/option_target_env.py b/glslc/test/option_target_env.py
index 5979111..93b7be0 100644
--- a/glslc/test/option_target_env.py
+++ b/glslc/test/option_target_env.py
@@ -30,6 +30,11 @@
void main() { int t = gl_VertexID; }"""
+def vulkan_vertex_shader():
+ return """#version 310 es
+void main() { int t = gl_VertexIndex; }"""
+
+
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglCompatWithOpenGlCompatShader(expect.ValidObjectFile):
"""Tests that compiling OpenGL Compatibility Fragment shader with
@@ -66,6 +71,28 @@
@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 TestTargetEnvEqVulkanWithVulkanShader(expect.ValidObjectFile):
+ """Tests that compiling a Vulkan-specific shader succeeds with
+ --target-env=vulkan"""
+ shader = FileShader(vulkan_vertex_shader(), '.vert')
+ glslc_args = ['--target-env=vulkan', '-c', shader]
+
+
+# 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')
diff --git a/glslc/test/placeholder.py b/glslc/test/placeholder.py
index 2cb8e50..9c5bcfc 100644
--- a/glslc/test/placeholder.py
+++ b/glslc/test/placeholder.py
@@ -22,6 +22,7 @@
"""
import os
import tempfile
+from string import Template
class PlaceHolderException(Exception):
@@ -115,3 +116,24 @@
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))
+
diff --git a/libshaderc/include/shaderc/shaderc.h b/libshaderc/include/shaderc/shaderc.h
index b31a5f0..7823671 100644
--- a/libshaderc/include/shaderc/shaderc.h
+++ b/libshaderc/include/shaderc/shaderc.h
@@ -154,6 +154,7 @@
void shaderc_compile_options_set_generate_debug_info(
shaderc_compile_options_t options);
+
// Forces the GLSL language version and profile to a given pair. The version
// number is the same as would appear in the #version annotation in the source.
// Version and profile specified here overrides the #version annotation in the
@@ -162,44 +163,57 @@
void shaderc_compile_options_set_forced_version_profile(
shaderc_compile_options_t options, int version, shaderc_profile profile);
-// Response to a request for #include content. "Includer" is client code that
-// resolves #include arguments into objects of this type.
-//
-// TODO: File inclusion needs to be context-aware.
-// e.g.
-// In file: /path/to/main_shader.vert:
-// #include "include/a"
-// In file: /path/to/include/a":
-// #include "b"
-// When compiling /path/to/main_shader.vert, the compiler should be able to
-// go to /path/to/include/b to find the file b.
-// This needs context info from compiler to client includer, and may needs
-// interface changes.
-typedef struct {
- const char* path;
- size_t path_length;
+// Source text inclusion via #include is supported with a pair of callbacks
+// to an "includer" on the client side. The first callback processes an
+// inclusion request, and returns an include result. The includer owns
+// the contents of the result, and those contents must remain valid until the
+// second callback is invoked to release the result. Both callbacks take a
+// user_data argument to specify the client context.
+
+// An include result.
+typedef struct shaderc_include_result {
+ // The name of the source file. The name should be fully resolved
+ // in the sense that it should be a unique name in the context of the
+ // includer. For example, if the includer maps source names to files in
+ // a filesystem, then this name should be the absolute path of the file.
+ const char* source_name;
+ size_t source_name_length;
+ // The text contents of the source file.
const char* content;
size_t content_length;
-} shaderc_includer_response;
+ // User data to be passed along with this request.
+ void* user_data;
+} shaderc_include_result;
-// A function mapping a #include argument to its includer response. The
-// includer retains memory ownership of the response object.
-typedef shaderc_includer_response* (*shaderc_includer_response_get_fn)(
- void* user_data, const char* filename);
+// The kinds of include requests.
+enum shaderc_include_type {
+ shaderc_include_type_relative, // E.g. #include "source"
+ shaderc_include_type_standard // E.g. #include <source>
+};
-// A function to destroy an includer response when it's no longer needed.
-typedef void (*shaderc_includer_response_release_fn)(
- void* user_data, shaderc_includer_response* data);
+// An includer callback type for mapping an #include request to an include
+// result. The user_data parameter specifies the client context. The
+// requested_source parameter specifies the name of the source being requested.
+// The type parameter specifies the kind of inclusion request being made.
+// The requesting_source parameter specifies the name of the source containing
+// the #include request. The includer owns the result object and its contents,
+// and both must remain valid until the release callback is called on the result object.
+typedef shaderc_include_result* (*shaderc_include_resolve_fn)(
+ void* user_data,
+ const char* requested_source,
+ int type,
+ const char* requesting_source,
+ size_t include_depth);
-// Sets includer callback functions. When a compiler encounters a #include in
-// the source, it will query the includer by invoking getter on user_data and
-// the #include argument. The includer must respond with a
-// shaderc_includer_response object that remains valid until releaser is invoked
-// on it. When the compiler is done processing the response, it will invoke
-// releaser on user_data and the response pointer.
-void shaderc_compile_options_set_includer_callbacks(
- shaderc_compile_options_t options, shaderc_includer_response_get_fn getter,
- shaderc_includer_response_release_fn releaser, void* user_data);
+// An includer callback type for destroying an include result.
+typedef void (*shaderc_include_result_release_fn)(
+ void* user_data, shaderc_include_result* include_result);
+
+// Sets includer callback functions.
+void shaderc_compile_options_set_include_callbacks(
+ shaderc_compile_options_t options, shaderc_include_resolve_fn resolver,
+ shaderc_include_result_release_fn result_releaser, void* user_data);
+
// Sets the compiler mode to suppress warnings, overriding warnings-as-errors
// mode. When both suppress-warnings and warnings-as-errors modes are
@@ -267,7 +281,6 @@
size_t source_text_size, shaderc_shader_kind shader_kind,
const char* input_file_name, const char* entry_point_name,
const shaderc_compile_options_t additional_options);
-
// The following functions, operating on shaderc_compilation_result_t objects,
// offer only the basic thread-safety guarantee.
diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp
index 116a100..5131995 100644
--- a/libshaderc/include/shaderc/shaderc.hpp
+++ b/libshaderc/include/shaderc/shaderc.hpp
@@ -166,27 +166,34 @@
// A C++ version of the libshaderc includer interface.
class IncluderInterface {
public:
- // Handles shaderc_includer_response_get_fn callbacks.
- virtual shaderc_includer_response* GetInclude(const char* filename) = 0;
+ // Handles shaderc_include_resolver_fn callbacks.
+ virtual shaderc_include_result* GetInclude(
+ const char* requested_source, shaderc_include_type type,
+ const char* requesting_source,
+ size_t include_depth) = 0;
- // Handles shaderc_includer_response_release_fn callbacks.
- virtual void ReleaseInclude(shaderc_includer_response* data) = 0;
+ // Handles shaderc_include_result_release_fn callbacks.
+ virtual void ReleaseInclude(shaderc_include_result* data) = 0;
};
- // Sets the includer instance for libshaderc to call on during compilation, as
- // described in shaderc_compile_options_set_includer_callbacks(). Callbacks
+ // Sets the includer instance for libshaderc to call during compilation, as
+ // described in shaderc_compile_options_set_include_callbacks(). Callbacks
// are routed to this includer's methods.
void SetIncluder(std::unique_ptr<IncluderInterface>&& includer) {
includer_ = std::move(includer);
- shaderc_compile_options_set_includer_callbacks(
+ shaderc_compile_options_set_include_callbacks(
options_,
- [](void* user_data, const char* filename) {
+ [](void* user_data, const char* requested_source,
+ int type, const char* requesting_source,
+ size_t include_depth) {
auto* includer = static_cast<IncluderInterface*>(user_data);
- return includer->GetInclude(filename);
+ return includer->GetInclude(requested_source,
+ (shaderc_include_type)type,
+ requesting_source, include_depth);
},
- [](void* user_data, shaderc_includer_response* data) {
+ [](void* user_data, shaderc_include_result* include_result) {
auto* includer = static_cast<IncluderInterface*>(user_data);
- return includer->ReleaseInclude(data);
+ return includer->ReleaseInclude(include_result);
},
includer_.get());
}
diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc
index 73cd6b6..4d83b45 100644
--- a/libshaderc/src/shaderc.cc
+++ b/libshaderc/src/shaderc.cc
@@ -23,6 +23,7 @@
#include "SPIRV/spirv.hpp"
#include "libshaderc_util/compiler.h"
+#include "libshaderc_util/counting_includer.h"
#include "libshaderc_util/resources.h"
#include "libshaderc_util/version_profile.h"
@@ -160,54 +161,92 @@
// A bridge between the libshaderc includer and libshaderc_util includer.
class InternalFileIncluder : public shaderc_util::CountingIncluder {
public:
- InternalFileIncluder(
- const shaderc_includer_response_get_fn get_includer_response,
- const shaderc_includer_response_release_fn release_includer_response,
- void* user_data)
- : get_includer_response_(get_includer_response),
- release_includer_response_(release_includer_response),
+ InternalFileIncluder(const shaderc_include_resolve_fn resolver,
+ const shaderc_include_result_release_fn result_releaser,
+ void* user_data)
+ : resolver_(resolver),
+ result_releaser_(result_releaser),
user_data_(user_data){};
InternalFileIncluder()
- : get_includer_response_(nullptr),
- release_includer_response_(nullptr),
- user_data_(nullptr){};
+ : resolver_(nullptr), result_releaser_(nullptr), user_data_(nullptr){};
private:
// Check the validity of the callbacks.
bool AreValidCallbacks() const {
- return get_includer_response_ != nullptr &&
- release_includer_response_ != nullptr;
+ return resolver_ != nullptr &&
+ result_releaser_ != nullptr;
}
- // Find filename in search path and returns its contents.
- std::pair<std::string, std::string> include_delegate(
- const char* filename) const override {
- if (!AreValidCallbacks())
- return std::make_pair<std::string, std::string>(
- "", "unexpected include directive");
- shaderc_includer_response* data =
- get_includer_response_(user_data_, filename);
- std::pair<std::string, std::string> entry =
- std::make_pair(std::string(data->path, data->path_length),
- std::string(data->content, data->content_length));
- release_includer_response_(user_data_, data);
- return entry;
+ // Maps a shaderc_include_type to the correpsonding Glslang include type.
+ shaderc_include_type GetIncludeType(
+ glslang::TShader::Includer::IncludeType type) {
+ switch (type) {
+ case glslang::TShader::Includer::EIncludeRelative:
+ return shaderc_include_type_relative;
+ case glslang::TShader::Includer::EIncludeStandard:
+ return shaderc_include_type_standard;
+ default:
+ break;
+ }
+ assert(0 && "Unhandled shaderc_include_type");
+ return shaderc_include_type_relative;
}
- const shaderc_includer_response_get_fn get_includer_response_;
- const shaderc_includer_response_release_fn release_includer_response_;
+ // Resolves an include request for the requested source of the given
+ // type in the context of the specified requesting source. On success,
+ // returns a newly allocated IncludeResponse containing the fully resolved
+ // name of the requested source and the contents of that source.
+ // On failure, returns a newly allocated IncludeResponse where the
+ // resolved name member is an empty string, and the contents members
+ // contains error details.
+ virtual glslang::TShader::Includer::IncludeResult* include_delegate(
+ const char* requested_source,
+ glslang::TShader::Includer::IncludeType type,
+ const char* requesting_source,
+ size_t include_depth) override {
+ if (!AreValidCallbacks()) {
+ const char kUnexpectedIncludeError[] =
+ "#error unexpected include directive";
+ return new glslang::TShader::Includer::IncludeResult{
+ "", kUnexpectedIncludeError, strlen(kUnexpectedIncludeError),
+ nullptr};
+ }
+ shaderc_include_result* include_result =
+ resolver_(user_data_, requested_source, GetIncludeType(type),
+ requesting_source, include_depth);
+ // Make a glslang IncludeResult from a shaderc_include_result. The
+ // user_data member of the IncludeResult is a pointer to the
+ // shaderc_include_result object, so we can later release the latter.
+ return new glslang::TShader::Includer::IncludeResult{
+ std::string(include_result->source_name,
+ include_result->source_name_length),
+ include_result->content, include_result->content_length,
+ include_result};
+ }
+
+ // Releases the given IncludeResult.
+ virtual void release_delegate(
+ glslang::TShader::Includer::IncludeResult* result) override {
+ if (result && result_releaser_) {
+ result_releaser_(user_data_,
+ static_cast<shaderc_include_result*>(result->user_data));
+ }
+ delete result;
+ }
+
+ const shaderc_include_resolve_fn resolver_;
+ const shaderc_include_result_release_fn result_releaser_;
void* user_data_;
};
} // anonymous namespace
struct shaderc_compile_options {
- shaderc_compile_options() : includer_user_data(nullptr) {}
-
+ shaderc_compile_options() : include_user_data(nullptr) {}
shaderc_util::Compiler compiler;
- shaderc_includer_response_get_fn get_includer_response;
- shaderc_includer_response_release_fn release_includer_response;
- void* includer_user_data;
+ shaderc_include_resolve_fn include_resolver;
+ shaderc_include_result_release_fn include_result_releaser;
+ void* include_user_data;
};
shaderc_compile_options_t shaderc_compile_options_initialize() {
@@ -237,6 +276,7 @@
options->compiler.SetGenerateDebugInfo();
}
+
void shaderc_compile_options_set_forced_version_profile(
shaderc_compile_options_t options, int version, shaderc_profile profile) {
// Transfer the profile parameter from public enum type to glslang internal
@@ -258,16 +298,17 @@
}
}
-void shaderc_compile_options_set_includer_callbacks(
+void shaderc_compile_options_set_include_callbacks(
shaderc_compile_options_t options,
- shaderc_includer_response_get_fn get_includer_response,
- shaderc_includer_response_release_fn release_includer_response,
+ shaderc_include_resolve_fn resolver,
+ shaderc_include_result_release_fn result_releaser,
void* user_data) {
- options->get_includer_response = get_includer_response;
- options->release_includer_response = release_includer_response;
- options->includer_user_data = user_data;
+ options->include_resolver = resolver;
+ options->include_result_releaser = result_releaser;
+ options->include_user_data = user_data;
}
+
void shaderc_compile_options_set_suppress_warnings(
shaderc_compile_options_t options) {
options->compiler.SetSuppressWarnings();
@@ -323,6 +364,10 @@
shaderc_util::string_piece(source_text, source_text + source_text_size);
StageDeducer stage_deducer(shader_kind);
if (additional_options) {
+ InternalFileIncluder includer(
+ additional_options->include_resolver,
+ additional_options->include_result_releaser,
+ additional_options->include_user_data);
// Depends on return value optimization to avoid extra copy.
std::tie(compilation_succeeded, compilation_output_data,
compilation_output_data_size_in_bytes) =
@@ -332,19 +377,17 @@
// We need to make this a reference wrapper, so that std::function
// won't make a copy for this callable object.
std::ref(stage_deducer),
- InternalFileIncluder(
- additional_options->get_includer_response,
- additional_options->release_includer_response,
- additional_options->includer_user_data),
+ includer,
output_type, &errors, &total_warnings, &total_errors,
compiler->initializer);
} else {
// Compile with default options.
+ InternalFileIncluder includer;
std::tie(compilation_succeeded, compilation_output_data,
compilation_output_data_size_in_bytes) =
shaderc_util::Compiler().Compile(
source_string, forced_stage, input_file_name_str,
- std::ref(stage_deducer), InternalFileIncluder(), output_type,
+ std::ref(stage_deducer), includer, output_type,
&errors, &total_warnings, &total_errors, compiler->initializer);
}
diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc
index 9e3595f..cd5bcad 100644
--- a/libshaderc/src/shaderc_cpp_test.cc
+++ b/libshaderc/src/shaderc_cpp_test.cc
@@ -642,19 +642,23 @@
: fake_fs_(fake_fs), responses_({}) {}
// Get path and content from the fake file system.
- shaderc_includer_response* GetInclude(const char* filename) override {
- responses_.emplace_back(shaderc_includer_response{
- filename, strlen(filename), fake_fs_.at(std::string(filename)).c_str(),
- fake_fs_.at(std::string(filename)).size()});
+ shaderc_include_result* GetInclude(const char* requested_source,
+ shaderc_include_type type,
+ const char* requesting_source,
+ size_t include_depth) override {
+ responses_.emplace_back(shaderc_include_result{
+ requested_source, strlen(requested_source),
+ fake_fs_.at(std::string(requested_source)).c_str(),
+ fake_fs_.at(std::string(requested_source)).size()});
return &responses_.back();
}
// Response data is owned as private property, no need to release explicitly.
- void ReleaseInclude(shaderc_includer_response*) override {}
+ void ReleaseInclude(shaderc_include_result*) override {}
private:
const FakeFS& fake_fs_;
- std::vector<shaderc_includer_response> responses_;
+ std::vector<shaderc_include_result> responses_;
};
using IncluderTests = testing::TestWithParam<IncluderTestCase>;
diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc
index ee5115a..50afe8e 100644
--- a/libshaderc/src/shaderc_test.cc
+++ b/libshaderc/src/shaderc_test.cc
@@ -99,7 +99,6 @@
return shaderc_compile_into_spv(compiler, shader.c_str(), shader.size(), kind,
input_file_name, "", options);
}
-
// RAII class for shaderc_compilation_result.
class Compilation {
public:
@@ -405,6 +404,7 @@
options_.get(), OutputType::SpirvAssemblyText);
EXPECT_THAT(disassembly_text, HasSubstr("Capability Shader"));
EXPECT_THAT(disassembly_text, HasSubstr("MemoryModel"));
+
}
TEST_F(CompileStringWithOptionsTest, DisassembleMinimalShader) {
@@ -668,32 +668,33 @@
: fake_fs_(fake_fs), responses_({}) {}
// Get path and content from the fake file system.
- shaderc_includer_response* GetInclude(const char* filename) {
- responses_.emplace_back(shaderc_includer_response{
+ shaderc_include_result* GetInclude(const char* filename) {
+ responses_.emplace_back(shaderc_include_result{
filename, strlen(filename), fake_fs_.at(std::string(filename)).c_str(),
fake_fs_.at(std::string(filename)).size()});
return &responses_.back();
}
// Response data is owned as private property, no need to release explicitly.
- void ReleaseInclude(shaderc_includer_response*) {}
+ void ReleaseInclude(shaderc_include_result*) {}
// Wrapper for the corresponding member function.
- static shaderc_includer_response* GetIncluderResponseWrapper(
- void* user_data, const char* filename) {
+ static shaderc_include_result* GetIncluderResponseWrapper(
+ void* user_data, const char* filename, int,
+ const char* includer, size_t include_depth) {
return static_cast<TestIncluder*>(user_data)->GetInclude(filename);
}
// Wrapper for the corresponding member function.
static void ReleaseIncluderResponseWrapper(void* user_data,
- shaderc_includer_response* data) {
+ shaderc_include_result* data) {
return static_cast<TestIncluder*>(user_data)->ReleaseInclude(data);
}
private:
// Includer response data is stored as private property.
const FakeFS& fake_fs_;
- std::vector<shaderc_includer_response> responses_;
+ std::vector<shaderc_include_result> responses_;
};
using IncluderTests = testing::TestWithParam<IncluderTestCase>;
@@ -706,7 +707,7 @@
TestIncluder includer(fs);
Compiler compiler;
compile_options_ptr options(shaderc_compile_options_initialize());
- shaderc_compile_options_set_includer_callbacks(
+ shaderc_compile_options_set_include_callbacks(
options.get(), TestIncluder::GetIncluderResponseWrapper,
TestIncluder::ReleaseIncluderResponseWrapper, &includer);
@@ -725,7 +726,7 @@
TestIncluder includer(fs);
Compiler compiler;
compile_options_ptr options(shaderc_compile_options_initialize());
- shaderc_compile_options_set_includer_callbacks(
+ shaderc_compile_options_set_include_callbacks(
options.get(), TestIncluder::GetIncluderResponseWrapper,
TestIncluder::ReleaseIncluderResponseWrapper, &includer);
diff --git a/libshaderc_util/CMakeLists.txt b/libshaderc_util/CMakeLists.txt
index c94dd1b..bb32520 100644
--- a/libshaderc_util/CMakeLists.txt
+++ b/libshaderc_util/CMakeLists.txt
@@ -25,7 +25,7 @@
PUBLIC include PRIVATE ${glslang_SOURCE_DIR})
find_package(Threads)
target_link_libraries(shaderc_util PRIVATE
- glslang OSDependent OGLCompiler glslang SPIRV
+ glslang OSDependent OGLCompiler HLSL glslang SPIRV
SPIRV-Tools ${CMAKE_THREAD_LIBS_INIT})
shaderc_add_tests(
diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h
index cb7c320..0c19be3 100644
--- a/libshaderc_util/include/libshaderc_util/compiler.h
+++ b/libshaderc_util/include/libshaderc_util/compiler.h
@@ -111,6 +111,7 @@
generate_debug_info_(false),
message_rules_(GetDefaultRules()) {}
+
// Requests that the compiler place debug information into the object code,
// such as identifier names and line numbers.
void SetGenerateDebugInfo();
@@ -143,7 +144,6 @@
SpirvAssemblyText, // Assembly syntax defined by the SPIRV-Tools project.
PreprocessedText, // Preprocessed source code.
};
-
// Compiles the shader source in the input_source_string parameter.
//
// If the forced_shader stage parameter is not EShLangCount then
@@ -179,7 +179,7 @@
const std::function<EShLanguage(
std::ostream* error_stream,
const shaderc_util::string_piece& error_tag)>& stage_callback,
- const CountingIncluder& includer, OutputType output_type,
+ CountingIncluder& includer, OutputType output_type,
std::ostream* error_stream, size_t* total_warnings, size_t* total_errors,
GlslInitializer* initializer) const;
@@ -208,7 +208,7 @@
const std::string& error_tag,
const shaderc_util::string_piece& shader_source,
const shaderc_util::string_piece& shader_preamble,
- const CountingIncluder& includer) const;
+ CountingIncluder& includer) const;
// Cleans up the preamble in a given preprocessed shader.
//
@@ -264,6 +264,7 @@
// When true, use the default version and profile from eponymous data members.
bool force_version_profile_;
+
// Macro definitions that must be available to reference in the shader source.
MacroDictionary predefined_macros_;
diff --git a/libshaderc_util/include/libshaderc_util/counting_includer.h b/libshaderc_util/include/libshaderc_util/counting_includer.h
index 7a4ae1e..d341ad1 100644
--- a/libshaderc_util/include/libshaderc_util/counting_includer.h
+++ b/libshaderc_util/include/libshaderc_util/counting_includer.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef LIBSHADERC_UTIL_INCLUDER_H
-#define LIBSHADERC_UTIL_INCLUDER_H
+#ifndef LIBSHADERC_UTIL_COUNTING_INCLUDER_H
+#define LIBSHADERC_UTIL_COUNTING_INCLUDER_H
#include <atomic>
@@ -33,26 +33,41 @@
num_include_directives_.store(0);
}
- // Bumps num_include_directives and returns the results of
+ // Resolves an include request for a source by name, type, and name of the
+ // requesting source. For the semantics of the result, see the base class.
+ // Also increments num_include_directives and returns the results of
// include_delegate(filename). Subclasses should override include_delegate()
- // instead of this one. Also see the base-class version.
- std::pair<std::string, std::string> include(
- const char* filename) const final {
+ // instead of this method.
+ glslang::TShader::Includer::IncludeResult* include(
+ const char* requested_source, glslang::TShader::Includer::IncludeType type,
+ const char* requesting_source,
+ size_t include_depth) final {
++num_include_directives_;
- return include_delegate(filename);
+ return include_delegate(requested_source, type, requesting_source,
+ include_depth);
+ }
+
+ // Releases the given IncludeResult.
+ void releaseInclude(glslang::TShader::Includer::IncludeResult* result) final {
+ release_delegate(result);
}
int num_include_directives() const { return num_include_directives_.load(); }
private:
// Invoked by this class to provide results to
- // TShader::Includer::include(filename).
- virtual std::pair<std::string, std::string> include_delegate(
- const char* filename) const = 0;
+ // glslang::TShader::Includer::include.
+ virtual glslang::TShader::Includer::IncludeResult* include_delegate(
+ const char* requested_source, glslang::TShader::Includer::IncludeType type,
+ const char* requesting_source, size_t include_depth) = 0;
+
+ // Release the given IncludeResult.
+ virtual void release_delegate(
+ glslang::TShader::Includer::IncludeResult* result) = 0;
// The number of #include directive encountered.
- mutable std::atomic_int num_include_directives_;
+ std::atomic_int num_include_directives_;
};
}
-#endif // LIBSHADERC_UTIL_INCLUDER_H
+#endif // LIBSHADERC_UTIL_COUNTING_INCLUDER_H
diff --git a/libshaderc_util/include/libshaderc_util/file_finder.h b/libshaderc_util/include/libshaderc_util/file_finder.h
index 8aec788..2c1c9d1 100644
--- a/libshaderc_util/include/libshaderc_util/file_finder.h
+++ b/libshaderc_util/include/libshaderc_util/file_finder.h
@@ -33,14 +33,18 @@
// If a search_path() element is non-empty and not ending in a slash, then a
// slash is inserted between it and filename before its search attempt. An
// empty string in search_path() means that the filename is tried as-is.
- //
- // Usage advice: when searching #include files, you almost certainly want ""
- // to be the first element in search_path(). That way both relative and
- // absolute filenames will work as expected. Note that a "." entry on the
- // search path may be prepended to an absolute filename (eg, "/a/b/c") to
- // create a relative result (eg, ".//a/b/c").
std::string FindReadableFilepath(const std::string& filename) const;
+ // Searches for a read-openable file based on filename, which must be
+ // non-empty. The search is first attempted as a path relative to
+ // the requesting_file parameter. If no file is found relative to the
+ // requesting_file then this acts as FindReadableFilepath does. If
+ // requesting_file does not contain a '/' or a '\' character then it is
+ // assumed to be a filename and the request will be relative to the
+ // current directory.
+ std::string FindRelativeReadableFilepath(const std::string& requesting_file,
+ const std::string& filename) const;
+
// Search path for Find(). Users may add/remove elements as desired.
std::vector<std::string>& search_path() { return search_path_; }
diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc
index 35c216b..7f24aa5 100644
--- a/libshaderc_util/src/compiler.cc
+++ b/libshaderc_util/src/compiler.cc
@@ -83,7 +83,7 @@
// error message to *text_or_error.
spv_result_t DisassembleBinary(const std::vector<uint32_t>& binary,
std::string* text_or_error) {
- auto spvtools_context = spvContextCreate();
+ auto spvtools_context = spvContextCreate(SPV_ENV_UNIVERSAL_1_0);
spv_text disassembled_text = nullptr;
spv_diagnostic spvtools_diagnostic = nullptr;
@@ -107,14 +107,13 @@
} // anonymous namespace
namespace shaderc_util {
-
std::tuple<bool, std::vector<uint32_t>, size_t> Compiler::Compile(
const string_piece& input_source_string, EShLanguage forced_shader_stage,
const std::string& error_tag,
const std::function<EShLanguage(std::ostream* error_stream,
const string_piece& error_tag)>&
stage_callback,
- const CountingIncluder& includer, Compiler::OutputType output_type,
+ CountingIncluder& includer, OutputType output_type,
std::ostream* error_stream, size_t* total_warnings, size_t* total_errors,
GlslInitializer* initializer) const {
// Compilation results to be returned:
@@ -155,7 +154,8 @@
if (!success) return result_tuple;
// Because of the behavior change of the #line directive, the #line
// directive introducing each file's content must use the syntax for the
- // specified version. So we need to probe this shader's version and profile.
+ // specified version. So we need to probe this shader's version and
+ // profile.
int version;
EProfile profile;
std::tie(version, profile) = DeduceVersionProfile(preprocessed_shader);
@@ -216,7 +216,8 @@
total_warnings, total_errors);
if (!success) return result_tuple;
- // 'spirv' is an alias for the compilation_output_data. This alias is added to
+ // 'spirv' is an alias for the compilation_output_data. This alias is added
+ // to
// serve as an input for the call to DissassemblyBinary.
std::vector<uint32_t>& spirv = compilation_output_data;
// Note the call to GlslangToSpv also populates compilation_output_data.
@@ -266,8 +267,7 @@
std::tuple<bool, std::string, std::string> Compiler::PreprocessShader(
const std::string& error_tag, const string_piece& shader_source,
- const string_piece& shader_preamble,
- const CountingIncluder& includer) const {
+ const string_piece& shader_preamble, CountingIncluder& includer) const {
// The stage does not matter for preprocessing.
glslang::TShader shader(EShLangVertex);
const char* shader_strings = shader_source.data();
diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc
index 8957a7b..9614f5d 100644
--- a/libshaderc_util/src/compiler_test.cc
+++ b/libshaderc_util/src/compiler_test.cc
@@ -68,6 +68,12 @@
#pragma shader_stage(vertex)
void main() { int t = gl_VertexID; })";
+// A shader that compiles under Vulkan rules.
+// See the GL_KHR_vuklan_glsl extension to GLSL.
+const char kVulkanVertexShader[] =
+ R"(#version 310 es
+ void main() { int t = gl_VertexIndex; })";
+
// A shader that needs valueless macro predefinition E, to be compiled
// successfully.
const std::string kValuelessPredefinitionShader =
@@ -83,10 +89,14 @@
class DummyCountingIncluder : public shaderc_util::CountingIncluder {
private:
// Returns a pair of empty strings.
- virtual std::pair<std::string, std::string> include_delegate(
- const char*) const override {
- return std::make_pair(std::string(), std::string());
+ virtual glslang::TShader::Includer::IncludeResult* include_delegate(
+ const char*, glslang::TShader::Includer::IncludeType,
+ const char*,
+ size_t) override {
+ return nullptr;
}
+ virtual void release_delegate(
+ glslang::TShader::Includer::IncludeResult*) override {}
};
// A test fixture for compiling GLSL shaders.
@@ -107,9 +117,11 @@
size_t total_errors = 0;
shaderc_util::GlslInitializer initializer;
bool result = false;
+ DummyCountingIncluder dummy_includer;
std::tie(result, std::ignore, std::ignore) = compiler_.Compile(
- source, stage, "shader", stage_callback, DummyCountingIncluder(),
- output_type, &errors, &total_warnings, &total_errors, &initializer);
+ source, stage, "shader", stage_callback, dummy_includer,
+ Compiler::OutputType::SpirvBinary, &errors, &total_warnings,
+ &total_errors, &initializer);
errors_ = errors.str();
return result;
}
@@ -120,7 +132,6 @@
return SimpleCompilationSucceedsForOutputType(
source, stage, Compiler::OutputType::SpirvBinary);
}
-
protected:
Compiler compiler_;
// The error string from the most recent compilation.
@@ -145,6 +156,10 @@
EXPECT_FALSE(SimpleCompilationSucceeds(" bogus ", EShLangVertex));
}
+TEST_F(CompilerTest, SimpleVulkanShaderCompilesWithDefaultCompilerSettings) {
+ EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));
+}
+
TEST_F(CompilerTest, RespectTargetEnvOnOpenGLCompatibilityShader) {
const EShLanguage stage = EShLangFragment;
@@ -193,8 +208,6 @@
compiler_.SetMessageRules(kOpenGLRules);
EXPECT_TRUE(SimpleCompilationSucceeds(kOpenGLVertexShader, stage));
-
- // TODO(dneto): Check Vulkan rules.
}
TEST_F(CompilerTest, RespectTargetEnvOnOpenGLShaderWhenDeducingStage) {
@@ -207,12 +220,41 @@
compiler_.SetMessageRules(kOpenGLRules);
EXPECT_TRUE(
SimpleCompilationSucceeds(kOpenGLVertexShaderDeducibleStage, stage));
-
- // TODO(dneto): Check Vulkan rules.
}
-TEST_F(CompilerTest, DISABLED_RespectTargetEnvOnVulkanShader) {
- // TODO(dneto): Add test for a shader that should only compile for Vulkan.
+TEST_F(CompilerTest, RespectTargetEnvOnVulkanShader) {
+ compiler_.SetMessageRules(kVulkanRules);
+ EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));
+}
+
+TEST_F(CompilerTest, VulkanSpecificShaderFailsUnderOpenGLCompatibilityRules) {
+ compiler_.SetMessageRules(kOpenGLCompatibilityRules);
+ EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));
+}
+
+TEST_F(CompilerTest, VulkanSpecificShaderFailsUnderOpenGLRules) {
+ compiler_.SetMessageRules(kOpenGLRules);
+ EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));
+}
+
+TEST_F(CompilerTest, OpenGLCompatibilitySpecificShaderFailsUnderDefaultRules) {
+ EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader,
+ EShLangFragment));
+}
+
+TEST_F(CompilerTest, OpenGLSpecificShaderFailsUnderDefaultRules) {
+ EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLVertexShader, EShLangVertex));
+}
+
+TEST_F(CompilerTest, OpenGLCompatibilitySpecificShaderFailsUnderVulkanRules) {
+ compiler_.SetMessageRules(kVulkanRules);
+ EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader,
+ EShLangFragment));
+}
+
+TEST_F(CompilerTest, OpenGLSpecificShaderFailsUnderVulkanRules) {
+ compiler_.SetMessageRules(kVulkanRules);
+ EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLVertexShader, EShLangVertex));
}
TEST_F(CompilerTest, AddMacroDefinition) {
diff --git a/libshaderc_util/src/counting_includer_test.cc b/libshaderc_util/src/counting_includer_test.cc
index 1f452e4..0400ae3 100644
--- a/libshaderc_util/src/counting_includer_test.cc
+++ b/libshaderc_util/src/counting_includer_test.cc
@@ -19,13 +19,24 @@
namespace {
+const auto kRelative = glslang::TShader::Includer::EIncludeRelative;
+const auto kStandard = glslang::TShader::Includer::EIncludeStandard;
+
// A trivial implementation of CountingIncluder's virtual methods, so tests can
// instantiate.
class ConcreteCountingIncluder : public shaderc_util::CountingIncluder {
public:
- std::pair<std::string, std::string> include_delegate(
- const char* filename) const override {
- return std::make_pair<std::string, std::string>("", "Unexpected #include");
+ virtual glslang::TShader::Includer::IncludeResult* include_delegate(
+ const char* requested, glslang::TShader::Includer::IncludeType,
+ const char* requestor,
+ size_t) override {
+ const char kError[] = "Unexpected #include";
+ return new glslang::TShader::Includer::IncludeResult{
+ "", kError, strlen(kError), nullptr};
+ }
+ virtual void release_delegate(
+ glslang::TShader::Includer::IncludeResult* include_result) override {
+ delete include_result;
}
};
@@ -35,21 +46,21 @@
TEST(CountingIncluderTest, OneInclude) {
ConcreteCountingIncluder includer;
- includer.include("random file name");
+ includer.include("random file name", kRelative, "from me", 0);
EXPECT_EQ(1, includer.num_include_directives());
}
-TEST(CountingIncluderTest, TwoIncludes) {
+TEST(CountingIncluderTest, TwoIncludesAnyIncludeType) {
ConcreteCountingIncluder includer;
- includer.include("name1");
- includer.include("name2");
+ includer.include("name1", kRelative, "from me", 0);
+ includer.include("name2", kStandard, "me", 0);
EXPECT_EQ(2, includer.num_include_directives());
}
TEST(CountingIncluderTest, ManyIncludes) {
ConcreteCountingIncluder includer;
for (int i = 0; i < 100; ++i) {
- includer.include("filename");
+ includer.include("filename", kRelative, "from me", i);
}
EXPECT_EQ(100, includer.num_include_directives());
}
@@ -57,9 +68,12 @@
#ifndef SHADERC_DISABLE_THREADED_TESTS
TEST(CountingIncluderTest, ThreadedIncludes) {
ConcreteCountingIncluder includer;
- std::thread t1([&includer]() { includer.include("name1"); });
- std::thread t2([&includer]() { includer.include("name2"); });
- std::thread t3([&includer]() { includer.include("name3"); });
+ std::thread t1(
+ [&includer]() { includer.include("name1", kRelative, "me", 0); });
+ std::thread t2(
+ [&includer]() { includer.include("name2", kRelative, "me", 1); });
+ std::thread t3(
+ [&includer]() { includer.include("name3", kRelative, "me", 2); });
t1.join();
t2.join();
t3.join();
diff --git a/libshaderc_util/src/file_finder.cc b/libshaderc_util/src/file_finder.cc
index df926b6..d25c611 100644
--- a/libshaderc_util/src/file_finder.cc
+++ b/libshaderc_util/src/file_finder.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "libshaderc_util/file_finder.h"
+#include "libshaderc_util/string_piece.h"
#include <cassert>
#include <fstream>
@@ -21,7 +22,7 @@
namespace {
// Returns "" if path is empty or ends in '/'. Otherwise, returns "/".
-std::string MaybeSlash(const std::string& path) {
+std::string MaybeSlash(const shaderc_util::string_piece& path) {
return (path.empty() || path.back() == '/') ? "" : "/";
}
@@ -42,4 +43,29 @@
return "";
}
+std::string FileFinder::FindRelativeReadableFilepath(
+ const std::string& requesting_file, const std::string& filename) const {
+ assert(!filename.empty());
+
+ string_piece dir_name(requesting_file);
+
+ size_t last_slash = requesting_file.find_last_of("/\\");
+ if (last_slash != std::string::npos) {
+ dir_name = string_piece(requesting_file.c_str(),
+ requesting_file.c_str() + last_slash);
+ }
+
+ if (dir_name.size() == requesting_file.size()) {
+ dir_name.clear();
+ }
+
+ static const auto for_reading = std::ios_base::in;
+ std::filebuf opener;
+ const std::string relative_filename =
+ dir_name.str() + MaybeSlash(dir_name) + filename;
+ if (opener.open(relative_filename, for_reading)) return relative_filename;
+
+ return FindReadableFilepath(filename);
+}
+
} // namespace shaderc_util
diff --git a/third_party/Android.mk b/third_party/Android.mk
index f192173..ed07147 100644
--- a/third_party/Android.mk
+++ b/third_party/Android.mk
@@ -39,6 +39,20 @@
LOCAL_STATIC_LIBRARIES:=OSDependent
include $(BUILD_STATIC_LIBRARY)
+
+# Build Glslang's HLSL parser library.
+include $(CLEAR_VARS)
+LOCAL_MODULE:=HLSL
+LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti
+LOCAL_SRC_FILES:= \
+ hlsl/hlslGrammar.cpp \
+ hlsl/hlslParseHelper.cpp \
+ hlsl/hlslScanContext.cpp
+LOCAL_C_INCLUDES:=$(GLSLANG_LOCAL_PATH) \
+ $(GLSLANG_LOCAL_PATH)/hlsl
+include $(BUILD_STATIC_LIBRARY)
+
+
include $(CLEAR_VARS)
GLSLANG_OUT_PATH=$(abspath $(TARGET_OUT))
@@ -79,22 +93,44 @@
LOCAL_C_INCLUDES:=$(GLSLANG_LOCAL_PATH) \
$(GLSLANG_LOCAL_PATH)/glslang/MachineIndependent \
$(GLSLANG_OUT_PATH)
-LOCAL_STATIC_LIBRARIES:=OSDependent OGLCompiler SPIRV
+LOCAL_STATIC_LIBRARIES:=OSDependent OGLCompiler SPIRV HLSL
include $(BUILD_STATIC_LIBRARY)
SPVTOOLS_LOCAL_PATH := $(THIRD_PARTY_PATH)/spirv-tools
LOCAL_PATH := $(SPVTOOLS_LOCAL_PATH)
+SPVTOOLS_OUT_PATH=$(abspath $(TARGET_OUT))
+
+define gen_spvtools_grammar_tables
+$(call generate-file-dir,$(1)/core.insts.inc)
+$(1)/core.insts.inc $(1)/operand.kinds.inc $(1)/glsl.std.450.insts.inc $(1)/opencl.std.insts.inc: \
+ $(SPVTOOLS_LOCAL_PATH)/utils/generate_grammar_tables.py \
+ $(SPVTOOLS_LOCAL_PATH)/source/spirv.core.grammar.json \
+ $(SPVTOOLS_LOCAL_PATH)/source/extinst.glsl.std.450.grammar.json \
+ $(SPVTOOLS_LOCAL_PATH)/source/extinst.opencl.std.grammar.json
+ @$(HOST_PYTHON) $(SPVTOOLS_LOCAL_PATH)/utils/generate_grammar_tables.py \
+ --spirv-core-grammar=$(SPVTOOLS_LOCAL_PATH)/source/spirv.core.grammar.json \
+ --extinst-glsl-grammar=$(SPVTOOLS_LOCAL_PATH)/source/extinst.glsl.std.450.grammar.json \
+ --extinst-opencl-grammar=$(SPVTOOLS_LOCAL_PATH)/source/extinst.opencl.std.grammar.json \
+ --core-insts-output=$(1)/core.insts.inc \
+ --glsl-insts-output=$(1)/glsl.std.450.insts.inc \
+ --opencl-insts-output=$(1)/opencl.std.insts.inc \
+ --operand-kinds-output=$(1)/operand.kinds.inc
+ @echo "[$(TARGET_ARCH_ABI)] Grammar : instructions & operands <= grammar JSON files"
+$(SPVTOOLS_LOCAL_PATH)/source/opcode.cpp: $(1)/core.insts.inc
+$(SPVTOOLS_LOCAL_PATH)/source/operand.cpp: $(1)/operand.kinds.inc
+$(SPVTOOLS_LOCAL_PATH)/source/ext_inst.cpp: $(1)/glsl.std.450.insts.inc $(1)/opencl.std.insts.inc
+endef
+$(eval $(call gen_spvtools_grammar_tables,$(SPVTOOLS_OUT_PATH)))
include $(CLEAR_VARS)
LOCAL_MODULE := SPIRV-Tools
LOCAL_C_INCLUDES := \
$(SPVTOOLS_LOCAL_PATH)/include \
- $(SPVTOOLS_LOCAL_PATH)/external/include \
- $(SPVTOOLS_LOCAL_PATH)/source
+ $(SPVTOOLS_LOCAL_PATH)/source \
+ $(SPVTOOLS_OUT_PATH)
LOCAL_EXPORT_C_INCLUDES := \
- $(SPVTOOLS_LOCAL_PATH)/include \
- $(SPVTOOLS_LOCAL_PATH)/external/include
+ $(SPVTOOLS_LOCAL_PATH)/include
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti
LOCAL_SRC_FILES:= \
source/assembly_grammar.cpp \
@@ -107,11 +143,12 @@
source/operand.cpp \
source/print.cpp \
source/spirv_endian.cpp \
+ source/spirv_target_env.cpp \
source/table.cpp \
source/text.cpp \
source/text_handler.cpp \
- source/validate_cfg.cpp \
source/validate.cpp \
+ source/validate_cfg.cpp \
source/validate_id.cpp \
source/validate_instruction.cpp \
source/validate_layout.cpp \