Merge remote branch 'origin/7.8'
[mesa.git] / src / mesa / main / fbobject.c
index c4454550dbca3fcd3238cfd759db2a58050b2c1c..8d44246618702de05c6eca96c694ffb224bf6806 100644 (file)
 #include "framebuffer.h"
 #include "hash.h"
 #include "macros.h"
-#include "mipmap.h"
 #include "renderbuffer.h"
 #include "state.h"
 #include "teximage.h"
 #include "texobj.h"
-#include "texstore.h"
-#include "texstate.h"
 
 
 /** Set this to 1 to help debug FBO incompleteness problems */
@@ -183,8 +180,12 @@ _mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
       return &fb->Attachment[BUFFER_COLOR0 + i];
    case GL_DEPTH_STENCIL_ATTACHMENT:
       /* fall-through */
+   case GL_DEPTH_BUFFER:
+      /* fall-through / new in GL 3.0 */
    case GL_DEPTH_ATTACHMENT_EXT:
       return &fb->Attachment[BUFFER_DEPTH];
+   case GL_STENCIL_BUFFER:
+      /* fall-through / new in GL 3.0 */
    case GL_STENCIL_ATTACHMENT_EXT:
       return &fb->Attachment[BUFFER_STENCIL];
    default:
@@ -377,8 +378,8 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
       }
       if (texImage->Width < 1 || texImage->Height < 1) {
          att_incomplete("teximage width/height=0");
-         _mesa_printf("texobj = %u\n", texObj->Name);
-         _mesa_printf("level = %d\n", att->TextureLevel);
+         printf("texobj = %u\n", texObj->Name);
+         printf("level = %d\n", att->TextureLevel);
          att->Complete = GL_FALSE;
          return;
       }
@@ -628,7 +629,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
       }
    }
 
-#ifndef FEATURE_OES_framebuffer_object
+#if !FEATURE_OES_framebuffer_object
    /* Check that all DrawBuffers are present */
    for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
       if (fb->ColorDrawBuffer[j] != GL_NONE) {
@@ -861,6 +862,9 @@ _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
  *
  * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
  *  GL_DEPTH_STENCIL_EXT or zero if error.
+ *
+ * XXX in the future when we support red-only and red-green formats
+ * we'll also return GL_RED and GL_RG.
  */
 GLenum
 _mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
@@ -954,7 +958,7 @@ renderbuffer_storage(GLenum target, GLenum internalFormat,
       /* NumSamples == 0 indicates non-multisampling */
       samples = 0;
    }
-   else if (samples > ctx->Const.MaxSamples) {
+   else if (samples > (GLsizei) ctx->Const.MaxSamples) {
       /* note: driver may choose to use more samples than what's requested */
       _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
       return;
@@ -987,7 +991,7 @@ renderbuffer_storage(GLenum target, GLenum internalFormat,
       assert(rb->Width == (GLuint) width);
       assert(rb->Height == (GLuint) height);
       rb->InternalFormat = internalFormat;
-      rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
+      rb->_BaseFormat = baseFormat;
       assert(rb->_BaseFormat != 0);
    }
    else {
@@ -1008,6 +1012,36 @@ renderbuffer_storage(GLenum target, GLenum internalFormat,
     */
 }
 
+#if FEATURE_OES_EGL_image
+void GLAPIENTRY
+_mesa_EGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image)
+{
+   struct gl_renderbuffer *rb;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.OES_EGL_image) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glEGLImageTargetRenderbufferStorageOES(unsupported)");
+      return;
+   }
+
+   if (target != GL_RENDERBUFFER) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "EGLImageTargetRenderbufferStorageOES");
+      return;
+   }
+
+   rb = ctx->CurrentRenderbuffer;
+   if (!rb) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "EGLImageTargetRenderbufferStorageOES");
+      return;
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
+}
+#endif
 
 /**
  * Helper function for _mesa_GetRenderbufferParameterivEXT() and
@@ -1149,11 +1183,20 @@ _mesa_IsFramebufferEXT(GLuint framebuffer)
 }
 
 
+/**
+ * Check if any of the attachments of the given framebuffer are textures
+ * (render to texture).  Call ctx->Driver.RenderTexture() for such
+ * attachments.
+ */
 static void
 check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
 {
    GLuint i;
    ASSERT(ctx->Driver.RenderTexture);
+
+   if (fb->Name == 0)
+      return; /* can't render to texture with winsys framebuffers */
+
    for (i = 0; i < BUFFER_COUNT; i++) {
       struct gl_renderbuffer_attachment *att = fb->Attachment + i;
       struct gl_texture_object *texObj = att->Texture;
@@ -1173,6 +1216,9 @@ check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
 static void
 check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
 {
+   if (fb->Name == 0)
+      return; /* can't render to texture with winsys framebuffers */
+
    if (ctx->Driver.FinishRenderTexture) {
       GLuint i;
       for (i = 0; i < BUFFER_COUNT; i++) {
@@ -1188,7 +1234,8 @@ check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
 void GLAPIENTRY
 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
 {
-   struct gl_framebuffer *newFb, *newFbread;
+   struct gl_framebuffer *newDrawFb, *newReadFb;
+   struct gl_framebuffer *oldDrawFb, *oldReadFb;
    GLboolean bindReadBuf, bindDrawBuf;
    GET_CURRENT_CONTEXT(ctx);
 
@@ -1237,74 +1284,88 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
 
    if (framebuffer) {
       /* Binding a user-created framebuffer object */
-      newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
-      if (newFb == &DummyFramebuffer) {
+      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
+      if (newDrawFb == &DummyFramebuffer) {
          /* ID was reserved, but no real framebuffer object made yet */
-         newFb = NULL;
+         newDrawFb = NULL;
       }
-      else if (!newFb && ctx->Extensions.ARB_framebuffer_object) {
+      else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
          /* All FBO IDs must be Gen'd */
          _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
          return;
       }
 
-      if (!newFb) {
+      if (!newDrawFb) {
         /* create new framebuffer object */
-        newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
-        if (!newFb) {
+        newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
+        if (!newDrawFb) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
            return;
         }
-         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
+         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
       }
-      newFbread = newFb;
+      newReadFb = newDrawFb;
    }
    else {
       /* Binding the window system framebuffer (which was originally set
        * with MakeCurrent).
        */
-      newFb = ctx->WinSysDrawBuffer;
-      newFbread = ctx->WinSysReadBuffer;
+      newDrawFb = ctx->WinSysDrawBuffer;
+      newReadFb = ctx->WinSysReadBuffer;
    }
 
-   ASSERT(newFb);
-   ASSERT(newFb != &DummyFramebuffer);
+   ASSERT(newDrawFb);
+   ASSERT(newDrawFb != &DummyFramebuffer);
+
+   /* save pointers to current/old framebuffers */
+   oldDrawFb = ctx->DrawBuffer;
+   oldReadFb = ctx->ReadBuffer;
+
+   /* check if really changing bindings */
+   if (oldDrawFb == newDrawFb)
+      bindDrawBuf = GL_FALSE;
+   if (oldReadFb == newReadFb)
+      bindReadBuf = GL_FALSE;
 
    /*
     * OK, now bind the new Draw/Read framebuffers, if they're changing.
+    *
+    * We also check if we're beginning and/or ending render-to-texture.
+    * When a framebuffer with texture attachments is unbound, call
+    * ctx->Driver.FinishRenderTexture().
+    * When a framebuffer with texture attachments is bound, call
+    * ctx->Driver.RenderTexture().
+    *
+    * Note that if the ReadBuffer has texture attachments we don't consider
+    * that a render-to-texture case.
     */
    if (bindReadBuf) {
-      if (ctx->ReadBuffer == newFbread) {
-         bindReadBuf = GL_FALSE; /* no change */
-      }
-      else {
-         FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-         _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
-      }
+      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+      /* check if old readbuffer was render-to-texture */
+      check_end_texture_render(ctx, oldReadFb);
+
+      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
    }
 
    if (bindDrawBuf) {
-      /* check if old FB had any texture attachments */
-      if (ctx->DrawBuffer->Name != 0) {
-         check_end_texture_render(ctx, ctx->DrawBuffer);
-      }
+      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
 
-      if (ctx->DrawBuffer == newFb) {
-         bindDrawBuf = GL_FALSE; /* no change */
-      }
-      else {
-         FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-         _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
-      }
+      /* check if old read/draw buffers were render-to-texture */
+      if (!bindReadBuf)
+         check_end_texture_render(ctx, oldReadFb);
 
-      if (newFb->Name != 0) {
-         /* check if newly bound framebuffer has any texture attachments */
-         check_begin_texture_render(ctx, newFb);
-      }
+      if (oldDrawFb != oldReadFb)
+         check_end_texture_render(ctx, oldDrawFb);
+
+      /* check if newly bound framebuffer has any texture attachments */
+      check_begin_texture_render(ctx, newDrawFb);
+
+      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
    }
 
    if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
-      ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread);
+      ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
    }
 }
 
@@ -1326,15 +1387,26 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
             ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
 
             /* check if deleting currently bound framebuffer object */
-            if (fb == ctx->DrawBuffer) {
-               /* bind default */
-               ASSERT(fb->RefCount >= 2);
-               _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+            if (ctx->Extensions.EXT_framebuffer_blit) {
+               /* separate draw/read binding points */
+               if (fb == ctx->DrawBuffer) {
+                  /* bind default */
+                  ASSERT(fb->RefCount >= 2);
+                  _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+               }
+               if (fb == ctx->ReadBuffer) {
+                  /* bind default */
+                  ASSERT(fb->RefCount >= 2);
+                  _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+               }
             }
-            if (fb == ctx->ReadBuffer) {
-               /* bind default */
-               ASSERT(fb->RefCount >= 2);
-               _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+            else {
+               /* only one binding point for read/draw buffers */
+               if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
+                  /* bind default */
+                  ASSERT(fb->RefCount >= 2);
+                  _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+               }    
             }
 
            /* remove from hash table immediately, to free the ID */
@@ -1487,6 +1559,7 @@ framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
       texObj = _mesa_lookup_texture(ctx, texture);
       if (texObj != NULL) {
          if (textarget == 0) {
+            /* XXX what's the purpose of this? */
             err = (texObj->Target != GL_TEXTURE_3D) &&
                 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
                 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
@@ -1497,6 +1570,13 @@ framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
                 : (texObj->Target != textarget);
          }
       }
+      else {
+         /* can't render to a non-existant texture */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glFramebufferTexture%sEXT(non existant texture)",
+                     caller);
+         return;
+      }
 
       if (err) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -1915,7 +1995,6 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
 void GLAPIENTRY
 _mesa_GenerateMipmapEXT(GLenum target)
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    GET_CURRENT_CONTEXT(ctx);
 
@@ -1934,8 +2013,12 @@ _mesa_GenerateMipmapEXT(GLenum target)
       return;
    }
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
+
+   if (texObj->BaseLevel >= texObj->MaxLevel) {
+      /* nothing to do */
+      return;
+   }
 
    _mesa_lock_texture(ctx, texObj);
    if (target == GL_TEXTURE_CUBE_MAP) {
@@ -2098,39 +2181,39 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
 
    /* Debug code */
    if (DEBUG_BLIT) {
-      _mesa_printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
-                   " 0x%x, 0x%x)\n",
-                   srcX0, srcY0, srcX1, srcY1,
-                   dstX0, dstY0, dstX1, dstY1,
-                   mask, filter);
+      printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
+            " 0x%x, 0x%x)\n",
+            srcX0, srcY0, srcX1, srcY1,
+            dstX0, dstY0, dstX1, dstY1,
+            mask, filter);
       if (colorReadRb) {
          const struct gl_renderbuffer_attachment *att;
 
          att = find_attachment(readFb, colorReadRb);
-         _mesa_printf("  Src FBO %u  RB %u (%dx%d)  ",
-                      readFb->Name, colorReadRb->Name,
-                      colorReadRb->Width, colorReadRb->Height);
+         printf("  Src FBO %u  RB %u (%dx%d)  ",
+               readFb->Name, colorReadRb->Name,
+               colorReadRb->Width, colorReadRb->Height);
          if (att && att->Texture) {
-            _mesa_printf("Tex %u  tgt 0x%x  level %u  face %u",
-                         att->Texture->Name,
-                         att->Texture->Target,
-                         att->TextureLevel,
-                         att->CubeMapFace);
+            printf("Tex %u  tgt 0x%x  level %u  face %u",
+                  att->Texture->Name,
+                  att->Texture->Target,
+                  att->TextureLevel,
+                  att->CubeMapFace);
          }
-         _mesa_printf("\n");
+         printf("\n");
 
          att = find_attachment(drawFb, colorDrawRb);
-         _mesa_printf("  Dst FBO %u  RB %u (%dx%d)  ",
-                      drawFb->Name, colorDrawRb->Name,
-                      colorDrawRb->Width, colorDrawRb->Height);
+         printf("  Dst FBO %u  RB %u (%dx%d)  ",
+               drawFb->Name, colorDrawRb->Name,
+               colorDrawRb->Width, colorDrawRb->Height);
          if (att && att->Texture) {
-            _mesa_printf("Tex %u  tgt 0x%x  level %u  face %u",
-                         att->Texture->Name,
-                         att->Texture->Target,
-                         att->TextureLevel,
-                         att->CubeMapFace);
+            printf("Tex %u  tgt 0x%x  level %u  face %u",
+                  att->Texture->Name,
+                  att->Texture->Target,
+                  att->TextureLevel,
+                  att->CubeMapFace);
          }
-         _mesa_printf("\n");
+         printf("\n");
       }
    }