WebGL: Add test for ES3 MRT feedback loops.
BUG=angleproject:1685
Change-Id: I0f1e24d7c27f0b3ef56f35debcd20f4c7cff8951
Reviewed-on: https://chromium-review.googlesource.com/425492
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
index 0964855..555f0a5 100644
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -41,6 +41,11 @@
const std::array<GLenum, 2> &drawBuffers,
GLenum expectedError);
+ // Called from RenderingFeedbackLoopWithDrawBuffers.
+ void drawBuffersFeedbackLoop(GLuint program,
+ const std::array<GLenum, 2> &drawBuffers,
+ GLenum expectedError);
+
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
};
@@ -596,67 +601,6 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
-// Test tests that texture copying feedback loops are properly rejected in WebGL.
-// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
-TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
-{
- GLTexture texture;
- glBindTexture(GL_TEXTURE_2D, texture.get());
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- 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);
-
- GLTexture texture2;
- glBindTexture(GL_TEXTURE_2D, texture2.get());
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- 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);
-
- GLFramebuffer framebuffer;
- glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
-
- // framebuffer should be FRAMEBUFFER_COMPLETE.
- ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
- ASSERT_GL_NO_ERROR();
-
- // testing copyTexImage2D
-
- // copyTexImage2D to same texture but different level
- glBindTexture(GL_TEXTURE_2D, texture.get());
- glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
- EXPECT_GL_NO_ERROR();
-
- // copyTexImage2D to same texture same level, invalid feedback loop
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
- EXPECT_GL_ERROR(GL_INVALID_OPERATION);
-
- // copyTexImage2D to different texture
- glBindTexture(GL_TEXTURE_2D, texture2.get());
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
- EXPECT_GL_NO_ERROR();
-
- // testing copyTexSubImage2D
-
- // copyTexSubImage2D to same texture but different level
- glBindTexture(GL_TEXTURE_2D, texture.get());
- glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
- EXPECT_GL_NO_ERROR();
-
- // copyTexSubImage2D to same texture same level, invalid feedback loop
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
- EXPECT_GL_ERROR(GL_INVALID_OPERATION);
-
- // copyTexSubImage2D to different texture
- glBindTexture(GL_TEXTURE_2D, texture2.get());
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
- EXPECT_GL_NO_ERROR();
-}
-
// Test for the max draw buffers and color attachments.
TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
{
@@ -862,6 +806,142 @@
drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
}
+// Test tests that texture copying feedback loops are properly rejected in WebGL.
+// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
+TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
+{
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D, texture.get());
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ 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);
+
+ GLTexture texture2;
+ glBindTexture(GL_TEXTURE_2D, texture2.get());
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ 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);
+
+ GLFramebuffer framebuffer;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
+
+ // framebuffer should be FRAMEBUFFER_COMPLETE.
+ ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ ASSERT_GL_NO_ERROR();
+
+ // testing copyTexImage2D
+
+ // copyTexImage2D to same texture but different level
+ glBindTexture(GL_TEXTURE_2D, texture.get());
+ glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
+ EXPECT_GL_NO_ERROR();
+
+ // copyTexImage2D to same texture same level, invalid feedback loop
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+
+ // copyTexImage2D to different texture
+ glBindTexture(GL_TEXTURE_2D, texture2.get());
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
+ EXPECT_GL_NO_ERROR();
+
+ // testing copyTexSubImage2D
+
+ // copyTexSubImage2D to same texture but different level
+ glBindTexture(GL_TEXTURE_2D, texture.get());
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
+ EXPECT_GL_NO_ERROR();
+
+ // copyTexSubImage2D to same texture same level, invalid feedback loop
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+
+ // copyTexSubImage2D to different texture
+ glBindTexture(GL_TEXTURE_2D, texture2.get());
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
+ EXPECT_GL_NO_ERROR();
+}
+
+void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
+ const std::array<GLenum, 2> &drawBuffers,
+ GLenum expectedError)
+{
+ glDrawBuffers(2, drawBuffers.data());
+
+ // Make sure framebuffer is complete before feedback loop detection
+ ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+ drawQuad(program, "aPosition", 0.5f, 1.0f, true);
+
+ // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
+ // it should be NO_ERROR"
+ EXPECT_GL_ERROR(expectedError);
+}
+
+// This tests that rendering feedback loops works as expected with WebGL 2.
+// Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
+TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
+{
+ const std::string vertexShader =
+ "#version 300 es\n"
+ "in vec4 aPosition;\n"
+ "out vec2 texCoord;\n"
+ "void main() {\n"
+ " gl_Position = aPosition;\n"
+ " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
+ "}\n";
+
+ const std::string fragmentShader =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "uniform sampler2D tex;\n"
+ "in vec2 texCoord;\n"
+ "out vec4 oColor;\n"
+ "void main() {\n"
+ " oColor = texture(tex, texCoord);\n"
+ "}\n";
+
+ GLsizei width = 8;
+ GLsizei height = 8;
+
+ GLint maxDrawBuffers = 0;
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
+ // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
+ ASSERT_GE(maxDrawBuffers, 2);
+
+ ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
+ glUseProgram(program.get());
+ glViewport(0, 0, width, height);
+
+ GLTexture tex0;
+ GLTexture tex1;
+ GLFramebuffer fbo;
+ FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
+ FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
+ ASSERT_GL_NO_ERROR();
+
+ glBindTexture(GL_TEXTURE_2D, tex1.get());
+ GLint texLoc = glGetUniformLocation(program.get(), "tex");
+ ASSERT_NE(-1, texLoc);
+ glUniform1i(texLoc, 0);
+
+ // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
+ ASSERT_GL_NO_ERROR();
+
+ drawBuffersFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
+ drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
+ GL_INVALID_OPERATION);
+ drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
@@ -874,9 +954,5 @@
ES2_OPENGLES(),
ES3_OPENGLES());
-ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest,
- ES3_D3D11(),
- ES3_OPENGL(),
- ES3_OPENGLES());
-
+ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
} // namespace