Merge remote-tracking branch 'aosp/upstream-master' into update-shaderc

Include:
849ae99 Install shaderc header files.
7ae44a1 Add -fauto-bind-uniforms to glslc
ea687fd Add C, C++ API option to auto bind uniforms
fc60017 Add libshader_util::Compiler::SetAutoBindUniforms
26c29e4 Test compiler option to auto bind uniforms

Test: checkbuild.py on Linux; unit tests on Windows
Change-Id: Id5812d91c4e04a87aba565baa9e9668ee34b6120
diff --git a/CHANGES b/CHANGES
index 90697e2..ba4316b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
 Revision history for Shaderc
 
 v2017.1-dev 2017-01-02
+ - Add option to automatically assign bindings to uniform variables
+   that don't have an explicit 'binding' layout in the shader source.
  - Fixes issues:
    #289: Don't output an object file when compilation fails.
 
diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc
index b1551cd..c8146c7 100644
--- a/glslc/README.asciidoc
+++ b/glslc/README.asciidoc
@@ -17,6 +17,7 @@
 
 glslc [-c|-S|-E]
       [-x ...] [-std=standard]
+      [-fauto-bind-uniforms]
       [-fentry-point=...]
       [-flimit=...]
       [-fshader-stage=...]
@@ -128,6 +129,20 @@
 
 === Language and Mode Selection Options
 
+[[option-f-auto-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-f-entry-point]]
 ==== `-fentry-point=`
 
diff --git a/glslc/src/main.cc b/glslc/src/main.cc
index 108212d..bddb6a5 100644
--- a/glslc/src/main.cc
+++ b/glslc/src/main.cc
@@ -49,6 +49,10 @@
   -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.
   -fentry-point=<name>
                     Specify the entry point name for HLSL compilation, for
                     all subsequent source files.  Default is "main".
@@ -194,6 +198,8 @@
                   << std::endl;
         return 1;
       }
+    } else if (arg == "-fauto-bind-uniforms") {
+      compiler.options().SetAutoBindUniforms(true);
     } else if (arg.starts_with("-fentry-point=")) {
       current_entry_point_name =
           arg.substr(std::strlen("-fentry-point=")).str();
diff --git a/glslc/test/expect.py b/glslc/test/expect.py
index 010ca93..1909b4f 100644
--- a/glslc/test/expect.py
+++ b/glslc/test/expect.py
@@ -335,6 +335,32 @@
         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.
diff --git a/glslc/test/option_fauto_bind_uniforms.py b/glslc/test/option_fauto_bind_uniforms.py
new file mode 100644
index 0000000..88d59e2
--- /dev/null
+++ b/glslc/test/option_fauto_bind_uniforms.py
@@ -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_WITH_UNIFORMS_WITHOUT_BINDINGS = """#version 140
+  uniform texture2D my_tex;
+  uniform sampler my_sam;
+  void main() {
+    texture(sampler2D(my_tex,my_sam),vec2(1.0));
+  }"""
+
+@inside_glslc_testsuite('OptionFAutoBindUniforms')
+class UniformBindingsNotCreatedByDefault(expect.ValidAssemblyFileWithoutSubstr):
+    """Tests that the compiler does not generate bindings for uniforms by default."""
+
+    shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
+    glslc_args = ['-S', shader]
+    # Sufficient to just check one of the uniforms.
+    unexpected_assembly_substr = "OpDecorate %my_sam Binding"
+
+
+@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"
diff --git a/glslc/test/parameter_tests.py b/glslc/test/parameter_tests.py
index ccef5d3..6f7a1fa 100644
--- a/glslc/test/parameter_tests.py
+++ b/glslc/test/parameter_tests.py
@@ -57,6 +57,10 @@
   -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.
   -fentry-point=<name>
                     Specify the entry point name for HLSL compilation, for
                     all subsequent source files.  Default is "main".
diff --git a/libshaderc/CMakeLists.txt b/libshaderc/CMakeLists.txt
index b40bff0..020d5f0 100644
--- a/libshaderc/CMakeLists.txt
+++ b/libshaderc/CMakeLists.txt
@@ -13,6 +13,13 @@
 shaderc_default_compile_options(shaderc)
 target_include_directories(shaderc PUBLIC include PRIVATE ${glslang_SOURCE_DIR})
 
+install(
+  FILES
+    include/shaderc/shaderc.h
+    include/shaderc/shaderc.hpp
+  DESTINATION
+    include/shaderc)
+
 install(TARGETS shaderc
   LIBRARY DESTINATION lib
   ARCHIVE DESTINATION lib)
diff --git a/libshaderc/include/shaderc/shaderc.h b/libshaderc/include/shaderc/shaderc.h
index 26d5421..9e23177 100644
--- a/libshaderc/include/shaderc/shaderc.h
+++ b/libshaderc/include/shaderc/shaderc.h
@@ -346,6 +346,11 @@
 void shaderc_compile_options_set_limit(
     shaderc_compile_options_t options, shaderc_limit limit, int value);
 
+// Sets whether the compiler should automatically assign bindings to uniforms
+// that aren't already explicitly bound in the shader source.
+void shaderc_compile_options_set_auto_bind_uniforms(
+    shaderc_compile_options_t options, bool auto_bind);
+
 // An opaque handle to the results of a call to any shaderc_compile_into_*()
 // function.
 typedef struct shaderc_compilation_result* shaderc_compilation_result_t;
diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp
index 3023ebb..9c5663e 100644
--- a/libshaderc/include/shaderc/shaderc.hpp
+++ b/libshaderc/include/shaderc/shaderc.hpp
@@ -248,6 +248,12 @@
     shaderc_compile_options_set_limit(options_, limit, value);
   }
 
+  // Sets whether the compiler should automatically assign bindings to uniforms
+  // that aren't already explicitly bound in the shader source.
+  void SetAutoBindUniforms(bool auto_bind) {
+    shaderc_compile_options_set_auto_bind_uniforms(options_, auto_bind);
+  }
+
  private:
   CompileOptions& operator=(const CompileOptions& other) = delete;
   shaderc_compile_options_t options_;
diff --git a/libshaderc/src/common_shaders_for_test.h b/libshaderc/src/common_shaders_for_test.h
index 0e72498..71dde55 100644
--- a/libshaderc/src/common_shaders_for_test.h
+++ b/libshaderc/src/common_shaders_for_test.h
@@ -218,6 +218,14 @@
          OpReturn
          OpFunctionEnd)";
 
+const char kShaderWithUniformsWithoutBindings[] =
+    R"(#version 450
+       uniform texture2D my_tex;
+       uniform sampler my_sam;
+       void main() {
+         texture(sampler2D(my_tex,my_sam),vec2(1.0));
+       })";
+
 #ifdef __cplusplus
 }
 #endif  // __cplusplus
diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc
index ee32d02..c67b29b 100644
--- a/libshaderc/src/shaderc.cc
+++ b/libshaderc/src/shaderc.cc
@@ -364,6 +364,11 @@
   options->compiler.SetLimit(CompilerLimit(limit), value);
 }
 
+void shaderc_compile_options_set_auto_bind_uniforms(
+    shaderc_compile_options_t options, bool auto_bind) {
+  options->compiler.SetAutoBindUniforms(auto_bind);
+}
+
 shaderc_compiler_t shaderc_compiler_initialize() {
   static shaderc_util::GlslangInitializer* initializer =
       new shaderc_util::GlslangInitializer;
diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc
index bf5aa33..a6f49bb 100644
--- a/libshaderc/src/shaderc_cpp_test.cc
+++ b/libshaderc/src/shaderc_cpp_test.cc
@@ -33,6 +33,7 @@
 using testing::Each;
 using testing::Eq;
 using testing::HasSubstr;
+using testing::Not;
 
 // Helper function to check if the compilation result indicates a successful
 // compilation.
@@ -1148,4 +1149,32 @@
                                   options_));
 }
 
+TEST_F(CppInterface, UniformsWithoutBindingsHaveNoBindingsByDefault) {
+  CompileOptions options;
+  const std::string disassembly_text = AssemblyOutput(
+      kShaderWithUniformsWithoutBindings, shaderc_glsl_vertex_shader, options);
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_tex Binding")));
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_sam Binding")));
+}
+
+TEST_F(CppInterface,
+       UniformsWithoutBindingsOptionSetNoBindingsHaveNoBindings) {
+  CompileOptions options;
+  options.SetAutoBindUniforms(false);
+  const std::string disassembly_text = AssemblyOutput(
+      kShaderWithUniformsWithoutBindings, shaderc_glsl_vertex_shader, options);
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_tex Binding")));
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_sam Binding")));
+}
+
+TEST_F(CppInterface,
+       UniformsWithoutBindingsOptionSetAutoBindingsAssignsBindings) {
+  CompileOptions options;
+  options.SetAutoBindUniforms(true);
+  const std::string disassembly_text = AssemblyOutput(
+      kShaderWithUniformsWithoutBindings, shaderc_glsl_vertex_shader, options);
+  EXPECT_THAT(disassembly_text, HasSubstr("OpDecorate %my_tex Binding 0"));
+  EXPECT_THAT(disassembly_text, HasSubstr("OpDecorate %my_sam Binding 1"));
+}
+
 }  // anonymous namespace
diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc
index 927a53d..8e76626 100644
--- a/libshaderc/src/shaderc_test.cc
+++ b/libshaderc/src/shaderc_test.cc
@@ -27,6 +27,7 @@
 
 using testing::Each;
 using testing::HasSubstr;
+using testing::Not;
 
 TEST(Init, MultipleCalls) {
   shaderc_compiler_t compiler1, compiler2, compiler3;
@@ -1425,4 +1426,44 @@
                                   options_.get()));
 }
 
+TEST_F(CompileStringWithOptionsTest,
+       UniformsWithoutBindingsHaveNoBindingsByDefault) {
+  const std::string disassembly_text = CompilationOutput(
+      kShaderWithUniformsWithoutBindings, shaderc_glsl_vertex_shader,
+      options_.get(), OutputType::SpirvAssemblyText);
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_tex Binding")));
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_sam Binding")));
+}
+
+TEST_F(CompileStringWithOptionsTest,
+       UniformsWithoutBindingsOptionSetNoBindingsHaveNoBindings) {
+  shaderc_compile_options_set_auto_bind_uniforms(options_.get(), false);
+  const std::string disassembly_text = CompilationOutput(
+      kShaderWithUniformsWithoutBindings, shaderc_glsl_vertex_shader,
+      options_.get(), OutputType::SpirvAssemblyText);
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_tex Binding")));
+  EXPECT_THAT(disassembly_text, Not(HasSubstr("OpDecorate %my_sam Binding")));
+}
+
+TEST_F(CompileStringWithOptionsTest,
+       UniformsWithoutBindingsOptionSetAutoBindingsAssignsBindings) {
+  shaderc_compile_options_set_auto_bind_uniforms(options_.get(), true);
+  const std::string disassembly_text = CompilationOutput(
+      kShaderWithUniformsWithoutBindings, shaderc_glsl_vertex_shader,
+      options_.get(), OutputType::SpirvAssemblyText);
+  EXPECT_THAT(disassembly_text, HasSubstr("OpDecorate %my_tex Binding 0"));
+  EXPECT_THAT(disassembly_text, HasSubstr("OpDecorate %my_sam Binding 1"));
+}
+
+TEST_F(CompileStringWithOptionsTest, AutoBindUniformsOptionsSurvivesCloning) {
+  shaderc_compile_options_set_auto_bind_uniforms(options_.get(), true);
+  compile_options_ptr cloned_options(
+      shaderc_compile_options_clone(options_.get()));
+  const std::string disassembly_text = CompilationOutput(
+      kShaderWithUniformsWithoutBindings, shaderc_glsl_vertex_shader,
+      cloned_options.get(), OutputType::SpirvAssemblyText);
+  EXPECT_THAT(disassembly_text, HasSubstr("OpDecorate %my_tex Binding 0"));
+  EXPECT_THAT(disassembly_text, HasSubstr("OpDecorate %my_sam Binding 1"));
+}
+
 }  // anonymous namespace
diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h
index 50ab01c..907ec5b 100644
--- a/libshaderc_util/include/libshaderc_util/compiler.h
+++ b/libshaderc_util/include/libshaderc_util/compiler.h
@@ -139,7 +139,8 @@
         enabled_opt_passes_(),
         target_env_(TargetEnv::Vulkan),
         source_language_(SourceLanguage::GLSL),
-        limits_(kDefaultTBuiltInResource) {}
+        limits_(kDefaultTBuiltInResource),
+        auto_bind_uniforms_(false) {}
 
   // Requests that the compiler place debug information into the object code,
   // such as identifier names and line numbers.
@@ -178,6 +179,10 @@
   // Returns the current limit.
   int GetLimit(Limit limit) const;
 
+  // Set whether the compiler automatically assigns bindings to
+  // uniform variables that don't have explicit bindings.
+  void SetAutoBindUniforms(bool auto_bind) { auto_bind_uniforms_ = auto_bind; }
+
   // Compiles the shader source in the input_source_string parameter.
   //
   // If the forced_shader stage parameter is not EShLangCount then
@@ -327,6 +332,10 @@
 
   // The resource limits to be used.
   TBuiltInResource limits_;
+
+  // True if the compiler should automatically bind uniforms that don't
+  // have explicit bindings.
+  bool auto_bind_uniforms_;
 };
 
 // Converts a string to a vector of uint32_t by copying the content of a given
diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc
index 096fece..69ac12b 100644
--- a/libshaderc_util/src/compiler.cc
+++ b/libshaderc_util/src/compiler.cc
@@ -204,6 +204,7 @@
                                        &string_names, 1);
   shader.setPreamble(preamble.c_str());
   shader.setEntryPoint(entry_point_name);
+  shader.setAutoMapBindings(auto_bind_uniforms_);
 
   // TODO(dneto): Generate source-level debug info if requested.
   bool success =
@@ -218,7 +219,7 @@
 
   glslang::TProgram program;
   program.addShader(&shader);
-  success = program.link(EShMsgDefault);
+  success = program.link(EShMsgDefault) && program.mapIO();
   success &= PrintFilteredErrors(error_tag, error_stream, warnings_as_errors_,
                                  suppress_warnings_, program.getInfoLog(),
                                  total_warnings, total_errors);
diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc
index 3c076ae..396f312 100644
--- a/libshaderc_util/src/compiler_test.cc
+++ b/libshaderc_util/src/compiler_test.cc
@@ -20,12 +20,14 @@
 
 #include "death_test.h"
 #include "libshaderc_util/counting_includer.h"
+#include "libshaderc_util/spirv_tools_wrapper.h"
 
 namespace {
 
 using shaderc_util::Compiler;
 using ::testing::HasSubstr;
 using ::testing::Eq;
+using ::testing::Not;
 
 // A trivial vertex shader
 const char kVertexShader[] =
@@ -84,6 +86,28 @@
     R"(float4 EntryPoint(uint index : SV_VERTEXID) : SV_POSITION
        { return float4(1.0, 2.0, 3.0, 4.0); })";
 
+// A GLSL vertex shader without bindings for its uniforms.
+const char kGlslFragShaderNoExplicitBinding[] =
+    R"(#version 450
+       #extension GL_ARB_sparse_texture2: enable
+       uniform texture2D my_tex;
+       uniform sampler my_sam;
+       layout(rgba32f) uniform image2D my_img;
+       void main() {
+         texture(sampler2D(my_tex,my_sam),vec2(1.0));
+         vec4 t = vec4(1.0);
+         sparseImageLoadARB(my_img,ivec2(0),t);
+       })";
+
+// Returns the disassembly of the given SPIR-V binary, as a string.
+// Assumes the disassembly will be successful when targeting Vulkan.
+std::string Disassemble(const std::vector<uint32_t> binary) {
+  std::string result;
+  shaderc_util::SpirvToolsDisassemble(Compiler::TargetEnv::Vulkan, binary,
+                                      &result);
+  return result;
+}
+
 // A CountingIncluder that never returns valid content for a requested
 // file inclusion.
 class DummyCountingIncluder : public shaderc_util::CountingIncluder {
@@ -455,4 +479,56 @@
   EXPECT_EQ(shaderc_over_glslang, words[generator_word_index] >> 16u);
 }
 
+TEST_F(CompilerTest, DefaultsDoNotSetBindings) {
+  const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,
+                                             EShLangFragment);
+  const auto disassembly = Disassemble(words);
+  EXPECT_THAT(disassembly, Not(HasSubstr("OpDecorate %my_tex Binding 0")));
+  EXPECT_THAT(disassembly, Not(HasSubstr("OpDecorate %my_sam Binding 1")));
+  EXPECT_THAT(disassembly, Not(HasSubstr("OpDecorate %my_img Binding 2")));
+}
+
+TEST_F(CompilerTest, NoAutoMapBindingsDoesNotSetBindings) {
+  compiler_.SetAutoBindUniforms(false);
+  const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,
+                                             EShLangFragment);
+  const auto disassembly = Disassemble(words);
+  EXPECT_THAT(disassembly, Not(HasSubstr("OpDecorate %my_tex Binding")))
+      << disassembly;
+  EXPECT_THAT(disassembly, Not(HasSubstr("OpDecorate %my_sam Binding")));
+  EXPECT_THAT(disassembly, Not(HasSubstr("OpDecorate %my_img Binding")));
+}
+
+TEST_F(CompilerTest, AutoMapBindingsSetsBindings) {
+  compiler_.SetAutoBindUniforms(true);
+  const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,
+                                             EShLangFragment);
+  const auto disassembly = Disassemble(words);
+  EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 0"))
+      << disassembly;
+  EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 1"));
+  EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 2"));
+}
+
+TEST_F(CompilerTest, EmitMessageTextOnlyOnce) {
+  // Emit a warning by compiling a shader without a default entry point name.
+  // The warning should only be emitted once even though we do parsing, linking,
+  // and IO mapping.
+  Compiler c;
+  std::stringstream errors;
+  size_t total_warnings = 0;
+  size_t total_errors = 0;
+  shaderc_util::GlslangInitializer initializer;
+  bool result = false;
+  DummyCountingIncluder dummy_includer;
+  std::tie(result, std::ignore, std::ignore) = c.Compile(
+      "#version 150\nvoid MyEntryPoint(){}", EShLangVertex, "shader", "",
+      dummy_stage_callback_, dummy_includer, Compiler::OutputType::SpirvBinary,
+      &errors, &total_warnings, &total_errors, &initializer);
+  const std::string errs = errors.str();
+  EXPECT_THAT(errs, Eq("shader: error: Linking vertex stage: Missing entry "
+                       "point: Each stage requires one entry point\n"))
+      << errs;
+}
+
 }  // anonymous namespace