Vulkan: SPIR-V Gen: Support multiview

Bug: angleproject:4889
Change-Id: Ibe66f53357473dbb4435af58775b524d83ed250b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3052675
Reviewed-by: Tim Van Patten <timvp@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/compiler/translator/BuildSPIRV.cpp b/src/compiler/translator/BuildSPIRV.cpp
index 4ae20a7..844a342 100644
--- a/src/compiler/translator/BuildSPIRV.cpp
+++ b/src/compiler/translator/BuildSPIRV.cpp
@@ -1623,6 +1623,11 @@
     mExecutionModes.set(executionMode);
 }
 
+void SPIRVBuilder::addExtension(SPIRVExtensions extension)
+{
+    mExtensions.set(extension);
+}
+
 void SPIRVBuilder::setEntryPointId(spirv::IdRef id)
 {
     ASSERT(!mEntryPointId.valid());
@@ -2038,7 +2043,8 @@
         spirv::WriteCapability(&result, capability);
     }
 
-    // - OpExtension instructions (TODO: http://anglebug.com/4889)
+    // - OpExtension instructions
+    writeExtensions(&result);
 
     // - OpExtInstImport
     if (mExtInstImportIdStd.valid())
@@ -2062,13 +2068,14 @@
                            mEntryPointInterfaceList);
 
     // - OpExecutionMode instructions
-    generateExecutionModes(&result);
+    writeExecutionModes(&result);
 
-    // - OpSource instruction.
+    // - OpSource and OpSourceExtension instructions.
     //
     // This is to support debuggers and capture/replay tools and isn't strictly necessary.
     spirv::WriteSource(&result, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
                        nullptr);
+    writeSourceExtensions(&result);
 
     // Append the already generated sections in order
     result.insert(result.end(), mSpirvDebug.begin(), mSpirvDebug.end());
@@ -2084,7 +2091,7 @@
     return result;
 }
 
-void SPIRVBuilder::generateExecutionModes(spirv::Blob *blob)
+void SPIRVBuilder::writeExecutionModes(spirv::Blob *blob)
 {
     switch (mShaderType)
     {
@@ -2166,4 +2173,34 @@
     }
 }
 
+void SPIRVBuilder::writeExtensions(spirv::Blob *blob)
+{
+    for (SPIRVExtensions extension : mExtensions)
+    {
+        switch (extension)
+        {
+            case SPIRVExtensions::MultiviewOVR:
+                spirv::WriteExtension(blob, "SPV_KHR_multiview");
+                break;
+            default:
+                UNREACHABLE();
+        }
+    }
+}
+
+void SPIRVBuilder::writeSourceExtensions(spirv::Blob *blob)
+{
+    for (SPIRVExtensions extension : mExtensions)
+    {
+        switch (extension)
+        {
+            case SPIRVExtensions::MultiviewOVR:
+                spirv::WriteSourceExtension(blob, "GL_OVR_multiview");
+                break;
+            default:
+                UNREACHABLE();
+        }
+    }
+}
+
 }  // namespace sh
diff --git a/src/compiler/translator/BuildSPIRV.h b/src/compiler/translator/BuildSPIRV.h
index 064b84b..392d73b 100644
--- a/src/compiler/translator/BuildSPIRV.h
+++ b/src/compiler/translator/BuildSPIRV.h
@@ -10,6 +10,7 @@
 #define COMPILER_TRANSLATOR_BUILDSPIRV_H_
 
 #include "common/FixedVector.h"
+#include "common/PackedEnums.h"
 #include "common/bitset_utils.h"
 #include "common/hash_utils.h"
 #include "common/spirv/spirv_instruction_builder_autogen.h"
@@ -274,6 +275,16 @@
     bool isBreakable = false;
 };
 
+// List of known extensions
+enum class SPIRVExtensions
+{
+    // GL_OVR_multiview / SPV_KHR_multiview
+    MultiviewOVR = 0,
+
+    InvalidEnum = 1,
+    EnumCount   = 1,
+};
+
 // Helper class to construct SPIR-V
 class SPIRVBuilder : angle::NonCopyable
 {
@@ -335,6 +346,7 @@
 
     void addCapability(spv::Capability capability);
     void addExecutionMode(spv::ExecutionMode executionMode);
+    void addExtension(SPIRVExtensions extension);
     void setEntryPointId(spirv::IdRef id);
     void addEntryPointInterfaceVariableId(spirv::IdRef id);
     void writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId);
@@ -432,7 +444,9 @@
     uint32_t nextUnusedInputLocation(uint32_t consumedCount);
     uint32_t nextUnusedOutputLocation(uint32_t consumedCount);
 
-    void generateExecutionModes(spirv::Blob *blob);
+    void writeExecutionModes(spirv::Blob *blob);
+    void writeExtensions(spirv::Blob *blob);
+    void writeSourceExtensions(spirv::Blob *blob);
 
     ANGLE_MAYBE_UNUSED TCompiler *mCompiler;
     ShCompileOptions mCompileOptions;
@@ -446,6 +460,8 @@
     // shader metadata, but some are only discovered while traversing the tree.  Only the latter
     // execution modes are stored here.
     angle::BitSet<32> mExecutionModes;
+    // Extensions used by the shader.
+    angle::PackedEnumBitSet<SPIRVExtensions> mExtensions;
 
     // The list of interface variables and the id of main() populated as the instructions are
     // generated.  Used for the OpEntryPoint instruction.
diff --git a/src/compiler/translator/OutputSPIRV.cpp b/src/compiler/translator/OutputSPIRV.cpp
index b00709f..246dc9b 100644
--- a/src/compiler/translator/OutputSPIRV.cpp
+++ b/src/compiler/translator/OutputSPIRV.cpp
@@ -459,6 +459,7 @@
         case EvqLocalInvocationID:
         case EvqGlobalInvocationID:
         case EvqLocalInvocationIndex:
+        case EvqViewIDOVR:
             return spv::StorageClassInput;
 
         case EvqFragDepth:
@@ -634,6 +635,14 @@
             builtInDecoration = spv::BuiltInLocalInvocationIndex;
             break;
 
+        // Extensions
+        case EvqViewIDOVR:
+            name              = "gl_ViewID_OVR";
+            builtInDecoration = spv::BuiltInViewIndex;
+            mBuilder.addCapability(spv::CapabilityMultiView);
+            mBuilder.addExtension(SPIRVExtensions::MultiviewOVR);
+            break;
+
         default:
             UNREACHABLE();
     }