merge of glsl-compiler-1 branch
[mesa.git] / src / mesa / main / renderbuffer.c
index 4b15634a6c822382cea0a48e65480c3ba6bdb9e6..49706b52516405b04e7e8648c6328a4c13446dfd 100644 (file)
@@ -47,6 +47,8 @@
 #include "fbobject.h"
 #include "renderbuffer.h"
 
+#include "rbadaptors.h"
+
 
 /* 32-bit color index format.  Not a public format. */
 #define COLOR_INDEX32 0x424243
@@ -624,10 +626,10 @@ static void
 get_row_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
                GLint x, GLint y, void *values)
 {
-   const GLbyte *src = (const GLbyte *) rb->Data + 4 * (y * rb->Width + x);
+   const GLubyte *src = (const GLubyte *) rb->Data + 4 * (y * rb->Width + x);
    ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
    ASSERT(rb->_ActualFormat == GL_RGBA8);
-   _mesa_memcpy(values, src, 4 * count * sizeof(GLbyte));
+   _mesa_memcpy(values, src, 4 * count * sizeof(GLubyte));
 }
 
 
@@ -1190,18 +1192,22 @@ _mesa_soft_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
    ASSERT(rb->PutMonoValues);
 
    /* free old buffer storage */
-   if (rb->Data)
+   if (rb->Data) {
       _mesa_free(rb->Data);
-
-   /* allocate new buffer storage */
-   rb->Data = _mesa_malloc(width * height * pixelSize);
-   if (rb->Data == NULL) {
-      rb->Width = 0;
-      rb->Height = 0;
-      _mesa_error(ctx, GL_OUT_OF_MEMORY,
-                  "software renderbuffer allocation (%d x %d x %d)",
-                  width, height, pixelSize);
-      return GL_FALSE;
+      rb->Data = NULL;
+   }
+
+   if (width > 0 && height > 0) {
+      /* allocate new buffer storage */
+      rb->Data = _mesa_malloc(width * height * pixelSize);
+      if (rb->Data == NULL) {
+         rb->Width = 0;
+         rb->Height = 0;
+         _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                     "software renderbuffer allocation (%d x %d x %d)",
+                     width, height, pixelSize);
+         return GL_FALSE;
+      }
    }
 
    rb->Width = width;
@@ -1429,6 +1435,17 @@ put_mono_values_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb,
 }
 
 
+static void
+copy_buffer_alpha8(struct gl_renderbuffer* dst, struct gl_renderbuffer* src)
+{
+   ASSERT(dst->_ActualFormat == GL_ALPHA8);
+   ASSERT(src->_ActualFormat == GL_ALPHA8);
+   ASSERT(dst->Width == src->Width);
+   ASSERT(dst->Height == src->Height);
+
+   _mesa_memcpy(dst->Data, src->Data, dst->Width * dst->Height * sizeof(GLubyte));
+}
+
 
 /**********************************************************************/
 /**********************************************************************/
@@ -1456,7 +1473,7 @@ _mesa_init_renderbuffer(struct gl_renderbuffer *rb, GLuint name)
 
    rb->ClassID = 0;
    rb->Name = name;
-   rb->RefCount = 1;
+   rb->RefCount = 0;
    rb->Delete = _mesa_delete_renderbuffer;
 
    /* The rest of these should be set later by the caller of this function or
@@ -1509,7 +1526,7 @@ _mesa_new_renderbuffer(GLcontext *ctx, GLuint name)
 
 /**
  * Delete a gl_framebuffer.
- * This is the default function for framebuffer->Delete().
+ * This is the default function for renderbuffer->Delete().
  */
 void
 _mesa_delete_renderbuffer(struct gl_renderbuffer *rb)
@@ -1759,6 +1776,27 @@ _mesa_add_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb,
 }
 
 
+/**
+ * For framebuffers that use a software alpha channel wrapper
+ * created by _mesa_add_alpha_renderbuffer or _mesa_add_soft_renderbuffers,
+ * copy the back buffer alpha channel into the front buffer alpha channel.
+ */
+void
+_mesa_copy_soft_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb)
+{
+   if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer &&
+       fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer)
+      copy_buffer_alpha8(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer,
+                         fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
+
+
+   if (fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer &&
+       fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer)
+      copy_buffer_alpha8(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer,
+                         fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer);
+}
+
+
 /**
  * Add a software-based depth renderbuffer to the given framebuffer.
  * This is a helper routine for device drivers when creating a
@@ -2046,9 +2084,93 @@ _mesa_add_renderbuffer(struct gl_framebuffer *fb,
       assert(!rb->Name);
    }
 
+   /* If Mesa's compiled with deep color channels (16 or 32 bits / channel)
+    * and the device driver is expecting 8-bit values (GLubyte), we can
+    * use a "renderbuffer adaptor/wrapper" to do the necessary conversions.
+    */
+   if (rb->_BaseFormat == GL_RGBA) {
+      if (CHAN_BITS == 16 && rb->DataType == GL_UNSIGNED_BYTE) {
+         GET_CURRENT_CONTEXT(ctx);
+         rb = _mesa_new_renderbuffer_16wrap8(ctx, rb);
+      }
+      else if (CHAN_BITS == 32 && rb->DataType == GL_UNSIGNED_BYTE) {
+         GET_CURRENT_CONTEXT(ctx);
+         rb = _mesa_new_renderbuffer_32wrap8(ctx, rb);
+      }
+      else if (CHAN_BITS == 32 && rb->DataType == GL_UNSIGNED_SHORT) {
+         GET_CURRENT_CONTEXT(ctx);
+         rb = _mesa_new_renderbuffer_32wrap16(ctx, rb);
+      }
+   }
+
    fb->Attachment[bufferName].Type = GL_RENDERBUFFER_EXT;
    fb->Attachment[bufferName].Complete = GL_TRUE;
-   fb->Attachment[bufferName].Renderbuffer = rb;
+   _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, rb);
+}
+
+
+/**
+ * Remove the named renderbuffer from the given framebuffer.
+ */
+void
+_mesa_remove_renderbuffer(struct gl_framebuffer *fb, GLuint bufferName)
+{
+   struct gl_renderbuffer *rb;
+
+   assert(bufferName < BUFFER_COUNT);
+
+   rb = fb->Attachment[bufferName].Renderbuffer;
+   if (!rb)
+      return;
+
+   _mesa_reference_renderbuffer(&rb, NULL);
+
+   fb->Attachment[bufferName].Renderbuffer = NULL;
+}
+
+
+/**
+ * Set *ptr to point to rb.  If *ptr points to another renderbuffer,
+ * dereference that buffer first.  The new renderbuffer's refcount will
+ * be incremented.  The old renderbuffer's refcount will be decremented.
+ */
+void
+_mesa_reference_renderbuffer(struct gl_renderbuffer **ptr,
+                             struct gl_renderbuffer *rb)
+{
+   assert(ptr);
+   if (*ptr == rb) {
+      /* no change */
+      return;
+   }
+
+   if (*ptr) {
+      /* Unreference the old renderbuffer */
+      GLboolean deleteFlag = GL_FALSE;
+      struct gl_renderbuffer *oldRb = *ptr;
+
+      _glthread_LOCK_MUTEX(oldRb->Mutex);
+      ASSERT(oldRb->RefCount > 0);
+      oldRb->RefCount--;
+      /*printf("RB DECR %p to %d\n", (void*) oldRb, oldRb->RefCount);*/
+      deleteFlag = (oldRb->RefCount == 0);
+      _glthread_UNLOCK_MUTEX(oldRb->Mutex);
+
+      if (deleteFlag)
+         oldRb->Delete(oldRb);
+
+      *ptr = NULL;
+   }
+   assert(!*ptr);
+
+   if (rb) {
+      /* reference new renderbuffer */
+      _glthread_LOCK_MUTEX(rb->Mutex);
+      rb->RefCount++;
+      /*printf("RB REF  %p to %d\n", (void*)rb, rb->RefCount);*/
+      _glthread_UNLOCK_MUTEX(rb->Mutex);
+      *ptr = rb;
+   }
 }
 
 
@@ -2073,4 +2195,3 @@ _mesa_new_depthstencil_renderbuffer(GLcontext *ctx, GLuint name)
 
    return dsrb;
 }
-