d3d11: Allow binding R/RG texture to EGLImage

Also allows GL_RED/RG/R16/RG16_EXT as well as GL_RGB10_A2_EXT which was
left out previously by accidently to match Chromium behavior.  Adapts
the existing ClearTextureImage test to parameterize over a number of
texture formats.

Bug: angleproject:6369
Change-Id: I91110a06b08379a3067a2161e345258415cd5e16
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3140744
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
diff --git a/extensions/EGL_ANGLE_d3d_texture_client_buffer.txt b/extensions/EGL_ANGLE_d3d_texture_client_buffer.txt
index 8f3b615..b8bc29d 100644
--- a/extensions/EGL_ANGLE_d3d_texture_client_buffer.txt
+++ b/extensions/EGL_ANGLE_d3d_texture_client_buffer.txt
@@ -149,6 +149,10 @@
                        DXGI_FORMAT_R16G16B16A16_FLOAT,
                        DXGI_FORMAT_R32G32B32A32_FLOAT,
                        DXGI_FORMAT_R10G10B10A2_UNORM,
+                       DXGI_FORMAT_R8_UNORM,
+                       DXGI_FORMAT_R16_UNORM,
+                       DXGI_FORMAT_R8G8_UNORM,
+                       DXGI_FORMAT_R16G16_UNORM,
                        DXGI_FORMAT_NV12,
                        DXGI_FORMAT_P010, or
                        DXGI_FORMAT_P016.
@@ -158,14 +162,22 @@
                        DXGI_FORMAT_P016, and must be 0 or 1. It is ignored for
                        all non-YUV formats.
 
-                       EGL_TEXTURE_INTERNAL_FORMAT_ANGLE (if supported) must be
-                       GL_RGBA (supported for all non-YUV formats),
-                       GL_RGB (supported for all non-YUV formats except
+                       EGL_TEXTURE_INTERNAL_FORMAT_ANGLE (if specified) must be
+                       GL_RGBA (supported for all RGBA and BGRA formats),
+                       GL_RGB (supported for all RGBA and BGRA formats except
                                DXGI_FORMAT_R10G10B10A2_UNORM),
                        GL_BGRA_EXT (supported only for
                                     DXGI_FORMAT_B8G8R8A8_UNORM,
-                                    DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, or
-                                    DXGI_FORMAT_B8G8R8A8_TYPELESS).
+                                    DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, and
+                                    DXGI_FORMAT_B8G8R8A8_TYPELESS),
+                       GL_RGB10_A2_EXT (supported for
+                                        DXGI_FORMAT_R10G10B10A2_UNORM),
+                       GL_RED_EXT (supported for DXGI_FORMAT_R8_UNORM
+                                   and DXGI_FORMAT_R16_UNORM),
+                       GL_RG_EXT (supported for DXGI_FORMAT_R8G8_UNORM
+                                  and DXGI_FORMAT_R16G16_UNORM),
+                       GL_R16_EXT (supported for DXGI_FORMAT_R16_UNORM), or
+                       GL_RG16_EXT (supported for DXGI_FORMAT_R16G16_UNORM).
                        It is ignored for all YUV formats.
     --------------------------------------------------------------------------
     Table egl.restrictions - Restrictions on D3D resources that can be used
@@ -226,6 +238,8 @@
 
 Revision History
 
+    Version 9, 2021/09/07 - added support for R/RG formats and GL_RGB10_A2_EXT.
+
     Version 8, 2021/01/13 - added support for texture array.
 
     Version 7, 2021/01/12 - added support for NV12/P010/P016 planar formats.
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 45c9d0a..d6a4c1a 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -1532,6 +1532,10 @@
             case DXGI_FORMAT_R16G16B16A16_FLOAT:
             case DXGI_FORMAT_R32G32B32A32_FLOAT:
             case DXGI_FORMAT_R10G10B10A2_UNORM:
+            case DXGI_FORMAT_R8_UNORM:
+            case DXGI_FORMAT_R8G8_UNORM:
+            case DXGI_FORMAT_R16_UNORM:
+            case DXGI_FORMAT_R16G16_UNORM:
                 break;
 
             default:
@@ -1553,6 +1557,11 @@
                 case GL_RGBA:
                 case GL_BGRA_EXT:
                 case GL_RGB:
+                case GL_RED_EXT:
+                case GL_RG_EXT:
+                case GL_RGB10_A2_EXT:
+                case GL_R16_EXT:
+                case GL_RG16_EXT:
                     break;
                 default:
                     return egl::EglBadParameter()
diff --git a/src/tests/gl_tests/D3DTextureTest.cpp b/src/tests/gl_tests/D3DTextureTest.cpp
index 8965655..61a5f7b 100644
--- a/src/tests/gl_tests/D3DTextureTest.cpp
+++ b/src/tests/gl_tests/D3DTextureTest.cpp
@@ -1191,61 +1191,165 @@
     eglDestroySurface(display, pbuffer);
 }
 
-TEST_P(D3DTextureTest, ClearTextureImage)
+class D3DTextureClearTest : public D3DTextureTest
 {
-    ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
+  protected:
+    D3DTextureClearTest() : D3DTextureTest() {}
 
-    EGLWindow *window  = getEGLWindow();
-    EGLDisplay display = window->getDisplay();
+    void RunClearTest(DXGI_FORMAT format)
+    {
+        ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
 
-    window->makeCurrent();
+        EGLWindow *window  = getEGLWindow();
+        EGLDisplay display = window->getDisplay();
 
-    const UINT bufferSize = 32;
-    EXPECT_TRUE(mD3D11Device != nullptr);
-    ID3D11Texture2D *d3d11_texture = nullptr;
-    CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1,
-                               D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
-    EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11_texture)));
+        window->makeCurrent();
 
-    const EGLint attribs[] = {EGL_NONE};
+        const UINT bufferSize = 32;
+        EXPECT_TRUE(mD3D11Device != nullptr);
+        ID3D11Texture2D *d3d11Texture = nullptr;
+        CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
+                                   D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
+        EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
 
-    EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
-                                       static_cast<EGLClientBuffer>(d3d11_texture), attribs);
-    ASSERT_EGL_SUCCESS();
-    ASSERT_NE(image, EGL_NO_IMAGE_KHR);
+        // Can use unsized formats for all cases, but use sized ones to match Chromium.
+        EGLint internalFormat = GL_NONE;
+        switch (format)
+        {
+            case DXGI_FORMAT_R8G8B8A8_UNORM:
+            case DXGI_FORMAT_R16G16B16A16_FLOAT:
+                internalFormat = GL_RGBA;
+                break;
+            case DXGI_FORMAT_B8G8R8A8_UNORM:
+                internalFormat = GL_BGRA_EXT;
+                break;
+            case DXGI_FORMAT_R8_UNORM:
+                internalFormat = GL_RED_EXT;
+                break;
+            case DXGI_FORMAT_R8G8_UNORM:
+                internalFormat = GL_RG_EXT;
+                break;
+            case DXGI_FORMAT_R10G10B10A2_UNORM:
+                internalFormat = GL_RGB10_A2_EXT;
+                break;
+            case DXGI_FORMAT_R16_UNORM:
+                internalFormat = GL_R16_EXT;
+                break;
+            case DXGI_FORMAT_R16G16_UNORM:
+                internalFormat = GL_RG16_EXT;
+                break;
+            default:
+                ASSERT_TRUE(false);
+                break;
+        }
 
-    GLuint texture;
-    glGenTextures(1, &texture);
-    glBindTexture(GL_TEXTURE_2D, texture);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    ASSERT_GL_NO_ERROR();
+        const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, internalFormat, EGL_NONE};
 
-    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
-    ASSERT_GL_NO_ERROR();
+        EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
+                                           static_cast<EGLClientBuffer>(d3d11Texture), attribs);
+        ASSERT_EGL_SUCCESS();
+        ASSERT_NE(image, EGL_NO_IMAGE_KHR);
 
-    GLuint fbo;
-    glGenFramebuffers(1, &fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
-    EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
-              static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
-    ASSERT_GL_NO_ERROR();
+        GLuint texture;
+        glGenTextures(1, &texture);
+        glBindTexture(GL_TEXTURE_2D, texture);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        ASSERT_GL_NO_ERROR();
 
-    glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
-    glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-    ASSERT_GL_NO_ERROR();
-    EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
-                    255, 255);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+        ASSERT_GL_NO_ERROR();
 
-    glDeleteFramebuffers(1, &fbo);
-    glDeleteTextures(1, &texture);
-    eglDestroyImageKHR(display, image);
+        GLuint fbo;
+        glGenFramebuffers(1, &fbo);
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+        EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
+                  static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
+        ASSERT_GL_NO_ERROR();
 
-    d3d11_texture->Release();
+        glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
+        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+        ASSERT_GL_NO_ERROR();
+
+        if (format == DXGI_FORMAT_R16G16B16A16_FLOAT)
+        {
+            EXPECT_PIXEL_32F_EQ(static_cast<GLint>(bufferSize) / 2,
+                                static_cast<GLint>(bufferSize) / 2, 1.0f, 1.0f, 1.0f, 1.0f);
+        }
+        else
+        {
+            GLuint readColor[4] = {0, 0, 0, 255};
+            switch (internalFormat)
+            {
+                case GL_RGBA:
+                case GL_BGRA_EXT:
+                case GL_RGB10_A2_EXT:
+                    readColor[0] = readColor[1] = readColor[2] = 255;
+                    break;
+                case GL_RG_EXT:
+                case GL_RG16_EXT:
+                    readColor[0] = readColor[1] = 255;
+                    break;
+                case GL_RED_EXT:
+                case GL_R16_EXT:
+                    readColor[0] = 255;
+                    break;
+            }
+            // Read back as GL_UNSIGNED_BYTE even though the texture might have more than 8bpc.
+            EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
+                            readColor[0], readColor[1], readColor[2], readColor[3]);
+        }
+
+        glDeleteFramebuffers(1, &fbo);
+        glDeleteTextures(1, &texture);
+        eglDestroyImageKHR(display, image);
+
+        d3d11Texture->Release();
+    }
+};
+
+TEST_P(D3DTextureClearTest, ClearRGBA8)
+{
+    RunClearTest(DXGI_FORMAT_R8G8B8A8_UNORM);
+}
+
+TEST_P(D3DTextureClearTest, ClearBGRA8)
+{
+    RunClearTest(DXGI_FORMAT_B8G8R8A8_UNORM);
+}
+
+TEST_P(D3DTextureClearTest, ClearR8)
+{
+    RunClearTest(DXGI_FORMAT_R8_UNORM);
+}
+
+TEST_P(D3DTextureClearTest, ClearRG8)
+{
+    RunClearTest(DXGI_FORMAT_R8G8_UNORM);
+}
+
+TEST_P(D3DTextureClearTest, ClearRGB10A2)
+{
+    RunClearTest(DXGI_FORMAT_R10G10B10A2_UNORM);
+}
+
+TEST_P(D3DTextureClearTest, ClearRGBAF16)
+{
+    RunClearTest(DXGI_FORMAT_R16G16B16A16_FLOAT);
+}
+
+TEST_P(D3DTextureClearTest, ClearR16)
+{
+    RunClearTest(DXGI_FORMAT_R16_UNORM);
+}
+
+TEST_P(D3DTextureClearTest, ClearRG16)
+{
+    RunClearTest(DXGI_FORMAT_R16G16_UNORM);
 }
 
 TEST_P(D3DTextureTest, NonRenderableTextureImage)
@@ -1433,7 +1537,7 @@
     d3d11_texture->Release();
 }
 
-TEST_P(D3DTextureTest, TextureArrayImage)
+TEST_P(D3DTextureTest, TextureArray)
 {
     ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
 
@@ -1745,6 +1849,7 @@
 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
 // tests should be run against.
 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureTest);
+ANGLE_INSTANTIATE_TEST_ES2(D3DTextureClearTest);
 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureYUVTest);
 ANGLE_INSTANTIATE_TEST_ES3(D3DTextureTestES3);
 ANGLE_INSTANTIATE_TEST_ES3(D3DTextureYUVTestES3);