Initialize ANGLE_multiview caps and workaround state

The patch checks whether ANGLE_multiview can be supported in the OpenGL
renderer, updates the caps and adds a workaround field to enable
multiview support through the NV_viewport_array2 extension.

BUG=angleproject:2062
TEST=angle_end2end_tests

Change-Id: I99dae10564db7bcca41d7624f8de272c1d996e09
Reviewed-on: https://chromium-review.googlesource.com/567934
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index a194071..92c850a 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -685,12 +685,14 @@
         << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
         << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
         << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
+        << ":OVR_multiview:" << compileResources.OVR_multiview
         << ":EXT_YUV_target:" << compileResources.EXT_YUV_target
         << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
         << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
         << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
         << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
         << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
+        << ":MaxViewsOVR:" << compileResources.MaxViewsOVR
         << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
         << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
         << ":MaxImageUnits:" << compileResources.MaxImageUnits
diff --git a/src/compiler/translator/ShaderLang.cpp b/src/compiler/translator/ShaderLang.cpp
index adeebf3..08c4bbf 100644
--- a/src/compiler/translator/ShaderLang.cpp
+++ b/src/compiler/translator/ShaderLang.cpp
@@ -179,7 +179,7 @@
     // Extensions constants.
     resources->MaxDualSourceDrawBuffers = 0;
 
-    resources->MaxViewsOVR = 2;
+    resources->MaxViewsOVR = 4;
 
     // Disable name hashing by default.
     resources->HashFunction = nullptr;
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 67085e4..8b159f6 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -188,6 +188,8 @@
       ARMshaderFramebufferFetch(false),
       NVshaderFramebufferFetch(false),
       fragDepth(false),
+      multiview(false),
+      maxViews(1u),
       textureUsage(false),
       translatedShaderSource(false),
       fboRenderMipmap(false),
@@ -659,6 +661,7 @@
         map["GL_ARM_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::ARMshaderFramebufferFetch);
         map["GL_EXT_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::shaderFramebufferFetch);
         map["GL_EXT_frag_depth"] = enableableExtension(&Extensions::fragDepth);
+        map["GL_ANGLE_multiview"] = enableableExtension(&Extensions::multiview);
         map["GL_ANGLE_texture_usage"] = esOnlyExtension(&Extensions::textureUsage);
         map["GL_ANGLE_translated_shader_source"] = esOnlyExtension(&Extensions::translatedShaderSource);
         map["GL_OES_fbo_render_mipmap"] = esOnlyExtension(&Extensions::fboRenderMipmap);
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 2588ad0..67dbbeb 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -251,6 +251,10 @@
     // GL_EXT_frag_depth
     bool fragDepth;
 
+    // ANGLE_multiview
+    bool multiview;
+    GLuint maxViews;
+
     // GL_ANGLE_texture_usage
     bool textureUsage;
 
diff --git a/src/libANGLE/Compiler.cpp b/src/libANGLE/Compiler.cpp
index 32267d1..87c58fa 100644
--- a/src/libANGLE/Compiler.cpp
+++ b/src/libANGLE/Compiler.cpp
@@ -76,6 +76,10 @@
     mResources.FragmentPrecisionHigh = 1;
     mResources.EXT_frag_depth        = extensions.fragDepth;
 
+    // OVR_multiview state
+    mResources.OVR_multiview = extensions.multiview;
+    mResources.MaxViewsOVR   = extensions.maxViews;
+
     // GLSL ES 3.0 constants
     mResources.MaxVertexOutputVectors  = caps.maxVertexOutputComponents / 4;
     mResources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4;
diff --git a/src/libANGLE/renderer/gl/ContextGL.cpp b/src/libANGLE/renderer/gl/ContextGL.cpp
index 457581c..2634d12 100644
--- a/src/libANGLE/renderer/gl/ContextGL.cpp
+++ b/src/libANGLE/renderer/gl/ContextGL.cpp
@@ -52,7 +52,8 @@
 ShaderImpl *ContextGL::createShader(const gl::ShaderState &data)
 {
     return new ShaderGL(data, getFunctions(), getWorkaroundsGL(),
-                        getExtensions().webglCompatibility);
+                        getExtensions().webglCompatibility,
+                        mRenderer->getMultiviewImplementationType());
 }
 
 ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index a391ad4..9716104 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -170,7 +170,8 @@
       mBlitter(nullptr),
       mHasDebugOutput(false),
       mSkipDrawCalls(false),
-      mCapsInitialized(false)
+      mCapsInitialized(false),
+      mMultiviewImplementationType(MultiviewImplementationTypeGL::UNSPECIFIED)
 {
     ASSERT(mFunctions);
     nativegl_gl::GenerateWorkarounds(mFunctions, &mWorkarounds);
@@ -606,7 +607,7 @@
                               gl::Limitations * /* outLimitations */) const
 {
     nativegl_gl::GenerateCaps(mFunctions, mWorkarounds, outCaps, outTextureCaps, outExtensions,
-                              &mMaxSupportedESVersion);
+                              &mMaxSupportedESVersion, &mMultiviewImplementationType);
 }
 
 GLint RendererGL::getGPUDisjoint()
@@ -655,6 +656,12 @@
     return mNativeLimitations;
 }
 
+MultiviewImplementationTypeGL RendererGL::getMultiviewImplementationType() const
+{
+    ensureCapsInitialized();
+    return mMultiviewImplementationType;
+}
+
 void RendererGL::applyNativeWorkarounds(gl::Workarounds *workarounds) const
 {
     ensureCapsInitialized();
diff --git a/src/libANGLE/renderer/gl/RendererGL.h b/src/libANGLE/renderer/gl/RendererGL.h
index 4902c4f..01a3d7f 100644
--- a/src/libANGLE/renderer/gl/RendererGL.h
+++ b/src/libANGLE/renderer/gl/RendererGL.h
@@ -13,6 +13,7 @@
 #include "libANGLE/Error.h"
 #include "libANGLE/Version.h"
 #include "libANGLE/renderer/gl/WorkaroundsGL.h"
+#include "libANGLE/renderer/gl/renderergl_utils.h"
 
 namespace gl
 {
@@ -162,6 +163,7 @@
     const WorkaroundsGL &getWorkarounds() const { return mWorkarounds; }
     BlitGL *getBlitter() const { return mBlitter; }
 
+    MultiviewImplementationTypeGL getMultiviewImplementationType() const;
     const gl::Caps &getNativeCaps() const;
     const gl::TextureCapsMap &getNativeTextureCaps() const;
     const gl::Extensions &getNativeExtensions() const;
@@ -199,6 +201,7 @@
     mutable gl::TextureCapsMap mNativeTextureCaps;
     mutable gl::Extensions mNativeExtensions;
     mutable gl::Limitations mNativeLimitations;
+    mutable MultiviewImplementationTypeGL mMultiviewImplementationType;
 };
 
 }  // namespace rx
diff --git a/src/libANGLE/renderer/gl/ShaderGL.cpp b/src/libANGLE/renderer/gl/ShaderGL.cpp
index 05888b4..b75dbe7 100644
--- a/src/libANGLE/renderer/gl/ShaderGL.cpp
+++ b/src/libANGLE/renderer/gl/ShaderGL.cpp
@@ -22,12 +22,14 @@
 ShaderGL::ShaderGL(const gl::ShaderState &data,
                    const FunctionsGL *functions,
                    const WorkaroundsGL &workarounds,
-                   bool isWebGL)
+                   bool isWebGL,
+                   MultiviewImplementationTypeGL multiviewImplementationType)
     : ShaderImpl(data),
       mFunctions(functions),
       mWorkarounds(workarounds),
       mShaderID(0),
-      mIsWebGL(isWebGL)
+      mIsWebGL(isWebGL),
+      mMultiviewImplementationType(multiviewImplementationType)
 {
     ASSERT(mFunctions);
 }
@@ -110,6 +112,12 @@
         options |= SH_INITIALIZE_UNINITIALIZED_LOCALS;
     }
 
+    if (mMultiviewImplementationType == MultiviewImplementationTypeGL::NV_VIEWPORT_ARRAY2)
+    {
+        options |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
+        options |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER;
+    }
+
     return options;
 }
 
diff --git a/src/libANGLE/renderer/gl/ShaderGL.h b/src/libANGLE/renderer/gl/ShaderGL.h
index 8ddf801..bfe01f2 100644
--- a/src/libANGLE/renderer/gl/ShaderGL.h
+++ b/src/libANGLE/renderer/gl/ShaderGL.h
@@ -15,6 +15,7 @@
 {
 class FunctionsGL;
 struct WorkaroundsGL;
+enum class MultiviewImplementationTypeGL;
 
 class ShaderGL : public ShaderImpl
 {
@@ -22,7 +23,8 @@
     ShaderGL(const gl::ShaderState &data,
              const FunctionsGL *functions,
              const WorkaroundsGL &workarounds,
-             bool isWebGL);
+             bool isWebGL,
+             MultiviewImplementationTypeGL multiviewImplementationType);
     ~ShaderGL() override;
 
     // ShaderImpl implementation
@@ -39,6 +41,7 @@
 
     GLuint mShaderID;
     bool mIsWebGL;
+    MultiviewImplementationTypeGL mMultiviewImplementationType;
 };
 
 }
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index bfa4bd9..bdcf53c 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -222,7 +222,8 @@
                   gl::Caps *caps,
                   gl::TextureCapsMap *textureCapsMap,
                   gl::Extensions *extensions,
-                  gl::Version *maxSupportedESVersion)
+                  gl::Version *maxSupportedESVersion,
+                  MultiviewImplementationTypeGL *multiviewImplementationType)
 {
     // Texture format support checks
     const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
@@ -873,6 +874,18 @@
                                    functions->hasGLESExtension("GL_EXT_shader_texture_lod");
     extensions->fragDepth = functions->standard == STANDARD_GL_DESKTOP ||
                             functions->hasGLESExtension("GL_EXT_frag_depth");
+
+    if (functions->hasGLExtension("GL_NV_viewport_array2"))
+    {
+        extensions->multiview = true;
+        // GL_MAX_ARRAY_TEXTURE_LAYERS is guaranteed to be at least 256.
+        const int maxLayers = QuerySingleGLInt(functions, GL_MAX_ARRAY_TEXTURE_LAYERS);
+        // GL_MAX_VIEWPORTS is guaranteed to be at least 16.
+        const int maxViewports       = QuerySingleGLInt(functions, GL_MAX_VIEWPORTS);
+        extensions->maxViews         = static_cast<GLuint>(std::min(maxLayers, maxViewports));
+        *multiviewImplementationType = MultiviewImplementationTypeGL::NV_VIEWPORT_ARRAY2;
+    }
+
     extensions->fboRenderMipmap = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_object") ||
                                   functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_fbo_render_mipmap");
     extensions->instancedArrays = functions->isAtLeastGL(gl::Version(3, 1)) ||
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.h b/src/libANGLE/renderer/gl/renderergl_utils.h
index d8df6f3..76eb478 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.h
+++ b/src/libANGLE/renderer/gl/renderergl_utils.h
@@ -32,6 +32,11 @@
 {
 class FunctionsGL;
 struct WorkaroundsGL;
+enum class MultiviewImplementationTypeGL
+{
+    NV_VIEWPORT_ARRAY2,
+    UNSPECIFIED
+};
 
 VendorID GetVendorID(const FunctionsGL *functions);
 std::string GetDriverVersion(const FunctionsGL *functions);
@@ -44,7 +49,8 @@
                   gl::Caps *caps,
                   gl::TextureCapsMap *textureCapsMap,
                   gl::Extensions *extensions,
-                  gl::Version *maxSupportedESVersion);
+                  gl::Version *maxSupportedESVersion,
+                  MultiviewImplementationTypeGL *multiviewImplementationType);
 
 void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds);
 void ApplyWorkarounds(const FunctionsGL *functions, gl::Workarounds *workarounds);