WebGL: Add test for MRT feedback loop detection.
BUG=angleproject:1685
Change-Id: Id5b1a9bfc33bada014a77ba2cbf4c2b92981df2a
Reviewed-on: https://chromium-review.googlesource.com/425490
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
index c415a33..0964855 100644
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -36,6 +36,11 @@
void TearDown() override { ANGLETest::TearDown(); }
+ // Called from RenderingFeedbackLoopWithDrawBuffersEXT.
+ void drawBuffersEXTFeedbackLoop(GLuint program,
+ const std::array<GLenum, 2> &drawBuffers,
+ GLenum expectedError);
+
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
};
@@ -504,6 +509,27 @@
}
}
+template <typename T>
+void FillTexture2D(GLuint texture,
+ GLsizei width,
+ GLsizei height,
+ const T &onePixelData,
+ GLint level,
+ GLint internalFormat,
+ GLenum format,
+ GLenum type)
+{
+ std::vector<T> allPixelsData(width * height, onePixelData);
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
+ allPixelsData.data());
+ 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);
+}
+
// Tests that a rendering feedback loop triggers a GL error under WebGL.
// Based on WebGL test conformance/renderbuffers/feedback-loop.html.
TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
@@ -526,12 +552,7 @@
"}\n";
GLTexture texture;
- glBindTexture(GL_TEXTURE_2D, texture.get());
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
- 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);
+ FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
@@ -565,12 +586,7 @@
// Drawing when texture is bound to an inactive uniform should succeed
GLTexture texture2;
- glBindTexture(GL_TEXTURE_2D, texture2.get());
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
- 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);
+ FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
glActiveTexture(GL_TEXTURE1);
@@ -758,6 +774,94 @@
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
+void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
+ const std::array<GLenum, 2> &drawBuffers,
+ GLenum expectedError)
+{
+ glDrawBuffersEXT(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 GL_EXT_draw_buffers.
+// Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
+TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
+{
+ const std::string vertexShader =
+ "attribute vec4 aPosition;\n"
+ "varying vec2 texCoord;\n"
+ "void main() {\n"
+ " gl_Position = aPosition;\n"
+ " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
+ "}\n";
+
+ const std::string fragmentShader =
+ "#extension GL_EXT_draw_buffers : require\n"
+ "precision mediump float;\n"
+ "uniform sampler2D tex;\n"
+ "varying vec2 texCoord;\n"
+ "void main() {\n"
+ " gl_FragData[0] = texture2D(tex, texCoord);\n"
+ " gl_FragData[1] = texture2D(tex, texCoord);\n"
+ "}\n";
+
+ GLsizei width = 8;
+ GLsizei height = 8;
+
+ // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
+ // extension and gl_FragData semantics are changed to enforce indexing by zero always.
+ // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
+ if (/*!extensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
+ {
+ // No WEBGL_draw_buffers support -- this is legal.
+ return;
+ }
+
+ GLint maxDrawBuffers = 0;
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
+
+ if (maxDrawBuffers < 2)
+ {
+ std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
+ return;
+ }
+
+ 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);
+ ASSERT_GL_NO_ERROR();
+
+ // 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);
+
+ drawBuffersEXTFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}},
+ GL_INVALID_OPERATION);
+ drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
+ GL_INVALID_OPERATION);
+ drawBuffersEXTFeedbackLoop(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,