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/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp
index 1f4f4e0..566de45 100644
--- a/src/libANGLE/renderer/gl/FramebufferGL.cpp
+++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp
@@ -8,6 +8,7 @@
 
 #include "libANGLE/renderer/gl/FramebufferGL.h"
 
+#include "common/BitSetIterator.h"
 #include "common/debug.h"
 #include "libANGLE/Data.h"
 #include "libANGLE/State.h"
@@ -21,10 +22,12 @@
 #include "libANGLE/renderer/gl/WorkaroundsGL.h"
 #include "platform/Platform.h"
 
+using namespace gl;
+
 namespace rx
 {
 
-FramebufferGL::FramebufferGL(const gl::Framebuffer::Data &data,
+FramebufferGL::FramebufferGL(const Framebuffer::Data &data,
                              const FunctionsGL *functions,
                              StateManagerGL *stateManager,
                              const WorkaroundsGL &workarounds,
@@ -43,7 +46,7 @@
 }
 
 FramebufferGL::FramebufferGL(GLuint id,
-                             const gl::Framebuffer::Data &data,
+                             const Framebuffer::Data &data,
                              const FunctionsGL *functions,
                              const WorkaroundsGL &workarounds,
                              StateManagerGL *stateManager)
@@ -62,14 +65,15 @@
     mFramebufferID = 0;
 }
 
-static void BindFramebufferAttachment(const FunctionsGL *functions, GLenum attachmentPoint,
-                                      const gl::FramebufferAttachment *attachment)
+static void BindFramebufferAttachment(const FunctionsGL *functions,
+                                      GLenum attachmentPoint,
+                                      const FramebufferAttachment *attachment)
 {
     if (attachment)
     {
         if (attachment->type() == GL_TEXTURE)
         {
-            const gl::Texture *texture = attachment->getTexture();
+            const Texture *texture     = attachment->getTexture();
             const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
 
             if (texture->getTarget() == GL_TEXTURE_2D)
@@ -94,7 +98,7 @@
         }
         else if (attachment->type() == GL_RENDERBUFFER)
         {
-            const gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
+            const Renderbuffer *renderbuffer     = attachment->getRenderbuffer();
             const RenderbufferGL *renderbufferGL = GetImplAs<RenderbufferGL>(renderbuffer);
 
             functions->framebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER,
@@ -112,74 +116,13 @@
     }
 }
 
-void FramebufferGL::onUpdateColorAttachment(size_t index)
-{
-    if (!mIsDefault)
-    {
-        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
-        BindFramebufferAttachment(mFunctions, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
-                                  mData.getColorAttachment(static_cast<unsigned int>(index)));
-    }
-}
-
-void FramebufferGL::onUpdateDepthAttachment()
-{
-    if (!mIsDefault)
-    {
-        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
-        BindFramebufferAttachment(mFunctions,
-                                  GL_DEPTH_ATTACHMENT,
-                                  mData.getDepthAttachment());
-    }
-}
-
-void FramebufferGL::onUpdateStencilAttachment()
-{
-    if (!mIsDefault)
-    {
-        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
-        BindFramebufferAttachment(mFunctions,
-                                  GL_STENCIL_ATTACHMENT,
-                                  mData.getStencilAttachment());
-    }
-}
-
-void FramebufferGL::onUpdateDepthStencilAttachment()
-{
-    if (!mIsDefault)
-    {
-        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
-        BindFramebufferAttachment(mFunctions,
-                                  GL_DEPTH_STENCIL_ATTACHMENT,
-                                  mData.getDepthStencilAttachment());
-    }
-}
-
-void FramebufferGL::setDrawBuffers(size_t count, const GLenum *buffers)
-{
-    if (!mIsDefault)
-    {
-        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
-        mFunctions->drawBuffers(static_cast<GLsizei>(count), buffers);
-    }
-}
-
-void FramebufferGL::setReadBuffer(GLenum buffer)
-{
-    if (!mIsDefault)
-    {
-        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
-        mFunctions->readBuffer(buffer);
-    }
-}
-
-gl::Error FramebufferGL::discard(size_t count, const GLenum *attachments)
+Error FramebufferGL::discard(size_t count, const GLenum *attachments)
 {
     UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    return Error(GL_INVALID_OPERATION);
 }
 
-gl::Error FramebufferGL::invalidate(size_t count, const GLenum *attachments)
+Error FramebufferGL::invalidate(size_t count, const GLenum *attachments)
 {
     // Since this function is just a hint and not available until OpenGL 4.3, only call it if it is available.
     if (mFunctions->invalidateFramebuffer)
@@ -188,10 +131,12 @@
         mFunctions->invalidateFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count), attachments);
     }
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
-gl::Error FramebufferGL::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
+Error FramebufferGL::invalidateSub(size_t count,
+                                   const GLenum *attachments,
+                                   const gl::Rectangle &area)
 {
     // Since this function is just a hint and not available until OpenGL 4.3, only call it if it is available.
     if (mFunctions->invalidateSubFramebuffer)
@@ -201,98 +146,106 @@
                                              attachments, area.x, area.y, area.width, area.height);
     }
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
-gl::Error FramebufferGL::clear(const gl::Data &data, GLbitfield mask)
+Error FramebufferGL::clear(const Data &data, GLbitfield mask)
 {
     syncClearState(mask);
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clear(mask);
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
-gl::Error FramebufferGL::clearBufferfv(const gl::Data &data,
-                                       GLenum buffer,
-                                       GLint drawbuffer,
-                                       const GLfloat *values)
+Error FramebufferGL::clearBufferfv(const Data &data,
+                                   GLenum buffer,
+                                   GLint drawbuffer,
+                                   const GLfloat *values)
 {
     syncClearBufferState(buffer, drawbuffer);
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferfv(buffer, drawbuffer, values);
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
-gl::Error FramebufferGL::clearBufferuiv(const gl::Data &data,
-                                        GLenum buffer,
-                                        GLint drawbuffer,
-                                        const GLuint *values)
+Error FramebufferGL::clearBufferuiv(const Data &data,
+                                    GLenum buffer,
+                                    GLint drawbuffer,
+                                    const GLuint *values)
 {
     syncClearBufferState(buffer, drawbuffer);
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferuiv(buffer, drawbuffer, values);
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
-gl::Error FramebufferGL::clearBufferiv(const gl::Data &data,
-                                       GLenum buffer,
-                                       GLint drawbuffer,
-                                       const GLint *values)
+Error FramebufferGL::clearBufferiv(const Data &data,
+                                   GLenum buffer,
+                                   GLint drawbuffer,
+                                   const GLint *values)
 {
     syncClearBufferState(buffer, drawbuffer);
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferiv(buffer, drawbuffer, values);
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
-gl::Error FramebufferGL::clearBufferfi(const gl::Data &data,
-                                       GLenum buffer,
-                                       GLint drawbuffer,
-                                       GLfloat depth,
-                                       GLint stencil)
+Error FramebufferGL::clearBufferfi(const Data &data,
+                                   GLenum buffer,
+                                   GLint drawbuffer,
+                                   GLfloat depth,
+                                   GLint stencil)
 {
     syncClearBufferState(buffer, drawbuffer);
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
 GLenum FramebufferGL::getImplementationColorReadFormat() const
 {
-    const gl::FramebufferAttachment *readAttachment = getData().getReadAttachment();
+    const FramebufferAttachment *readAttachment = getData().getReadAttachment();
     GLenum internalFormat = readAttachment->getInternalFormat();
-    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
+    const InternalFormat &internalFormatInfo    = GetInternalFormatInfo(internalFormat);
     return internalFormatInfo.format;
 }
 
 GLenum FramebufferGL::getImplementationColorReadType() const
 {
-    const gl::FramebufferAttachment *readAttachment = getData().getReadAttachment();
+    const FramebufferAttachment *readAttachment = getData().getReadAttachment();
     GLenum internalFormat = readAttachment->getInternalFormat();
-    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
+    const InternalFormat &internalFormatInfo    = GetInternalFormatInfo(internalFormat);
     return internalFormatInfo.type;
 }
 
-gl::Error FramebufferGL::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
+Error FramebufferGL::readPixels(const State &state,
+                                const gl::Rectangle &area,
+                                GLenum format,
+                                GLenum type,
+                                GLvoid *pixels) const
 {
     // TODO: don't sync the pixel pack state here once the dirty bits contain the pixel pack buffer
     // binding
-    const gl::PixelPackState &packState = state.getPackState();
+    const PixelPackState &packState = state.getPackState();
     mStateManager->setPixelPackState(packState);
 
     mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID);
     mFunctions->readPixels(area.x, area.y, area.width, area.height, format, type, pixels);
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
-gl::Error FramebufferGL::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
-                              GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
+Error FramebufferGL::blit(const State &state,
+                          const gl::Rectangle &sourceArea,
+                          const gl::Rectangle &destArea,
+                          GLbitfield mask,
+                          GLenum filter,
+                          const Framebuffer *sourceFramebuffer)
 {
     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(sourceFramebuffer);
 
@@ -302,7 +255,7 @@
     mFunctions->blitFramebuffer(sourceArea.x, sourceArea.y, sourceArea.x1(), sourceArea.y1(),
                                 destArea.x, destArea.y, destArea.x1(), destArea.y1(), mask, filter);
 
-    return gl::Error(GL_NO_ERROR);
+    return Error(GL_NO_ERROR);
 }
 
 bool FramebufferGL::checkStatus() const
@@ -316,6 +269,53 @@
     return (status == GL_FRAMEBUFFER_COMPLETE);
 }
 
+void FramebufferGL::syncState(const Framebuffer::DirtyBits &dirtyBits)
+{
+    // Don't need to sync state for the default FBO.
+    if (mIsDefault)
+    {
+        return;
+    }
+
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+
+    for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
+    {
+        switch (dirtyBit)
+        {
+            case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
+                BindFramebufferAttachment(mFunctions, GL_DEPTH_ATTACHMENT,
+                                          mData.getDepthAttachment());
+                break;
+            case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
+                BindFramebufferAttachment(mFunctions, GL_STENCIL_ATTACHMENT,
+                                          mData.getStencilAttachment());
+                break;
+            case Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
+            {
+                const auto &drawBuffers = mData.getDrawBufferStates();
+                mFunctions->drawBuffers(static_cast<GLsizei>(drawBuffers.size()),
+                                        drawBuffers.data());
+                break;
+            }
+            case Framebuffer::DIRTY_BIT_READ_BUFFER:
+                mFunctions->readBuffer(mData.getReadBufferState());
+                break;
+            default:
+            {
+                ASSERT(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 &&
+                       dirtyBit < Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX);
+                size_t index =
+                    static_cast<size_t>(dirtyBit - Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
+                BindFramebufferAttachment(mFunctions,
+                                          static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index),
+                                          mData.getColorAttachment(index));
+                break;
+            }
+        }
+    }
+}
+
 GLuint FramebufferGL::getFramebufferID() const
 {
     return mFramebufferID;
@@ -369,7 +369,7 @@
             const auto &drawbufferState  = mData.getDrawBufferStates();
             const auto &colorAttachments = mData.getColorAttachments();
 
-            const gl::FramebufferAttachment *attachment = nullptr;
+            const FramebufferAttachment *attachment = nullptr;
             if (drawbufferState[drawBuffer] >= GL_COLOR_ATTACHMENT0 &&
                 drawbufferState[drawBuffer] < GL_COLOR_ATTACHMENT0 + colorAttachments.size())
             {
@@ -389,4 +389,4 @@
         }
     }
 }
-}
+}  // namespace rx