Creates separate bind points for read & write framebuffers.
TRAC #12712
Signed-off-by: Nicolas Capens
Signed-off-by: Daniel Koch

Author:    Shannon Woods

git-svn-id: https://angleproject.googlecode.com/svn/trunk@387 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index f711be0..9ee64d7 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -131,7 +131,8 @@
     bindElementArrayBuffer(0);
     bindTextureCubeMap(0);
     bindTexture2D(0);
-    bindFramebuffer(0);
+    bindReadFramebuffer(0);
+    bindDrawFramebuffer(0);
     bindRenderbuffer(0);
 
     for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
@@ -662,9 +663,14 @@
     mState.activeSampler = active;
 }
 
-GLuint Context::getFramebufferHandle() const
+GLuint Context::getReadFramebufferHandle() const
 {
-    return mState.framebuffer;
+    return mState.readFramebuffer;
+}
+
+GLuint Context::getDrawFramebufferHandle() const
+{
+    return mState.drawFramebuffer;
 }
 
 GLuint Context::getRenderbufferHandle() const
@@ -847,9 +853,14 @@
     return mResourceManager->getRenderbuffer(handle);
 }
 
-Framebuffer *Context::getFramebuffer()
+Framebuffer *Context::getReadFramebuffer()
 {
-    return getFramebuffer(mState.framebuffer);
+    return getFramebuffer(mState.readFramebuffer);
+}
+
+Framebuffer *Context::getDrawFramebuffer()
+{
+    return getFramebuffer(mState.drawFramebuffer);
 }
 
 void Context::bindArrayBuffer(unsigned int buffer)
@@ -884,14 +895,24 @@
     mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler].set(mState.textureCubeMap.get());
 }
 
-void Context::bindFramebuffer(GLuint framebuffer)
+void Context::bindReadFramebuffer(GLuint framebuffer)
 {
     if (!getFramebuffer(framebuffer))
     {
         mFramebufferMap[framebuffer] = new Framebuffer();
     }
 
-    mState.framebuffer = framebuffer;
+    mState.readFramebuffer = framebuffer;
+}
+
+void Context::bindDrawFramebuffer(GLuint framebuffer)
+{
+    if (!getFramebuffer(framebuffer))
+    {
+        mFramebufferMap[framebuffer] = new Framebuffer();
+    }
+
+    mState.drawFramebuffer = framebuffer;
 }
 
 void Context::bindRenderbuffer(GLuint renderbuffer)
@@ -1097,7 +1118,9 @@
       case GL_SHADER_BINARY_FORMATS:      /* no shader binary formats are supported */          break;
       case GL_ARRAY_BUFFER_BINDING:             *params = mState.arrayBuffer.id();              break;
       case GL_ELEMENT_ARRAY_BUFFER_BINDING:     *params = mState.elementArrayBuffer.id();       break;
-      case GL_FRAMEBUFFER_BINDING:              *params = mState.framebuffer;                   break;
+      //case GL_FRAMEBUFFER_BINDING:              // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
+      case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE:     *params = mState.drawFramebuffer;               break;
+      case GL_READ_FRAMEBUFFER_BINDING_ANGLE:     *params = mState.readFramebuffer;               break;
       case GL_RENDERBUFFER_BINDING:             *params = mState.renderbuffer.id();             break;
       case GL_CURRENT_PROGRAM:                  *params = mState.currentProgram;                break;
       case GL_PACK_ALIGNMENT:                   *params = mState.packAlignment;                 break;
@@ -1159,7 +1182,7 @@
       case GL_BLUE_BITS:
       case GL_ALPHA_BITS:
         {
-            gl::Framebuffer *framebuffer = getFramebuffer();
+            gl::Framebuffer *framebuffer = getDrawFramebuffer();
             gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer();
 
             if (colorbuffer)
@@ -1180,7 +1203,7 @@
         break;
       case GL_DEPTH_BITS:
         {
-            gl::Framebuffer *framebuffer = getFramebuffer();
+            gl::Framebuffer *framebuffer = getDrawFramebuffer();
             gl::DepthStencilbuffer *depthbuffer = framebuffer->getDepthbuffer();
 
             if (depthbuffer)
@@ -1195,7 +1218,7 @@
         break;
       case GL_STENCIL_BITS:
         {
-            gl::Framebuffer *framebuffer = getFramebuffer();
+            gl::Framebuffer *framebuffer = getDrawFramebuffer();
             gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer();
 
             if (stencilbuffer)
@@ -1392,7 +1415,7 @@
 {
     IDirect3DDevice9 *device = getDevice();
 
-    Framebuffer *framebufferObject = getFramebuffer();
+    Framebuffer *framebufferObject = getDrawFramebuffer();
 
     if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
     {
@@ -1530,7 +1553,7 @@
     GLint alwaysFront = !isTriangleMode(drawMode);
     programObject->setUniform1iv(pointsOrLines, 1, &alwaysFront);
 
-    Framebuffer *framebufferObject = getFramebuffer();
+    Framebuffer *framebufferObject = getDrawFramebuffer();
 
     if (mCullStateDirty || mFrontFaceDirty)
     {
@@ -1610,7 +1633,7 @@
 
     if (mStencilStateDirty || mFrontFaceDirty)
     {
-        if (mState.stencilTest && hasStencil())
+        if (mState.stencilTest && framebufferObject->hasStencil())
         {
             device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
             device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
@@ -1628,8 +1651,7 @@
             }
 
             // get the maximum size of the stencil ref
-            gl::Framebuffer *framebuffer = getFramebuffer();
-            gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+            gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer();
             GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1;
 
             device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask);
@@ -1681,7 +1703,7 @@
     {
         if (mState.polygonOffsetFill)
         {
-            gl::DepthStencilbuffer *depthbuffer = getFramebuffer()->getDepthbuffer();
+            gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer();
             if (depthbuffer)
             {
                 device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor));
@@ -1876,7 +1898,7 @@
 
 void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
 {
-    Framebuffer *framebuffer = getFramebuffer();
+    Framebuffer *framebuffer = getReadFramebuffer();
 
     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
     {
@@ -2110,7 +2132,7 @@
 
 void Context::clear(GLbitfield mask)
 {
-    Framebuffer *framebufferObject = getFramebuffer();
+    Framebuffer *framebufferObject = getDrawFramebuffer();
 
     if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
     {
@@ -2639,11 +2661,17 @@
     // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this
     // image was attached in the currently bound framebuffer.
 
-    Framebuffer *framebuffer = getFramebuffer();
+    Framebuffer *readFramebuffer = getReadFramebuffer();
+    Framebuffer *drawFramebuffer = getDrawFramebuffer();
 
-    if (framebuffer)
+    if (readFramebuffer)
     {
-        framebuffer->detachTexture(texture);
+        readFramebuffer->detachTexture(texture);
+    }
+
+    if (drawFramebuffer && drawFramebuffer != readFramebuffer)
+    {
+        drawFramebuffer->detachTexture(texture);
     }
 }
 
@@ -2653,9 +2681,14 @@
     // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though
     // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero.
 
-    if (mState.framebuffer == framebuffer)
+    if (mState.readFramebuffer == framebuffer)
     {
-        bindFramebuffer(0);
+        bindReadFramebuffer(0);
+    }
+
+    if (mState.drawFramebuffer == framebuffer)
+    {
+        bindDrawFramebuffer(0);
     }
 }
 
@@ -2675,11 +2708,17 @@
     // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment
     // point to which this image was attached in the currently bound framebuffer.
 
-    Framebuffer *framebuffer = getFramebuffer();
+    Framebuffer *readFramebuffer = getReadFramebuffer();
+    Framebuffer *drawFramebuffer = getDrawFramebuffer();
 
-    if (framebuffer)
+    if (readFramebuffer)
     {
-        framebuffer->detachRenderbuffer(renderbuffer);
+        readFramebuffer->detachRenderbuffer(renderbuffer);
+    }
+
+    if (drawFramebuffer && drawFramebuffer != readFramebuffer)
+    {
+        drawFramebuffer->detachRenderbuffer(renderbuffer);
     }
 }
 
@@ -2751,23 +2790,6 @@
     return false;
 }
 
-bool Context::hasStencil()
-{
-    Framebuffer *framebufferObject = getFramebuffer();
-
-    if (framebufferObject && framebufferObject->getStencilbufferType() != GL_NONE)
-    {
-        DepthStencilbuffer *stencilbufferObject = framebufferObject->getStencilbuffer();
-
-        if (stencilbufferObject)
-        {
-            return stencilbufferObject->getStencilSize() > 0;
-        }
-    }
-
-    return false;
-}
-
 void Context::setVertexAttrib(GLuint index, const GLfloat *values)
 {
     ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index adfd5bd..27a556d 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -181,7 +181,8 @@
     BindingPointer<Buffer> elementArrayBuffer;
     BindingPointer<Texture> texture2D;
     BindingPointer<Texture> textureCubeMap;
-    GLuint framebuffer;
+    GLuint readFramebuffer;
+    GLuint drawFramebuffer;
     BindingPointer<Renderbuffer> renderbuffer;
     GLuint currentProgram;
 
@@ -273,7 +274,8 @@
 
     void setActiveSampler(int active);
 
-    GLuint getFramebufferHandle() const;
+    GLuint getReadFramebufferHandle() const;
+    GLuint getDrawFramebufferHandle() const;
     GLuint getRenderbufferHandle() const;
 
     GLuint getArrayBufferHandle() const;
@@ -314,7 +316,8 @@
     void bindElementArrayBuffer(GLuint buffer);
     void bindTexture2D(GLuint texture);
     void bindTextureCubeMap(GLuint texture);
-    void bindFramebuffer(GLuint framebuffer);
+    void bindReadFramebuffer(GLuint framebuffer);
+    void bindDrawFramebuffer(GLuint framebuffer);
     void bindRenderbuffer(GLuint renderbuffer);
     void useProgram(GLuint program);
 
@@ -337,7 +340,8 @@
     Texture2D *getTexture2D();
     TextureCubeMap *getTextureCubeMap();
     Texture *getSamplerTexture(unsigned int sampler, SamplerType type);
-    Framebuffer *getFramebuffer();
+    Framebuffer *getReadFramebuffer();
+    Framebuffer *getDrawFramebuffer();
 
     bool getFloatv(GLenum pname, GLfloat *params);
     bool getIntegerv(GLenum pname, GLint *params);
@@ -390,7 +394,6 @@
 
     bool cullSkipsDraw(GLenum drawMode);
     bool isTriangleMode(GLenum drawMode);
-    bool hasStencil();
 
     const egl::Config *const mConfig;
 
diff --git a/src/libGLESv2/Framebuffer.cpp b/src/libGLESv2/Framebuffer.cpp
index 8a457d5..9a6c38b 100644
--- a/src/libGLESv2/Framebuffer.cpp
+++ b/src/libGLESv2/Framebuffer.cpp
@@ -224,6 +224,21 @@
     return mStencilbufferPointer.id();
 }
 
+bool Framebuffer::hasStencil()
+{
+    if (mStencilbufferType != GL_NONE)
+    {
+        DepthStencilbuffer *stencilbufferObject = getStencilbuffer();
+
+        if (stencilbufferObject)
+        {
+            return stencilbufferObject->getStencilSize() > 0;
+        }
+    }
+
+    return false;
+}
+
 GLenum Framebuffer::completeness()
 {
     int width = 0;
diff --git a/src/libGLESv2/Framebuffer.h b/src/libGLESv2/Framebuffer.h
index 5f4e481..d328c92 100644
--- a/src/libGLESv2/Framebuffer.h
+++ b/src/libGLESv2/Framebuffer.h
@@ -57,6 +57,8 @@
     GLuint getDepthbufferHandle();
     GLuint getStencilbufferHandle();
 
+    bool hasStencil();
+
     virtual GLenum completeness();
 
   protected:
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 795f4b9..5fddf6f 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -180,7 +180,7 @@
 
     try
     {
-        if (target != GL_FRAMEBUFFER)
+        if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
         {
             return error(GL_INVALID_ENUM);
         }
@@ -189,7 +189,15 @@
 
         if (context)
         {
-            context->bindFramebuffer(framebuffer);
+            if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+            {
+                context->bindReadFramebuffer(framebuffer);
+            }
+            
+            if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+            {
+                context->bindDrawFramebuffer(framebuffer);
+            }
         }
     }
     catch(std::bad_alloc&)
@@ -559,7 +567,7 @@
 
     try
     {
-        if (target != GL_FRAMEBUFFER)
+        if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
         {
             return error(GL_INVALID_ENUM, 0);
         }
@@ -568,7 +576,15 @@
 
         if (context)
         {
-            gl::Framebuffer *framebuffer = context->getFramebuffer();
+            gl::Framebuffer *framebuffer = NULL;
+            if (target == GL_READ_FRAMEBUFFER_ANGLE)
+            {
+                framebuffer = context->getReadFramebuffer();
+            }
+            else
+            {
+                framebuffer = context->getDrawFramebuffer();
+            }
 
             return framebuffer->completeness();
         }
@@ -848,7 +864,7 @@
 
         if (context)
         {
-            gl::Framebuffer *framebuffer = context->getFramebuffer();
+            gl::Framebuffer *framebuffer = context->getReadFramebuffer();
             if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
             {
                 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
@@ -921,7 +937,7 @@
 
         if (context)
         {
-            gl::Framebuffer *framebuffer = context->getFramebuffer();
+            gl::Framebuffer *framebuffer = context->getReadFramebuffer();
             if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
             {
                 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
@@ -1569,7 +1585,8 @@
 
     try
     {
-        if (target != GL_FRAMEBUFFER || renderbuffertarget != GL_RENDERBUFFER)
+        if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+            || renderbuffertarget != GL_RENDERBUFFER)
         {
             return error(GL_INVALID_ENUM);
         }
@@ -1578,9 +1595,20 @@
 
         if (context)
         {
-            gl::Framebuffer *framebuffer = context->getFramebuffer();
+            gl::Framebuffer *framebuffer = NULL;
+            GLuint framebufferHandle = 0;
+            if (target == GL_READ_FRAMEBUFFER_ANGLE)
+            {
+                framebuffer = context->getReadFramebuffer();
+                framebufferHandle = context->getReadFramebufferHandle();
+            }
+            else 
+            {
+                framebuffer = context->getDrawFramebuffer();
+                framebufferHandle = context->getDrawFramebufferHandle();
+            }
 
-            if (context->getFramebufferHandle() == 0 || !framebuffer)
+            if (framebufferHandle == 0 || !framebuffer)
             {
                 return error(GL_INVALID_OPERATION);
             }
@@ -1614,7 +1642,7 @@
 
     try
     {
-        if (target != GL_FRAMEBUFFER)
+        if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
         {
             return error(GL_INVALID_ENUM);
         }
@@ -1677,9 +1705,20 @@
                 }
             }
 
-            gl::Framebuffer *framebuffer = context->getFramebuffer();
+            gl::Framebuffer *framebuffer = NULL;
+            GLuint framebufferHandle = 0;
+            if (target == GL_READ_FRAMEBUFFER_ANGLE)
+            {
+                framebuffer = context->getReadFramebuffer();
+                framebufferHandle = context->getReadFramebufferHandle();
+            }
+            else
+            {
+                framebuffer = context->getDrawFramebuffer();
+                framebufferHandle = context->getDrawFramebufferHandle();
+            }
 
-            if (context->getFramebufferHandle() == 0 || !framebuffer)
+            if (framebufferHandle == 0 || !framebuffer)
             {
                 return error(GL_INVALID_OPERATION);
             }
@@ -2235,31 +2274,46 @@
 
         if (context)
         {
-            if (context->getFramebufferHandle() == 0)
-            {
-                return error(GL_INVALID_OPERATION);
-            }
-
-            if (target != GL_FRAMEBUFFER)
+            if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
             {
                 return error(GL_INVALID_ENUM);
             }
 
+            gl::Framebuffer *framebuffer = NULL;
+            if (target == GL_READ_FRAMEBUFFER_ANGLE)
+            {
+                if(context->getReadFramebufferHandle() == 0)
+                {
+                    return error(GL_INVALID_OPERATION);
+                }
+
+                framebuffer = context->getReadFramebuffer();
+            }
+            else 
+            {
+                if (context->getDrawFramebufferHandle() == 0)
+                {
+                    return error(GL_INVALID_OPERATION);
+                }
+
+                framebuffer = context->getDrawFramebuffer();
+            }
+
             GLenum attachmentType;
             GLuint attachmentHandle;
             switch (attachment)
             {
               case GL_COLOR_ATTACHMENT0:    
-                attachmentType = context->getFramebuffer()->getColorbufferType();
-                attachmentHandle = context->getFramebuffer()->getColorbufferHandle(); 
+                attachmentType = framebuffer->getColorbufferType();
+                attachmentHandle = framebuffer->getColorbufferHandle(); 
                 break;
               case GL_DEPTH_ATTACHMENT:     
-                attachmentType = context->getFramebuffer()->getDepthbufferType();
-                attachmentHandle = context->getFramebuffer()->getDepthbufferHandle();
+                attachmentType = framebuffer->getDepthbufferType();
+                attachmentHandle = framebuffer->getDepthbufferHandle();
                 break;
               case GL_STENCIL_ATTACHMENT:   
-                attachmentType = context->getFramebuffer()->getStencilbufferType();
-                attachmentHandle = context->getFramebuffer()->getStencilbufferHandle();
+                attachmentType = framebuffer->getStencilbufferType();
+                attachmentHandle = framebuffer->getStencilbufferHandle();
                 break;
               default: return error(GL_INVALID_ENUM);
             }