Merge branch 'master' of git+ssh://michal@git.freedesktop.org/git/mesa/mesa into...
[mesa.git] / src / mesa / main / framebuffer.c
index 465197401b7b8ab0b99f852890a07505863916b7..c9b30d3252829993b796366dcf096f7928f441c3 100644 (file)
@@ -65,43 +65,9 @@ compute_depth_max(struct gl_framebuffer *fb)
       fb->_DepthMax = 0xffffffff;
    }
    fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
-   fb->_MRD = 1.0;  /* Minimum resolvable depth value, for polygon offset */
-}
-
 
-/**
- * Set the framebuffer's _DepthBuffer field, taking care of
- * reference counts, etc.
- */
-static void
-set_depth_renderbuffer(struct gl_framebuffer *fb,
-                       struct gl_renderbuffer *rb)
-{
-   if (fb->_DepthBuffer) {
-      _mesa_dereference_renderbuffer(&fb->_DepthBuffer);
-   }
-   fb->_DepthBuffer = rb;
-   if (rb) {
-      rb->RefCount++;
-   }
-}
-
-
-/**
- * Set the framebuffer's _StencilBuffer field, taking care of
- * reference counts, etc.
- */
-static void
-set_stencil_renderbuffer(struct gl_framebuffer *fb,
-                         struct gl_renderbuffer *rb)
-{
-   if (fb->_StencilBuffer) {
-      _mesa_dereference_renderbuffer(&fb->_StencilBuffer);
-   }
-   fb->_StencilBuffer = rb;
-   if (rb) {
-      rb->RefCount++;
-   }
+   /* Minimum resolvable depth value, for polygon offset */
+   fb->_MRD = 1.0 / fb->_DepthMaxF;
 }
 
 
@@ -166,6 +132,8 @@ _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
 
    _glthread_INIT_MUTEX(fb->Mutex);
 
+   fb->RefCount = 1;
+
    /* save the visual */
    fb->Visual = *visual;
 
@@ -198,7 +166,6 @@ void
 _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
 {
    if (fb) {
-      _glthread_DESTROY_MUTEX(fb->Mutex);
       _mesa_free_framebuffer_data(fb);
       _mesa_free(fb);
    }
@@ -215,48 +182,81 @@ _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
    GLuint i;
 
    assert(fb);
+   assert(fb->RefCount == 0);
+
+   _glthread_DESTROY_MUTEX(fb->Mutex);
 
    for (i = 0; i < BUFFER_COUNT; i++) {
       struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
       if (att->Renderbuffer) {
-         struct gl_renderbuffer *rb = att->Renderbuffer;
-         /* remove framebuffer's reference to renderbuffer */
-         _mesa_dereference_renderbuffer(&rb);
-         if (rb && rb->Name == 0) {
-            /* delete window system renderbuffer */
-            _mesa_dereference_renderbuffer(&rb);
+         _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
+      }
+      if (att->Texture) {
+         /* render to texture */
+         att->Texture->RefCount--;
+         if (att->Texture->RefCount == 0) {
+            GET_CURRENT_CONTEXT(ctx);
+            if (ctx) {
+               ctx->Driver.DeleteTexture(ctx, att->Texture);
+            }
          }
       }
       att->Type = GL_NONE;
-      att->Renderbuffer = NULL;
+      att->Texture = NULL;
    }
 
-   /* unbind depth/stencil to decr ref counts */
-   set_depth_renderbuffer(fb, NULL);
-   set_stencil_renderbuffer(fb, NULL);
+   /* unbind _Depth/_StencilBuffer to decr ref counts */
+   _mesa_reference_renderbuffer(&fb->_DepthBuffer, NULL);
+   _mesa_reference_renderbuffer(&fb->_StencilBuffer, NULL);
+}
+
+
+/**
+ * Set *ptr to point to fb, with refcounting and locking.
+ */
+void
+_mesa_reference_framebuffer(struct gl_framebuffer **ptr,
+                            struct gl_framebuffer *fb)
+{
+   assert(ptr);
+   if (*ptr == fb) {
+      /* no change */
+      return;
+   }
+   if (*ptr) {
+      _mesa_unreference_framebuffer(ptr);
+   }
+   assert(!*ptr);
+   assert(fb);
+   _glthread_LOCK_MUTEX(fb->Mutex);
+   fb->RefCount++;
+   _glthread_UNLOCK_MUTEX(fb->Mutex);
+   *ptr = fb;
 }
 
 
 /**
- * Decrement the reference count on a framebuffer and delete it when
+ * Undo/remove a reference to a framebuffer object.
+ * Decrement the framebuffer object's reference count and delete it when
  * the refcount hits zero.
- * Note: we pass the address of a pointer and set it to NULL if we delete it.
+ * Note: we pass the address of a pointer and set it to NULL.
  */
 void
-_mesa_dereference_framebuffer(struct gl_framebuffer **fb)
+_mesa_unreference_framebuffer(struct gl_framebuffer **fb)
 {
-   GLboolean deleteFlag = GL_FALSE;
+   assert(fb);
+   if (*fb) {
+      GLboolean deleteFlag = GL_FALSE;
 
-   _glthread_LOCK_MUTEX((*fb)->Mutex);
-   {
+      _glthread_LOCK_MUTEX((*fb)->Mutex);
       ASSERT((*fb)->RefCount > 0);
       (*fb)->RefCount--;
       deleteFlag = ((*fb)->RefCount == 0);
-   }
-   _glthread_UNLOCK_MUTEX((*fb)->Mutex);
+      _glthread_UNLOCK_MUTEX((*fb)->Mutex);
+      
+      if (deleteFlag)
+         (*fb)->Delete(*fb);
 
-   if (deleteFlag) {
-      (*fb)->Delete(*fb);
       *fb = NULL;
    }
 }
@@ -535,13 +535,13 @@ _mesa_update_depth_buffer(GLcontext *ctx,
          /* need to update wrapper */
          struct gl_renderbuffer *wrapper
             = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
-         set_depth_renderbuffer(fb, wrapper);
+         _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper);
          ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
       }
    }
    else {
       /* depthRb may be null */
-      set_depth_renderbuffer(fb, depthRb);
+      _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb);
    }
 }
 
@@ -576,13 +576,13 @@ _mesa_update_stencil_buffer(GLcontext *ctx,
          /* need to update wrapper */
          struct gl_renderbuffer *wrapper
             = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
-         set_stencil_renderbuffer(fb, wrapper);
+         _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper);
          ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
       }
    }
    else {
       /* stencilRb may be null */
-      set_stencil_renderbuffer(fb, stencilRb);
+      _mesa_reference_renderbuffer(&fb->_StencilBuffer, stencilRb);
    }
 }
 
@@ -605,21 +605,25 @@ update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
       GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
       GLuint count = 0;
       GLuint i;
-      /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
-       * can specify writing to two or four color buffers (for example).
-       */
-      for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
-         const GLuint bufferBit = 1 << i;
-         if (bufferBit & bufferMask) {
-            struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
-            if (rb) {
-               fb->_ColorDrawBuffers[output][count] = rb;
-               count++;
+      if (!fb->DeletePending) {
+         /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
+          * can specify writing to two or four color buffers (for example).
+          */
+         for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
+            const GLuint bufferBit = 1 << i;
+            if (bufferBit & bufferMask) {
+               struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
+               if (rb && rb->Width > 0 && rb->Height > 0) {
+                  fb->_ColorDrawBuffers[output][count] = rb;
+                  count++;
+               }
+               else {
+                  /*
+                  _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
+                  */
+               }
+               bufferMask &= ~bufferBit;
             }
-            else {
-               /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
-            }
-            bufferMask &= ~bufferBit;
          }
       }
       fb->_NumColorDrawBuffers[output] = count;
@@ -635,7 +639,10 @@ static void
 update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
 {
    (void) ctx;
-   if (fb->_ColorReadBufferIndex == -1) {
+   if (fb->_ColorReadBufferIndex == -1 ||
+       fb->DeletePending ||
+       fb->Width == 0 ||
+       fb->Height == 0) {
       fb->_ColorReadBuffer = NULL; /* legal! */
    }
    else {
@@ -647,6 +654,27 @@ update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
 }
 
 
+static void
+update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
+{
+   /* Completeness only matters for user-created framebuffers */
+   if (fb->Name != 0) {
+      /* XXX: EXT_framebuffer_blit:
+         framebuffer must still be complete wrt read/draw? */
+      _mesa_test_framebuffer_completeness(ctx, fb);
+      _mesa_update_framebuffer_visual(fb);
+   }
+
+   /* update_color_draw/read_buffers not needed for
+      read/draw only fb, but shouldn't hurt ??? */
+   update_color_draw_buffers(ctx, fb);
+   update_color_read_buffer(ctx, fb);
+   _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
+   _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
+
+   compute_depth_max(fb);
+}
+
 /**
  * Update state related to the current draw/read framebuffers.
  * Specifically, update these framebuffer fields:
@@ -664,19 +692,11 @@ void
 _mesa_update_framebuffer(GLcontext *ctx)
 {
    struct gl_framebuffer *fb = ctx->DrawBuffer;
+   struct gl_framebuffer *fbread = ctx->ReadBuffer;
 
-   /* Completeness only matters for user-created framebuffers */
-   if (fb->Name != 0) {
-      _mesa_test_framebuffer_completeness(ctx, fb);
-      _mesa_update_framebuffer_visual(fb);
-   }
-
-   update_color_draw_buffers(ctx, fb);
-   update_color_read_buffer(ctx, fb);
-   _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
-   _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
-
-   compute_depth_max(fb);
+   update_framebuffer(ctx, fb);
+   if (fbread != fb)
+      update_framebuffer(ctx, fbread);
 }