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(),