Commit dbce1f89 by Olli Etuaho Committed by Commit Bot

Fix trying to clear nonexistent FBO attachments

The D3D11 backend used to crash to a null pointer dereference if a glClearBuffer call was done on a nonexistent depth or stencil attachment. Validate for these conditions so that the backend can't crash in this case. BUG=angleproject:2827 TEST=angle_end2end_tests Change-Id: Iecee78d213d11d492d52f246b4b068e8b6f34244 Reviewed-on: https://chromium-review.googlesource.com/1233675Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent bf7cfbea
...@@ -3534,6 +3534,11 @@ void Context::clear(GLbitfield mask) ...@@ -3534,6 +3534,11 @@ void Context::clear(GLbitfield mask)
void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values) void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values)
{ {
if (buffer == GL_DEPTH && !getGLState().getDrawFramebuffer()->getDepthbuffer())
{
// It's not an error to try to clear a non-existent depth buffer, but it's a no-op.
return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer)); ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY( ANGLE_CONTEXT_TRY(
mGLState.getDrawFramebuffer()->clearBufferfv(this, buffer, drawbuffer, values)); mGLState.getDrawFramebuffer()->clearBufferfv(this, buffer, drawbuffer, values));
...@@ -3548,6 +3553,11 @@ void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *valu ...@@ -3548,6 +3553,11 @@ void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *valu
void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values) void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values)
{ {
if (buffer == GL_STENCIL && !getGLState().getDrawFramebuffer()->getStencilbuffer())
{
// It's not an error to try to clear a non-existent stencil buffer, but it's a no-op.
return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer)); ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY( ANGLE_CONTEXT_TRY(
mGLState.getDrawFramebuffer()->clearBufferiv(this, buffer, drawbuffer, values)); mGLState.getDrawFramebuffer()->clearBufferiv(this, buffer, drawbuffer, values));
......
...@@ -532,6 +532,80 @@ TEST_P(FramebufferTest_ES3, AttachmentWith3DLayers) ...@@ -532,6 +532,80 @@ TEST_P(FramebufferTest_ES3, AttachmentWith3DLayers)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Test that clearing the stencil buffer when the framebuffer only has a color attachment does not
// crash.
TEST_P(FramebufferTest_ES3, ClearNonexistentStencil)
{
GLRenderbuffer rbo;
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
GLint clearValue = 0;
glClearBufferiv(GL_STENCIL, 0, &clearValue);
// There's no error specified for clearing nonexistent buffers, it's simply a no-op.
EXPECT_GL_NO_ERROR();
}
// Test that clearing the depth buffer when the framebuffer only has a color attachment does not
// crash.
TEST_P(FramebufferTest_ES3, ClearNonexistentDepth)
{
GLRenderbuffer rbo;
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
GLfloat clearValue = 0.0f;
glClearBufferfv(GL_DEPTH, 0, &clearValue);
// There's no error specified for clearing nonexistent buffers, it's simply a no-op.
EXPECT_GL_NO_ERROR();
}
// Test that clearing a nonexistent color attachment does not crash.
TEST_P(FramebufferTest_ES3, ClearNonexistentColor)
{
GLRenderbuffer rbo;
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
std::vector<GLfloat> clearValue = {{0.0f, 1.0f, 0.0f, 1.0f}};
glClearBufferfv(GL_COLOR, 1, clearValue.data());
// There's no error specified for clearing nonexistent buffers, it's simply a no-op.
EXPECT_GL_NO_ERROR();
}
// Test that clearing the depth and stencil buffers when the framebuffer only has a color attachment
// does not crash.
TEST_P(FramebufferTest_ES3, ClearNonexistentDepthStencil)
{
GLRenderbuffer rbo;
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0);
// There's no error specified for clearing nonexistent buffers, it's simply a no-op.
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(FramebufferTest_ES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(FramebufferTest_ES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
class FramebufferTest_ES31 : public ANGLETest class FramebufferTest_ES31 : public ANGLETest
......
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