Test RGB invalidate with user FBOs

When an RGB image is invalidated and then used as attachment, the
cleared alpha value was previously lost due to loadOp=DONT_CARE.  This
was fixed by making the following render pass use loadOp=CLEAR instead.
The test for this relied on RGB backbuffers, which is not easily
testable on many platforms.  This change adds a similar test using user
FBOs.

Bug: b/180139027
Bug: angleproject:6860
Change-Id: I11f408d6cd925b45bc9bcec455563cd23a226fec
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3536387
Reviewed-by: Ian Elliott <ianelliott@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index b53f90b..520dd7f 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -260,6 +260,7 @@
 // D3D does not support compressed textures where the base mip level is not a multiple of 4
 4841 D3D9 : DXT1CompressedTextureTest.NonBlockSizesMipLevels/* = SKIP
 4841 D3D11 : DXT1CompressedTextureTest.NonBlockSizesMipLevels/* = SKIP
+7109 D3D11 : ClearTestRGB_ES3.*/* = SKIP
 
 // Android
 6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
diff --git a/src/tests/gl_tests/ClearTest.cpp b/src/tests/gl_tests/ClearTest.cpp
index 45304da..a78162f 100644
--- a/src/tests/gl_tests/ClearTest.cpp
+++ b/src/tests/gl_tests/ClearTest.cpp
@@ -113,6 +113,9 @@
     }
 };
 
+class ClearTestRGB_ES3 : public ClearTestRGB
+{};
+
 // Each int parameter can have three values: don't clear, clear, or masked clear.  The bool
 // parameter controls scissor.
 using MaskedScissoredClearVariationsTestParams =
@@ -346,7 +349,7 @@
 
 // Invalidate the RGB default framebuffer and verify that the alpha channel is not cleared, and
 // stays set after drawing.
-TEST_P(ClearTestRGB, InvalidateDefaultFramebufferRGB)
+TEST_P(ClearTestRGB_ES3, InvalidateDefaultFramebufferRGB)
 {
     ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
 
@@ -358,9 +361,6 @@
     EGLint backbufferAlphaBits = 0;
     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &backbufferAlphaBits);
     ANGLE_SKIP_TEST_IF(backbufferAlphaBits != 0);
-    // glInvalidateFramebuffer() isn't supported with GLES 2.0
-    ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
-    ANGLE_SKIP_TEST_IF(IsD3D11());
 
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -380,8 +380,40 @@
     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
 }
 
+// Invalidate an RGB user framebuffer and verify that the alpha channel is not cleared, and
+// stays set after drawing.
+TEST_P(ClearTestRGB_ES3, InvalidateUserFramebufferRGB)
+{
+    ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
+
+    GLTexture texture;
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
+                 GL_UNSIGNED_BYTE, nullptr);
+
+    GLFramebuffer fbo;
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+    EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+    ASSERT_GL_NO_ERROR();
+
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+    // Verify that clearing alpha is ineffective on an RGB format.
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
+
+    // Invalidate the framebuffer contents.
+    const GLenum discards[] = {GL_COLOR_ATTACHMENT0};
+    glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards);
+
+    // Without an explicit clear, draw blue and make sure alpha is unaffected.  If RGB is emualted
+    // with RGBA, the previous invalidate shouldn't affect the alpha value.
+    drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
+}
+
 // Draw with a shader that outputs alpha=0.5. Readback and ensure that alpha=1.
-TEST_P(ClearTestRGB, ShaderOutputsAlphaVerifyReadingAlphaIsOne)
+TEST_P(ClearTestRGB_ES3, ShaderOutputsAlphaVerifyReadingAlphaIsOne)
 {
     ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
     glUseProgram(blueProgram);
@@ -394,9 +426,6 @@
     EGLint backbufferAlphaBits = 0;
     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &backbufferAlphaBits);
     ANGLE_SKIP_TEST_IF(backbufferAlphaBits != 0);
-    // glInvalidateFramebuffer() isn't supported with GLES 2.0
-    ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
-    ANGLE_SKIP_TEST_IF(IsD3D11());
 
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -2652,4 +2681,7 @@
                        ES2_METAL(),
                        ES3_METAL());
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClearTestRGB_ES3);
+ANGLE_INSTANTIATE_TEST(ClearTestRGB_ES3, ES3_D3D11(), ES3_VULKAN(), ES3_METAL());
+
 }  // anonymous namespace