Implement dirty bits for Framebuffer.
The dirty bits set the stage for performance improvements in D3D, but
don't actually reduce any of the redundant work just yet.
BUG=angleproject:1260
Change-Id: Ib84e6a9b7aa40c37c41790f492361b22faaf4742
Reviewed-on: https://chromium-review.googlesource.com/318730
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tryjob-Request: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/StateChangeTest.cpp b/src/tests/gl_tests/StateChangeTest.cpp
new file mode 100644
index 0000000..789e99f
--- /dev/null
+++ b/src/tests/gl_tests/StateChangeTest.cpp
@@ -0,0 +1,244 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// StateChangeTest:
+// Specifically designed for an ANGLE implementation of GL, these tests validate that
+// ANGLE's dirty bits systems don't get confused by certain sequences of state changes.
+//
+
+#include "test_utils/ANGLETest.h"
+
+using namespace angle;
+
+namespace
+{
+
+class StateChangeTest : public ANGLETest
+{
+ protected:
+ StateChangeTest() : mFramebuffer(0)
+ {
+ setWindowWidth(64);
+ setWindowHeight(64);
+ setConfigRedBits(8);
+ setConfigGreenBits(8);
+ setConfigBlueBits(8);
+ setConfigAlphaBits(8);
+
+ // Enable the no error extension to avoid syncing the FBO state on validation.
+ setNoErrorEnabled(true);
+ }
+
+ void SetUp() override
+ {
+ ANGLETest::SetUp();
+
+ glGenFramebuffers(1, &mFramebuffer);
+
+ mTextures.resize(2, 0);
+ glGenTextures(2, mTextures.data());
+
+ ASSERT_GL_NO_ERROR();
+ }
+
+ void TearDown() override
+ {
+ if (mFramebuffer != 0)
+ {
+ glDeleteFramebuffers(1, &mFramebuffer);
+ mFramebuffer = 0;
+ }
+
+ if (!mTextures.empty())
+ {
+ glDeleteTextures(static_cast<GLsizei>(mTextures.size()), mTextures.data());
+ mTextures.clear();
+ }
+
+ ANGLETest::TearDown();
+ }
+
+ GLuint mFramebuffer;
+ std::vector<GLuint> mTextures;
+};
+
+class StateChangeTestES3 : public StateChangeTest
+{
+ protected:
+ StateChangeTestES3() {}
+};
+
+} // anonymous namespace
+
+// Ensure that CopyTexImage2D syncs framebuffer changes.
+TEST_P(StateChangeTest, CopyTexImage2DSync)
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+
+ // Init first texture to red
+ glBindTexture(GL_TEXTURE_2D, mTextures[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ // Init second texture to green
+ glBindTexture(GL_TEXTURE_2D, mTextures[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+
+ // Copy in the red texture to the green one.
+ // CopyTexImage should sync the framebuffer attachment change.
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 16, 16, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ ASSERT_GL_NO_ERROR();
+}
+
+// Ensure that CopyTexSubImage2D syncs framebuffer changes.
+TEST_P(StateChangeTest, CopyTexSubImage2DSync)
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+
+ // Init first texture to red
+ glBindTexture(GL_TEXTURE_2D, mTextures[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ // Init second texture to green
+ glBindTexture(GL_TEXTURE_2D, mTextures[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+
+ // Copy in the red texture to the green one.
+ // CopyTexImage should sync the framebuffer attachment change.
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 16, 16);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ ASSERT_GL_NO_ERROR();
+}
+
+// Ensure that CopyTexSubImage3D syncs framebuffer changes.
+TEST_P(StateChangeTestES3, CopyTexSubImage3DSync)
+{
+ if (isD3D11())
+ {
+ // TODO(jmadill): Fix the bug in the D3D11 back-end.
+ std::cout << "Test diabled on D3D11." << std::endl;
+ return;
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+
+ // Init first texture to red
+ glBindTexture(GL_TEXTURE_3D, mTextures[0]);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 16, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[0], 0, 0);
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ // Init second texture to green
+ glBindTexture(GL_TEXTURE_3D, mTextures[1]);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 16, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[1], 0, 0);
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+
+ // Copy in the red texture to the green one.
+ // CopyTexImage should sync the framebuffer attachment change.
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[0], 0, 0);
+ glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 16, 16);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[1], 0, 0);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ ASSERT_GL_NO_ERROR();
+}
+
+// Ensure that BlitFramebuffer syncs framebuffer changes.
+TEST_P(StateChangeTestES3, BlitFramebufferSync)
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+
+ // Init first texture to red
+ glBindTexture(GL_TEXTURE_2D, mTextures[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ // Init second texture to green
+ glBindTexture(GL_TEXTURE_2D, mTextures[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+
+ // Change to the red textures and blit.
+ // BlitFramebuffer should sync the framebuffer attachment change.
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
+ 0);
+ glBlitFramebuffer(0, 0, 16, 16, 0, 0, 16, 16, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ ASSERT_GL_NO_ERROR();
+}
+
+// Ensure that ReadBuffer and DrawBuffers sync framebuffer changes.
+TEST_P(StateChangeTestES3, ReadBufferAndDrawBuffersSync)
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+
+ // Initialize two FBO attachments
+ glBindTexture(GL_TEXTURE_2D, mTextures[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
+ glBindTexture(GL_TEXTURE_2D, mTextures[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);
+
+ // Clear first attachment to red
+ GLenum bufs1[] = {GL_COLOR_ATTACHMENT0, GL_NONE};
+ glDrawBuffers(2, bufs1);
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Clear second texture to green
+ GLenum bufs2[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
+ glDrawBuffers(2, bufs2);
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Verify first attachment is red and second is green
+ glReadBuffer(GL_COLOR_ATTACHMENT1);
+ EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+
+ ASSERT_GL_NO_ERROR();
+}
+
+ANGLE_INSTANTIATE_TEST(StateChangeTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
+ANGLE_INSTANTIATE_TEST(StateChangeTestES3, ES3_D3D11(), ES3_OPENGL());