Vulkan: Support multiple vertex outputs.

This is a bit of a hack, similar to how D3D11 works. We need to write
output locations in the GLSL shader before we send them to glslang,
so we wait until the link call, then string-replace some hard-coded
identifeir code to the attribute location determined by ANGLE.

This CL also fills in some of the vertex format conversion tables in
formatutilsvk.cpp.

BUG=angleproject:2167

Change-Id: I2424d0d990bdbcd831a4dd130e61e87d8f8f479f
Reviewed-on: https://chromium-review.googlesource.com/677555
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
diff --git a/src/tests/gl_tests/SimpleOperationTest.cpp b/src/tests/gl_tests/SimpleOperationTest.cpp
index d5850d8..4e40215 100644
--- a/src/tests/gl_tests/SimpleOperationTest.cpp
+++ b/src/tests/gl_tests/SimpleOperationTest.cpp
@@ -142,13 +142,6 @@
 
 TEST_P(SimpleOperationTest, LinkProgramWithAttributes)
 {
-    if (IsVulkan())
-    {
-        // TODO(jmadill): Complete Vulkan implementation.
-        std::cout << "Test skipped on Vulkan." << std::endl;
-        return;
-    }
-
     const std::string vsSource =
         R"(attribute vec4 a_input;
         void main()
@@ -269,6 +262,74 @@
     EXPECT_GL_NO_ERROR();
 }
 
+// Tests a shader program with more than one vertex attribute, with vertex buffers.
+TEST_P(SimpleOperationTest, ThreeVertexAttributes)
+{
+    const std::string vertexShader =
+        R"(attribute vec2 position;
+attribute vec4 color1;
+attribute vec4 color2;
+varying vec4 color;
+void main()
+{
+    gl_Position = vec4(position, 0, 1);
+    color = color1 + color2;
+})";
+
+    const std::string fragmentShader =
+        R"(precision mediump float;
+varying vec4 color;
+void main()
+{
+    gl_FragColor = color;
+}
+)";
+
+    ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
+
+    glUseProgram(program);
+
+    GLint color1Loc = glGetAttribLocation(program, "color1");
+    GLint color2Loc = glGetAttribLocation(program, "color2");
+    ASSERT_NE(-1, color1Loc);
+    ASSERT_NE(-1, color2Loc);
+
+    const auto &indices = GetQuadIndices();
+
+    // Make colored corners with red == x or 1 -x , and green = y or 1 - y.
+
+    std::array<GLColor, 4> baseColors1 = {
+        {GLColor::black, GLColor::red, GLColor::green, GLColor::yellow}};
+    std::array<GLColor, 4> baseColors2 = {
+        {GLColor::yellow, GLColor::green, GLColor::red, GLColor::black}};
+
+    std::vector<GLColor> colors1;
+    std::vector<GLColor> colors2;
+
+    for (GLushort index : indices)
+    {
+        colors1.push_back(baseColors1[index]);
+        colors2.push_back(baseColors2[index]);
+    }
+
+    GLBuffer color1Buffer;
+    glBindBuffer(GL_ARRAY_BUFFER, color1Buffer);
+    glBufferData(GL_ARRAY_BUFFER, colors1.size() * sizeof(GLColor), colors1.data(), GL_STATIC_DRAW);
+    glVertexAttribPointer(color1Loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
+    glEnableVertexAttribArray(color1Loc);
+
+    GLBuffer color2Buffer;
+    glBindBuffer(GL_ARRAY_BUFFER, color2Buffer);
+    glBufferData(GL_ARRAY_BUFFER, colors2.size() * sizeof(GLColor), colors2.data(), GL_STATIC_DRAW);
+    glVertexAttribPointer(color2Loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
+    glEnableVertexAttribArray(color2Loc);
+
+    // Draw a non-indexed quad with all vertex buffers. Should draw yellow to the entire window.
+    drawQuad(program, "position", 0.5f, 1.0f, true);
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
+}
+
 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
 ANGLE_INSTANTIATE_TEST(SimpleOperationTest,
                        ES2_D3D9(),