Implement FramebufferGL.

BUG=angleproject:885

Change-Id: Ifb5818f185236c671cd7f20ed352edb887b49675
Reviewed-on: https://chromium-review.googlesource.com/258420
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp
index 2679c99..08497e9 100644
--- a/src/libANGLE/renderer/gl/FramebufferGL.cpp
+++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp
@@ -10,126 +10,273 @@
 
 #include "common/debug.h"
 #include "libANGLE/State.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/gl/FunctionsGL.h"
+#include "libANGLE/renderer/gl/RenderBufferGL.h"
+#include "libANGLE/renderer/gl/StateManagerGL.h"
+#include "libANGLE/renderer/gl/TextureGL.h"
 
 namespace rx
 {
 
-FramebufferGL::FramebufferGL(const gl::Framebuffer::Data &data)
-    : FramebufferImpl(data)
-{}
+FramebufferGL::FramebufferGL(const gl::Framebuffer::Data &data, const FunctionsGL *functions, StateManagerGL *stateManager, bool isDefault)
+    : FramebufferImpl(data),
+      mFunctions(functions),
+      mStateManager(stateManager),
+      mFramebufferID(0)
+{
+    if (!isDefault)
+    {
+        mFunctions->genFramebuffers(1, &mFramebufferID);
+    }
+}
 
 FramebufferGL::~FramebufferGL()
-{}
+{
+    if (mFramebufferID != 0)
+    {
+        mFunctions->deleteFramebuffers(1, &mFramebufferID);
+        mFramebufferID = 0;
+    }
+}
+
+static void BindFramebufferAttachment(const FunctionsGL *functions, GLenum attachmentPoint,
+                                      const gl::FramebufferAttachment *attachment)
+{
+    if (attachment)
+    {
+        if (attachment->type() == GL_TEXTURE)
+        {
+            const gl::Texture *texture = GetAs<gl::TextureAttachment>(attachment)->getTexture();
+            const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
+
+            if (texture->getTarget() == GL_TEXTURE_2D)
+            {
+                functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D,
+                                                textureGL->getTextureID(), attachment->mipLevel());
+            }
+            else if (texture->getTarget() == GL_TEXTURE_CUBE_MAP)
+            {
+                functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, attachment->cubeMapFace(),
+                                                textureGL->getTextureID(), attachment->mipLevel());
+            }
+            else if (texture->getTarget() == GL_TEXTURE_2D_ARRAY || texture->getTarget() == GL_TEXTURE_3D)
+            {
+                functions->framebufferTextureLayer(GL_FRAMEBUFFER, attachmentPoint, textureGL->getTextureID(),
+                                                   attachment->mipLevel(), attachment->layer());
+            }
+            else
+            {
+                UNREACHABLE();
+            }
+        }
+        else if (attachment->type() == GL_RENDERBUFFER)
+        {
+            // TODO: support RenderbufferGL
+            UNIMPLEMENTED();
+
+            //const gl::Renderbuffer *renderbuffer = GetAs<gl::RenderbufferAttachment>(attachment)->getRenderbuffer();
+            //const RenderbufferGL *renderbufferGL = GetImplAs<RenderbufferGL>(renderbuffer);
+
+            //functions->framebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER,
+            //                                   renderbufferGL->getRenderbufferID());
+        }
+        else
+        {
+            UNREACHABLE();
+        }
+    }
+    else
+    {
+        // Unbind this attachment
+        functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D, 0, 0);
+    }
+}
 
 void FramebufferGL::setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment)
 {
-    //UNIMPLEMENTED();
+    if (mFramebufferID != 0)
+    {
+        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+        BindFramebufferAttachment(mFunctions, GL_COLOR_ATTACHMENT0 + index, attachment);
+    }
 }
 
 void FramebufferGL::setDepthAttachment(const gl::FramebufferAttachment *attachment)
 {
-    //UNIMPLEMENTED();
+    if (mFramebufferID != 0)
+    {
+        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+        BindFramebufferAttachment(mFunctions, GL_DEPTH_ATTACHMENT, attachment);
+    }
 }
 
 void FramebufferGL::setStencilAttachment(const gl::FramebufferAttachment *attachment)
 {
-    //UNIMPLEMENTED();
+    if (mFramebufferID != 0)
+    {
+        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+        BindFramebufferAttachment(mFunctions, GL_STENCIL_ATTACHMENT, attachment);
+    }
 }
 
 void FramebufferGL::setDepthStencilAttachment(const gl::FramebufferAttachment *attachment)
 {
-    //UNIMPLEMENTED();
+    if (mFramebufferID != 0)
+    {
+        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+        BindFramebufferAttachment(mFunctions, GL_DEPTH_STENCIL_ATTACHMENT, attachment);
+    }
 }
 
 void FramebufferGL::setDrawBuffers(size_t count, const GLenum *buffers)
 {
-    //UNIMPLEMENTED();
+    if (mFramebufferID != 0)
+    {
+        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+        mFunctions->drawBuffers(count, buffers);
+    }
 }
 
 void FramebufferGL::setReadBuffer(GLenum buffer)
 {
-    //UNIMPLEMENTED();
+    if (mFramebufferID != 0)
+    {
+        mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+        mFunctions->readBuffer(buffer);
+    }
 }
 
 gl::Error FramebufferGL::invalidate(size_t count, const GLenum *attachments)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    mFunctions->invalidateFramebuffer(GL_FRAMEBUFFER, count, attachments);
+    return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error FramebufferGL::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    mFunctions->invalidateSubFramebuffer(GL_FRAMEBUFFER, count, attachments, area.x, area.y, area.width, area.height);
+    return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error FramebufferGL::clear(const gl::State &state, GLbitfield mask)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mStateManager->setClearState(state, mask);
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    mFunctions->clear(mask);
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+static GLbitfield GetClearBufferMask(GLenum buffer)
+{
+    switch (buffer)
+    {
+      case GL_COLOR:          return GL_COLOR_BUFFER_BIT;
+      case GL_DEPTH:          return GL_DEPTH_BUFFER_BIT;
+      case GL_STENCIL:        return GL_STENCIL_BUFFER_BIT;
+      case GL_DEPTH_STENCIL:  return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
+      default: UNREACHABLE(); return 0;
+    }
 }
 
 gl::Error FramebufferGL::clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mStateManager->setClearState(state, GetClearBufferMask(buffer));
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    mFunctions->clearBufferfv(buffer, drawbuffer, values);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error FramebufferGL::clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mStateManager->setClearState(state, GetClearBufferMask(buffer));
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    mFunctions->clearBufferuiv(buffer, drawbuffer, values);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error FramebufferGL::clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mStateManager->setClearState(state, GetClearBufferMask(buffer));
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    mFunctions->clearBufferiv(buffer, drawbuffer, values);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error FramebufferGL::clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mStateManager->setClearState(state, GetClearBufferMask(buffer));
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 GLenum FramebufferGL::getImplementationColorReadFormat() const
 {
-    UNIMPLEMENTED();
-    return GLenum();
+    const gl::FramebufferAttachment *readAttachment = getData().getReadAttachment();
+    GLenum internalFormat = readAttachment->getInternalFormat();
+    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
+    return internalFormatInfo.format;
 }
 
 GLenum FramebufferGL::getImplementationColorReadType() const
 {
-    UNIMPLEMENTED();
-    return GLenum();
+    const gl::FramebufferAttachment *readAttachment = getData().getReadAttachment();
+    GLenum internalFormat = readAttachment->getInternalFormat();
+    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
+    return internalFormatInfo.type;
 }
 
 gl::Error FramebufferGL::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
 {
     const gl::PixelPackState &packState = state.getPackState();
 
+    // TODO: set pack state
     if (packState.rowLength != 0 || packState.skipRows != 0 || packState.skipPixels != 0)
     {
         UNIMPLEMENTED();
         return gl::Error(GL_INVALID_OPERATION, "invalid pixel store parameters in readPixels");
     }
 
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    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);
 }
 
 gl::Error FramebufferGL::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
                               GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(sourceFramebuffer);
+
+    mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
+    mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferID);
+
+    mFunctions->blitFramebuffer(sourceArea.x, sourceArea.y, sourceArea.x + sourceArea.width, sourceArea.y + sourceArea.height,
+                                destArea.x, destArea.y, destArea.x + destArea.width, destArea.y + destArea.height,
+                                mask, filter);
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 GLenum FramebufferGL::checkStatus() const
 {
-    UNIMPLEMENTED();
-    return GLenum();
+    mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+    return mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER);
+}
+
+GLuint FramebufferGL::getFramebufferID() const
+{
+    return mFramebufferID;
 }
 
 }