Commit cad97eee by Jamie Madill Committed by Commit Bot

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: 's avatarJamie Madill <jmadill@chromium.org>
parent 08c24e6e
...@@ -36,6 +36,11 @@ class WebGLCompatibilityTest : public ANGLETest ...@@ -36,6 +36,11 @@ class WebGLCompatibilityTest : public ANGLETest
void TearDown() override { ANGLETest::TearDown(); } void TearDown() override { ANGLETest::TearDown(); }
// Called from RenderingFeedbackLoopWithDrawBuffersEXT.
void drawBuffersEXTFeedbackLoop(GLuint program,
const std::array<GLenum, 2> &drawBuffers,
GLenum expectedError);
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr; PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
}; };
...@@ -504,6 +509,27 @@ TEST_P(WebGLCompatibilityTest, NPOT) ...@@ -504,6 +509,27 @@ TEST_P(WebGLCompatibilityTest, NPOT)
} }
} }
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. // Tests that a rendering feedback loop triggers a GL error under WebGL.
// Based on WebGL test conformance/renderbuffers/feedback-loop.html. // Based on WebGL test conformance/renderbuffers/feedback-loop.html.
TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop) TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
...@@ -526,12 +552,7 @@ TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop) ...@@ -526,12 +552,7 @@ TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
"}\n"; "}\n";
GLTexture texture; GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture.get()); FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
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);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -565,12 +586,7 @@ TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop) ...@@ -565,12 +586,7 @@ TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
// Drawing when texture is bound to an inactive uniform should succeed // Drawing when texture is bound to an inactive uniform should succeed
GLTexture texture2; GLTexture texture2;
glBindTexture(GL_TEXTURE_2D, texture2.get()); FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
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);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
...@@ -758,6 +774,94 @@ TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction) ...@@ -758,6 +774,94 @@ TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); 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 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest, ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
......
...@@ -78,9 +78,11 @@ class GLProgram ...@@ -78,9 +78,11 @@ class GLProgram
mHandle = LoadBinaryProgramES3(binary, binaryFormat); mHandle = LoadBinaryProgramES3(binary, binaryFormat);
} }
bool valid() const { return mHandle != 0; }
GLuint get() GLuint get()
{ {
ASSERT(mHandle != 0); ASSERT(valid());
return mHandle; return mHandle;
} }
...@@ -92,22 +94,22 @@ class GLProgram ...@@ -92,22 +94,22 @@ class GLProgram
#define ANGLE_GL_PROGRAM(name, vertex, fragment) \ #define ANGLE_GL_PROGRAM(name, vertex, fragment) \
priv::GLProgram name; \ priv::GLProgram name; \
name.makeRaster(vertex, fragment); \ name.makeRaster(vertex, fragment); \
ASSERT_NE(0u, name.get()); ASSERT_TRUE(name.valid());
#define ANGLE_GL_COMPUTE_PROGRAM(name, compute) \ #define ANGLE_GL_COMPUTE_PROGRAM(name, compute) \
priv::GLProgram name; \ priv::GLProgram name; \
name.makeCompute(compute); \ name.makeCompute(compute); \
ASSERT_NE(0u, name.get()); ASSERT_TRUE(name.valid());
#define ANGLE_GL_BINARY_OES_PROGRAM(name, binary, binaryFormat) \ #define ANGLE_GL_BINARY_OES_PROGRAM(name, binary, binaryFormat) \
priv::GLProgram name; \ priv::GLProgram name; \
name.makeBinaryOES(binary, binaryFormat); \ name.makeBinaryOES(binary, binaryFormat); \
ASSERT_NE(0u, name.get()); ASSERT_TRUE(name.valid());
#define ANGLE_GL_BINARY_ES3_PROGRAM(name, binary, binaryFormat) \ #define ANGLE_GL_BINARY_ES3_PROGRAM(name, binary, binaryFormat) \
priv::GLProgram name; \ priv::GLProgram name; \
name.makeBinaryES3(binary, binaryFormat); \ name.makeBinaryES3(binary, binaryFormat); \
ASSERT_NE(0u, name.get()); ASSERT_TRUE(name.valid());
} // namespace angle } // namespace angle
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment