Update FBO completeness checks for depth textures

Trac #20875
Signed-off-by: Nicolas Capens

- improve missing attachment logic to allow no color attachments
- disallow depth texture color attachments
- allow texture depth and stencil attachments
- update simulaneous depth/stencil logic

git-svn-id: https://angleproject.googlecode.com/svn/trunk@1113 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Framebuffer.cpp b/src/libGLESv2/Framebuffer.cpp
index 18c2d94..0f3969b 100644
--- a/src/libGLESv2/Framebuffer.cpp
+++ b/src/libGLESv2/Framebuffer.cpp
@@ -247,6 +247,7 @@
     int width = 0;
     int height = 0;
     int samples = -1;
+    bool missingAttachment = true;
 
     if (mColorbufferType != GL_NONE)
     {
@@ -286,6 +287,11 @@
             {
                 return GL_FRAMEBUFFER_UNSUPPORTED;
             }
+
+            if (dx2es::IsDepthFormat(d3dformat) || dx2es::IsStencilFormat(d3dformat))
+            {
+                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+            }
         }
         else
         {
@@ -296,10 +302,7 @@
         width = colorbuffer->getWidth();
         height = colorbuffer->getHeight();
         samples = colorbuffer->getSamples();
-    }
-    else
-    {
-        return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+        missingAttachment = false;
     }
 
     Renderbuffer *depthbuffer = NULL;
@@ -307,11 +310,6 @@
 
     if (mDepthbufferType != GL_NONE)
     {
-        if (mDepthbufferType != GL_RENDERBUFFER)
-        {
-            return GL_FRAMEBUFFER_UNSUPPORTED;   // Requires GL_OES_depth_texture
-        }
-
         depthbuffer = getDepthbuffer();
 
         if (!depthbuffer)
@@ -324,20 +322,45 @@
             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
         }
 
-        if (width == 0)
+        if (mDepthbufferType == GL_RENDERBUFFER)
+        {
+            if (!gl::IsDepthRenderable(depthbuffer->getInternalFormat()))
+            {
+                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+            }
+        }
+        else if (IsInternalTextureTarget(mDepthbufferType))
+        {
+            D3DFORMAT d3dformat = depthbuffer->getD3DFormat();
+
+            // depth texture attachments require OES/ANGLE_depth_texture
+            if (!context->supportsDepthTextures())
+            {
+                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+            }
+
+            if (!dx2es::IsDepthFormat(d3dformat))
+            {
+                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+            }
+        }
+        else
+        {
+            UNREACHABLE();
+            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+        }
+
+        if (missingAttachment)
         {
             width = depthbuffer->getWidth();
             height = depthbuffer->getHeight();
+            samples = depthbuffer->getSamples();
+            missingAttachment = false;
         }
         else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
         {
             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
         }
-
-        if (samples == -1)
-        {
-            samples = depthbuffer->getSamples();
-        }
         else if (samples != depthbuffer->getSamples())
         {
             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
@@ -346,11 +369,6 @@
 
     if (mStencilbufferType != GL_NONE)
     {
-        if (mStencilbufferType != GL_RENDERBUFFER)
-        {
-            return GL_FRAMEBUFFER_UNSUPPORTED;
-        }
-
         stencilbuffer = getStencilbuffer();
 
         if (!stencilbuffer)
@@ -363,34 +381,63 @@
             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
         }
 
-        if (width == 0)
+        if (mStencilbufferType == GL_RENDERBUFFER)
+        {
+            if (!gl::IsStencilRenderable(stencilbuffer->getInternalFormat()))
+            {
+                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+            }
+        }
+        else if (IsInternalTextureTarget(mStencilbufferType))
+        {
+            D3DFORMAT d3dformat = stencilbuffer->getD3DFormat();
+
+            // texture stencil attachments come along as part
+            // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
+            if (!context->supportsDepthTextures())
+            {
+                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+            }
+
+            if (!dx2es::IsStencilFormat(d3dformat))
+            {
+                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+            }
+        }
+        else
+        {
+            UNREACHABLE();
+            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+        }
+
+        if (missingAttachment)
         {
             width = stencilbuffer->getWidth();
             height = stencilbuffer->getHeight();
+            samples = stencilbuffer->getSamples();
+            missingAttachment = false;
         }
         else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
         {
             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
         }
-
-        if (samples == -1)
-        {
-            samples = stencilbuffer->getSamples();
-        }
         else if (samples != stencilbuffer->getSamples())
         {
             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
         }
     }
 
-    if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER)
+    // if we have both a depth and stencil buffer, they must refer to the same object
+    // since we only support packed_depth_stencil and not separate depth and stencil
+    if (depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
     {
-        if (depthbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES ||
-            stencilbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES ||
-            depthbuffer->getSerial() != stencilbuffer->getSerial())
-        {
-            return GL_FRAMEBUFFER_UNSUPPORTED;
-        }
+        return GL_FRAMEBUFFER_UNSUPPORTED;
+    }
+
+    // we need to have at least one attachment to be complete
+    if (missingAttachment)
+    {
+        return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
     }
 
     return GL_FRAMEBUFFER_COMPLETE;