Add helpers for multiview framebuffer init

Multiview tests now use common helpers to create textures for
multiview framebuffers and often also to attach the textures to the
framebuffers.

The tests now rely on uploaded texture data to initialize the buffers
instead of clearing the framebuffers with glClear.

BUG=angleproject:2765
TEST=angle_end2end_tests

Change-Id: I7d6d63add5943cab610ab888045d5b0f8ba29215
Reviewed-on: https://chromium-review.googlesource.com/1184712
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/tests/test_utils/MultiviewTest.cpp b/src/tests/test_utils/MultiviewTest.cpp
index 42298a2..79f6475 100644
--- a/src/tests/test_utils/MultiviewTest.cpp
+++ b/src/tests/test_utils/MultiviewTest.cpp
@@ -40,6 +40,171 @@
     return CompileProgram(vsSource, fsSource);
 }
 
+void CreateMultiviewBackingTextures(GLenum multiviewLayout,
+                                    int viewWidth,
+                                    int height,
+                                    int numLayers,
+                                    std::vector<GLuint> colorTextures,
+                                    GLuint depthTexture,
+                                    GLuint depthStencilTexture)
+{
+    // The same zero data is used to initialize both color and depth/stencil textures.
+    std::vector<GLubyte> textureData;
+    textureData.resize(viewWidth * height * numLayers * 4, 0u);
+
+    // Create color and depth textures.
+    switch (multiviewLayout)
+    {
+        case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
+        {
+            int textureWidth = viewWidth * numLayers;
+            for (auto colorTexture : colorTextures)
+            {
+                glBindTexture(GL_TEXTURE_2D, colorTexture);
+                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA,
+                             GL_UNSIGNED_BYTE, textureData.data());
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            }
+
+            if (depthTexture != 0)
+            {
+                glBindTexture(GL_TEXTURE_2D, depthTexture);
+                glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0,
+                             GL_DEPTH_COMPONENT, GL_FLOAT, textureData.data());
+            }
+            if (depthStencilTexture != 0)
+            {
+                glBindTexture(GL_TEXTURE_2D, depthStencilTexture);
+                glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, textureWidth, height, 0,
+                             GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, textureData.data());
+            }
+            glBindTexture(GL_TEXTURE_2D, 0);
+            break;
+        }
+        case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
+            for (auto colorTexture : colorTextures)
+            {
+                glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture);
+                glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, height, numLayers, 0,
+                             GL_RGBA, GL_UNSIGNED_BYTE, textureData.data());
+                glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+                glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            }
+
+            if (depthTexture != 0)
+            {
+                glBindTexture(GL_TEXTURE_2D_ARRAY, depthTexture);
+                glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, height,
+                             numLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, textureData.data());
+            }
+            if (depthStencilTexture != 0)
+            {
+                glBindTexture(GL_TEXTURE_2D_ARRAY, depthStencilTexture);
+                glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH24_STENCIL8, viewWidth, height,
+                             numLayers, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
+                             textureData.data());
+            }
+            glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
+            break;
+        default:
+            UNREACHABLE();
+    }
+    ASSERT_GL_NO_ERROR();
+}
+
+void CreateMultiviewBackingTextures(GLenum multiviewLayout,
+                                    int viewWidth,
+                                    int height,
+                                    int numLayers,
+                                    GLuint colorTexture,
+                                    GLuint depthTexture,
+                                    GLuint depthStencilTexture)
+{
+    ASSERT(colorTexture != 0u);
+    std::vector<GLuint> colorTextures(1, colorTexture);
+    CreateMultiviewBackingTextures(multiviewLayout, viewWidth, height, numLayers, colorTextures,
+                                   depthTexture, depthStencilTexture);
+}
+
+void AttachMultiviewTextures(GLenum target,
+                             GLenum multiviewLayout,
+                             int viewWidth,
+                             int numViews,
+                             int baseViewIndex,
+                             std::vector<GLuint> colorTextures,
+                             GLuint depthTexture,
+                             GLuint depthStencilTexture)
+{
+    ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE || (baseViewIndex == 0));
+    ASSERT(depthTexture == 0u || depthStencilTexture == 0u);
+    switch (multiviewLayout)
+    {
+        case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
+        {
+            std::vector<GLint> viewportOffsets(numViews * 2);
+            for (int i = 0u; i < numViews; ++i)
+            {
+                viewportOffsets[i * 2]     = i * viewWidth;
+                viewportOffsets[i * 2 + 1] = 0;
+            }
+            for (size_t i = 0; i < colorTextures.size(); ++i)
+            {
+                glFramebufferTextureMultiviewSideBySideANGLE(target, GL_COLOR_ATTACHMENT0 + i,
+                                                             colorTextures[i], 0, numViews,
+                                                             viewportOffsets.data());
+            }
+            if (depthTexture)
+            {
+                glFramebufferTextureMultiviewSideBySideANGLE(
+                    target, GL_DEPTH_ATTACHMENT, depthTexture, 0, numViews, viewportOffsets.data());
+            }
+            if (depthStencilTexture)
+            {
+                glFramebufferTextureMultiviewSideBySideANGLE(target, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                             depthStencilTexture, 0, numViews,
+                                                             viewportOffsets.data());
+            }
+            break;
+        }
+        case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
+            for (size_t i = 0; i < colorTextures.size(); ++i)
+            {
+                glFramebufferTextureMultiviewLayeredANGLE(
+                    target, GL_COLOR_ATTACHMENT0 + i, colorTextures[i], 0, baseViewIndex, numViews);
+            }
+            if (depthTexture)
+            {
+                glFramebufferTextureMultiviewLayeredANGLE(target, GL_DEPTH_ATTACHMENT, depthTexture,
+                                                          0, baseViewIndex, numViews);
+            }
+            if (depthStencilTexture)
+            {
+                glFramebufferTextureMultiviewLayeredANGLE(target, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                          depthStencilTexture, 0, baseViewIndex,
+                                                          numViews);
+            }
+            break;
+        default:
+            UNREACHABLE();
+    }
+}
+
+void AttachMultiviewTextures(GLenum target,
+                             GLenum multiviewLayout,
+                             int viewWidth,
+                             int numViews,
+                             int baseViewIndex,
+                             GLuint colorTexture,
+                             GLuint depthTexture,
+                             GLuint depthStencilTexture)
+{
+    ASSERT(colorTexture != 0u);
+    std::vector<GLuint> colorTextures(1, colorTexture);
+    AttachMultiviewTextures(target, multiviewLayout, viewWidth, numViews, baseViewIndex,
+                            colorTextures, depthTexture, depthStencilTexture);
+}
+
 std::ostream &operator<<(std::ostream &os, const MultiviewImplementationParams &params)
 {
     const PlatformParameters &base = static_cast<const PlatformParameters &>(params);