Vulkan: Support GL_LUMINANCE and GL_LUMINANCE_ALPHA

The dEQP tests cannot be turned on before immediate data for drawElements
is supported.

Bug:angleproject:2364

Change-Id: Id5fd6fbc0c74f2dba08341f36ca0091d540f4ed8
Reviewed-on: https://chromium-review.googlesource.com/951402
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Luc Ferron <lucferron@chromium.org>
diff --git a/src/libANGLE/renderer/gen_load_functions_table.py b/src/libANGLE/renderer/gen_load_functions_table.py
index 9326894..c91b201 100755
--- a/src/libANGLE/renderer/gen_load_functions_table.py
+++ b/src/libANGLE/renderer/gen_load_functions_table.py
@@ -4,7 +4,9 @@
 # found in the LICENSE file.
 #
 # gen_load_functions_table.py:
-#  Code generation for the load function tables used for texture formats
+#  Code generation for the load function tables used for texture formats. These mappings are
+#  not renderer specific. The mappings are done from the GL internal format, to the ANGLE
+#  format ID, and then for the specific data type.
 #
 
 import json, sys
diff --git a/src/libANGLE/renderer/load_functions_data.json b/src/libANGLE/renderer/load_functions_data.json
index b644d01..ef66848 100644
--- a/src/libANGLE/renderer/load_functions_data.json
+++ b/src/libANGLE/renderer/load_functions_data.json
@@ -113,7 +113,10 @@
     }
   },
   "GL_LUMINANCE8_EXT": {
-    "NONE": {
+    "R8_UNORM": {
+      "GL_UNSIGNED_BYTE": "LoadToNative<GLubyte, 1>"
+    },
+    "R8G8B8A8_UNORM": {
       "GL_UNSIGNED_BYTE": "LoadL8ToRGBA8"
     }
   },
@@ -166,7 +169,10 @@
     }
   },
   "GL_LUMINANCE8_ALPHA8_EXT": {
-    "NONE": {
+    "R8G8_UNORM": {
+      "GL_UNSIGNED_BYTE": "LoadToNative<GLubyte, 2>"
+    },
+    "R8G8B8A8_UNORM": {
       "GL_UNSIGNED_BYTE": "LoadLA8ToRGBA8"
     }
   },
diff --git a/src/libANGLE/renderer/load_functions_table_autogen.cpp b/src/libANGLE/renderer/load_functions_table_autogen.cpp
index 6da1a7a..236338f 100644
--- a/src/libANGLE/renderer/load_functions_table_autogen.cpp
+++ b/src/libANGLE/renderer/load_functions_table_autogen.cpp
@@ -648,7 +648,7 @@
     }
 }
 
-LoadImageFunctionInfo LUMINANCE8_ALPHA8_EXT_to_default(GLenum type)
+LoadImageFunctionInfo LUMINANCE8_ALPHA8_EXT_to_R8G8B8A8_UNORM(GLenum type)
 {
     switch (type)
     {
@@ -660,7 +660,19 @@
     }
 }
 
-LoadImageFunctionInfo LUMINANCE8_EXT_to_default(GLenum type)
+LoadImageFunctionInfo LUMINANCE8_ALPHA8_EXT_to_R8G8_UNORM(GLenum type)
+{
+    switch (type)
+    {
+        case GL_UNSIGNED_BYTE:
+            return LoadImageFunctionInfo(LoadToNative<GLubyte, 2>, false);
+        default:
+            UNREACHABLE();
+            return LoadImageFunctionInfo(UnreachableLoadFunction, true);
+    }
+}
+
+LoadImageFunctionInfo LUMINANCE8_EXT_to_R8G8B8A8_UNORM(GLenum type)
 {
     switch (type)
     {
@@ -672,6 +684,18 @@
     }
 }
 
+LoadImageFunctionInfo LUMINANCE8_EXT_to_R8_UNORM(GLenum type)
+{
+    switch (type)
+    {
+        case GL_UNSIGNED_BYTE:
+            return LoadImageFunctionInfo(LoadToNative<GLubyte, 1>, false);
+        default:
+            UNREACHABLE();
+            return LoadImageFunctionInfo(UnreachableLoadFunction, true);
+    }
+}
+
 LoadImageFunctionInfo LUMINANCE_ALPHA_to_R16G16B16A16_FLOAT(GLenum type)
 {
     switch (type)
@@ -1867,9 +1891,31 @@
         case GL_LUMINANCE32F_EXT:
             return LUMINANCE32F_EXT_to_default;
         case GL_LUMINANCE8_ALPHA8_EXT:
-            return LUMINANCE8_ALPHA8_EXT_to_default;
+        {
+            switch (angleFormat)
+            {
+                case Format::ID::R8G8B8A8_UNORM:
+                    return LUMINANCE8_ALPHA8_EXT_to_R8G8B8A8_UNORM;
+                case Format::ID::R8G8_UNORM:
+                    return LUMINANCE8_ALPHA8_EXT_to_R8G8_UNORM;
+                default:
+                    break;
+            }
+            break;
+        }
         case GL_LUMINANCE8_EXT:
-            return LUMINANCE8_EXT_to_default;
+        {
+            switch (angleFormat)
+            {
+                case Format::ID::R8G8B8A8_UNORM:
+                    return LUMINANCE8_EXT_to_R8G8B8A8_UNORM;
+                case Format::ID::R8_UNORM:
+                    return LUMINANCE8_EXT_to_R8_UNORM;
+                default:
+                    break;
+            }
+            break;
+        }
         case GL_LUMINANCE_ALPHA:
         {
             switch (angleFormat)
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index e6371cd..a653c55 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -17,6 +17,57 @@
 
 namespace rx
 {
+namespace
+{
+VkComponentSwizzle ConvertSwizzleStateToVkSwizzle(const GLenum swizzle)
+{
+    switch (swizzle)
+    {
+        case GL_ALPHA:
+            return VK_COMPONENT_SWIZZLE_A;
+        case GL_RED:
+            return VK_COMPONENT_SWIZZLE_R;
+        case GL_GREEN:
+            return VK_COMPONENT_SWIZZLE_G;
+        case GL_BLUE:
+            return VK_COMPONENT_SWIZZLE_B;
+        case GL_ZERO:
+            return VK_COMPONENT_SWIZZLE_ZERO;
+        case GL_ONE:
+            return VK_COMPONENT_SWIZZLE_ONE;
+        default:
+            UNREACHABLE();
+            return VK_COMPONENT_SWIZZLE_IDENTITY;
+    }
+}
+
+void FillComponentsSwizzleParameters(GLenum internalFormat,
+                                     const gl::SwizzleState &swizzleState,
+                                     VkComponentMapping *componentMapping)
+{
+    switch (internalFormat)
+    {
+        case GL_LUMINANCE:
+            componentMapping->r = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleRed);
+            componentMapping->g = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleRed);
+            componentMapping->b = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleRed);
+            componentMapping->a = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleAlpha);
+            break;
+        case GL_LUMINANCE_ALPHA:
+            componentMapping->r = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleRed);
+            componentMapping->g = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleRed);
+            componentMapping->b = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleRed);
+            componentMapping->a = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleGreen);
+            break;
+        default:
+            componentMapping->r = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleRed);
+            componentMapping->g = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleGreen);
+            componentMapping->b = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleBlue);
+            componentMapping->a = ConvertSwizzleStateToVkSwizzle(swizzleState.swizzleAlpha);
+            break;
+    }
+}
+}  // anonymous namespace
 
 TextureVk::TextureVk(const gl::TextureState &state) : TextureImpl(state)
 {
@@ -128,16 +179,15 @@
         viewInfo.image                           = mImage.getHandle();
         viewInfo.viewType                        = VK_IMAGE_VIEW_TYPE_2D;
         viewInfo.format                          = vkFormat.vkTextureFormat;
-        viewInfo.components.r                    = VK_COMPONENT_SWIZZLE_R;
-        viewInfo.components.g                    = VK_COMPONENT_SWIZZLE_G;
-        viewInfo.components.b                    = VK_COMPONENT_SWIZZLE_B;
-        viewInfo.components.a                    = VK_COMPONENT_SWIZZLE_A;
         viewInfo.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
         viewInfo.subresourceRange.baseMipLevel   = 0;
         viewInfo.subresourceRange.levelCount     = 1;
         viewInfo.subresourceRange.baseArrayLayer = 0;
         viewInfo.subresourceRange.layerCount     = 1;
 
+        FillComponentsSwizzleParameters(internalFormat, mState.getSwizzleState(),
+                                        &viewInfo.components);
+
         ANGLE_TRY(mImageView.init(device, viewInfo));
 
         // TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361
diff --git a/src/libANGLE/renderer/vulkan/gen_vk_format_table.py b/src/libANGLE/renderer/vulkan/gen_vk_format_table.py
index 3130433..7bd7d1c 100644
--- a/src/libANGLE/renderer/vulkan/gen_vk_format_table.py
+++ b/src/libANGLE/renderer/vulkan/gen_vk_format_table.py
@@ -27,7 +27,7 @@
 // {out_file_name}:
 //   Queries for full Vulkan format information based on GL format.
 
-#include "libANGLE/renderer/vulkan/formatutilsvk.h"
+#include "libANGLE/renderer/vulkan/vk_format_utils.h"
 
 #include "image_util/copyimage.h"
 #include "image_util/generatemip.h"
@@ -90,21 +90,20 @@
 
     if isinstance(vk_format_name, dict):
         info = vk_format_name
-        vk_format_name = info["native"]
 
         if "buffer" in info:
             buffer_format_id = info["buffer"]
             vk_buffer_format = vk_map[buffer_format_id]
             assert(not isinstance(vk_buffer_format, dict))
         else:
-            vk_buffer_format = vk_format_name
+            vk_buffer_format = info["native"]
 
         if "texture" in info:
             texture_format_id = info["texture"]
             vk_texture_format = vk_map[texture_format_id]
             assert(not isinstance(vk_texture_format, dict))
         else:
-            vk_texture_format = vk_format_name
+            vk_texture_format = info["native"]
 
     initializer = angle_format.get_internal_format_initializer(
         internal_format, texture_format_id)
diff --git a/src/libANGLE/renderer/vulkan/vk_format_map.json b/src/libANGLE/renderer/vulkan/vk_format_map.json
index af7c3bf..47e7788 100644
--- a/src/libANGLE/renderer/vulkan/vk_format_map.json
+++ b/src/libANGLE/renderer/vulkan/vk_format_map.json
@@ -98,6 +98,14 @@
     "R64G64B64A64_UINT": "VK_FORMAT_R64G64B64A64_UINT",
     "R64G64B64A64_SINT": "VK_FORMAT_R64G64B64A64_SINT",
     "R64G64B64A64_FLOAT": "VK_FORMAT_R64G64B64A64_SFLOAT",
+    "L8_UNORM": {
+        "buffer": "NONE",
+        "texture": "R8_UNORM"
+    },
+    "L8A8_UNORM": {
+        "buffer": "NONE",
+        "texture": "R8G8_UNORM"
+    },
     "B10G11R11_UFLOAT_PACK32": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
     "E5B9G9R9_UFLOAT_PACK32": "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32",
     "D16_UNORM": "VK_FORMAT_D16_UNORM",
diff --git a/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp b/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp
index 1ddc660..93689b1 100644
--- a/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp
@@ -625,12 +625,26 @@
             break;
 
         case angle::Format::ID::L8A8_UNORM:
-            // This format is not implemented in Vulkan.
+        {
+            internalFormat          = GL_LUMINANCE8_ALPHA8_EXT;
+            textureFormatID         = angle::Format::ID::R8G8_UNORM;
+            vkTextureFormat         = VK_FORMAT_R8G8_UNORM;
+            bufferFormatID          = angle::Format::ID::NONE;
+            vkBufferFormat          = VK_FORMAT_UNDEFINED;
+            dataInitializerFunction = nullptr;
             break;
+        }
 
         case angle::Format::ID::L8_UNORM:
-            // This format is not implemented in Vulkan.
+        {
+            internalFormat          = GL_LUMINANCE8_EXT;
+            textureFormatID         = angle::Format::ID::R8_UNORM;
+            vkTextureFormat         = VK_FORMAT_R8_UNORM;
+            bufferFormatID          = angle::Format::ID::NONE;
+            vkBufferFormat          = VK_FORMAT_UNDEFINED;
+            dataInitializerFunction = nullptr;
             break;
+        }
 
         case angle::Format::ID::NONE:
             // This format is not implemented in Vulkan.
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 507bc9a..0dfba60 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -1237,6 +1237,10 @@
 
 TEST_P(Texture2DTest, ZeroSizedUploads)
 {
+    // TODO(lucferron): Enable this test on Vulkan after this bug is done.
+    // http://anglebug.com/2392
+    ANGLE_SKIP_TEST_IF(IsVulkan());
+
     glBindTexture(GL_TEXTURE_2D, mTexture2D);
     EXPECT_GL_ERROR(GL_NO_ERROR);
 
@@ -1570,6 +1574,9 @@
 // Run against GL_ALPHA/UNSIGNED_BYTE format, to ensure that D3D11 Feature Level 9_3 correctly handles GL_ALPHA
 TEST_P(Texture2DTest, TextureNPOT_GL_ALPHA_UBYTE)
 {
+    // TODO(lucferron): DIRTY_BIT_UNPACK_STATE isn't implemented on Vulkan yet.
+    ANGLE_SKIP_TEST_IF(IsVulkan());
+
     const int npotTexSize = 5;
     const int potTexSize = 4; // Should be less than npotTexSize
     GLuint tex2D;
@@ -1658,6 +1665,10 @@
 // ANGLE previously rejected this if GL_OES_texture_npot wasn't active, which is incorrect.
 TEST_P(Texture2DTest, NPOTSubImageParameters)
 {
+    // TODO(lucferron): Generate mipmap on vulkan isn't implemented yet. Re-enable this when it
+    // is.
+    ANGLE_SKIP_TEST_IF(IsVulkan());
+
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture2D);
 
@@ -2379,8 +2390,10 @@
 
 // When sampling a texture without an alpha channel, "1" is returned as the alpha value.
 // ES 3.0.4 table 3.24
-TEST_P(Texture2DTestES3, TextureLuminanceImplicitAlpha1)
+TEST_P(Texture2DTest, TextureLuminanceImplicitAlpha1)
 {
+    setUpProgram();
+
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture2D);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, nullptr);
@@ -2391,10 +2404,50 @@
     EXPECT_PIXEL_ALPHA_EQ(0, 0, 255);
 }
 
+// Validate that every component of the pixel will be equal to the luminance value we've set
+// and that the alpha channel will be 1 (or 255 to be exact).
+TEST_P(Texture2DTest, TextureLuminanceRGBSame)
+{
+    setUpProgram();
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mTexture2D);
+    uint8_t pixel = 50;
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pixel);
+    EXPECT_GL_NO_ERROR();
+
+    drawQuad(mProgram, "position", 0.5f);
+
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(pixel, pixel, pixel, 255));
+}
+
+// Validate that every component of the pixel will be equal to the luminance value we've set
+// and that the alpha channel will be the second component.
+TEST_P(Texture2DTest, TextureLuminanceAlphaRGBSame)
+{
+    setUpProgram();
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mTexture2D);
+    uint8_t pixel[] = {50, 25};
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 1, 1, 0, GL_LUMINANCE_ALPHA,
+                 GL_UNSIGNED_BYTE, pixel);
+    EXPECT_GL_NO_ERROR();
+
+    drawQuad(mProgram, "position", 0.5f);
+
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(pixel[0], pixel[0], pixel[0], pixel[1]));
+}
+
 // When sampling a texture without an alpha channel, "1" is returned as the alpha value.
 // ES 3.0.4 table 3.24
-TEST_P(Texture2DTestES3, TextureLuminance32ImplicitAlpha1)
+TEST_P(Texture2DTest, TextureLuminance32ImplicitAlpha1)
 {
+    // TODO(lucferron): Enable Vulkan when we implement float support in ES3.0.
+    ANGLE_SKIP_TEST_IF(IsVulkan() || IsD3D9());
+
+    setUpProgram();
+
     if (extensionEnabled("GL_OES_texture_float"))
     {
         glActiveTexture(GL_TEXTURE0);
@@ -2410,10 +2463,15 @@
 
 // When sampling a texture without an alpha channel, "1" is returned as the alpha value.
 // ES 3.0.4 table 3.24
-TEST_P(Texture2DTestES3, TextureLuminance16ImplicitAlpha1)
+TEST_P(Texture2DTest, TextureLuminance16ImplicitAlpha1)
 {
+    // TODO(lucferron): Enable Vulkan when we implement float support in ES3.0.
+    ANGLE_SKIP_TEST_IF(IsVulkan() || IsD3D9());
+
     if (extensionEnabled("GL_OES_texture_half_float"))
     {
+        setUpProgram();
+
         ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGLES());
 
         // TODO(ynovikov): re-enable once root cause of http://anglebug.com/1420 is fixed
@@ -3677,7 +3735,8 @@
                        ES2_D3D11(),
                        ES2_D3D11_FL9_3(),
                        ES2_OPENGL(),
-                       ES2_OPENGLES());
+                       ES2_OPENGLES(),
+                       ES2_VULKAN());
 ANGLE_INSTANTIATE_TEST(TextureCubeTest,
                        ES2_D3D9(),
                        ES2_D3D11(),